一、概述

在Unity中需要配合使用材质和Unity Shader才能达到需要的效果。常见的流程:(1)创建一个材质;(2)创建一个Unity Shader,并把它赋给创建的材质;(3)把材质赋给要渲染的对象;(4)在材质面板中调整Unity Shader的属性,以得到满意的效果。

二、Unity中的材质

Unity中的材质需要结合一个GameObject的Mesh或者Particle Systems组件来工作。它决定了我们的游戏对象看起来是什么样子的。

三、Unity中的Shader

Unity提供了四种Unity Shader模板:

1、Standard Surface Shader:产生一个包含了标准光照模型的表面着色器。

2、Unlit Shader:产生一个不包含光照(但包含雾效)的基本的顶点/片元着色器。

3、Image Effect Shader:为实现各种屏幕后处理效果提供基本模板。

4、Compute Shader:产生一种特殊的Shader文件,旨在利用GPU的并行性进行一些与常规渲染流水线无关的计算。

Shader文件说明:

Default Maps指定该Shader使用的默认纹理,当任何材质第一次使用该Shader时,这些纹理就自动被赋予到相应的属性上。

Surface shader和Fixed function用于表明该shader是一个表面着色器还是固定函数着色器,如果是某个着色器,在对应的位置就有Show generated code按钮,单击该按钮打开一个新的文件,该文件里将显示Unity在背后为该表面着色器生成的顶点/片元着色器。这可以方便我们对这些生成的代码进行修改(需要复制到一个新的Unity Shader中才可保存)和研究。

Cast shadows(是否会投射阴影)、Render queue(渲染队列)、LOD(LOD值)等,和我们在Shader中的标签设置有关。

Compile and show code下拉列表用于检查该Shader针对不同图像编程接口(例如OpenGL、D3D9等)最终编译成的Shader代码。

除此之外,面板还可以查看其是否关闭批处理(Disable batching)、属性列表(Properties)等信息。

四、Unity Shader的结构

基础结构:

Shader "ShaderName"{
Properties{
//属性
}
SubShader{
//显卡A使用的子着色器
}
SubShader{
//显卡B使用的子着色器
}
Fallback "VertexLit"
}

(1)Shader文件的第一行通过Shader语义指定该Shader的名字,由一个字符串来定义。通过在字符串中添加“/”,可以控制Shader在材质面板中出现的位置。例如:

Shader "Custom/MyShader"{   }

该Shader在材质面板中的位置就是:Shader->Custom->MyShader。

(2)Properties语义块包含了一系列属性,这些属性将会显示在材质面板中。

Properties {
Name ("display name", PropertyType) = DefaultValue
Name ("display name", PropertyType) = DefaultValue
//更多属性
}

指定名字(Name)可以让我们在Shader中访问它们。

显示的名字(display name)是出现在材质面板上的名字。

类型(Property Type)是每个值的类型。

默认值(DefaultValue)是为每个属性指定的默认值,当第一次把该Shader赋给某个材质时,面板上显示的就是这些值。

下面给出展示所有属性类型的例子:

Shader "Custom/ShaderLabProperties" {
Properties {
//Numbers and Sliders
_Int ("Int", Int) = 2
_Float ("Float", Float) = 1.5
_Range ("Range", Range(0.0, 5.0)) = 3.0
//Colors and Vectors
_Color ("Color", Color) = (1, 1, 1, 1)
_Vector ("Vector", Vector) = (2, 3, 6, 1)
//Textures
_2D ("2D", 2D) = "" {}
_Cube ("Cube", Cube) = "white" {}
_3D ("3D", 3D) = "black" {}
}
FallBack "Diffuse"
}

对于Int、Float、Range这些数字类型的属性,其默认值就是一个单独的数字;

对于Color和Vector这类属性,默认值就是用圆括号包围的一个四维向量;

对于2D、Cube、3D这类属性,默认值通过一个字符串后跟一个花括号来指定。其中,字符串要么是空的,要么是内置的纹理名称,花括号的作用原本是用于指定一些纹理属性,但在Unity5.0之后便取消了,如果需要类似功能,就需要自己在顶点着色器中编写计算相应纹理坐标的代码。

如果想要在材质面板上显示更多类型的变量,Unity允许重载默认的材质编辑面板,以提供更多自定义的数据类型。

参考: https://docs.unity3d.com/Manual/SL-CustomShaderGUI.html

(3)每一个Unity Shader文件可以包含多个SubShader语义块,但最少有一个。当Unity需要加载这个Unity Shader时,Unity会扫描所有的SubShader语义块,然后选择第一个能够在目标平台上运行的SubShader。如果都不支持的话,Unity就会使用Fallback语义指定的Unity Shader。Unity提供这种语义的目的在于适应不同能力的显卡。

