unity—Shader

  1. 是运⾏在GPU上的一段代码,控制GPU的运算方式
  2. 着色器就是给定了输入,然后出输给Material进行着色的代码。
  • GameObject里有MeshRenderer
  • MeshRenderer里有Material列表
  • 每个Material里有且只有一个Shader
  • Material在编辑器暴露该Shader的可调属性

Shader的大体格式:

//格式1: ->  Shader "路径"    路径名跟Shader的名没有任何关系
Shader "Custom/MyShader/01" 
{
    //属性
    Properties  
    {      
        
    }
       //子着色器
      SubShader
      {
    
      }
      //默认Shadr(备胎),当上面的SubShader都不能用的时候,系统会使用这个备胎(渲染方案、Shader)
      FallBack "Diffuse" 
}
格式1的说明

Shader——Properties(属性):

Properties是通过在Inspector面板上提供出你所写出的控件

      Properties
      {
        //代码块
        //格式2:->  变量名("变量显示在编辑器中的名字",变量的类型)=初始值
        //语法2:_Name("Display Name", type) = defaultValue[{options}]
        
        _FloatValue("FloatValue",Float) =0.5        //定义一个浮点数
       
        _IntValue("IntValue",Int)=10                //定义一个整数   
        
        _Shininess("Shininess",Range(1,10))=5       //范围浮点数  :光泽度
     
        _Vector4("Vector4",Vector)=(1,2,3,4)                //四维变量  :四维数
        
        _MainColor("MainColor",Color)=(1,0,0,1)     //颜色   :主颜色
       
        _MainTexture("MainTexture",2D) = "white"{}  //贴图   :主纹理
       
        _RecTexture("RecTexture",Rect) = ""{}       //非2阶贴图变量   :副纹理
        
        _CubeTexture("CubeTexture",Cube) = ""{}         //立方体贴图变量   :天空盒子
       
        _3DTexture("3DTexture",3D) = ""{}           //3D贴图变量  :3D纹理
      }
语法2的说明

注:如果写完Shader出错优先检查上图(语法2的说明)的红色标注部分

语法2中type的种类:

类型 说明
Color 由RGBA(红绿蓝和透明度)四个量来定义
Color的效果展示
2D 2的阶数大小(256,512之类)的贴图。这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,最终被显示出来;
2D的效果展示
Rect 非2阶数大小的贴图
3D
Cube 立方体纹理(Cube map texture) [6张有联系的2D贴图的组合] 主要用来做反射效果(比如天空盒和动态反射),也会被转换为对应点的采样
Range(min, max) 介于min和max之间的浮点数,一般用来当作调整Shader某些特性的参数(比如透明度渲染的截止值可以是从0至1的值等)
Range的效果展示
Vector 创建4个栏位,让用户可以填入相应的浮点数,代表一个Vecto4(四维数)
Vector的效果展示

语法2中的defaultValue:(定义了这个属性的默认值)

类型 说明
Color 以0~1定义的rgba颜色,比如(1,1,1,1);
2D/Rect/Cube 对于贴图来说,默认值可以为一个代表默认tint(色彩)颜色的字符串,可以是空字符串或者”white”,”black”,”gray”,”bump”中的一个 —> "白","黑","灰","(碰撞???)"
Float,Range 某个指定的浮点数
Vector 一个4维数,写为 (x,y,z,w)

语法2中的{option}:

