学习《Shader入门精要》自我总结

参考了冯乐乐的入门精要

一、渲染管线三大阶段

应用准备阶段、几何变换阶段、光栅化阶段。

详细介绍各阶段

应用阶段:CPU将当前场景所包含的如:模型网格、纹理贴图等,从硬盘到内存,再到显存。数据细节是一些 顶点的 位置、法线、切线、颜色、纹理坐标等,还有设置一些渲染的状态如:所使用的顶点/片元着色器、光源属性、材质等。最后CPU调用图形API(Draw Call)驱动GPU进行绘制处理。

几何变换阶段:

(1)由顶点着色器接收上一阶段传递过来的顶点数据(模型空间的坐标、法线、切线、纹理坐标、颜色)。顶点着色器主要用于将顶点从

模型空间 -> 世界空间 -> 观察空间 -> 裁剪空间(齐次裁剪坐标系)。

(2)再由硬件做透视除法,得到归一化的设备坐标。OpenGL 所有轴是 -1 到 +1,DirectX 的Z轴是 0 到 1。

(3)裁剪操作将不在摄像机视野外的物体剔除。

(4)屏幕映射,将以上的三维坐标转换到二维的屏幕坐标。OpenGL左下角是(0,0)点,DirectX左上角是(0,0)点。

光栅化阶段:

(1)三角形的设置和遍历,根据上一步得到的屏幕坐标信息计算一个个的三角形,筛查每个三角网格所覆盖的像素点,每个被覆盖的像素进行插值处理生成片元。

(2)执行片元着色器,根据上一步生成的片元执行一系列颜色计算,如光照计算、纹理采样等。

(3)逐片元操作。如 模板测试 -> 深度测试 -> Alpha混合,再输出到颜色缓冲区。GPU会使用双重缓冲区,对场景的渲染是在幕后发生的,即后置缓冲区,一旦后置缓冲区工作完毕就会跟前置缓冲区交换,由此保证了我们看到画面是连续的。

名词解释:

裁剪空间:又叫齐次裁剪空间,裁剪空间的目标是能够方便的对渲染图元进行剪裁:完全位于这个空间的图元会被保留,完全在外的会被剔除,空间边界的会被裁剪。这块空间是由摄像机可看到空间,即一个视锥体决定的。视锥体的6个面叫裁剪平面。

视椎体(view frustum):会决定对渲染图元的裁剪,视椎体是决定摄像机可以看到的区域,由6个平面组成,称为裁剪平面,其中还有两个近裁剪平面(near clip plane)和远裁剪平面(far clip plane),其决定了摄像机可以看到的深度范围。视椎体还有两种类型:透视投影(perspective projection)和正交投影(orthographic projection)。

二、基础光照

兰伯特光照模型

c_diffuse漫反射 = c_light入射光强度 * m_diffuse反射系数 * max(0, n法线*l光源方向)

半兰伯特

c_diffuse漫反射 = c_light入射光强度 * m_diffuse反射系数 *(0.5*(n法线*l光源方向) + 0.5)

高光(镜面)反射光照模型

c_specular高光 = c_light入射光强度 * m_specular反射系数 * pow(max(0, v视角方向 * r反射方向), gloss光泽度)

phong光照模型 = 环境光 + 自发光 + 兰伯特光照模型 + 高光(镜面)反射光照模型

特殊高效的高光(镜面)反射光照模型

h半程向量 = (v视角方向 + l光照方向)的归一化

c_specular特殊的高光 = c_light入射光强度 * m_specular反射系数 * pow(max(0, n法线 * h半程向量), gloss光泽度)

blinn-phong光照模型 = 环境光 + 自发光 + 兰伯特光照模型 + 特殊的高光(镜面)反射光照模型

三、纹理

高度纹理:高度图存储的是强度值,用于表示模型表面局部的海拔高度。在实际的计算时不能直接得到表面法线,而是由像素的灰度值计算而得,需要消耗更多的性能。通常和法线映射一起使用。

法线纹理:存储的是表面法线的方向,法线方向的分量分布在[-1, 1],像素的分量分布在[0, 1],他们之间要做一个映射,像素->法线 是乘2减1。采用的坐标空间是模型顶点的切线空间,x轴是顶点的切线方向,z轴是顶点的法线方向,y轴副切线需要自己根据xz叉乘计算。

使用切线空间的优势:(1)自由度高,记录的是相对信息,应用到不同模型上也可以得到比较合理的结果(2)可用于UV动画,便于实现凹凸移动的效果(3)可复用,模型不同且相似的面可使用同一张法线纹理,如砖块的6个面(4)可压缩,移除总是正方面的Z方向。

遮罩纹理:保护某些区域,使他们免于修改。通常采样得到纹素值的某个通道值,乘以某种表面属性,当该通道值为0,可以保护表面不受该属性的影响。如 高光反射区域细分其中的强弱部分。

四、透明效果

透明度测试:只要一个片元的透明度不满足条件(通常小于某个阈值),那么它对应的片元就会被舍弃。否则就按照普通不透明物体来处理。通常,我们会在片元着色器中使用clip函数来进行透明度测试。

