Unity 6.3
0 онлайн 118 гостей 3 в системе
Вход
Материалы и шейдеры Шаг 342 из 442

Пример обычного шейдера для текстурирования карт во Встроенном Render Pipeline

Кот-подобный персонаж с металлической поверхностью, которая отражает сцену.
Кот-подобный персонаж с металлической поверхностью, которая отражает сцену.

Часто Нормальные карты используются для создания дополнительных деталей на объектах, без создания дополнительной геометрии. Давайте посмотрим, как сделать шейдер, который отражает окружающую среду, с обычной текстурой карты.

Теперь математика начинает вовлекать в, так что мы сделаем это в нескольких шагах. В шейдере выше, направление отражения было вычислено per-vertex (в вертикальном шейдере), а шейдер фрагмента только делал поиск кубического отображения пробы отражения. Однако, как только мы начнем использовать нормальные отображения, сама поверхностная нормальная должна быть вычислена на пиксельной основе, что означает, что мы также должны вычислить, как окружающая среда отражается на пиксель!

Теперь нам придется изучить еще одну вещь: так называемое «пространство касания». Нормальные текстуры карт чаще всего выражаются в координатном пространстве, которое можно рассматривать как «следующее за поверхностью» модели. В нашем шейдере нам нужно будет знать базовые векторы касательного пространства, прочитать нормальный вектор из текстуры, преобразовать его в мировое пространство, а затем выполнить все математические операции из вышеуказанного шейдера. Давайте приступим!

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
        }
    }
}

Уф, это было довольно сложно. Но посмотрите, нормальные отраженные отражения!