Unity Shader:表面着色器

本文同时发布在我的个人博客上:https://dragon_boy.gitee.io

表面着色器是一种对艺术家友好的着色器,它不同于传统的顶点着色器和片元着色器等流程,而是添加了一层抽象,整个渲染流程的着色器被分为三个:表面着色器、光照模型和光照着色器。其中,表面着色器定义了模型表面的反射率、法线和高光等,光照模型则选择兰伯特、Phong和Bliin-Phong等模型。光照着色器负责计算光照衰减和阴影等。绝大部分时候只需要关注表面着色器,例如纹理和颜色等,光照模型是提前定义的,光照着色其由系统定义,不会轻易更改。

表面着色器例子

Shader代码如下:

Shader "Unlit/BumpedDiffuse"
{
    Properties
    {
        _Color ("Color",Color) = (1,1,1,1)
        _MainTex ("Texture", 2D) = "white" {}
        _BumpMap("Normal Map", 2D) = "bump" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

       
            CGPROGRAM
            #pragma surface surf Lambert
            #pragma target 3.0
         
            
            struct Input {
                float2 uv_MainTex;
                float2 uv_BumpMap;
            };

            float4 _Color;
            sampler2D _MainTex;
           
            sampler2D _BumpMap;
           
            void surf(Input IN, inout SurfaceOutput o)
            {
                fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
                o.Albedo = tex.rgb * _Color.rgb;
                o.Alpha = tex.a * _Color.a;
                o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
            }
            ENDCG
       
    }
    FallBack "Diffuse"
}

效果如下:


编译指令

编译指令最重要的作用是指明该表面着色器使用的表面函数和光照函数,并设置一些可选参数。编译指令一般格式如下:

#pragma surface surfaceFunction lightModel [optionalparams]

表面函数

表面函数的输入结构体由自己定义,输出结构体有三种:

void surf(Input IN, inout surfaceOutput o);
void surf(Input IN, inout surfaceOutputStandard o);
void surf(Input IN, inout surfaceOutputStandardSpecular o);

光照函数

内置的光照函数有StandardStandardSpecularLambertBlinnPhong,我们也可以定义自己的光照函数,使用下面这种格式:

//不依赖视角的光照模型
half4 Lighting<Name> (SurfaceOutput s, half3 lightDir, half atten)
//依赖视角
half4 Lighting<Name> (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)

更多的例子参考官方文档。

其它可选参数。

这些参数包括是否开启透明度测试,透明度混合,指明自定义函数,控制生成的代码等。

  • 自定义的修改函数。表面着色器支持另外两种自定义的函数:顶点修改函数(vertex:VertexFunction)和最后颜色修改函数(final:ColorFunction)。顶点修改函数允许我们自定义一些顶点属性,最后颜色修改函数则可以最后修改一次颜色值。

其它的可选参数参考官方文档。

两个结构体

Input

表面函数的输入结构体Input,它定义了许多内置的变量,一些不同空间下的的顶点坐标,视角方向,法线方向,反射方向等。然后可以自定义一些变量,这些变量可以在自定义的函数中计算。

SurfaceOutPut结构体

相关定义在Lighting.cgincUnityPBSLighting.cginc中寻找。

表面着色器的实现

Unity在背后会根据表面着色器生成一个包含很多Pass的顶点\片元着色器,这些着色器会根据设置的渲染路径设置标签。同时还会根据编译指令的额外参数生成相应的Pass,我们可以在Shader面板点击Show generated code按钮来查看Unity自动生成的顶点\片元着色器。

Unity生成代码的过程如下:

  • 直接将表面着色器中CGPROGRAM和ENDCG之间的代码复制过来,这些代码包括我们对Input结构体、表面幻术、光照函数等变量和函数的定义。这些函数和变量会在之后的处理过程中被当成正常的结构体和函数进行调用。

  • Unity会分析上述代码,并据此生成顶点着色器的输出——v2f_surf结构体,用于在顶点着色器和片元着色器之间进行数据传递。Unity会分析我们在自定义函数中所使用的变量,如果需要就会在结构体中生成。

  • 接着生成顶点着色器。

  1. 如果我们自定义了顶点修改函数,Unity会首先调用定点修改函数来修改顶点数据,或填充自定义的Input结构体中的变量。然后,Unity会分析顶点修改函数中修改的数据,在需要通过Input结构体将修改结果存储到v2f_surf结构体中。

  2. 计算v2f_surf中其它生成的变量值。这主要包括顶点位置、纹理坐标等。

  3. 最后,将v2f_surf传递给接下来的片元着色器。

  • 生成片元着色器
  1. 使用v2f_sur中对应变量填充Input结构体。

  2. 调用我们自定义的表面函数填充SurfaceOuput结构体,或其它。

  3. 调用光照函数得到初始的颜色值。

  4. 进行其它的颜色叠加。

  5. 最后,如果自定义了最后的颜色修改函数,Unity就会调用它进行最后的颜色修改。

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