跳转到内容

Cg 编程/Unity/弯曲玻璃

来自维基教科书,开放世界中的开放书籍
水晶球是弯曲透明表面的例子。

本教程涵盖折射映射及其与立方体贴图的实现。

它是“反射表面”部分的变体,应该先阅读。

折射映射

[编辑 | 编辑源代码]

“反射表面”部分中,我们反射了视角射线,然后在反射方向的立方体贴图中执行纹理查找。在这里,我们在弯曲的透明表面上折射视角射线,然后使用折射方向执行查找。该效果将忽略光线再次离开透明物体时的第二次折射;然而,许多人几乎没有注意到差异,因为这种折射通常不是我们日常生活的一部分。

我们没有使用reflect函数,而是使用refract函数;因此,片段着色器可能是

         float4 frag(vertexOutput input) : COLOR
         {
            float refractiveIndex = 1.5;
            float3 refractedDir = refract(normalize(input.viewDir), 
               normalize(input.normalDir), 1.0 / refractiveIndex);
            return texCUBE(_Cube, refractedDir);
         }

请注意,refract 接受第三个参数,即外部介质的折射率(例如,空气的折射率为 1.0)除以物体的折射率(例如,某些类型的玻璃的折射率为 1.5)。还要注意,第一个参数必须是标准化的,而reflect则不需要。

完整着色器代码

[编辑 | 编辑源代码]

使用经过调整的片段着色器,完整的着色器代码变为

Shader "Cg shader with refraction mapping" {
   Properties {
      _Cube("Reflection Map", Cube) = "" {}
   }
   SubShader {
      Pass {   
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
 
         #include "UnityCG.cginc"

         // User-specified uniforms
         uniform samplerCUBE _Cube;   
 
         struct vertexInput {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float3 normalDir : TEXCOORD0;
            float3 viewDir : TEXCOORD1;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            float4x4 modelMatrix = unity_ObjectToWorld;
            float4x4 modelMatrixInverse = unity_WorldToObject; 
 
            output.viewDir = mul(modelMatrix, input.vertex).xyz 
               - _WorldSpaceCameraPos;
            output.normalDir = normalize(
               mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);
            output.pos = UnityObjectToClipPos(input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            float refractiveIndex = 1.5;
            float3 refractedDir = refract(normalize(input.viewDir), 
               normalize(input.normalDir), 1.0 / refractiveIndex);
            return texCUBE(_Cube, refractedDir);
         }
 
         ENDCG
      }
   }
}

恭喜你。这是另一个教程的结尾。我们已经看到了

  • 如何使用refract指令将反射映射调整为折射映射。

进一步阅读

[编辑 | 编辑源代码]

如果你还想了解更多

< Cg 编程/Unity

除非另有说明,否则此页面上的所有示例源代码均授予公共领域。
华夏公益教科书