SubShader {
//可选的
[Tags] //可选的
[RenderSetup] Pass {
}
//Other Passes
}

SubShader中定义了一系列Pass以及可选的状态([RenderSetup])和标签([Tags])设置。每个Pass定义了一次完整的渲染流程,但如果Pass的数目过多,往往会造成渲染性能的下降。因此,应尽量使用最小数目的Pass。

状态和标签同样可以在Pass声明。对于状态设置来说,SubShader和Pass是相同的,在SubShader进行的状态设置将会用于所有的Pass。不过对于标签设置来说,SubShader和Pass是不一样的。

状态设置

状  态  名  称 设  置  指  令 解    释
Cull Cull Back | Front | Off 设置剔除模式:剔除背面/正面/关闭剔除
ZTest ZTest Less Greater | LEqual | GEqual |Equal | NotEqual | Always 设置深度测试时使用的函数
ZWrite ZWrite On | Off 开启/关闭深度写入
Blend Blend SrcFactor DstFactor 开启并设置混合模式

SubShader的标签

SubShader的标签(Tags)是一个键值对,它的键和值都是字符串类型。

SubShader的标签类型
标  签  类  型 说    明 例    子
Queue 控制渲染顺序,指定该物体属于哪一个渲染队列,通过这种方式可以保证所有的透明物体可以在所有不透明物体后面被渲染,我们也可以自定义使用的渲染队列来控制物体的渲染顺序 Tags{"Queue"="Transparent"}
RenderType 对着色器进行分类,例如这是一个不透明的着色器,或是一个透明的着色器等。这可以被用于着色器替换(Shader Replacement)功能 Tags{"RenderType"="Opaque"}
DisableBatching 一些SubShader在使用Unity的批处理功能时会出现问题,例如使用了模型空间下的坐标进行顶点动画。这时可以通过该标签来直接指明是否对该SubShader使用批处理 Tags{"DisableBatching"="True"}
ForceNoShadowCasting 控制使用该SubShader的物体是否会投射阴影 Tags{"ForceNoShadowCasting"="True"}
IgnoreProjector 如果该标签值为“True”,那么使用该SubShader的物体将不会受Projector的影响。通常用于半透明物体 Tags{"IgnoreProjector"="True"}
CanUseSpriteAtlas 当该SubShader是用于精灵(sprites)时,将该标签设为“False” Tags{"CanUseSpriteAtlas"="False"}
PreviewType 指明材质面板将如何预览该材质。默认情况下,材质将显示为一个球形,我们可以通过把该标签的值设为“Plane”“SkyBox”来改变预览类型 Tags{"PreviewType"="Plane"}

Pass语义块

Pass {
[Name]
[Tags]
[RenderSetup]
//Other code
} 

我们可以在Pass中定义该Pass的名称,例如:

Name "MyPassName"

  通过这个名称,我们可以使用UsePass命令来直接使用其他Shader中的Pass。例如:

UsePass "MyShader/MYPASSNAME"

  这样可以提高代码的复用性。需要注意的是,Unity内部会把所有Pass的名称转换为大写字母表示。因此,使用UsePass命令时必须使用大写形式的名字。

Pass中设置的标签不同于SubShader的标签。这些标签也是用于告诉渲染引擎我们希望怎样来渲染物体。

标  签  类  型 说    明 例    子
LightMode 定义该Pass在Unity的渲染流水线中的角色 Tags{"LightMode"="ForwardBase"}
RequireOptions 用于指定当满足某些条件时才渲染该Pass,它的值是一个由空格分隔的字符串。 Tags{"RequireOptions"="SoftVegetation"}

除了上面普通的Pass定义外,Shader还支持一些特殊的Pass。

1.UsePass:可以使用该命令来复用其他Shader中的Pass。

2.GrabPass:该Pass负责抓取屏幕并将结果存储在一张纹理中,以用于后续的Pass处理。

(4)当所有的SubShader都不能在某张显卡上运行时,就使用Fallback指定的最低级的Shader,语义如下:

Fallback "name"
//或者
Fallback Off

  事实上,Fallback还会影响阴影的投射。在渲染阴影纹理时,Unity会在每个Untiy Shader中寻找一个阴影透视的Pass。通常,我们不需要自己专门实现一个Pass,这是因为Fallback使用的内置Shader中包含了这样一个通用的Pass。因此,为每个Untiy Shader正确设置Fallback是非常重要的。

