Unity Shader入门精要 阅读笔记五

最简Shader框架

unity的shader基础的一些知识可以从阅读笔记一中获得。
这里讲一些最简框架,之后的shader其实都可以从最简框架中来扩展。

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

Shader"Custom/1.1.1"{
//lowest level shader

Subshader{
    Pass{
//渲染通道,用来完整描述一个渲染流水线
    CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//定义基本的顶点着色器的编程函数,以及片元着色器的编程函数。
        float4 vert(float4 v:SV_POSITIO):SV_POSITION {
            return UnityObjectToClipPos(v);
            //矩阵乘法,将模型空间中的点,转到齐次剪裁空间中。
        }
        float4 frag() :SV_Target {//SVTarget是着色器的语义
            return fixed4(1.0,1.0,1.0,1.0);
            //定义所有的片元光栅化的颜色为白色。
        }
        ENDCG
    }
}

}

这里可以看到,这个可以称之为最简框架,虽然很小,但是包含有基本的一些内容。

这里有些地方需要做一些笔记:
- shader脚本在unity里面其实已经简化了很多。这脚本里面主要有Unity的shaderLab脚本以及CG脚本组成。
- shaderLab脚本主要是出unity用来标记的一些部分
- CG脚本主要是CGPROGRAM 到 ENDCG部分的脚本。
- SV_POSITION,SV_POSITIO,这些都是语义,用来描述类型和属性,告诉GPU,这些是什么类型。
- 函数中float4 vert(float4 v:SV_POSITIO):SV_POSITION,括号中冒号后的SV_POSITIO的语义是对输入参数进行描述,而括号外的SV_POSITION是对输出参数进行描述。
- 函数的命名可以通过宏来自定义,通过#pragma语句来。
- Pass里面其实使用CG语言去定义了一个完整的渲染流程。

在最简Shader框架增加结构体1

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

Shader"Custom/1.1.2"{

    Subshader{
        Pass{
        //渲染通道,用来完整描述一个渲染流水线
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
            //应用2顶点着色器
            struct a2v {//名称不能自定义
                //这里面定义顶点着色器的输入
                //每个输入都需要填写类型,名称,语义
                float4 ve:POSITION;//每一个定义以分号结尾
                float4 tex:TEXCOORD0;//输入一个纹理信息
                float3 normal:NORMAL;
            };//这里需要注意,需要有个分号
            //定义基本的顶点着色器的编程函数,以及片元着色器的编程函数。
            float4 vert(a2v v) : SV_POSITION {//SV_POSITION在这里用来描述输出的语义
                return UnityObjectToClipPos(v.ve);
                //矩阵乘法,将模型空间中的点,转到齐次剪裁空间中。
            }
            float4 frag() :SV_Target {//SVTarget是着色器的语义
                return fixed4(1.0,1.0,1.0,1.0);
                //定义所有的片元光栅化的颜色为白色。
            }
            ENDCG
        }
    }

}

这里面相对与之前的最简框架进行了一些添加,主要添加了一个结构体:
- 结构体的使用与传统的C语言的结构体相似,但是命名上面需要按照一定规则:a代表应用,v代表顶点。这里其实就对应渲染管线中的一些内容:顶点着色器的输入内容其实是应用阶段(application)经过处理传来的值。
- 结构体重定义了几个变量,变量的名称可以自定义,但是语义不能。语义就是告诉GPU,这个变量的具体用处,不然同样是float4,ve和tex就没区别了。
- float4可以看成是行向量或者是列向量,具体怎么看要看和矩阵的乘法是左边还是右边。
- 由于输入的时候传入的是结构体,所以在输入参数是不用写语义的。

在最简Shader框架增加结构体2

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

