美文网首页
Unity Shader 入门到改行2——最简单的顶点/片元着色

Unity Shader 入门到改行2——最简单的顶点/片元着色

作者: 太刀 | 来源:发表于2020-12-13 22:57 被阅读0次
    暴力反抗机器

    1. 去掉 Default Shader 中的干扰项

    重复上一篇文章提到的操作,新建一个场景 02_Simplest.unity, 去掉自带天空盒。在场景中创建一个 Cube、新建Material 文件 02_Simplest,然后新建 Unity Unlit Shader 并命名为 02_Simplest.shader并打开,用如下的代码覆盖 02_Simplest.shader

    Shader "Shader_Examples/02_Simplest"
    {
        SubShader
        {       
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag                                               
                
                float4 vert (float4 v : POSITION) : SV_POSITION         
                {               
                    return UnityObjectToClipPos(v);             
                }
                
                fixed4 frag () : SV_Target
                {   
                    return fixed4(1.0,0,0,1.0);             
                }
    
                ENDCG
            }
        }
    }
    

    这是包含最简单的顶点和片元着色器的 shader 了,顶点着色函数只干一件事:进行坐标变换,将顶点的模型坐标(由MeshRender 组件提供)变换到裁剪空间坐标。这是顶点着色器最基本的任务。片元着色器只干一件事:返回一个 RGBA 颜色。

    2. 顶点着色器的执行

    我们给新建的 Cube 指定02_Simplest 进行渲染,可以看到整个 Cube 是红色的。我们先来看顶点着色器运行逻辑。如果了解渲染管线的话我们知道,在应用程序阶段,CPU 会将顶点数据准备好,提交给管线,在 Unity 中,这个工作由 MeshRender 来完成。我们假设这个 Cube 在 MeshRender 中由6个顶点表示(在 Unty 中实际并不是,原因先不管),那么在调用 DrawCall 渲染这个 Cube时,通过MeshRender 提交的顶点数据是一个长度为6的 Vector4 数组(为什么不用Vector3,涉及到具体的变换过程,齐次坐标,先不要考虑)。

    执行的过程可以这样理解(我这段代码只是帮助理解,实际过程是GPU来处理的)

             for (int i = 0; i < vertexList.length; i++)
             {
                    float4 v = vertexList[i].POSITION;
                    vert(v);
             }
    

    划重点:顶点着色器是逐顶点执行的,针对提交的每个顶点,执行一次顶点着色函数。顶点着色函数将顶点坐标进行 MVP 变换后得到的裁剪空间坐标作为返回值,提供给下一阶段的片元着色器。

    3. 片元着色器的执行

    暂时可以把“片元”理解为”屏幕像素”(事实上他们差别巨大,但是此时姑且这么认为,有助于你理解片元着色器的工作)。先看片元着色函数的返回,是一个颜色值。就是说绘制了某个像素的颜色。事实上,片元着色器是逐片元执行的。也就是针对当前渲染图元覆盖的每一个像素,执行一遍。伪代码如下:

            for (int i = 0; i < fragmentList.length;i++)
            {
                    fixed4 red = new fixed4(1,0,0,1);
                    fragmentList.color = red;
             }
    

    可以简单的理解为:当片段着色器执行完成,屏幕上对应的像素立即变成红色。

    如何计算 Cube 覆盖了哪些像素,这个过程叫“光栅化”,是GPU渲染流程的一个阶段,具体的算法暂不讨论。

    4. 顶点着色器和片元着色器的数据传输

    最简单的顶点着色器对每个顶点执行 MVP 变换,得到顶点在裁剪空间的坐标,作为顶点着色器的输出,也是片元着色器的输入。那么,我们的 Cube 只有6个顶点,只返回了6次,而片元着色器执行的次数却不是6次,那么它的输入是怎么得来的?
    线性插值 得到。根据某一个片元中心位置(片元有大小)坐标距离覆盖它的三角形(顶点数组中的3个元素组成)的三个顶点的距离,加权计算得到(如 0.1p1 + 0.3p2 + 0.6*p3)。
    不仅仅位置属性是插值计算得到,其它属性(例如法线、uv坐标等)也是这么计算得到的。

    5. 顶点着色器的输入可以是哪些属性?

    在我们这个最简单的 shader 里面,顶点着色函数的输入就是一个顶点位置

            float4 vert (float4 v : POSITION) : SV_POSITION
    

    通常顶点数据有很多,除了位置还有法线、切线、纹理坐标等,我们怎么知道这个参数 v 是用的位置的数据?因为我们给它制定了 POSITION 这个语义,意思就是将顶点数据中的 位置作为v传递给顶点着色函数,SV_POSITION 则表示,这个顶点着色函数的返回是一个裁剪空间的坐标。

    顶点着色器必须包含 SV_POSITION 的输出,也就是说顶点着色器的输出里面必须包含顶点的裁剪空间坐标。否则后续阶段将无法知道这个顶点的位置,无法渲染出来。

    6. 自定义输入输出结构

    02_Simplest 这个 shader 里面,顶点着色函数只处理了位置信息,也只返回了位置信息,那当我们需要处理其它顶点数据信息时,怎么处理?我们可以自定义顶点数据结构,可以自定义字段,只要指定语义就可以了。比如

            
        struct appdata
        {
            float4 vertex : POSITION;  // 将顶点的位置信息作为vertext
            float2 uv : TEXCOORD0;   // 将顶点的第0组纹理坐标作为 uv
        };
    
        struct v2f
        {
            float2 uv : TEXCOORD0;    // uv表示处理后的顶点纹理坐标
            float4 vertex : SV_POSITION;   // vertext 标示处理后的顶点坐标
        };
    

    有了上面的结构体定义,我们就可以在顶点着色函数和片元着色函数中如下使用:

     
        v2f vert (appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);  // 对顶点坐标进行变化
            o.uv = TRANSFORM_TEX(v.uv, _MainTex);       
            return o;
        }
                
        fixed4 frag (v2f i) : SV_Target
        {               
            fixed4 col = tex2D(_MainTex, i.uv);     
            return col;
        }
    

    片元着色函数的 SV_Target 是啥?SV_Taget 表示,将这个片元输出的颜色,放到一个 RT(RenderTarget)中,这里先简单理解为放到一个缓冲区中。

    目前 Unity Shader 中有哪些 语义呢

    6.1 顶点着色函数输入参数语义:

    顶点着色器输入

    6.2 顶点着色器传递给片元着色器参数语义:

    片元着色器输入

    6.3 片元着色器输出参数语义:

    片元着色器输出

    相关文章

      网友评论

          本文标题:Unity Shader 入门到改行2——最简单的顶点/片元着色

          本文链接:https://www.haomeiwen.com/subject/kxipgktx.html