Unity Shader概述的更多相关文章

  1. Unity3D for VR 学习(8): Unity Shader概述

    从西安到北京高铁上,一位VR老外团队的华人leader对VR技术做了画龙点睛: “3D游戏的核心部分在Render, 国内很多团队美术.程序中间缺失严重.所以3d游戏做不好. VR这块更是至关重要.” ...

  2. 【我的书】Unity Shader的书 — 文件夹(2015.12.21更新)

    写在前面 感谢全部点进来看的朋友.没错.我眼下打算写一本关于Unity Shader的书. 出书的目的有以下几个: 总结我接触Unity Shader以来的历程,给其它人一个借鉴.我非常明确学Shad ...

  3. 【我的书】Unity Shader的书 — 目录(2016.5.19最后一次更新)

    写在前面 感谢所有点进来看的朋友.没错,我目前打算写一本关于Unity Shader的书. 出书的目的有下面几个: 总结我接触Unity Shader以来的历程,给其他人一个借鉴.我非常明白学Shad ...

  4. Unity3D for VR 学习(9): Unity Shader 光照模型 (illumination model)

    关于光照模型 所谓模型,一般是由学术算法发起, 经过大量实际数据验证而成的可靠公式 现在还记得2009年做TD-SCDMA移动通信算法的时候,曾经看过自由空间传播模型(Free space propa ...

  5. Unity Shader基础

    Unity Shader基础 先上代码,代码一般是这样的. void Initialization(){ //先从硬盘加载代码再加载到GPU中 string vertexShaderCode = Lo ...

  6. 【Unity Shaders】Shader学习资源和Surface Shader概述

    写在前面 写这篇文章的时候,我断断续续学习Unity Shader半年了,其实还是个门外汉.我也能体会很多童鞋那种想要学好Shader却无从下手的感觉.在这个期间,我找到一些学习Shader的教程以及 ...

  7. Unity Shader入门精要读书笔记(二)UnityShader概述

    第三章<UnityShader概述>的读书笔记: 1.Unity Shader模板提供了几种选择: 标准光照模型(新添加的基于物理的渲染方法) 不含光照的基本的顶点.片元着色器 屏幕后处理 ...

  8. 【Unity Shader】Shader基础

    目录 Chapter3 Unity Shader 基础 Chapter3 Unity Shader 基础 概述 在Unity需要材质(Material)与Unity Shader配合使用来达到满意的效 ...

  9. Unity Shader入门精要学习笔记 - 第3章 Unity Shader 基础

    来源作者:candycat   http://blog.csdn.net/candycat1992/article/ 概述 总体来说,在Unity中我们需要配合使用材质和Unity Shader才能达 ...

随机推荐

  1. P5496 【模板】回文自动机(PAM)

    做一下强制在线处理即可 #include <cstdio> #include <algorithm> #include <cstring> using namesp ...

  2. BZOJ1791 [Ioi2008]Island 岛屿[基环树+单调队列优化DP]

    基环树直径裸题. 首先基环树直径只可能有两种形式:每棵基环树中的环上挂着的树的直径,或者是挂在环上的两个树的最大深度根之间的距离之和. 所以,先对每个连通块跑一遍,把环上的点找出来,然后对环上每个点跑 ...

  3. TypeError: Cannot read property '$$' of undefined at HTMLElement._attached.wx.getPlatform._touchstartHandlerForDevtools

    TypeError: Cannot read property '$$' of undefined     at HTMLElement._attached.wx.getPlatform._touch ...

  4. Codeforces Round #589 (Div. 2) A. Distinct Digits

    链接: https://codeforces.com/contest/1228/problem/A 题意: You have two integers l and r. Find an integer ...

  5. 立即执行函数与For. . .in语句

    ㈠立即执行函数 ⑴定义:在函数定义完,立即被调用,这样的函数叫做立即执行函数 ⑵语法:函数对象() ⑶注意:立即执行函数往往只会执行一次 ⑷示例1: (function(){ alert(" ...

  6. nginx之location模式

    这篇博客写的很nice, 转载:   https://www.jianshu.com/p/e154c2ef002f 简单记一下: 匹配语法:  =    ^~    ~(区分大小写)    ~*(不区 ...

  7. BZOJ 4562: [Haoi2016]食物链 拓扑排序

    建反图,跑一个拓扑排序dp即可. Code: #include <bits/stdc++.h> #define ll long long #define N 100005 #define ...

  8. Combine String HDU - 5707 dp or 广搜

    Combine String HDU - 5707 题目大意:给你三个串a,b,c,问a和b是不是恰好能组成c,也就是a,b是不是c的两个互补的子序列. 根据题意就可以知道对于c的第一个就应该是a第一 ...

  9. Linux版本内核及安装后的简单操作命令介绍

    一.Linux的版本与内核 1.Linux发行版 Linux发行版= Linux内核+应用程序 Redhat,CentOS,Ubuntu,Suse,红旗,Mint,Fedora CentOS:社区版操 ...

  10. CSS子元素在父元素中水平垂直居中的几种方法

    1. 水平居中(margin: auto;)子父元素宽度固定,子元素上设置 margin: auto; 子元素不能设置浮动,否则居中失效. #div1{ width: 300px; height: 3 ...