透明度混合:使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲区中的颜色值进行混合,得到新的颜色。透明度混合需要关闭深度写入。

默认混合公式:DstColor = SrcAlpha该片元的a通道值 * SrcColor该片元的颜色值 + (1 - SrcAlpha该片元的a通道值) * DstColor缓冲区的颜色值;

五、复杂光照

前向渲染路径:

最传统最常见的渲染方式。基本概念,每进行一次完整的前向渲染,需要渲染该对象的渲染图元,并计算两个缓冲区的信息:一个是颜色缓冲区,一个是深度缓冲区。利用深度缓冲区来决定一个片元是否可见,如果可见就更新颜色缓冲区的颜色值。

在Unity中,前向渲染路径有3种处理光照的方式:逐顶点、逐像素、球谐函数(SH)。决定一个光源使用哪种处理取决于它的类型和渲染模式。类型有 平行光、点光源、聚光灯等,渲染模式即设置它是否Important。(1)场景中最亮的平行光总是以逐像素处理(2)渲染模式设置成Important的光源,会使用逐像素(3)渲染模式设置成not Important的光源,会使用逐顶点或SH。

前向渲染路径的两种pass通道。BassPass:可实现的光照效果有 光照纹理、环境光、自发光、平行光的阴影,仅会执行一次。光照计算包括:一个逐像素平行光以及所有逐顶点和SH光源。AdditionalPass:可实现的光照效果 默认不支持阴影,可通过编译指令开启。光照计算包括:其他影响该物体的逐像素光源,每个光源执行一次Pass。

延迟渲染路径:

因为在场景中包含大量实时光源时,前向渲染执行的pass过多,性能会急速下降。延迟渲染只使用两个PAss,跟场景光源数目没有关系,每个光源都可以按逐像素的方式处理。

在第一个pass中不进行任何光照计算,仅仅计算哪些片元可见,这主要通过深度缓冲技术来实现,当发现一个片元是可见的,就把它相关信息(漫反射颜色、高光反射颜色、平滑度、法线、自发光、深度)存储到G缓冲区;在第二个pass中,利用G缓冲区各个片元信息进行真正的光照计算。

缺点:(1)不支持真正的抗锯齿(2)不能处理半透明物体(3)对显卡有一定的要求,ShaderMode 3.0及以上、深度渲染纹理以及双面的模板缓冲。

光照衰减:

Unity使用一张纹理作为查找表来在片元着色器中计算逐像素光照的衰减,好处是不依赖于数学公式的复杂性 _LightTexture0。缺点:需要预处理得到采样纹理,纹理的大小也会影响衰减的精度。把数据存储到查找表中,就无法使用其他数学公式来计算衰减。但是在一定程度上提升性能,Unity默认使用这种方式来计算逐像素的点光源和聚光灯的衰减的。

阴影:

基本概念:在前向渲染路径中,如果场景中最重要的平行光开启了阴影,Unity就会为该光源计算它的阴影映射纹理(shadowmap),本质上也是一张深度图。

传统的阴影映射纹理:把摄像机移动到光源位置得到的shadowmap的深度值是在光源空间下的,故而我们需要在正常渲染的pass中把顶点位置变换到光源空间中。然后,使用xy分量对阴影映射纹理进行采样,得到阴影纹理下的深度值,如果该深度值小于该顶点的深度值(z分量),说明该顶点被遮挡,也就是处于阴影的后面。

屏幕空间的阴影映射技术(需要显卡支持MRT):unity首先会通过调用LightMode为shadowcaster的pass来得到两张纹理,一张是可投射阴影的光源的阴影映射纹理(基于光源的位置得到的深度纹理),一张是摄像机的深度纹理(基于摄像机的位置得到的深度纹理),然后再根据这两张纹理得到屏幕空间的阴影图,摄像机的深度图记录了所有可见面片的深度,如果摄像机的深度图中记录的表面深度大于阴影映射纹理中的深度值,那么就说明这个表面虽然是可见的,但是却处于该光源的阴影中。

总结:一个物体接收来自其他物体的阴影,以及它向其他物体投射阴影是两个过程:(1)如果一个物体要接收其他物体的阴影,就必须在Shader中对阴影映射纹理进行采样,把采样结果和最后的光照结果相乘来产生阴影效果。(2)如果想要一个物体向其他物体投射阴影,就必须把该物体加入到光源的阴影映射纹理的计算中,从而让其他物体在对阴影映射纹理采样是可以得到该物体的相关信息。在Unity中,这个过程是通过为该物体执行LightMode为ShawowCaster的Pass来实现的。

阴影的投射,需要开启MeshRenderer中的CastShadows为On。shader一般是在Fallback中找到。

阴影的接收,需要开启MeshRenderer中的ReceiveShadows。shader中使用三个内置宏 SHADOW_COORDS, TRANSFER_SHADOW, SHADOW_ATTENUATION,注意点(1)顶点着色器的输入结构体a2v必须命名为v;(2)a2v中的坐标变量名必须命名为vertex;(3)顶点函数传递到片元函数的v2f中的顶点变量名必须为pos。

