文章

shader入门基础-基础纹理

shader入门基础-基础纹理

本文内容主要参考 《Unity shader 入门精要》一书,旨在总结所学知识与加深个人理解

光照模型实践,使用单张纹理代替漫反射颜色

高光公式

\[\mathtt{c}_{specular}=(\mathtt{c}_{light}\cdot\mathtt{m}_{specular})max(0,\vec n\cdot\vec h)^{m_{gloss}} \qquad \vec h=\frac{\vec v+\vec l}{|\vec v+\vec l|}\]

漫反射公式\(\mathtt{c}_{diffuse}=(\mathtt{c}_{light}\cdot \mathtt{m}_{diffuse})max(0,\vec n \cdot \vec l)\)
根据公式 我们需要取到$\vec n$ 表面法线,$\vec l$ 指向光源的单位矢量,$m_{diffuse}$ 材质漫反射颜色,$m_{specular}$ 材质高光颜色,$c_{light}$ 是光源颜色 _MainTex_ST:在 Unity 中,我们需要使用纹理名_ST 的方式来声明某个纹理的属性。其中 ST 是缩放(scale)和平移(translation)的缩写。_MainTex_ST 可以让我们得到该纹理的缩放和平移值,_MainTex_ST.xy 存储的是缩放值,而_MainTex_ST.zw 存储的是偏移值。在顶点着色器中,我们使用纹理的属性值_MainTex_ST 来对 顶点的纹理坐标进行变换,得到最终的纹理。在 UnityCG.cginc 中有预定义 #define TRANSFORM_TEX(tex,name) (tex.xy*name##_ST.xy+name##_ST.zw)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
Shader "Practice/SingleTex"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color("Color Tint",Color)= (1,1,1,1) //漫反射颜色
        _Gloss("Gloss",Range(8.0,256)) = 20 //光泽度,光泽度越高反光面积越大
        _Specular("Specular",Color) = (1,1,1,1) //高光颜色
    }
    SubShader
    {
        Tags { "LightMode"="ForwardBase" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float4 normal : NORMAL;
                float2 texcoord : TEXCOORD0;
            };

            struct v2f
            {
               float4 pos : SV_POSITION;
               float3 worldNormal : TEXCOORD0;
               float3 worldPos : TEXCOORD1;
               float2 uv : TEXCOORD2;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            half _Gloss;
            fixed4 _Specular;
            fixed4 _Color;

            v2f vert (appdata v)
            {
              v2f o;
              o.pos = UnityObjectToClipPos(v.vertex); //转换到裁剪空间
              o.worldNormal = UnityObjectToWorldNormal(v.normal);
              o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;//转换到世界空间
              o.uv = _MainTex_ST.xy*v.texcoord.xy+_MainTex_ST.zw;
              // ==>  o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);  等价于上面的转换
              return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col;
                //C_diffuse = (C_light·M_diffuse)max(0,N·L)
                fixed3 worldNormal = normalize(i.worldNormal); //归一化后的世界坐标
                fixed3 wolrdLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); //光线
                fixed3 albedo = tex2D(_MainTex,i.uv).rgb*_Color.rgb; //取样当前纹理映射坐标的颜色 * 漫反射颜色 <==> 反射的颜色
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo; //环境光*反射光
                //C_diffuse = (C_light·m_diffuse)max(0,N·L) //漫反射计算公式 这里m_diffuse用的是纹理颜色
                fixed3 diffuse = _LightColor0.rgb*albedo*saturate(dot(worldNormal,wolrdLightDir));
                //WolrdSpaceViewDir 输入的是模型空间中顶点
                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));//输入的是世界空间的顶点坐标
                //H=(V+L)/|V+L|
                fixed3 halfDir = normalize(wolrdLightDir+viewDir);
                //C_specular = (C_light*m_specular)pow(max(0,N·H),m_gloss)
                fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(worldNormal,halfDir)),_Gloss);
                col = fixed4(ambient+diffuse+specular,1.0);
                return col;
            }
            ENDCG
        }
    }
}

使用单张纹理效果图 单张纹理

本文由作者按照 CC BY 4.0 进行授权