图形 4 Unity Shader的简单了解(四)·逐顶点的漫反射光照

准备工作:

  1.unity新建场景,去掉天空盒子(window->rendering->lightingsetting->enviroment->sky box meterial 置空即可)。

  2.创建一个场景对象,创建一个新的材质,新建一个新的 shader 并赋给材质,将材质赋给场景对象。

  3.修改 shader,(这里是把代码删掉了,然后重新写,ε=(´ο`*))))代码如下:

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

// 1.Shader 名称
Shader "Unity Shaders Book/Chapter 6/Diffuse Vertex-Level" {
    Properties{
        // 2.为了得到并控制材质的漫反射颜色,在 Properties 语义块中声明了一个Color属性,并将初始值设置为白色
        _Diffuse("Diffuse", Color) = (1, 1, 1, 1)
    }
        SubShader{
            // 3.SubShader 语义块中定义了一个 Paass 语义块。因为顶点/片元着色器的代码需要写在 Pass 语义块,而非 SubShader 语义块中
            Pass {
                // 4.指明 Pass 的光照模式。LightMode 是 Pass 标签的一种,定义 Pass 在 Unity 的光照流水线中的角色,正确的义才能得到 Unity 的内置光照变量
                Tags { "LightMode" = "ForwardBase" }

                // 5.使用 CGPROGRAM 和 ENDCG 来包围 Cg代码片,以定义最重要的顶点着色器和片元着色器代码。
                CGPROGRAM
                
                // 6.使用 #pragma 来告诉 Unity ,我们定义的顶点着色器和片元着色器叫什么名字
                #pragma vertex vert
                #pragma fragment frag
                
                // 7.为了使用 Unity 内置的一些变量,如 _LightColor0 等,需要包含进 Unity 的内置文件 Lighting.cginc
                #include "Lighting.cginc"
                
                // 8.为了在 Shader 中使用 Properties 语义块块中声明的属性,我们需要定义一个和该属性类型相匹配的变量
                // 9.此种方式,可得到了漫反射公式中需要的参数之一:材质的漫反射属性。由于颜色属性的范围在 0 到 1 之间,因此可使用 fixed 精度的变量来存储它
                fixed4 _Diffuse;

                // 10.定义顶点着色器的输入和输出结构体(同时也是片元着色器的输入结构体)
                struct a2v {
                    float4 vertex : POSITION;
                    // 11.为了访问顶点的法线,在 a2v 中定义一个 normal 变量,并通过使用 NORMAL 语义来告诉 Unity 要将模型顶点的发现信息存储到 normal 变量中。
                    float3 normal : NORMAL;
                };

                struct v2f {
                    float4 pos : SV_POSITION;
                    // 12.为了将在顶点着色器中计算的带的光照颜色传递给片元着色器,需要在 v2f 中定义一个 color 变量,并且不是必须使用 COLOR 语义,可使用 TEXCOORD0 语义。
                    fixed3 color : COLOR;
                };

                // 13.顶点着色器,实现逐顶点的漫反射光照,漫反射部分的计算在顶点着色器中进行。
                v2f vert(a2v v) {
                    // 14.定义返回值。顶点着色器最基本的任务就是把顶点位置从模型空间转到裁剪空间中,
                    v2f o;
                    // 15.使用unity内置的UnityObjectToClipPos,完成坐标变换
                    o.pos = UnityObjectToClipPos(v.vertex);

                    // 16.使用unity内置的 UNITY_LIGHTMODEL_AMBIENT 变量,得到环境光部分
                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                    // 17.模型空间到世界空间的变换矩阵:unity_WorldToObject ,用于将顶点/方向矢量从世界空间转换到模型空间
                    // 18.由于发现是一个三维矢量,只需要截取 unity_WorldToObject 的前三行前三列即可
                    // 19.通过调换它在 mul 函数中的位置得到和转置矩阵相同的矩阵乘法
                    fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));

                    // 20.unity内置的 _WorldSpaceLightPos0 变量,此时只有一个平行光光源,可用于获取光源的方向
                    // 21.多个光源或点光源等情况下,直接使用 _WorldSpaceLightPos0 得不到正确的结果。
                    fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

                    // 22.unity内置的 _LightColor0 变量,可访问该 Pass 处理的光源的颜色和强度信息
                    // 23.想要得到正确的 _LightColor0 信息,则需要确定使用合适的 LightMode 。
                    fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));
                    
                    // 24.环境光与漫反射相加,得到最后的光照结果。
                    o.color = ambient + diffuse;

                    return o;
                }
                // 25.片元着色器
                fixed4 frag(v2f i) : SV_Target {
                    // 26.计算已经在顶点着色器治中完成,则片元着色器只需要输出顶点颜色。
                    return fixed4(i.color, 1.0);
                }

                ENDCG
            }
    }
        // 27.回调 shader 设置为内置的 Diffuse
        FallBack "Diffuse"
}

    shader 代码的效果如下(左1的立方体是直接创建的,中间的立方体是使用了修改过的shader,右1的胶囊体是使用了修改过的shader):图形 4 Unity Shader的简单了解(四)·逐顶点的漫反射光照

上一篇:shader入门精要:单张纹理带法线贴图材质(世界空间)(笔记12)


下一篇:shader入门精要读书笔记22 高级纹理-立方体纹理-环境映射反射折射