统一管理光照衰减和阴影,将以上SHADOW_ATTENUATION替换成UNITY_LIGHT_ATTENUATION即可。如果要在AdditionalPass中添加阴影效果,就需要使用#pragma_multi_compile_fwdadd_fullshadows编译指令代替#pragma_multi_compile_fwdadd,这样就可以为这些额外的逐像素光源计算阴影,并传递给Shader。

六、高级纹理

MRT(Multiple Render Targets 多重渲染目标):指的是GPU允许把场景同时渲染到多个渲染目标纹理(颜色值、深度值 等)中,而不再需要为每个渲染目标纹理单独渲染完整的场景。延迟渲染就是使用的该技术。

立方体纹理:是环境映射的一种实现方法。模拟物体周围的环境。

反射:使物体像镀了一层金属。通过入射光线的方向和表面法线的方向来计算反射方向,再利用反射方向对立方体纹理采样即可。

折射:模拟玻璃物体,真实环境是两次折射,但这里近似模拟折射一次即可。通过入射光线的方向和表面法线的方向,以及入射光线所在介质的折射率和折射光线所在介质的折射率的比值来计算折射方向,最后利用折射方向对立方体纹理采样即可。

菲涅尔反射:根据视角方向控制反射程度,即当光线照射到物体表面上时,一部分发生反射,一部分进入物体内部发生折射或散射。被反射的光和入射光之间存在一定的比率关系,这个比率关系就是菲涅尔等式。应用如湖面效果,近处的水透明,远处的水如镜面。

渲染纹理:一种方式是在屏幕后处理时使用GrabPass命令或OnRenderImage函数来获取当前屏幕图像,Unity会把这个屏幕图像放到一张和屏幕分辨率等同的渲染纹理中。一种是自己创建一个渲染纹理(RenderTexture)和一个摄像机进行关联。

程序纹理:由计算机生成的图像,通常使用一些特定的算法来创建个性化图案或非常真实的自然元素。好处是可以使用不同的参数来控制纹理的外观。

七、基于物理的渲染(Physically Based Shading, PBS)

基本概念:它指的是一些在不同程度上都基于与现实世界的物理原理更相符的基本理论所构成的渲染技术的集合。正因为基于物理的渲染目的便是为了使用一种更符合物理学规律的方式来模拟光线,因此这种渲染方式与我们原来的Phong或者Blinn-Phong光照算法相比总体上看起来要更真实一些。除了看起来更好些以外,由于它与物理性质非常接近,因此我们(尤其是美术师们)可以直接以物理参数为依据来编写表面材质,而不必依靠粗劣的修改与调整来让光照效果看上去正常。使用基于物理参数的方法来编写材质还有一个更大的好处,就是不论光照条件如何,这些材质看上去都会是正确的,而在非PBR的渲染管线当中有些东西就不会那么真实了。

全局光照:表现了直接照明和间接照明的综合效果。光线碰到拍摄对象,反射正反射光或漫反射光,这就控制了色彩、物体间相互作用的反射、折射、焦散等光效,最后演绎了现实的自然光。

HDR:通过在场景相机上启用HDR,将会以更高的精度去存储颜色(使用浮点表示)。HDR使我们能够在我们的场景和阴影区域之间保持亮度的巨大差异,例如户外照明。我们还可以通过在场景中对这些鲜艳的颜色进行应用,创造出“绽放”或发光效果。这样的特殊效果,可以增加场景的现实感。

伽马空间 和 伽马矫正:

人眼对光强的感知能力并非线性的——对暗部颜色变化更敏感,但很难识别亮部的颜色差异。如果用函数曲线表示的话,近似于y = x的 1/2.2 次方(曲线向上弯,x匀速增长时,y先快后慢)。

早期的CRT显示器,根据电压输出颜色值也并非现行,近似于 y = x的2.2次方(曲线向下弯,x匀速增长时,y先慢后快),和人眼叠加抵消的话,人眼看上去就会以为是均匀的颜色变化。

一直到今天的LED也一直沿用该函数,所谓的伽马空间就是指这个 y = x的2.2次方 的映射方式,2.2 即伽马系数。

如果是用相机拍摄的照片用显示器打开,会发现颜色偏暗,因为相机是线性空间,所以需要对照片叠加一个 y = x的 1/2.2 次方 进行抵消增亮,那么看上去就跟实际照片没有区别了,而这种校准的方式就叫做 伽马矫正

我们在PS作图的时候是在伽马空间下操作的,一般保存的时候会进行伽马矫正,这种方式也叫sRGB编码。同时这样还有一个好处:用较多的存储空间来记录对于人眼比较敏感的暗部,把较少的空间分配给亮部,那么相对地可以看到更加丰富的细节。而在图形渲染中计算时,会把纹理反矫正到线性空间,最后颜色输出时再次伽马矫正输出到屏幕。

需要补充的一点是:只对用于提供色彩信息的贴图(比如Albedo和Specular Color)进行sRGB编码。而法线贴图/金属度贴图这类用以存储数值信息的贴图,是没有sRGB编码的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值