Unity Shader入门精要第3 章 Unity Shader 基础--1

Unity系列文章目录

前言

一、3.3 Unity Shader 的结构

3.3.1 给我们的Shader 起个名字

每个Unity Shader 文件的第一行都需要通过Shader
语义来指定该Unity Shader 的名字。这个名字由一个字
符串来定义,例如“MyShader”。当为材质选择使用的
Unity Shader 时,这些名称就会出现在材质面板的下拉列
表里。通过在字符串中添加斜杠(“/”),可以控制Unity
Shader 在材质面板中出现的位置。例如:
Shader “Custom/MyShader” { }
那么这个Unity Shader 在材质面板中的位置就是:
Shader -> Custom -> MyShader,如图3.7 所示。
在这里插入图片描述

3.3.2 材质和Unity Shader 的桥梁:Properties

Properties 语义块中包含了一系列属性(property),
这些属性将会出现在材质面板中。
Properties 语义块的定义通常如下:

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

开发者们声明这些属性是为了在材质面板中能够方便地调整各种材质属性。如果我们需要在
Shader 中访问它们,就需要使用每个属性的名字(Name)。在Unity 中,这些属性的名字通常由
一个下划线开始。显示的名称(display name)则是出现在材质面板上的名字。我们需要为每个
属性指定它的类型(PropertyType),常见的属性类型如表3.1 所示。除此之外,我们还需要为每
个属性指定一个默认值,在我们第一次把该Unity Shader 赋给某个材质时,材质面板上显示的就
是这些默认值。

在这里插入图片描述

对于Int、Float、Range 这些数字类型的属性,其默认值就是一个单独的数字;对于Color
和Vector 这类属性,默认值是用圆括号包围的一个四维向量;对于2D、Cube、3D 这3 种纹理类
型,默认值的定义稍微复杂,它们的默认值是通过一个字符串后跟一个花括号来指定的,其中,
字符串要么是空的,要么是内置的纹理名称,如“white”“black”“gray”或者“bump”。花括号
的用处原本是用于指定一些纹理属性的,例如在Unity 5.0 以前的版本中,我们可以通过TexGen
CubeReflect、TexGen CubeNormal 等选项来控制固定管线的纹理坐标的生成。但在Unity 5.0 以
后的版本中,这些选项被移除了,如果我们需要类似的功能,就需要自己在顶点着色器中编写计
算相应纹理坐标的代码。
下面的代码给出了一个展示所有属性类型的例子:

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"
}