它只对2D,Rect或者Cube贴图有关,在写输入时我们最少要在贴图之后写一对什么都不含的空白的{},当我们需要打开特定选项时可以把其写在这对花括号内。如果需要同时打开多个选项,可以使用空白分隔。可能的选择有ObjectLinear, EyeLinear, SphereMap, CubeReflect, CubeNormal中的一个,这些都是OpenGL(https://en.wikibooks.org/wiki/GLSL_Programming/Unity)中TexGen的模式

Shader——SubShader(子着色器)

一个Shader有多个SubShader。每个Shader至少1个SubShader。一个SubShader可理解为一个Shader的一个渲染方案。(SubShader是为了针对不同的渲染情况而编写的)

      SubShader
      {
            Tags{"RenderType" = "Opaque"}
            LOD 200
      }   

Tags

表面着色器可以被若干的标签(tags)所修饰,而硬件将通过判定这些标签来决定什么时候调用该着色器。告诉了系统应该在渲染非透明物体时调用我们。

Queue指定了物体的渲染顺序,预定义的Queue有:

语法:Tags { "RenderType"="Opaque" }

标签类型:

  • "IgnoreProjector"="True"(值为"true"时,表示不接受Projector组件的投影。)
  • "ForceNoShadowCasting"="True"(从不产生阴影)
  • "Queue"="xxx"(指定渲染顺序队列)《--如果你使用Unity做过一些透明和不透明物体的混合的话,很可能已经遇到过不透明物体无法呈现在透明物体之后的情况。这种情况很可能是由于Shader的渲染顺序不正确导致的--》
  • Background - 最早被调用的渲染,用来渲染天空盒或者背景
  • Geometry - 这是默认值,用来渲染非透明物体(普通情况下,场景中的绝大多数物体应该是非透明的)
  • AlphaTest - 用来渲染经过Alpha Test的像素,单独为AlphaTest设定一个Queue是出于对效率的考虑
  • Transparent - 以从后往前的顺序渲染透明物体(绝大部分透明的物体、包括粒子特效都使用这个)
  • Overlay - 用来渲染叠加的效果,是渲染的最后阶段(比如镜头光晕等特效)

LOD:

LOD很简单,它是Level of Detail的缩写,在这里例子里我们指定了其为200(其实这是Unity的内建Diffuse着色器的设定值)。这个数值决定了我们能用什么样的Shader。在Unity的Quality Settings中我们可以设定允许的最大LOD,当设定的LOD小于SubShader所指定的LOD时,这个SubShader将不可用。Unity内建Shader定义了一组LOD的数值,我们在实现自己的Shader的时候可以将其作为参考来设定自己的LOD数值,这样在之后调整根据设备图形性能来调整画质时可以进行比较精确的控制。

  • VertexLit及其系列 = 100
  • Decal, Reflective VertexLit = 150
  • Diffuse = 200
  • Diffuse Detail, Reflective Bumped Unlit, Reflective Bumped VertexLit = 250
  • Bumped, Specular = 300
  • Bumped Specular = 400
  • Parallax = 500
  • Parallax Specular = 600

《重点》

Shader "Custom/MyShader/01" 
{
    Properties
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }
    SubShader
    {
        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;

        struct Input 
        {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutput o) 
        {
            half4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

CG语言的使用:

编译指令:#pragma surface surf Lambert

它声明了我们要写一个表面Shader,并指定了光照模型。

  • surface :声明的是一个表面着色器
  • surfaceFunction : 着色器代码的方法的名字
  • lightModel : 使用的光照模型。

GLSL贴图类型:

  • sampler1D
  • sampler2D
  • sampler3D
  • samplerCube

sampler2D就是和texture所绑定的一个数据容器接口
解释下为什么在这里需要一句对_MainTex的声明
已经在Properties里声明过_MainTex,Shader其实是由两个相对独立的块组成的,外层的属性声明,回滚等等是Unity可以直接使用和编译的ShaderLab;而在CGPROGRAM...ENDCG这样一个代码块中,这是一段CG程序。对于CG程序,要访问在Properties中所定义的变量,必须使用和之前变量相同的名字进行再次声明。sampler2D _MainTex; 就是再次声明并链接了Properties中的_MainTex,使得CG程序能够使用这个变量。

struct结构体

struct中的Input是需要我们去定义的结构,把所需要参与计算的数据都放到这个Input结构中,然后再传入surf函数使用。

struct Input{}的效果图

UV:

UV mapping的作用是将一个2D贴图上的点按照一定规则映射到3D模型上,是3D渲染中最常见的一种顶点处理手段。规定: 在一个贴图变量(在我们例子中是_MainTex)之前加上uv两个字母,且代表提取它的uv值(相当于贴图上点的二维坐标),这样就可以在surf函数中通过访问uv_MainTex来取得这张贴图当前需要计算的点的坐标值。

surf函数:着色器的工作核心

CG规定了声明为表面着色器的方法(surf)的参数类型和名字,因此我们没有权利决定surf的输入输出参数的类型,只能按照规定写。规定是:它的两个参数:

  • 第一个是Input
  • 第二个是一个可写的SurfaceOutput。
    SurfaceOutput是已经定义好了里面类型输出结构,但是一开始的时候内容暂时是空白的,我们需要向里面填写输出,这样就可以完成着色了**SurfaceOutput是预定义的输出结构,surf函数的目的是根据输入的数据把这个输出结构给填上。
    surf函数

    tex2D函数

    tex2D函数:是CG程序中用来在一张贴图中对一个点进行采样的方法,返回一个half4。这里对_MainTex在输入点上进行了采样,并将其颜色的rbg值赋予了输出的像素颜色,将a值赋予透明度。于是,着色器就明白了应当怎样工作:即找到贴图上对应的uv点,直接使用颜色信息来进行着色

SurfaceOutput

half指的是半精度浮点数,精度最低,运算性能相对比高精度浮点数高一些,因此被大量使用

Shader中变量类型在相应位置的写法

CG标准库函数
UnityCG.cginc

参考资料:
https://onevcat.com/2013/07/shader-tutorial-1/
https://www.jianshu.com/p/7b9498e58659

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