Unity Shader 入门到改行1——Unity Shader 结构

the Division Bell

0.本文示例代码地址

GitHub

1. 明确 Unity 中纹理、材质、Shader、模型的关系

以下的说法严格来说不准确,但是如果你对 Unity 不熟悉,可以先按照最简单的方式来理解:

  • 模型就是物体的形状,由一堆三角形组成
  • 纹理就是一张图片
  • Shader 是一段代码,描述了一种渲染的过程和方式
  • 材质就是用来描述物体的渲染,不同材质的物体渲染结果不一样

2. 默认的新建材质

2.1 在Unity 中新建一个场景并保存,如果场景带了默认的天空盒,把天空盒去掉。

如何去掉默认天空盒:Unity 菜单中 Window->Lighting->Settings,在面板中将 Environment->Skybox Material 设置为 None。
在新建的场景中将默认有一个摄像机 Camera,位置在(0,0,-10)

2.2 创建一个 Cube

在场景的 Hierarchy 视图中右键->3D Object->Cube,或 Unity 菜单 GameObject->3D Object->Cube,新建后的 Cube默认位置在(0,0,0),选中 Cube,查看 Inspector 视图,Cube 有一个组件 MeshRender

2.3 创建一个 Shader 文件

Unity 菜单 Assets->Create->Shader->Unlit Shader,将在对应目录产生一个 NewUnlitShader.shader 文件,重命名为01_Default.shader

2.4 创建一个材质

Unity 菜单 Assets->Create->Material, 创建一个材质,重命名为 01_Default.mat

2.5 为 Cube 指定材质和shader

新建的 Cube 的组件 MeshRender 有属性 material,如图所示:


MeshRender

将新创建的 Material 拖到 MeshRender 组件的 material 数组第一个元素中,就然后在材质下方选择我们新建的 01_Default shader,并在该shader的属性中指定一张贴图,步骤如下:


为材质指定shader和贴图

可以看到 Cube 的渲染结果为:
Cube

简单来说,就是 GameObject 有 MeshRender 组件,MeshRender 有材质,材质可以指定shader和纹理。也即是说通常 shader + 纹理共同确定了材质,材质可以指定给 MeshRender,决定 GameObject 的渲染结果。

3. Shader 结构分析

我们打开新建的 01_Default.shader 文件,代码如下:

Shader "Shader_Examples/01_Default"
  {
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog
            
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

可以看出 Unity Shader 的基本结构。

3.1 Shader名字

Shader "Shader_Examples/01_Default" 

Shader 的"查找路径" 和名字,在我们为某个材质指定 shader 时,在编辑器中将看到这个路径和名字,用来指定 shader。

3.2 Shader 属性

Shader 属性将会出现在材质面板中供我们调整,可以是数值、纹理、颜色等,01_Default 中只有一个纹理属性

        Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }

3.3 SubShader

通常一个 Shader 有一个或多个 SubShader 定义块,Shader 执行时,会按照 SubShader 的顺序,从上到下选择第一个能够在目标平台上运行的 SubShader 来执行,如果都不支持的话,会使用 Fallback 指定的 Shader,如果没有指定 Fallback,则不会渲染。

SubShader 的结构通常是这样的

SubShader {
        // 可选的
        [Tags]

        // 可选的
        [RenderSetup]
        
        Pass
        {
        }

        Pass
        {
        }
}
3.3.1 SubShader 的标签 Tags

Tags 是一个字符串类型的 key-value 结构,用来告诉 Unity,如何及何时渲染这个对象,标签的结构一般是:

        Tags { "TagName1" = "TagValue1", "TagName2"="TagValue2" }

SubShader 支持的标签类型如下:


Tags类型
3.3.2 SubShader 的状态设置 RenderSetup

RenderSetup 可以设置渲染的状态,例如是否开启深度测试、指定混合函数等,UnityShader 中常见的渲染状态设置:


RenderSetup

3.4 Pass

一个 SubShader 中可以指定多个 Pase,每个 Pass 定义了一次完整的渲染流程,Pass 过多会造成渲染性能下降,我们通常希望能够使用尽量少的 Pass 数目。

  • Pass 也可以指定 Tags,但是和 SubShader 的Tags 类型不同。
  • Pass 也可以指定 RenderSetup,和SubShader 可以指定的 RenderSetup 相同。区别在于 SubShader 指定的 RenderSetup 将应用于它的所有 Pass,而 Pass 指定的 RenderSetup 只应用于自己。
  • Pass 可以通过 Name "MyPass" 指定名字


    Pass的标签类型

3.5 顶点/片元着色器

我们创建了一个 Unity 的 Unlit Shader,这是一个 ShaderLab 封装后的着色器,术语 顶点/片元 着色器,在每个 Pass 语句块中需要定义 顶点着色器和片元着色器的实现。

通过 #pragma vertext vert_name 来指定顶点着色器
通过 #pragma fragment frag_name 来指定片元着色器,

在 我们创建的 01_Default 中,“函数” [v2f vert (appdata v) ] 和 [fixed4 frag (v2f i) : SV_Target] 分别就是 顶点着色器和 片段着色器。

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

推荐阅读更多精彩内容