图3.8 给出了上述代码在材质面板中的显示结果。
有时,我们想要在材质面板上显示更多类型的变量,例如使用
布尔变量来控制Shader 中使用哪种计算。Unity 允许我们重载默认的
材质编辑面板,以提供更多自定义的数据类型。我们在本书资源的材
质Assets -> Materials -> Chapter3 -> RedifyMat 中提供了这样一个简
单的例子,这个例子参考了官方手册的Custom Shader GUI 一文
(http://docs.unity3d.com/Manual/SL-CustomShaderGUI.html)中的代码。
为了在Shader 中可以访问到这些属性,我们需要在Cg 代码片
中定义和这些属性类型相匹配的变量。需要说明的是,即使我们不
在Properties 语义块中声明这些属性,也可以直接在Cg 代码片中定
义变量。此时,我们可以通过脚本向Shader 中传递这些属性。因此,Properties 语义块的作用仅仅是为了让这些属性可以出现在材质面板中。
在这里插入图片描述

3.3.3 重量级成员:SubShader

每一个Unity Shader 文件可以包含多个SubShader 语义块,但最少要有一个。当Unity 需要加
载这个Unity Shader 时,Unity 会扫描所有的SubShader 语义块,然后选择第一个能够在目标平台
上运行的SubShader。如果都不支持的话,Unity 就会使用Fallback 语义指定的Unity Shader。
Unity 提供这种语义的原因在于,不同的显卡具有不同的能力。例如,一些旧的显卡仅能支
持一定数目的操作指令,而一些更高级的显卡可以支持更多的指令数,那么我们希望在旧的显卡
上使用计算复杂度较低的着色器,而在高级的显卡上使用计算复杂度较高的着色器,以便提供更
出色的画面。
SubShader 语义块中包含的定义通常如下:

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

SubShader 中定义了一系列Pass 以及可选的状态([RenderSetup])和标签([Tags])设置。每个
Pass 定义了一次完整的渲染流程,但如果Pass 的数目过多,往往会造成渲染性能的下降。因此,我
们应尽量使用最小数目的Pass。状态和标签同样可以在Pass 声明。不同的是,SubShader 中的一些标
签设置是特定的。也就是说,这些标签设置和Pass 中使用的标签是不一样的。而对于状态设置来说,
其使用的语法是相同的。但是,如果我们在SubShader 进行了这些设置,那么将会用于所有的Pass。
 状态设置
ShaderLab 提供了一系列渲染状态的设置指令,这些指令可以设置显卡的各种状态,例如是
否开启混合/深度测试等。表3.2 给出了ShaderLab 中常见的渲染状态设置选项。
在这里插入图片描述
当在SubShader 块中设置了上述渲染状态时,将会应用到所有的Pass。如果我们不想这样(例
如在双面渲染中,我们希望在第一个Pass 中剔除正面来对背面进行渲染,在第二个Pass 中剔除
背面来对正面进行渲染),可以在Pass 语义块中单独进行上面的设置。
 SubShader 的标签
SubShader 的标签(Tags)是一个键值对(Key/Value Pair),它的键和值都是字符串类型。这
些键值对是SubShader 和渲染引擎之间的沟通桥梁。它们用来告诉Unity 的渲染引擎:我希望怎
样以及何时渲染这个对象。
标签的结构如下:

Tags { "TagName1" = "Value1" "TagName2" = "Value2" }

在这里插入图片描述

具体的标签设置我们会在本书后面的章节中讲到。
需要注意的是,上述标签仅可以在SubShader 中声明,而不可以在Pass 块中声明。Pass 块虽
然也可以定义标签,但这些标签是不同于SubShader 的标签类型。这是我们下面将要讲到的。
 Pass 语义块
Pass 语义块包含的语义如下:

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

首先,我们可以在Pass 中定义该Pass 的名称,例如:
Name “MyPassName”
通过这个名称,我们可以使用ShaderLab 的UsePass 命令来直接使用其他Unity Shader 中的
Pass。例如:
UsePass “MyShader/MYPASSNAME”
这样可以提高代码的复用性。需要注意的是,由于Unity 内部会把所有Pass 的名称转换成大
写字母的表示,因此,在使用UsePass 命令时必须使用大写形式的名字。
其次,我们可以对Pass 设置渲染状态。SubShader 的状态设置同样适用于Pass。除了上面提
到的状态设置外,在Pass 中我们还可以使用固定管线的着色器(详见3.4.3 节)命令。
Pass 同样可以设置标签,但它的标签不同于SubShader 的标签。这些标签也是用于告诉渲染引擎我们希望怎样来渲染该物体。表3.4 给出了Pass 中使用的标签类型。
在这里插入图片描述
除了上面普通的Pass 定义外,Unity Shader 还支持一些特殊的Pass,以便进行代码复用或实
现更复杂的效果。
 UsePass:如我们之前提到的一样,可以使用该命令来复用其他Unity Shader 中的Pass;
 GrabPass:该Pass 负责抓取屏幕并将结果存储在一张纹理中,以用于后续的Pass 处理(详
见10.2.2 节)。
如果读者对上述出现的某些定义和名词无法理解,也不要担心。在本书后面的章节中,我们
会对这些内容进行更加深入的讲解。

3.3.4 留一条后路:Fallback

紧跟在各个SubShader 语义块后面的,可以是一个Fallback 指令。它用于告诉Unity,“如果
上面所有的SubShader 在这块显卡上都不能运行,那么就使用这个最低级的Shader 吧!”
它的语义如下:
Fallback “name”
// 或者
Fallback Off
如上所述,我们可以通过一个字符串来告诉Unity 这个“最低级的Unity Shader”是谁。我们
也可以任性地关闭Fallback 功能,但一旦你这么做,你的意思大概就是:“如果一块显卡跑不了
上面所有的SubShader,那就不要管它了!”
下面给出了一个使用Fallback 语句的例子:
Fallback “VertexLit”
事实上,Fallback 还会影响阴影的投射。在渲染阴影纹理时,Unity 会在每个Unity Shader 中
寻找一个阴影投射的Pass。通常情况下,我们不需要自己专门实现一个Pass,这是因为Fallback
使用的内置Shader 中包含了这样一个通用的Pass。因此,为每个Unity Shader 正确设置Fallback
是非常重要的。更多关于Unity 中阴影的实现,可以参见9.4 节。

3.3.5 ShaderLab 还有其他的语义吗

除了上述的语义,还有一些不常用到的语义。例如,如果我们不满足于Unity 内置的属性类
型,想要自定义材质面板的编辑界面,就可以使用CustomEditor 语义来扩展编辑界面。我们还可
以使用Category 语义来对Unity Shader 中的命令进行分组。由于这些命令很少用到,本书将不再
进行深入的讲解。

3.4 Unity Shader 的形式

在上面,我们讲了Unity Shader 文件的结构以及ShaderLab 的语法。尽管Unity Shader 可以做的事情非常多(例如设置渲染状态等),但其最重要的任务还是指定各种着色器所需的代码。这些
着色器代码可以写在SubShader 语义块中(表面着色器的做法),也可以写在Pass 语义块中(顶
点/片元着色器和固定函数着色器的做法)。
在Unity 中,我们可以使用下面3 种形式来编写Unity Shader。而不管使用哪种形式,真正意
义上的Shader 代码都需要包含在ShaderLab 语义块中,如下所示:
Shader “MyShader” {
Properties {
// 所需的各种属性
}
SubShader {
// 真正意义上的Shader 代码会出现在这里
// 表面着色器(Surface Shader)或者
// 顶点/片元着色器(Vertex/Fragment Shader)或者
// 固定函数着色器(Fixed Function Shader)
}
SubShader {
// 和上一个SubShader 类似
}
}
3.4.1 Unity 的宠儿:表面着色器
表面着色器(Surface Shader)是Unity 自己创造的一种着色器代码类型。它需要的代码量很
少,Unity 在背后做了很多工作,但渲染的代价比较大。它在本质上和下面要讲到的顶点/片元着
色器是一样的。也就是说,当给Unity 提供一个表面着色器的时候,它在背后仍旧把它转换成对
应的顶点/片元着色器。我们可以理解成,表面着色器是Unity 对顶点/片元着色器的更高一层的抽
象。它存在的价值在于,Unity 为我们处理了很多光照细节,使得我们不需要再操心这些“烦人
的事情”。
一个非常简单的表面着色器示例代码如下:
Shader “Custom/Simple Surface Shader” {
SubShader {
Tags { “RenderType” = “Opaque” }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : COLOR;
};
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = 1;
}
ENDCG
}
Fallback “Diffuse”
}
从上述程序中可以看出,表面着色器被定义在SubShader 语义块(而非Pass 语义块)中的
CGPROGRAM 和ENDCG 之间。原因是,表面着色器不需要开发者关心使用多少个Pass、每个
Pass 如何渲染等问题,Unity 会在背后为我们做好这些事情。我们要做的只是告诉它:“嘿,使
用这些纹理去填充颜色,使用这个法线纹理去填充法线,使用Lambert 光照模型,其他的不要
来烦我!”。
CGPROGRAM 和ENDCG 之间的代码是使用Cg/HLSL 编写的,也就是说,我们需要把
Cg/HLSL 语言嵌套在ShaderLab 语言中。值得注意的是,这里的Cg/HLSL 是Unity 经封装后提供
的,它的语法和标准的Cg/HLSL 语法几乎一样,但还是有细微的不同,例如有些原生的函数和用
法Unity 并没有提供支持。

