Version: 6000.3
语言: 中文
内置渲染管线中的反射着色器示例
内置渲染管线中的三平面纹理着色器示例

内置渲染管线中的法线贴图纹理着色器示例

一个类似猫的角色,具有反射场景的金属表面。
一个类似猫的角色,具有反射场景的金属表面。

经常法线贴图(Normal Maps)一种凹凸贴图纹理,可用于向模型添加表面细节,如凹凸、凹槽和划痕,这些细节可以捕捉光线,就好像它们由真实几何体表示一样。
请参阅术语表
用于在对象上创建额外的细节,而不创建额外的几何体。让我们看看如何制作一个着色器在 GPU 上运行的程序。更多信息
请参阅术语表
反映环境,并带有法线贴图纹理。

现在数学开始真正参与其中,所以我们将分几个步骤完成。在上面的着色器中,反射direction 是按顶点计算的(在顶点着色器中),片段着色器只做反射 探针立方体贴图六个方形纹理的集合,可以表示环境中的反射或几何体后面绘制的天空盒。这六个正方形形成了一个围绕对象的假想立方体的面;每个面代表沿世界轴方向(上、下、左、右、前和后)的视图。更多信息
请参阅术语表
查找。 然而,一旦我们开始使用法线贴图,表面法线本身就需要按像素计算,这意味着我们还必须计算环境如何反映每个像素!

我们现在也必须学习一个新东西;所谓的“切线空间”。法线贴图纹理通常以坐标空间表示,该坐标空间可以被认为是模型的“跟随表面”。在我们的着色器中,我们需要知道切线空间基向量,从纹理中读取法线向量,将其转换为世界空间,然后进行所有数学运算从上面的着色器。让我们开始吧!

Shader "Unlit/SkyReflection Per Pixel"
{
    Properties {
        // normal map texture on the material,
        // default to dummy "flat surface" normalmap
        _BumpMap("Normal Map", 2D) = "bump" {}
    }
    SubShader
    {
        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct v2f {
                float3 worldPos : TEXCOORD0;
                // these three vectors will hold a 3x3 rotation matrix
                // that transforms from tangent to world space
                half3 tspace0 : TEXCOORD1; // tangent.x, bitangent.x, normal.x
                half3 tspace1 : TEXCOORD2; // tangent.y, bitangent.y, normal.y
                half3 tspace2 : TEXCOORD3; // tangent.z, bitangent.z, normal.z
                // texture coordinate for the normal map
                float2 uv : TEXCOORD4;
                float4 pos : SV_POSITION;
            };

            // vertex shader now also needs a per-vertex tangent vector.
            // in Unity tangents are 4D vectors, with the .w component used to
            // indicate direction of the bitangent vector.
            // we also need the texture coordinate.
            v2f vert (float4 vertex : POSITION, float3 normal : NORMAL, float4 tangent : TANGENT, float2 uv : TEXCOORD0)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(vertex);
                o.worldPos = mul(_Object2World, vertex).xyz;
                half3 wNormal = UnityObjectToWorldNormal(normal);
                half3 wTangent = UnityObjectToWorldDir(tangent.xyz);
                // compute bitangent from cross product of normal and tangent
                half tangentSign = tangent.w * unity_WorldTransformParams.w;
                half3 wBitangent = cross(wNormal, wTangent) * tangentSign;
                // output the tangent space matrix
                o.tspace0 = half3(wTangent.x, wBitangent.x, wNormal.x);
                o.tspace1 = half3(wTangent.y, wBitangent.y, wNormal.y);
                o.tspace2 = half3(wTangent.z, wBitangent.z, wNormal.z);
                o.uv = uv;
                return o;
            }

            // normal map texture from shader properties
            sampler2D _BumpMap;
        
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the normal map, and decode from the Unity encoding
                half3 tnormal = UnpackNormal(tex2D(_BumpMap, i.uv));
                // transform normal from tangent to world space
                half3 worldNormal;
                worldNormal.x = dot(i.tspace0, tnormal);
                worldNormal.y = dot(i.tspace1, tnormal);
                worldNormal.z = dot(i.tspace2, tnormal);

                // rest the same as in previous shader
                half3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                half3 worldRefl = reflect(-worldViewDir, worldNormal);
                half4 skyData = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldRefl);
                half3 skyColor = DecodeHDR (skyData, unity_SpecCube0_HDR);
                fixed4 c = 0;
                c.rgb = skyColor;
                return c;
            }
            ENDHLSL
        }
    }
}

唷,这很复杂。但是看,法线贴图反射!

内置渲染管线中的反射着色器示例
内置渲染管线中的三平面纹理着色器示例