Unity Shader 入门精要 | 第五章 开始 Unity Shader 学习之旅

欢迎前往个人博客 驽马点滴 和视频空间 哔哩哔哩-《挨踢日志》

5.1 本书使用的软件和环境

介绍 Unity Shader 的学习环境,开发平台、Unity 版本等信息。

5.2 一个最简单的顶点/片元着色器

5.2.1 顶点/片元着色器的基本结构

Shader "Unity Shaders Book/Chapter 5/ Simple Shader" {
    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            float4 vert(v: POSITION): SV_POSITION {
                // return mul(UNITY_MATRIX_MVP, v);
                // Unity Upgrade NOTE: replace 'mul(UNITY_MATRIX_MVP, *)' with 'UnityObjectToClipPos(*)'
                return UnityObjectToClipPos(v);
            }
            fixed4 frag(): SV_Target {
                return fixed4(1.0, 1.0, 1.0, 1.0);
            }
            ENDCG
        }
    }
}

几个点:

  1. Properties 属性不是必须的(方便材质面板中友好的用户显示);
  2. 顶点/片元着色器的 CGPROGRAM 和 ENDCG 写在 Pass 中;
  3. '#pragma vertex' 和 '#pragma fragment frag' 属于编译指令,告诉 Unity 顶点着色器和片元着色器的代码包含在哪个函数中;
  4. POSITION 是 Cg/HLSL 中的语义,用来指明顶点坐标;
  5. SV_POSITION 也是 Cg/HLSL 中的语义,用来指明顶点着色器的输出是裁剪空间中顶点坐标;
  6. mul(UNITY_MATRIX_MVP, v) 将顶点坐标变换到裁剪空间中(在第四章数学基础中已知),该使用方法,在新版本的 Unity 中,已替换成 UnityObjectToClipPos(v);
  7. SV_Target 是 HLSL 中的语义,它告诉渲染器把用户的输出颜色存储到一个渲染目标(Render Target)中;
  8. 片元着色器返回 fixed4 类型的变量,每个分量在 [0, 1] 中取值,[0, 0, 0] 表示黑色,[1, 1, 1] 表示白色;

上述 Shader 中,传入顶点着色器的只有顶点的位置 POSITION,而我们知道,顶点还记录了其他的信息,比如 法线、纹理坐标、颜色等等。为了获得这些的数据,该如何做呢?因此引出下一节的内容,定义一个结构体,给顶点着色器传入更多的数据。

5.2.2 模型数据从哪里来

我们想获取顶点的法线和纹理坐标信息,因此将 Shader 改写如下:

Shader "Unity Shaders Book/Chapter 5/ Simple Shader" {
    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert 
            #pragma fragment frag 

            struct a2v {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };

            float4 vert(a2v v): SV_POSITION {
                return UnityObjectToClipPos(v.vertex);
            }

            fixed4 frag(): SV_Target {
                return fixed4(1.0, 1.0, 1.0, 1.0);
            }
            ENDCG
        }
    }
}

其中:

  1. struct 书写格式需要注意,结构体的定义在末尾需要加分号;
  2. a2v 的意思是应用程序数据转为顶点数据(application data to vertex data);
  3. 结构体中,声明 float4 vertex : POSITION ,那么 Unity 会将顶点数据自动填充到 vertex 变量中;声明 float3 normal: NORMAL,那么 Unity 会将法线数据自动填充到 normal 变量中;声明 float4 texcoord: TEXCOORD0, Unity 会将第一个纹理坐标填充到 texcoord 变量中;

5.2.3 顶点着色器和片元着色器之间如何通信

  1. 定义从顶点着色器输出的数据结构 v2f;
  2. 片元着色器中,将 v2f 对象作为参数传入;
Shader "Unity Shaders Book/Chapter 5/ Simple Shader" {
    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert 
            #pragma fragment frag 

            struct a2v {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };

            struct v2f {
                float4 pos: SV_POSITION;
                fixed3 color: COLOR0;
            };

           v2f vert(a2v v) {
               v2f o;
               o.pos = UnityObjectToClipPos(v.vertex);
               o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
               return o;
            }

            fixed4 frag(v2f i): SV_Target {
                return fixed4(i.color, 1.0);
            }
            ENDCG
        }
    }
}

注意点:

  1. 顶点着色器输出结构中,必须包含一个变量,其语义为 SV_POSITION ;
  2. COLOR0 语义中的数据可以由用户自己定义,一般存储颜色(如漫反射颜色或者高光反射颜色);
  3. 片元着色器中的输入,实际是将顶点着色器中的顶点数据进行插值后得到的结果;

5.2.4 如何使用属性

  1. 在 Shader 的 Properties 中添加变量 _Color("Color Tint", Color) = (1.0, 1.0, 1.0, 1.0);
  2. 在 CGPROGRAM 中定义同名变量 fixed4 _Color;
    3.在 frag 中使用该变量;
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unity Shaders Book/Chapter 5/ Simple Shader" {
    Properties {
        _Color ("Color Tint", Color) = (1.0, 1.0, 1.0, 1.0)
    }

    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert 
            #pragma fragment frag 

            fixed4 _Color;

            struct a2v {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };

            struct v2f {
                float4 pos : SV_POSITION;
                fixed3 color : COLOR0; 
            };

            v2f vert(a2v v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
                return o;
            }

            fixed4 frag(v2f i): SV_Target {
                fixed3 c = i.color;
                c *= _Color.rgb;
                return fixed4(c, 1.0);
            }
            ENDCG
        }
    }
}

5.3 强大的援手:Unity 提供的内置文件和变量

官方网站(http://unity3d.com/cn/get-unity/download/archive)上下载 Unity 的包含文件。

Unity 中常用的包含文件:
UnityCG.cginc ——包含了常用的帮助函数、宏和结构体;
HLSLSupport.cginc ——声明了很多用于跨平台编译的宏和定义,编译 Unity Shader 时,会自动包含;
UnityShaderVariables.cginc——包含了许多内置的全局变量,如 UNITY_MATRIX_MVP 等,编译 Unity Shader 时,会自动包含;
Lighting.cginc ——包含各种内置光照,如果是 Surface Shader ,会自动包含进来。

UnityCG.cginc 中包含的常用结构体:
appdata_base:可用于顶点着色器的输入,包含顶点位置、顶点法线、第一组纹理坐标;
appdata_tan: 可用于顶点着色器的输入,包含顶点位置、顶点法线、顶点切线、第一组纹理坐标;
appdata_full: 可用于顶点着色器的输入,包含顶点位置、顶点法线、顶点切线、四组(或更多组)纹理坐标;
appdata_img: 可用于顶点着色器的输入,包含顶点位置、第一组纹理坐标;
v2f_img: 可用于顶点着色器的输出,包含裁剪空间中的位置、纹理坐标;

一些帮助函数:(略)

5.5 程序员的烦恼:Debug

(略)主要通过输出颜色来调试,比较原始。

欢迎前往个人博客 驽马点滴 和视频空间 哔哩哔哩-《挨踢日志》

你可能感兴趣的:(Unity Shader 入门精要 | 第五章 开始 Unity Shader 学习之旅)