Shader"Custom/1.1.3"{

    Subshader{
        Pass{
        //渲染通道,用来完整描述一个渲染流水线
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
            //应用2顶点着色器
            struct a2v {//名称不能自定义
                //这里面定义顶点着色器的输入
                //每个输入都需要填写类型,名称,语义
                float4 v:POSITION;//每一个定义以分号结尾
                float4 tex:TEXCOORD0;//输入一个纹理信息
                float3 normal:NORMAL;
            };//这里需要注意,需要有个分号

            struct v2f {//顶点着色器与片元着色器之间传值的结构体
                float4 v:SV_POSITION;//不可缺少,传递剪裁空间的顶点
                float3 color:COLOR0;//输入颜色
            };


            //定义基本的顶点着色器的编程函数,以及片元着色器的编程函数。
            v2f vert(a2v v)  {//当有自定义结构体的时候,取消语义描述,因为语义已经在结构体中了
                v2f o;
                o.v = UnityObjectToClipPos(v.v);
                o.color = v.normal *0.5 + fixed3(0.5,0.5,0.5);//先缩小1/2,然后再+0.5,将范围定在0-1,现实效果就是表现出法线的方向
                return o;
                //矩阵乘法,将模型空间中的点,转到齐次剪裁空间中。
            }
            float4 frag(v2f i) :SV_Target {//SVTarget是着色器的语义
                return fixed4(i.color,1.0);
                //定义所有的片元光栅化的颜色为白色。
            }
            ENDCG
        }
    }

}

这里面多了一个v2f的结构体:
- v代表顶点,f代表片元着色器。
- 这里frag函数传入函数为v2f的实例,实际这个就是vert的输入参数。

- v2f中必须要定义一个SV_POSITION的参数。

连接shaderlab语言

之前所有的代码编写工作都是在顶点着色器以及片元着色器中,写成,与shaderlab语言基本上没有什么交集。
shaderlab语言是与unity项目对接的一个窗口,在这里将shaderlab与CG语言部分进行联合。

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

Shader"Custom/1.1.4"{
    Properties{
        _Color("color",Color) = (1.0,1.0,1.0,1.0)//定义了一个颜色属性,并给了一个初值
    }
        Subshader{
            Pass{
        //渲染通道,用来完整描述一个渲染流水线
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

            float4 _Color;//需要定义一个名称相同的变量。与properties中的相同
            //应用2顶点着色器
            struct a2v {//名称不能自定义
                //这里面定义顶点着色器的输入
                //每个输入都需要填写类型,名称,语义
                float4 v:POSITION;//每一个定义以分号结尾
                float4 tex:TEXCOORD0;//输入一个纹理信息
                float3 normal:NORMAL;
            };//这里需要注意,需要有个分号

            struct v2f {//顶点着色器与片元着色器之间传值的结构体
                float4 v:SV_POSITION;//不可缺少,传递剪裁空间的顶点
                float3 color:COLOR0;//输入颜色
            };


            //定义基本的顶点着色器的编程函数,以及片元着色器的编程函数。
            v2f vert(a2v v)  {//当有自定义结构体的时候,取消语义描述,因为语义已经在结构体中了
                v2f o;
                o.v = UnityObjectToClipPos(v.v);//模型空间到剪裁空间。中间需要经历模型空间到世界空间,世界空间到齐次剪裁空间
                o.color = v.normal *0.5 + fixed3(0.5,0.5,0.5);//先缩小1/2,然后再+0.5,将范围定在0-1,现实效果就是表现出法线的方向
                return o;
                //矩阵乘法,将模型空间中的点,转到齐次剪裁空间中。
            }
            float4 frag(v2f i) :SV_Target {//SVTarget是着色器的语义
                fixed3 c = i.color;
                c *= _Color;
                return fixed4(c,1.0);
                //定义所有的片元光栅化的颜色为白色。
            }
            ENDCG
        }
    }

}

这里面添加了一个Properties的模块,所有的unity窗口都在这里进行定义。
- 这里定义了一个_Color变量,这个变量名也就是我们与CG语言进行对接的一个名称,那么定义了一个color属性的变量 Color是shaderlab中的一个属性。等号后面就是初值。
- 除了Properties中的值,还需要在CG中定义一个与Properties相同的类型:float4 _Color
- 之后就能在CG语言中应用我们在unity中定义的值。

PS:后面的笔记将会以常用文本的方式记录,而不是使用markdown来写。

猜你喜欢

转载自blog.csdn.net/u011618339/article/details/78687352