3.4.2 最聪明的孩子:顶点/片元着色器

在Unity 中我们可以使用Cg/HLSL 语言来编写顶点/片元着色器(Vertex/Fragment Shader)。
它们更加复杂,但灵活性也更高。
一个非常简单的顶点/片元着色器示例代码如下:
Shader “Custom/Simple VertexFragment Shader” {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 v : POSITION) : SV_POSITION {
return mul (UNITY_MATRIX_MVP, v);
}
fixed4 frag() : SV_Target {
return fixed4(1.0,0.0,0.0,1.0);
}
ENDCG
}
}
}
和表面着色器类似,顶点/片元着色器的代码也需要定义在CGPROGRAM 和ENDCG 之间,
但不同的是,顶点/片元着色器是写在Pass 语义块内,而非SubShader 内的。原因是,我们需要自
己定义每个Pass 需要使用的Shader 代码。虽然我们可能需要编写更多的代码,但带来的好处是
灵活性很高。更重要的是,我们可以控制渲染的实现细节。同样,这里的CGPROGRAM 和ENDCG
之间的代码也是使用Cg/HLSL 编写的。
3.4.3 被抛弃的角落:固定函数着色器
上面两种Unity Shader 形式都使用了可编程管线。而对于一些较旧的设备(其GPU 仅支持
DirectX 7.0、OpenGL 1.5 或OpenGL ES 1.1),例如iPhone 3,它们不支持可编程管线着色器,因
此,这时候我们就需要使用固定函数着色器(Fixed Function Shader)来完成渲染。这些着色器
往往只可以完成一些非常简单的效果。
一个非常简单的固定函数着色器示例代码如下:
Shader “Tutorial/Basic” {
Properties {
_Color (“Main Color”, Color) = (1,0.5,0.5,1)
}
SubShader {
Pass {
Material {
Diffuse [_Color]
}
Lighting On
}
}
}
可以看出,固定函数着色器的代码被定义在Pass 语义块中,这些代码相当于Pass 中的一些
渲染设置,正如我们之前在3.3.3 节中提到的一样。
对于固定函数着色器来说,我们需要完全使用ShaderLab 的语法(即使用ShaderLab 的渲染
设置命令)来编写,而非使用Cg/HLSL。

