Unity Shader概述
一、概述
在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)是一个键值对,它的键和值都是字符串类型。
| 标 签 类 型 | 说 明 | 例 子 |
| 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概述的更多相关文章
- Unity3D for VR 学习(8): Unity Shader概述
从西安到北京高铁上,一位VR老外团队的华人leader对VR技术做了画龙点睛: “3D游戏的核心部分在Render, 国内很多团队美术.程序中间缺失严重.所以3d游戏做不好. VR这块更是至关重要.” ...
- 【我的书】Unity Shader的书 — 文件夹(2015.12.21更新)
写在前面 感谢全部点进来看的朋友.没错.我眼下打算写一本关于Unity Shader的书. 出书的目的有以下几个: 总结我接触Unity Shader以来的历程,给其它人一个借鉴.我非常明确学Shad ...
- 【我的书】Unity Shader的书 — 目录(2016.5.19最后一次更新)
写在前面 感谢所有点进来看的朋友.没错,我目前打算写一本关于Unity Shader的书. 出书的目的有下面几个: 总结我接触Unity Shader以来的历程,给其他人一个借鉴.我非常明白学Shad ...
- Unity3D for VR 学习(9): Unity Shader 光照模型 (illumination model)
关于光照模型 所谓模型,一般是由学术算法发起, 经过大量实际数据验证而成的可靠公式 现在还记得2009年做TD-SCDMA移动通信算法的时候,曾经看过自由空间传播模型(Free space propa ...
- Unity Shader基础
Unity Shader基础 先上代码,代码一般是这样的. void Initialization(){ //先从硬盘加载代码再加载到GPU中 string vertexShaderCode = Lo ...
- 【Unity Shaders】Shader学习资源和Surface Shader概述
写在前面 写这篇文章的时候,我断断续续学习Unity Shader半年了,其实还是个门外汉.我也能体会很多童鞋那种想要学好Shader却无从下手的感觉.在这个期间,我找到一些学习Shader的教程以及 ...
- Unity Shader入门精要读书笔记(二)UnityShader概述
第三章<UnityShader概述>的读书笔记: 1.Unity Shader模板提供了几种选择: 标准光照模型(新添加的基于物理的渲染方法) 不含光照的基本的顶点.片元着色器 屏幕后处理 ...
- 【Unity Shader】Shader基础
目录 Chapter3 Unity Shader 基础 Chapter3 Unity Shader 基础 概述 在Unity需要材质(Material)与Unity Shader配合使用来达到满意的效 ...
- Unity Shader入门精要学习笔记 - 第3章 Unity Shader 基础
来源作者:candycat http://blog.csdn.net/candycat1992/article/ 概述 总体来说,在Unity中我们需要配合使用材质和Unity Shader才能达 ...
随机推荐
- Python 基础知识 (1) 持续更新
(1)数字和表达式 当进入Python交互式的时候,Python就可以直接当成计算机使用 如 >>> 2 + 2 4 但是 当 1个整数 和 另外一个整数 相除的时候,计算的结果,只 ...
- 自定义类似smarty模板
自定义类封装模板解析功能 原理其实比较简单,就是把html文件解析为一个超级字符串,然后把类似{{$mytitle}}这种结构的变量进行替换(str_replace)当然,实际中这样做可能导致频繁的磁 ...
- nodejs解析url参数的三种方法
要解析的url:http://127.0.0.1:8090/?name=cpc&age=21 利用js字符串操作函数进行解析 const myserver = require("ht ...
- http range request
range request: 要求实现该功能需要指定下载的实体范围
- 洛谷P4317 花神的数论题
洛谷题目链接 数位$dp$ 我们对$n$进行二进制拆分,于是就阔以像十进制一样数位$dp$了,基本就是套模板.. 接下来是美滋滋的代码时间~~~ #include<iostream> #i ...
- [Hihocoder] 字符串排序
题目 http://hihocoder.com/problemset/problem/1712 题解 https://www.zybuluo.com/wsndy-xx/note/1135606
- ubuntu安装chrome driver
首先下载Chrome Driver(Firefox Driver的安装与该步骤相同) 链接: http://chromedriver.storage.googleapis.com/index.html ...
- c 判断一个字符是否为字母数字
#include <stdio.h> #include <wctype.h> int main () { int i; wchar_t str[] = L"c3po. ...
- Manacher 算法学习小记
概要 一个字符串有多少个回文的字串?最多有 \(O(n^2)\) 级别个.但 Manacher 算法却可以用 \(O(n)\) 的时间复杂度解决这个问题.同时 Manacher 算法实现非常简单. 一 ...
- 如何知道,当前redis实例是处于阻塞状态?
随便get一个key,然后卡着不动就行,简单粗暴.优雅一点是看latency的延迟,blocked_clients的数量,rejected_connections的数量等 或者 方法一:登录 Redi ...