再探PBR--微表面模型
还记得面试被问到是否了解PBR的时候,我每次都能吟唱而出:“PBR基于能量守恒理论,能保证入射能量和出射能量一致,其中,漫反射由Lambert项模拟,而金属材质由Cook-Torrance项模拟,Cook-Torrance基于微表面模型包括法线分布,几何遮蔽以及菲涅尔反射项。”每当被问到这些问题,我心里都在祈祷面试官不会继续追问下去,因为我并不清楚这几个神奇的式子究竟是从哪里冒出来的,和它声称的“微表面”模型的联系在哪里(实际上工业界可能确实不关心这些问题)。
最近刷了一下UCSD CSE 272,并阅读了Eric[1],在这方面又有些新的感悟,随撰文记录。
1.再探微表面模型微表面模型假设了物体表面由无数微小表面构成的,这些微小表面的表现累积成了宏观上物体表面的表现。目前,网上很多流行的PBR教程都是这么描述的。然而,目前鲜有资料说明用更严谨的数学语言描述这些微表面的行为,微表面模型中法线分布D, 菲涅尔F以及几何遮蔽项G这些描述宏观统计表现的项是怎么”统计”出来的。而这就是本节的重点。
考虑一个微表面分布,如图1所示。
对于一个法线为 的物体表面(黑色线段),其由无数微表面构成( ...
再探体渲染(二)--Ray Marching 从理论到实现
前文中探讨了基于物理的体渲染的理论以及相关结论的推导。在本文中,我将展示如何按照前文推导的公式,在unity中实现一套基于ray marching的”丐版“体积雾(只支持方形,全局只能有一个volume)。最后,我们会简单讨论该方案的一些优化方案。
理论回顾关于体渲染的理论以及公式在上一篇文章中有详细介绍。
这里只列出几个重要的公式。
体渲染公式如下所示:
L_i(p,\omega) = L_o(p'',-\omega) Tr(p''\to p) + \int_{p\to p'} Tr(p'\to p)\sigma_t(p',\omega)L_s(p',\omega) dt (1)其中
Tr(p\to p') =\frac{L_o(p',\omega)}{L_o(p,\omega)}= e^{\int_0^d - \sigma_t(p+\omega t,\omega) dt} (2)
L_s(p,\omega) = \frac{\sigma_\alpha(p,\omega)}{\sigma_t (p,\omega)} L_e(p,\omega) + \frac{\sigma_{s} ...
再探体渲染(一)-- 理论
由于之前实习接触到体积雾相关的东西,想顺带把这一系列相关渲染技术复现一下,于是从这篇文章开始看起RayMarching实时体积云渲染入门(上) - 知乎 [1] 。实现到一半发现自己很多理论不扎实的地方(代码和公式没法联系到一起),遂重新研读了PBRT的Volume Rendering [2]部分。不得不说,这东西不隔一阵子梳理一下真的巨容易忘,也应了闫在课上说的”常看常新“了。
微分形式以下部分均来自[2]
对于一小段体积微元的出射强度 主要和一下几项有关:
吸收当入射光线穿过体微元时,其能量损失为
dL_o(p, \omega) = -\sigma_\alpha (p, \omega) L_i(p,-\omega) dt (1.1)其中, 为当前点吸收能量的多少。该项模拟了光线射入粒子内部造成的能量损失。
自发光由于光线穿过的微元内粒子的化学,辐射等现象导致的能量出射。其微分形式和吸收类似
dL_o(p,\omega) = \sigma_\alpha(p,\omega) L_e(p,\omega)dt (1.2)其中 为粒子的自发光强度。由于该现象在游戏中不常见,因此很少有和 ...
校招面试题汇总
收集校招面试中遇到的基础问题。
本人校招已结束,故停更。后面随缘更新。
八股C++C++构造函数能否为虚函数 不能,有两点原因
使用角度:虚函数主要用于在信息不全的情况下,使得重载的函数得到相应的调用。构造函数的目的是初始化实例,使用虚函数在这里没有实际意义。而且,构造函数是在创建对象时自己主动调用的,不可能通过父类的指针或者引用去调用,因此构造函数没有必要是虚函数。
实现角度:在C++中,对象的虚表指针(VPTR)是在构造函数调用后才建立的。因此,在调用构造函数时还不能确定对象的真实类型(因为子类会调用父类的构造函数),并且构造函数的作用是提供初始化,在对象生命周期中仅运行一次,不是对象的动态行为,也没有必要成为虚函数。
*析构函数与构造函数的区别:虚函数的作用在于通过父类的指针或者引用来调用它的时候可以变成调用子类的那个成员函数。而析构函数可以是虚函数,因为我们往往通过基类的指针来销毁对象。如果析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数,可能会导致资源泄露*
C++的构造函数中能否使用throw不能,原因:
构造函数异常的问题:如果构造函 ...
Unreal Advanced Locomotion Animation (一) 基础
本文为 虚幻4(UE4) 动画技术 深入浅出 高级运动系统 的笔记
项目设置这个教程基于Advanced Locomotion System的动画资源(在Advanced Locomotion System插件的CharacterAssets/MannequinSkeleton/AnimationExamples路径中) 上展开的。因此,需要订阅该插件后从中提取资源。
由于订阅插件到提取资源过程教程中介绍的不详细,这里给出详细步骤。
在Epic Games Launcher的商城中订阅Advanced Locomotion System(下简称ALS)插件。
由于ALS插件无法直接加入到现有项目中因此,需要创建一个临时项目。
在临时项目中,找到CharacterAssets/MannequinSkeleton/AnimationExample文件夹,右键文件夹选择Migrate。将文件夹迁移到目标项目的Content文件夹中。
骨骼-姿势-动画在UE中带有骨骼动画的资源都由一个Skeleton Mesh资源表示。其中一个Skeleton Mesh与一个Skeleton一一对应,且 ...
Position Based Dynamic (一)
本文简要介绍了目前游戏工业界中软体模拟的一种常用方法Position Based Dynamic的原理以及实现。本文分为两个部分:原理以及实现。原理部分主要解读2005年的论文[1],简要介绍了Position Based Dynamic的思想和原理。在实现部分,本文给出了一个基于Position Based Dynamic框架下的简单三角形模拟程序并详细解读了其代码。
原理 非刚性物体的模拟在当下的游戏产业日渐成为重要的组成部分 (懂得都懂)。相比传统模拟,游戏产业对求解结果的精确性并没有那么高的要求,相反如何快速高效的求出视觉上具有说服力的结果是游戏相关模拟技术关注的重点。因此,Position Based Dynamic(PBD)应运而生。相比于有限元,Material Point Method等更加准确的方法,PBD更关注数值稳定性以及模拟结果的说服力,这点在PBD如何处理碰撞上表现的尤为突出。相比传统方法中通过力的作用修正碰撞结果,PBD在处理碰撞时往往会先估计碰撞后系统的状态,再通过碰撞结果更新当前系统的状态。
PBD的世界 对于PBD方法, ...
Unity中的Newtonsoft.Json---(1)
最近在做实验室项目的过程中,碰到了需要用Json序列化数据并在unity中读取的需求。搜索网络,发现unity内置的json序列化以及反序列化工具均只支持有结构的数据,因此我试着在unity中引入Newtonsoft.Json来对数据做非序列化的访问和遍历。此帖为导入过程中的踩坑帖。
1. 下载Newtonsoft.Json二进制文件在Newtonsoft的官方网站 下载编译好的二进制文件
2. 导入Unity关于如何将编译好的库导入到unity,一篇知乎文章讲的很详细。然而,根据我的实际测试,导入过程完全不需要这么麻烦。
在解压缩上述的zip文件后能得到json库的源文件以及编译好的二进制dll。在[解压缩文件的根目录]/Bin/文件夹下,能看到不同.net版本的dll
选择最接近unity使用的.net版本即可,在unity中可通过edit/Project Settings/Player的Configuration中查看
虽然我的unity使用的.net版本是 .net standard 2.1,经实际测试使用netstandard2.0版本的dll文件不会出问题。
接着, ...
物质质点法--从理论到实现
本文为The Material Point Method for Simulating Continuum Materials 的笔记。首先本文介绍了push forward和pull back,它们为欧拉视角和拉格朗日视角之间的转换提供了重要视角。接着,本文从形变梯度,拉格朗日欧拉视角,压力的定义出发,根据动量守恒以及能量守恒推导了整个系统应遵守的核心方程。物质质点法采用了欧拉以及拉格朗日的混合视角,对空间给出了质点以及网格两种不同离散形式,本文还讨论了这两种离散形式之间物理量如何转化,以及核心方程的离散化形式。最后,本文给出了一个简单原始的mpm实现,并详细解读它的代码。
Push Forward and Pull Back对于一个双射映射,能找到 我们都有 有
对于任意映射 我们都能定义 ,
Push Forward和Pull back在拉格朗日视角和欧拉视角之间相互转换起着重要作用。它定义了如何看待两个变化着的系统的不变量。
形变梯度为了研究物体随时间形变的受力,我们通常会研究物体的deform空间以及reference空间。其中reference空间种物体处于不受任何力的自然 ...
如何在glsl中使用printf--debugPrintfExt
主要参考VulkanでShaderからprintfする方法
在shader中开启GL_EXT_debug_printf拓展可以很方便的在shader中使用print。用法为:
在shader开头开启GL_EXT_debug_printf拓展:
1#extension GL_EXT_debug_printf : enable
在shader中用和printf同样的方法调用debugPrintfEXT
123456void main(){ ... debugPrintfEXT("from mesh thread group %d %d %d\n",gl_GlobalInvocationID.x, gl_GlobalInvocationID.y, gl_GlobalInvocationID.z); ...}
接着需要在vulkan configurator中添加对这个拓展的支持。
在validation settings 中标红线处的选项改为Debug Printf Present
在vulkan创建instance的过程中需要初始化Vk ...
vulkan 光线追踪
1.准备部分需要添加的device extension:VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME,VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME以及 VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME在创建device的过程中,需要将其加到 VkDeviceCreateInfo 结构体的 ppEnabledExtensionNames 中。
123456vector<const char*> usedExtensions;...//添加其它extensionusedExtensions.push_back();...VkDeviceCreateInfo createInfo{};createInfo.ppEnabledExtensionNames = usedExtensions.data();
之后,我们可以通过VkPhysicalDeviceRayTracingPipelinePropertiesKHR 结构体取得vul ...