由于现在绝大多数GPU 都支持可编程的渲染管线,这种固定管线的编程方式已经逐渐被抛
弃。实际上,在Unity 5.2 中,所有固定函数着色器都会在背后被Unity 编译成对应的顶点/片元着
色器,因此真正意义上的固定函数着色器已经不存在了。
3.4.4 选择哪种Unity Shader 形式
那么,我们究竟选择哪一种来进行Unity Shader 的编写呢?这里给出了一些建议。
 除非你有非常明确的需求必须要使用固定函数着色器,例如需要在非常旧的设备上运行你
的游戏(这些设备非常少见),否则请使用可编程管线的着色器,即表面着色器或顶点/
片元着色器。
 如果你想和各种光源打交道,你可能更喜欢使用表面着色器,但需要小心它在移动平台的
性能表现。
 如果你需要使用的光照数目非常少,例如只有一个平行光,那么使用顶点/片元着色器是
一个更好的选择。
 最重要的是,如果你有很多自定义的渲染效果,那么请选择顶点/片元着色器。

3.5 本书使用的Unity Shader 形式

本书的目的不仅在于教给读者如何使用Unity Shader,更重要的是想要让读者掌握渲染背后
的原理。仅仅了解高层抽象虽然可能会暂时使工作简化,但从长久来看“知其然而不知其所以然”
所带来的影响更加深远。
因此,在本书接下来的内容中,我们将着重使用顶点/片元着色器来进行Unity Shader 的编写。
对于表面着色器来说,我们会在本书的第17 章中进行剖析,读者可以在那里找到更多的学习内容。

3.6 答疑解惑

尽管在之前的内容中涵盖了很多基础内容,这里仍给出一些初学者常见的困惑之处,并给予
说明和解释。
3.6.1 Unity Shader != 真正的Shader
需要读者注意的是,Unity Shader 并不等同于第2 章中所讲的Shader,尽管Unity Shader 翻译
过来就是Unity 着色器。在Unity 里,Unity Shader 实际上指的就是一个ShaderLab 文件—硬盘
上以.shader 作为文件后缀的一种文件。
在Unity Shader(或者说是ShaderLab 文件)里,我们可以做的事情远多于一个传统意义上的
Shader。
 在传统的Shader 中,我们仅可以编写特定类型的Shader,例如顶点着色器、片元着色器
