第十章 管道和组合
第十章 管道和组合public static T Pipe<T>(this T source, params Func<T, T>[] funcs){ return funcs.Aggregate(source, (current, func) => func(current));}
第四章 诚实函数、null 与 Option
第四章 诚实函数、null 与 Option诚实函数
诚实函数,我更愿意称其为: 可靠函数
诚实函数:
代码即文档,名称就是行为
健壮性强
// 非诚实函数public static int Divide(int numerator, int denominator){ return numerator / denominator;}//诚实函数public static int? Divide(int numerator, int denominator){ if(denominator == 0) return null; return numerator / denominator;}
null破坏代码健壮性的一大元凶就是null
我们有一些方法来解决这个问题
解决null的最终兵器:Option 类型
Option 类型的值有两种可能:
Some(value):表示确实有值。
None(或 null 的替代):表示值缺失。
Option类型示例
public abstract class Opti ...
无题
Anisotropy前提:
必须定义切线空间
normalTex 和 anisotropyTex必须使用同一组uv
参数:
anisotropyStrength(float): [0,1] 表示沿指定方向增加粗糙度,默认方向是切线方向
anisotropyRoataion(float):
anisotropyTexture(Texture)
r & g : anisotropy Dir in [-1,1] tangent, bitangent
b : anisotropy strength
映射rg: [0,1] -> [-1,1]
directonalAlphaRoughness = mix(materialAlphaRoughness, 1, anisotropyStrength^2)
其中:
materialAlphaRoughness = materialRoughness^2
materialRoughness: 设计师填入的粗糙度
anisotropyStrength: 设计师填入的各向异性强度
directionalAl ...
无题
Render Graph 是现代渲染引擎的一个中间层,下接RHI层,上接渲染管线.
为什么使用Render Graph传统渲染管线背景:
Render Graph 优势:
高效内存管理,只分配实际使用的资源 -一个pass的资源
自动处理同步点 -graph可以处理pass之间依赖
可维护性高 -pass高内聚,低耦合
名词
Render Graph: 渲染图,管理 Pass DAG
Pass: 一个完成的渲染过程,是Render Graph 的一个节点
主要原则
Resource Haldles:你无法直接处理资源,而是通过Handle来间接处理,如RTHandles,ComputeBuffers,RendererLists
资源访问限制:你只被允许在 Render Pass 的 Execution 中访问资源
显示Pass声明:你必须明确每个 Pass 读取和写入的资源
No Persistence每次Excute之间,资源没有持久性,即上次创建的资源无法在下一次中使用
持久性资源解决办法对于需要持久性的资源,你需要在Render Graph外部创建后导入.注意,Render ...
glTF格式入门(三)--Buffer,BufferView,Accessor
Buffer一个Buffer表示了一个二进制数据块.
BufferViewBufferView是对Buffer的切分.切分通过byteOffset和byteLength两个属性来定义.同时,每个BufferView对象包括了一个target属性,用于对BufferView引用的数据进行分类.
"bufferViews" : [ { "buffer" : 0, "byteOffset" : 0, "byteLength" : 6, "target" : 34963 }, { "buffer" : 0, "byteOffset" : 8, "byteLength" : 36, "target" : 34962 }
上图浅色部分(无意义部分)用于数据对齐.
34 ...
glTF格式入门(二)--glTF基本结构
glTF基本结构glTF文件本质上是一个Json文件,其描述了整个3D场景的内容.
glTF的元素可以将glTF的元素分为两类: 核心元素与拓展元素
核心元素
asset: 保留了glTF文件的元数据, 如版本号, 作者, 标题等信息.
scenes: 场景列表, 用于指定场景的层级结构.
nodes: 节点列表, 用于指定场景中的对象及其关系.
materials: 材质
meshes: 网格
accessors: 访问器列表, 用于指定缓冲区视图中的数据格式.
bufferViews: 缓冲区视图列表, 用于指定缓冲区中的数据.
buffers: 缓冲区列表, 用于存储二进制数据.
Textures: 纹理
Images: 图像列表, 用于指定纹理的图像数据.
Samplers: 采样器列表, 用于指定纹理的采样方式.
Animations: 动画
Cameras: 摄像机
Skins: 蒙皮
拓展元素拓展元素让glTF可以支持更多功能,比如压缩网格,透明材质,GPU Instancing等.
详细的拓展元素可以参考官方文档
外部数据引用二进制数据,比如3D对象的几何数据和纹理 ...
glTF格式入门(一)--概述
简介glTF(GL Transmission Format) 是一种3D模型格式.被称为是”3D”的JPEG.其主要优点有:
轻量化
快速加载
跨平台
包含完整3D数据,包括:
几何
材质
动画
场景结构与层级
为什么需要glTFglTF正如其名称所言,目标是在于作为一种便于传输的中间格式.
当前的各种3D格式并不能够方便地在互联网上进行传输,以及直接高效地进行渲染.glTF正是为了解决这个问题.
glTF相较于其他格式的优势在于:
OBJ: 简单,兼容好,但功能有限
FBX:功能强大,但专有格式,文件大
glTF:轻量,功能完全,便于传输.
路径追踪之重要性采样
困扰路径追踪的最大问题就在于–采样.重要性采样就是把宝贵的算力资源投入在收益更高的地方–好钢用在刀刃上.本文默认读者对路径追踪有基本了解,下文会介绍各种重要性采样.
光源重要性采样(Sampling Light)
对于p点来说,如果有一片区域是直接照亮p点的,那么可以通过将积分区域分为紫色和黄色两部分.令整个区域为$\Omega_+$紫色区域为$M$黄色区域为$\Omega_-$
那么我们就可以改写渲染方程:
$L = \int_{\Omega^-} L_i(p, \omega_i) f_r(p, \omega_i, \omega_o) (n \cdot \omega_i) \mathrm{d}\omega_i +\int_M L_i(p, \omega_i) f_r(p, \omega_i, \omega_o) (n \cdot \omega_i) \mathrm{d}\omega_i$
光源重要性采样是无偏的.
$\cos\theta$重要性采样(Cosine-Weighted Sampling)路径追踪中我们使用蒙特卡洛方法进行积分.积分效率最高(收敛最快)的情况为:p ...
Split Sum原理介绍
基于图像的光照(Image based lighting, IBL)是一类光照技术的集合.其光源不是如点光源等直接光源,而是将周围环境整体视为一个大光源.
那么在shader中我们有了一张cubeMap(也可能是别的形式),如何用它来实现PBS(Physically Based Shading)呢?
或者说,我们如何用一张环境贴图来解渲染方程呢?
首先回顾渲染方程:
$$L(p, \omega_o) = \int_{H^2} f(p, \omega_i \cdot \omega_o) L_i(p, \omega_i) V(p,wi) \cos \theta_i dw_i$$
在环境光照中,我们不考虑Visibility即不考虑阴影(任何方向光照都能到达),所以可以去除这一项:
$$L(p, \omega_o) = \int_{H^2} f(p, \omega_i \cdot \omega_o) L_i(p, \omega_i) \cos \theta_i dw_i$$
我们可以用蒙特卡洛方法来积分:
$$L(p, \omega_o) \approx \frac{1} ...
