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

暴力反抗机器

0.本文示例代码地址

GitHub

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 片元着色器输出参数语义:

片元着色器输出
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,378评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,970评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,983评论 0 362
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,938评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,955评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,549评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,063评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,991评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,522评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,604评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,742评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,413评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,094评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,572评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,671评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,159评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,747评论 2 361

推荐阅读更多精彩内容