等。而在Unity Shader 中,我们可以在同一个文件里同时包含需要的顶点着色器和片元着
色器代码。
 在传统的Shader 中,我们无法设置一些渲染设置,例如是否开启混合、深度测试等,这
些是开发者在另外的代码中自行设置的。而在Unity Shader 中,我们通过一行特定的指令
就可以完成这些设置。
 在传统的Shader 中,我们需要编写冗长的代码来设置着色器的输入和输出,要小心地处
理这些输入输出的位置对应关系等。而在Unity Shader 中,我们只需要在特定语句块中声
明一些属性,就可以依靠材质来方便地改变这些属性。而且对于模型自带的数据(如顶点
位置、纹理坐标、法线等),Unity Shader 也提供了直接访问的方法,不需要开发者自行
编码来传给着色器。
当然,Unity Shader 除了上述这些优点外,也有一些缺点。由于Unity Shader 的高度封装性,
我们可以编写的Shader 类型和语法都被限制了。对于一些类型的Shader,例如曲面细分着色器
(Tessellation Shader)、几何着色器(Geometry Shader)等,Unity 的支持就相对差一些。例如,
Unity 4.x 仅在DirectX 11 平台下提供曲面细分着色器、几何着色器的相关功能,而对于OpenGL
平台则没有这些支持。除此之外,一些高级的Shader 语法Unity Shader 也不支持。
可以说,Unity Shader 提供了一种让开发者同时控制渲染流水线中多个阶段的一种方式,不
仅仅是提供Shader 代码。作为开发者而言,我们绝大部分时候只需要和Unity Shader 打交道,而
不需要关心渲染引擎底层的实现细节。
3.6.2 Unity Shader 和Cg/HLSL 之间的关系
正如我们之前所讲,Unity Shader 是用ShaderLab 语言编写的,但对于表面着色器和顶点/片
元着色器,我们可以在ShaderLab 内部嵌套Cg/HLSL 语言来编写这些着色器代码。这些Cg/HLSL
代码是嵌套在CGPROGRAM 和ENDCG 之间的,正如我们之前看到的示例代码一样。由于Cg 和
DX9 风格的HLSL 从写法上来说几乎是同一种语言,因此在Unity 里Cg 和HLSL 是等价的。我
们可以说,Cg/HLSL 代码是区别于ShaderLab 的另一个世界。
通常,Cg 的代码片段是位于Pass 语义块内部的,如下所示:
Pass {
// Pass 的标签和状态设置
CGPROGRAM
// 编译指令,例如:
#pragma vertex vert
#pragma fragment frag
// Cg 代码
ENDCG
// 其他一些设置
}
读者可能会有疑问:“之前不是说在表面着色器中,Cg/HLSL 代码是写在SubShader 语义块内
吗?而不是Pass 块内。”的确,在表面着色器中,Cg/HLSL 代码是写在SubShader 语义块内,但是
读者应该还记得,表面着色器在本质上就是顶点/片元着色器,它们看起来很不像是因为表面着色器
是Unity 在顶点/片元着色器上层为开发者提供的一层抽象封装,但在背后,Unity 还是会把它转化
成一个包含多Pass 的顶点/片元着色器。我们可以在Unity Shader 的导入设置面板中单击Show
generated code 按钮来查看生成的真正的顶点/片元着色器代码。可以说,从本质上来讲,Unity Shader
只有两种形式:顶点/片元着色器和固定函数着色器(在Unity 5.2 以后的版本中,固定函数着色器
也会在背后被转化成顶点/片元着色器,因此从本质上来说Unity 中只存在顶点/片元着色器)。
在提供给编程人员这些便利的背后,Unity 编辑器会把这些Cg 片段编译成低级语言,如汇编
语言等。通常,Unity 会自动把这些Cg 片段编译到所有相关平台(这里的平台是指不同的渲染平
台,例如Direct3D 9、OpenGL、Direct3D 11、OpenGL ES 等)上。这些编译过程比较复杂,Unity
会使用不同的编译器来把Cg 转换成对应平台的代码。这样就不会在切换平台时再重新编译,而
且如果代码在某些平台上发生错误就可以立刻得到错误信息。
正如在3.1.3 节中看到的一样,我们可以在Unity Shader 的导入设置面板上查看这些编译后的
代码,查看这些代码有助于进行Debug 或优化等,如图3.9 所示。

