读UnityShader入门精要第五章-开始Unity Shader之旅


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

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

//定义Shader的位置和名称
Shader " Unity Shaders Book/Chapter 5/ Simple Shader"
{
    //可以不定义Properties,但是必须有至少一个SubShader
    SubShader
    {
        Pass
        {
            //使用CGPROGRAM和ENDCG包裹CG代码片段
            CGPROGRAM

            //编译指令,指明顶点着色器代码是vert函数
            #pragma vertex vert
            //编译指令,指明片元着色器代码是frag函数
            #pragma fragment frag

            //顶点着色器函数,v为形参名称,POSITION为CG/HLSL的语义,代表将模型的顶点坐标输入,SV_POSITION也是CG/HLSL的语义,代表输出为裁剪空间中的顶点坐标
            float4 vert(float4 v : POSITION) : SV_POSITION
            {
                return UnityObjectToClipPos(v);
            }

            //片元着色器函数,SV_Target语义代表将输出颜色存储到一个渲染目标中
            fixed4 frag() : SV_Target
            {
                return fixed4(1.0, 0.0, 0.0, 1.0);
            }

            ENDCG
        }
    }
}

1.2  模型数据从哪里来

  在着色器中使用语义(semantics)定义数据的来源,想得到更多的数据,我们可以定义一个结构体参数获取这些数据:

Shader " Unity Shaders Book/Chapter 5/ Simple Shader"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            //使用结构体定义参数
            struct a2v 
            {
                //POSITION语义,代表使用模型空间的顶点坐标填充这个变量
                float4 vertex : POSITION;
                //NORMAL语义,代表使用模型空间的法线方向填充这个变量
                float3 normal : NORMAL;
                //TEXCOORD0语义,代表使用模型的第一套纹理坐标填充这个变量
                float4 texcoord : TEXCOORD0;
            };

            //顶点着色器函数
            float4 vert(a2v v) : SV_POSITION
            {
                return UnityObjectToClipPos(v.vertex);
            }

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

            ENDCG
        }
    }
}

1.3  顶点着色器和片元着色器之间的通信

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
            {
                //SV_POSITION语义代表这里存储了裁剪空间的位置信息
                float4 pos : SV_POSITION;
                //COLOR0语义用于存储颜色信息
                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)在结构体v2f中,必须包含语义为SV_POSITION的float4类型变量,否则片元着色器无法得到片元的位置信息;

    2)顶点着色器输出的v2f结构体中存储的信息和片元着色器中输入的v2f结构体中的信息并不一致,片元着色器得到的点可能是三角片元内的点,它的信息是经过三角形顶点的插值得到的.

1.4  如何使用属性

Shader " Unity Shaders Book/Chapter 5/ Simple Shader"
{
    Properties
    {
        //声明一个color类型的属性
        //属性名_Color, 在Shader属性面板中显示名称Color Tint,属性类型Color, 属性默认值(1.0, 1.0, 1.0, 1.0)
        _Color("Color Tint", Color) = (1.0, 1.0, 1.0, 1.0)
    }

        SubShader
    {
        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            //在CG代码中,需要定义一个与属性名称相同,类型匹配的变量,才能使用这个变量
            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;
                //使用_Color属性控制颜色输出
                c *= _Color.rgb;
                return fixed4(c, 1.0);
            }

            ENDCG
        }
    }
}

  ShaderLab的属性类型和Cg的变量类型匹配关系如下:

读UnityShader入门精要第五章-开始Unity Shader之旅

2.Unity提供的内置文件

  在Unity中,包含文件的后缀是.cginc.在编写Shader是,可以使用#include指令将这些文件包含进来,类似于C#包含其他命名空间.#include指令在CGPROGRAM和ENDCG中间的代码块中定义.

3.Unity提供的Cg/HLSL语义

3.1  语义的概念

  语义(semantics)是一个赋给Shader输入和输出的字符串,这个字符串表达了这个参数的含义.通常情况下,语义可以让我们指定Shader从哪里读取数据,或者指定Shader将数据输出到哪里.

  一些语义有特殊的含义规定,如TEXCOORD0,但是其他语义则没有这样的含义,如COLOR0,这些语义修饰的变量Shader并不关心它是用来做什么的,我们可以自己决定这些变量的用途.

  在DirecX 10以后,出现了一种新的语义类型:系统数值语义(system-value semantics).系统数值语义都是以SV(system value)开头的,如SV_POSITION.在Unity中有时系统数值语义和普通语义是可以替换的,但是最好使用系统数值语义,因为某些平台上必须使用系统数值语义.

3.2  Unity支持的语义

读UnityShader入门精要第五章-开始Unity Shader之旅

读UnityShader入门精要第五章-开始Unity Shader之旅

读UnityShader入门精要第五章-开始Unity Shader之旅

3.3  CG的数据类型

  Cg支持7种基础数据类型:

  1)float, 32位浮点数据

  2)half, 16位浮点数据

  3)fixed, 12位定点数据

  4)int, 32位整形数据

  5)bool, 布尔数据

  6)sampler*, 纹理对象的句柄,分为6类:sampler, sampler1D, sampler2D, sampler3D, samplerCUBE, samplerRECT

  7)string, 字符类型(几乎不会用到)

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/279378.html

(0)
上一篇 2022年8月7日 14:47
下一篇 2022年8月7日 14:56

相关推荐

发表回复

登录后才能评论