CD-ROM着色器:衍射光栅(二)
本帖最后由 492899250 于 2018-2-22 20:30 编辑 CD-ROM着色器:衍射光栅(二) 这篇文章是,如何创建CD-ROMs着色器的后续。 你可以从下面的链接找到这个系列的所有文章。 · Part 1. The Nature of Light · Part 2. Improving the Rainbow (Part 1) · Part 3. Improving the Rainbow (Part 2) · Part 4. Understanding Diffraction Grating · Part 5. The Mathematics of Diffraction Grating · Part 6. CD-ROM Shader: Diffraction Grating (Part 1) · Part 7. CD-ROM Shader: Diffraction Grating (Part 2) · Part 8. Iridescence on Mobile · Part 9. The Mathematics of Thin-Film Interference · Part 10. Car Paint Shader: Thin-Film Interference 在页面的底部,有本系列中用到的Unity工程的下载链接。 介绍 在教程的第1部分,我们创建了第一个彩虹反射的近似效果,就是CD-ROM的上的那种效果。这个着色器是基于物理的。为了正确的模拟这种反射效果,我们需要确保CD-ROM上轨道是环行排列的。这是径向反射的基础。 狭缝方向 衍射光栅的数学原理(The Mathematics of Diffraction Grating)一篇中,推导出的衍射方程有很大限制:它假设狭缝是朝同一方向的。这种情况在昆虫的外壳比较常见,而CD-ROM表面的分布是环形的。如果单纯按照上一节的方法实现,那么是无法得到我们想要的反射效果的(如下,右图) 为了修正这个问题,我们需要考虑,CD-ROM上狭缝的自身方向。使用普通的向量是没用的,因为狭缝的法线方向是相同的,指向远离光盘表面的方向。狭缝的切线方向矢量,才能正确反映狭缝自身的方向。 如上图所示,法向量N是蓝色的,切向量T是红色的。光源、观察者分别和法线N之间的夹角,被称为θL和θV。类似地,和T之间的夹角被称为ƏL和ƏV。如前所述,使用θL和θV,我们计算出的是“扁”的反射,因为所有狭缝的N是相同的。我们需要使用ƏL和ƏV,这样才能正确获取狭缝的自身方向。 至此,我们知道: 因为T 和N是正交的,所以下面的属性也是成立的。 因为Cg提供了点积的计算,所以这很简单,剩下的就是计算T。 计算切向量 为了完成着色器,我们需要计算切向量T。通常,这会在网格顶点中计算,但是CD-ROM的表面非常简单,我们可以直接计算。请记住,本教程介绍的方法相当简单,同时假设CD-ROM的表面的UV贴图是正确的。 上图显示了切向量的计算过程。这里有一个潜在的假设,光盘表面的UV贴图是方形面片,坐标范围在(0,0) 到 (1,1)之间。一旦明确这些,CD-ROM表面的每一点,都可以重映射到 (-1,-1) 和(+1,+1)之间。随着这一参考系的变换,这个点有了新的坐标,它的方向远离中心(绿色箭头)。将这个方向旋转90度,就是CD-ROM上,环形轨道的切向量方向(红色箭头)。 这些操作需要在着色器的surf函数中完成,因为在光照函数LightingDiffraction前,UV坐标是不可用的。 [C#] 纯文本查看 复制代码 // IN.uv_MainTex: [ 0, +1]// uv: [-1, +1]fixed2 uv = IN.uv_MainTex * 2 -1;fixed2 uv_orthogonal = normalize(uv);fixed3 uv_tangent = fixed3(-uv_orthogonal.y, 0, uv_orthogonal.x); 现在剩下的就是将计算出的切向量,从物体空间转换到世界空间。转换需要考虑上物体的变化、旋转和缩放。 [C#] 纯文本查看 复制代码 worldTangent = normalize( mul(unity_ObjectToWorld, float4(uv_tangent, 0)) ); 整合…… 现在我们所需要的计算的就是,颜色对彩虹反射的影响。 <div align="left"><div style="padding:15px 0;">[C#] 纯文本查看 复制代码 inline fixed4 LightingDiffraction(SurfaceOutputStandard s, fixed3 viewDir, UnityGI gi){// Original colourfixed4 pbr = LightingStandard(s, viewDir, gi);// --- Diffraction grating effect ---float3 L = gi.light.dir;float3 V = viewDir;float3 T = worldTangent;float d = _Distance;float cos_ThetaL = dot(L, T);float cos_ThetaV = dot(V, T);float u = abs(cos_ThetaL - cos_ThetaV);if (u == 0)return pbr;// Reflection colourfixed3 color = 0;for (int n = 1; n |
关注CG资源素材