Unity Shader初步编写

        新建一个Shader和Material,将Shader挂载到材质上,然后在场景中新建一个球体,将材质挂载到物体上,打开Shader代码文件。

Shader "Unlit/SimpleShader"
{
    //属性不是必需的
    SubShader
    {
        Pass
        {
            CGPROGRAM
            //说明顶点着色器函数名为vert
            #pragma vertex vert
            //片元着色器函数名为frag
            #pragma fragment frag

            float4 vert(float4 v : POSITION) : SV_POSITION
            {
                //2021.3.4版本会提醒修改为return UnityObjectToClipPos(v);
                return mul(UNITY_MATRIX_MVP, v);
            }

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

        vert函数的输入v包含了这个顶点的位置,它的返回值类型是一个float4类型变量,它是该顶点在裁剪空间的位置,POSITION和SV_POSITION都是CG/HLSL中的语义,他们是不可省略的,告诉了系统用户需要输入哪些值,以及用户的输出是什么 。

        比如这里的POSITION就告诉Unity,把模型的顶点坐标填充到输入参数v中,SV_POSITION将告诉Unity,顶点着色器的输出是裁剪空间中的顶点坐标。

         farg函数在本例中没有任何的输入,而它的输出是一个fixed4类型的变量,并且使用了SV_Target语义进行限定,它的意思是将用户的输出颜色存储到一个渲染目标中,这里将输出到啊默认的帧缓存中。

        片元着色器中的代码很简单,返回了一个表示白色的fixed4类型的变量,片元着色器输出的每个颜色分量在[0,1]之间。


        如果我们不仅想要模型的顶点位置,我们想要得到每个顶点的纹理坐标(访问纹理)和法线方向 (计算光照),因此我们需要定义一个新的输入参数,它不再是一个简单的数据模型,而是一个结构体。

            //使用一个结构体来定义顶点着色器的输入
            struct a2v {
                //用模型空间的顶点坐标填充vertex变量
                float4 vertex : POSITION;
                //用模型空间的法线方向填充normal变量
                float3 normal : NORMAL;
                //用模型的第一套纹理坐标填充texcoord变量
                float4 texcoord : TEXCOORD0;
            };

            float4 vert(a2v v) : SV_POSITION
            {
                //使用v.vertex来访问模型空间的顶点坐标
                return UnityObjectToClipPos(v.vertex);
            }

         填充到POSITION,TANGENT,NORMAL这些语义中的数据是由使用该材质的Mesh Render组件提供的,在每帧调用Draw Call的时候,Mesh Render组件会把他负责渲染的模型数据发送给Unity Shader。

        每个顶点包含了顶点位置、法线、切线、纹理坐标、顶点颜色等,我们可以在顶点着色器中访问顶点的这些模型数据。


        在实践中,我们往往需要从顶点着色器中输出一些数据,例如把模型的法线、纹理坐标等传递给片元着色器,这就涉及两者之间的通信,为此,我们需要再定义一个新的结构体 。

            struct v2f {
                //pos里包含了顶点在裁剪空间中的位置信息
                float4 pos : SV_POSITION;
                //COLOR0 语义可以用于存储颜色信息
                fixed3 color : COLOR0;
            };

            v2f vert(a2v v)
            {
                //声明输出结构
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                //因为法线方向范围是[-1.0,1.0],因此我们需要映射范围到[0.0,1.0]
                o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                //将插值后的i.color显示到屏幕上
                return fixed4(i.color 1.0);
            }

        我们声明了一个新的结构体v2f用于在顶点着色器和片元着色器之间传递信息,在顶点着色器的输出结构中,必须包含一个变量,它的语义是SV_POSITION,否则渲染器将无法得到裁剪空间中的顶点坐标,也就无法把顶点渲染的屏幕上。

        COLOR0语义中的数据可以由用户自行定义,但一般都是储存颜色。


         材质提供给我们一个可以方便地调节Unity Shader中参数的方式,通过这些参数,我们可以随时调整材质的效果,而这些参数就需要卸载Properties语义块中。

    Properties{
        //声明一个Color类型的属性
        _Color("Color Tint",Color) = (1.0,1.0,1.0,1.0)
    }
            //在CG代码中,我们需要定义一个与属性名称和类型都匹配的变量
            fixed4 _Color;

            fixed4 frag(v2f i) : SV_Target
            {
                fixed3 c = i.color;
                //使用_Color属性来控制输出颜色
                c *= _Color.rgb;
                return fixed4(c, 1.0);
            }

        在上面的代码中,我们首先添加了Properties语义块,并在其中声明了一个属性_Color,初始值是(1.0,1.0,1.0,1.0),对应白色。为了可以在CG代码中访问它,我们还需要在CG代码片段中提前定义一个新的变量,这个变量的名称和类型必须与Properties语义块中的属性定义相匹配。


        为了方便开发者的编码过程,Unity提供了很多的内置文件,这些文件中包含了很多提前定义的函数、变量、宏等,我们可以在官方网站上选择下载>内置着色器来直接下载这些文件。

CGPGOGRAM
//...
#include "UnityCG.cginc"
//...
ENDCG


        再来总结一下语义,刚刚使用到的语义其实都是CG/HLSL提供的,语义实际上就是一个赋给Shader输入和输出的字符串,这个字符串表达了参数的含义(但是unity并没有支持所有语义)。

        通常情况下,我们可以自行决定这些变量的用途,它储存的东西Shader流水线并不关心,但是Unity为了方便对模型数据的传输,对一些语义进行了特别的规定,例如Unity会识别TEXCOORD0语义,把模型的第一组纹理坐标填充到被语义定义的texcoord中,但它只在输入结构体a2f中有特别含义,而输出结构体v2f中,它修饰的变量含义就可以由我们来决定。

        而有些语义是以SV开头的,SV代表的就是系统数值,这些语义在渲染流水线中有特殊含义,比如我们使用SV_POSITION语义修饰顶点着色器的输出变量pos,那么就表示pos包含了可用于光栅化的变换后的顶点坐标(即齐次裁剪空间中的坐标)。这些语义描述的变量是不可以随便赋值的,因为流水线需要他们来完成特定的目的。在绝大多数平台上,它和POSITION的语义是等价的,但是在某些平台上就必须使用SV_POSITION来修饰顶点着色器的输出。

猜你喜欢

转载自blog.csdn.net/weixin_45081191/article/details/129201032