在这里插入图片描述
但当发布游戏的时候,游戏数据文件中只包含目标平台需要的编译代码,而那些在目标平台
上不需要的代码部分就会被移除。例如,当发布到Mac OS X 平台上时,DirectX 对应的代码部分
就会被移除。
3.6.3 我可以使用GLSL 来写吗
当然可以。如果你坚持说:“我就是不想用Cg/HLSL 来写!就是要使用GLSL 来写!”,但是
这意味着你可以发布的目标平台就只有Mac OS X、OpenGL ES 2.0 或者Linux,而对于PC、Xbox
360 这样的仅支持DirectX 的平台来说,你就放弃它们了。
建立在你坚持要用GLSL 来写Unity Shader 的意愿下,你可以怎么写呢?和Cg/HLSL 需要嵌
套在CGPROGRAM 和ENDCG 之间类似,GLSL 的代码需要嵌套在GLSLPROGRAM 和ENDGLSL
之间。
更多关于如何在Unity Shader 中写GLSL 代码的内容可以在Unity 官方手册的GLSL Shader
Programs 一文(http://docs.unity3d.com/Manual/SL-GLSLShaderPrograms.html)中找到。

3.7 扩展阅读

Unity 官网上关于Unity Shader 方面的文档正在不断补充中,由于Unity 封装了很多功能和细
节, 因此, 如果读者在使用Unity Shader 的过程中遇到了问题可以去到官方文档
(http://docs.unity3d.com/Manual/SL-Reference.html)中查看。除此之外,Unity 也提供了一些简单
的着色器编写教程(http://docs.unity3d.com/Manual/ShaderTut1.html,http://docs.unity3d.com/Manual/
ShaderTut2.html)。由于在Unity Shader 中,绝大多数可编程管线的着色器代码是使用Cg 语言编
写的,读者可以在NVIDIA 提供的Cg 文档(http://http.developer.nvidia.com/Cg/)中找到更多的内
容。NVIDIA 同样提供了一个系列教程(http://http.developer.nvidia.com/CgTutorial/cg_tutorial_
chapter01.html)来帮助初学者掌握Cg 的基本语法。

参考

Unity Shader入门精要
作者:冯乐乐

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity Shader是一种用于渲染图形的程序,它可以控制对象的表面颜色、纹理、透明度、反射等属性,从而实现特殊的视觉效果。对于游戏开发者来说,掌握Shader编写技巧是非常重要的。 以下是关于Unity Shader入门精要: 1. ShaderLab语言 ShaderLab是Unity中用于编写Shader的语言,它是一种基于标记的语言,类似于HTML。ShaderLab可以用于定义Shader的属性、子着色器、渲染状态等信息。 2. CG语言 CG语言是Unity中用于编写Shader的主要语言,它是一种类似于C语言的语言,可以进行数学运算、向量计算、流程控制等操作。CG语言可以在ShaderLab中嵌入,用于实现Shader的具体逻辑。 3. Unity的渲染管线 Unity的渲染管线包括顶点着色器、片元着色器、几何着色器等组件,每个组件都有不同的作用。顶点着色器用于对对象的顶点进行变换,片元着色器用于计算每个像素的颜色,几何着色器用于处理几何图形的变形和细节等。 4. 模板和纹理 在Shader中,我们可以使用纹理来给对象添加图案或者贴图,也可以使用模板来控制对象的透明度、反射等属性。纹理可以通过内置函数tex2D()来获取,模板可以通过内置函数clip()来实现裁剪。 5. Shader的实现 Shader的实现需要注意以下几点: - 在ShaderLab中定义Shader的属性、子着色器、渲染状态等信息。 - 在CG语言中实现Shader的具体逻辑,包括顶点着色器、片元着色器等内容。 - 使用纹理和模板来实现特定的视觉效果。 - 在对象上应用Shader,通过调整Shader的属性来达到不同的效果。 以上是关于Unity Shader入门精要,希望对你有所帮助。如果你想更深入地了解Shader的编写技巧,可以参考官方文档或者相关教程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值