Unity Shader 入门精要 | 第五章 开始 Unity Shader 学习之旅

欢迎前往个人博客 驽马点滴 和视频空间 哔哩哔哩-《挨踢日志》

5.1 本书使用的软件和环境

介绍 Unity Shader 的学习环境,开发平台、Unity 版本等信息。

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

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

Shader "Unity Shaders Book/Chapter 5/ Simple Shader" {
    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            float4 vert(v: POSITION): SV_POSITION {
                // return mul(UNITY_MATRIX_MVP, v);
                // Unity Upgrade NOTE: replace 'mul(UNITY_MATRIX_MVP, *)' with 'UnityObjectToClipPos(*)'
                return UnityObjectToClipPos(v);
            }
            fixed4 frag(): SV_Target {
                return fixed4(1.0, 1.0, 1.0, 1.0);
            }
            ENDCG
        }
    }
}

几个点:

  1. Properties 属性不是必须的(方便材质面板中友好的用户显示);
  2. 顶点/片元着色器的 CGPROGRAM 和 ENDCG 写在 Pass 中;
  3. '#pragma vertex' 和 '#pragma fragment frag' 属于编译指令,告诉 Unity 顶点着色器和片元着色器的代码包含在哪个函数中;
  4. POSITION 是 Cg/HLSL 中的语义,用来指明顶点坐标;
  5. SV_POSITION 也是 Cg/HLSL 中的语义,用来指明顶点着色器的输出是裁剪空间中顶点坐标;
  6. mul(UNITY_MATRIX_MVP, v) 将顶点坐标变换到裁剪空间中(在第四章数学基础中已知),该使用方法,在新版本的 Unity 中,已替换成 UnityObjectToClipPos(v);
  7. SV_Target 是 HLSL 中的语义,它告诉渲染器把用户的输出颜色存储到一个渲染目标(Render Target)中;
  8. 片元着色器返回 fixed4 类型的变量,每个分量在 [0, 1] 中取值,[0, 0, 0] 表示黑色,[1, 1, 1] 表示白色;

上述 Shader 中,传入顶点着色器的只有顶点的位置 POSITION,而我们知道,顶点还记录了其他的信息,比如 法线、纹理坐标、颜色等等。为了获得这些的数据,该如何做呢?因此引出下一节的内容,定义一个结构体,给顶点着色器传入更多的数据。

5.2.2 模型数据从哪里来

我们想获取顶点的法线和纹理坐标信息,因此将 Shader 改写如下:

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;
            };

            float4 vert(a2v v): SV_POSITION {
                return UnityObjectToClipPos(v.vertex);
            }

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

其中:

  1. struct 书写格式需要注意,结构体的定义在末尾需要加分号;
  2. a2v 的意思是应用程序数据转为顶点数据(application data to vertex data);
  3. 结构体中,声明 float4 vertex : POSITION ,那么 Unity 会将顶点数据自动填充到 vertex 变量中;声明 float3 normal: NORMAL,那么 Unity 会将法线数据自动填充到 normal 变量中;声明 float4 texcoord: TEXCOORD0, Unity 会将第一个纹理坐标填充到 texcoord 变量中;

5.2.3 顶点着色器和片元着色器之间如何通信

  1. 定义从顶点着色器输出的数据结构 v2f;
  2. 片元着色器中,将 v2f 对象作为参数传入;
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 {
                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 {
                return fixed4(i.color, 1.0);
            }
            ENDCG
        }
    }
}

注意点:

  1. 顶点着色器输出结构中,必须包含一个变量,其语义为 SV_POSITION ;
  2. COLOR0 语义中的数据可以由用户自己定义,一般存储颜色(如漫反射颜色或者高光反射颜色);
  3. 片元着色器中的输入,实际是将顶点着色器中的顶点数据进行插值后得到的结果;

5.2.4 如何使用属性

  1. 在 Shader 的 Properties 中添加变量 _Color("Color Tint", Color) = (1.0, 1.0, 1.0, 1.0);
  2. 在 CGPROGRAM 中定义同名变量 fixed4 _Color;
    3.在 frag 中使用该变量;
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unity Shaders Book/Chapter 5/ Simple Shader" {
    Properties {
        _Color ("Color Tint", Color) = (1.0, 1.0, 1.0, 1.0)
    }

    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert 
            #pragma fragment frag 

            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;
                c *= _Color.rgb;
                return fixed4(c, 1.0);
            }
            ENDCG
        }
    }
}

5.3 强大的援手:Unity 提供的内置文件和变量

官方网站(http://unity3d.com/cn/get-unity/download/archive)上下载 Unity 的包含文件。

Unity 中常用的包含文件:
UnityCG.cginc ——包含了常用的帮助函数、宏和结构体;
HLSLSupport.cginc ——声明了很多用于跨平台编译的宏和定义,编译 Unity Shader 时,会自动包含;
UnityShaderVariables.cginc——包含了许多内置的全局变量,如 UNITY_MATRIX_MVP 等,编译 Unity Shader 时,会自动包含;
Lighting.cginc ——包含各种内置光照,如果是 Surface Shader ,会自动包含进来。

UnityCG.cginc 中包含的常用结构体:
appdata_base:可用于顶点着色器的输入,包含顶点位置、顶点法线、第一组纹理坐标;
appdata_tan: 可用于顶点着色器的输入,包含顶点位置、顶点法线、顶点切线、第一组纹理坐标;
appdata_full: 可用于顶点着色器的输入,包含顶点位置、顶点法线、顶点切线、四组(或更多组)纹理坐标;
appdata_img: 可用于顶点着色器的输入,包含顶点位置、第一组纹理坐标;
v2f_img: 可用于顶点着色器的输出,包含裁剪空间中的位置、纹理坐标;

一些帮助函数:(略)

5.5 程序员的烦恼:Debug

(略)主要通过输出颜色来调试,比较原始。

欢迎前往个人博客 驽马点滴 和视频空间 哔哩哔哩-《挨踢日志》

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

推荐阅读更多精彩内容