找回密码
 立即注册
查看: 7163|回复: 75

[特效Shader] Unity3D Shader基础教程

  [复制链接]
发表于 2012-12-16 16:11 | 显示全部楼层 |阅读模式
资源信息 Tutorial Information
教程名称: Unity3D Shader基础教程(发帖教程)
适用引擎:   (适用引擎,为空默认为Unity)
教程语种: 中文
教程等级: 1
教程格式: 图文(请用IE9以上浏览器访问本版块)
教程作者: 转载自互联网 (如有问题请短消息联系作者或发表回复)
下载地址: (兑换积分)
点击查看原图
美丽分割线

此教程将指引你如何建立自己的Shaders,让你的游戏场景看起来更好。Unity配备了强大
的阴影和材料的语言工具称为ShaderLab,以程式语言来看,它类似于CgFX和Direct3D的语法,
它不只纪录基本的端点或者映像点(vertex/pixel)资讯,也描述了材质所必要的一切资讯。
在unity材质检视器中可以看到Shaders的性质及多重shader(SubShaders)的描述,针对不同图
形硬件,每个描述也都完整的说明了图形硬件的彩现状态,fixed function pipeline如何设定、
vertex/ fragment programs如何作用。 Vertex and fragment程序可以使用高阶Cg程式语言或
低阶shader组合。
在这个教程中,我们将描述如何使用fixed function与programmable pipelines两种方式于
ShaderLab中撰写shaders,我们假设读者拥有基本的OpenGL或Direct3D彩现概念,并对cg有
fixed function与programmable pipelines的常识,HLSL或GLSL编程语言技术,一些Shader教
程与参考文件可于NVIDIA以及AMD的开发站上取得。
建立一个新的shader有两种方法,可以由菜单Assets->Create->Shader新增,或复制一个既有
的shader再进行编辑,新的shader可以透过双击来启动编辑画面(UniSciTE)
下面开始介绍一个基础的shader范例:
Shader "Tutorial/Basic" {
Properties {
_Color ("Main Color", Color) = (1,0.5,0.5,1)
}
SubShader {
Pass {
Material {
Diffuse [_Color]
}
Lighting On
}
着色器:开始
1
}
}
Shader "Tutorial/Basic" {
Properties {
_Color ("Main Color", Color) = (1,0.5,0.5,1)
}
SubShader {
Pass {
Material {
Diffuse [_Color]
}
Lighting On
}
}
}
这个shader范例只是众多shader中最基本的一个,它定义了一个颜色性质,名称为Main Color,
并指定了玫瑰色的效果(red=100% green=50% blue=50% alpha=100%),在调用时会跳过
Diffuse的材质设定(_Color)并开启顶点光源。
要测试这个shader,你可以建立一个新的材质,并于Shader下拉菜单选择(Tutorial->Basic),
再把这个新材质指定到物件上,拖拉材质检视器的颜色表并查看其变化。是时候研究更复杂的事情
了!
假如你开启一个既有的复合shader,刚开始看可能会觉得有点难,在开始以前,我们将详细说明
unity内建的VertexLit shader。这个shader使用fixed function pipeline产生标准的per-vertex
照明。
Shader "VertexLit" {
Properties {
2
_Color ("Main Color", Color) = (1,1,1,0.5)
_SpecColor ("Spec Color", Color) = (1,1,1,1)
_Emission ("Emmisive Color", Color) = (0,0,0,0)
_Shininess ("Shininess", Range (0.01, 1)) = 0.7
_MainTex ("Base (RGB)", 2D) = "white" { }
}
SubShader {
Pass {
Material {
Diffuse [_Color]
Ambient [_Color]
Shininess [_Shininess]
Specular [_SpecColor]
Emission [_Emission]
}
Lighting On
SeperateSpecular On
SetTexture [_MainTex] {
constantColor [_Color]
Combine texture * primary DOUBLE, texture * constant
}
}
}
}
Shader "VertexLit" {
Properties {
_Color ("Main Color", Color) = (1,1,1,0.5)
_SpecColor ("Spec Color", Color) = (1,1,1,1)
3
_Emission ("Emmisive Color", Color) = (0,0,0,0)
_Shininess ("Shininess", Range (0.01, 1)) = 0.7
_MainTex ("Base (RGB)", 2D) = "white" { }
}
SubShader {
Pass {
Material {
Diffuse [_Color]
Ambient [_Color]
Shininess [_Shininess]
Specular [_SpecColor]
Emission [_Emission]
}
Lighting On
SeperateSpecular On
SetTexture [_MainTex] {
constantColor [_Color]
Combine texture * primary DOUBLE, texture * constant
}
}
}
}
所有的shaders都必须以Shader作为开始,接着是这个shader的名称(例如:VertexLit),这个名
称将会显示于检视器(Inspector)。所有的语法都必须放在{ }之内。
如果要把shaders放在unity的submenus下面,请使用斜线,例如:MyShaders/Test,你将会
看到有个submenu名为MyShaders,下面有个shader名为Test,或是像这样MyShaders->Test
在Properties block下面接着的是SubShader block,每个描述都在这个段落中
4
Properties
properties位于shader block一开始的位置,你可以定义任何性质,这些性质将可在材质检视器中
编辑,在VertexLit的个范例中,properties block看起来像这样:


properties block内的语法都是单行的,每一个性质描述都由内名称开始(例如:Color,
MainTex),在后方的括弧号中所显示的名字也会显示于inspector检视器上,在此之后,描述的是
该性质的预设值:


可用的性质类型请参考Properties Reference。预设值与性质有关,以color为例,预设值应该由
四个值组成。
现在我们已经定义了四个性质,可以开始撰写实际的shader了
在开始以前,先了解shader的结构是如何定义的。
不同的绘图卡有不同的能力,例如:有的绘图卡支援fragment programs但有些没有,有些可以
一次处理四个贴图?(four textures)其他的可能只能处理两个或一个,为了要符合所有用户的硬体需
求,一个shader可以包涵多个SubShaders,当unity在运算shader时,它将详细察看所有的
subshaders而且使用硬体可支持的第一个。
5
Shader "Structure Example" {
Properties { /* ...shader properties... }
SubShader {
// ...subshader that uses vertex/fragment programs...
}
SubShader {
// ...subshader that uses four textures per pass...
}
SubShader {
// ...subshader that uses two textures per pass...
}
SubShader {
// ...subshader that might look ugly but runs on anything : )
}
}
Shader "Structure Example" {
Properties { /* ...shader properties... }
SubShader {
// ...subshader that uses vertex/fragment programs...
}
SubShader {
// ...subshader that uses four textures per pass...
}
SubShader {
// ...subshader that uses two textures per pass...
}
SubShader {
// ...subshader that might look ugly but runs on anything : )
6
}
}
此系统提供unity可以支援现有所有的硬体并取得最佳的品质。它作到了,然而,结果是必须撰写
很长的shaders语法
在每一个SubShader block,你可以设定彩现途径的状态;并定义彩现途径本身。完整的
SubShader语法请参照SubShader Reference章节
每个subshader等于是一个途径集。要对几何物件进行彩现,至少一定要有一个途径,内定的
VertexLit shader里面仅有一个途径:
view plaincopy to clipboardprint?
// ...snip...
Pass {
Material {
Diffuse [_Color]
Ambient [_Color]
Shininess [_Shininess]
Specular [_SpecColor]
Emission [_Emission]
}
Lighting On
SeperateSpecular On
SetTexture [_MainTex] {
constantColor [_Color]
Combine texture * primary DOUBLE, texture * constant
}
}
// ...snip...
// ...snip...
7
Pass {
Material {
Diffuse [_Color]
Ambient [_Color]
Shininess [_Shininess]
Specular [_SpecColor]
Emission [_Emission]
}
Lighting On
SeperateSpecular On
SetTexture [_MainTex] {
constantColor [_Color]
Combine texture * primary DOUBLE, texture * constant
}
}
// ...snip...
通过指令可以定义一个特殊的方法,用来驱动绘图硬体彩现指定的几何物件
例如:上方语法中有一个Material block,定义了照明时所需要几项固定参数。而指令Lighting
On用来开启该照明设备,而SeperateSpecular On则是启用Seperate作为特殊镜射效果。
到目前为止的所有命令,皆属于支援OpenGL/Direct3D技术硬体本身可使用的固定功能,您可以
参考OpenGL红皮书,可以找到更多相关资料。
下一个命令是SetTexture,这是个非常重要的命令,这个命令可以定义影像纹理如何混合、组合
以及如何运用于我们的彩现环境里,SetTexture通常跟随于纹理的属性名称之后(我们在这里使用
_MainTex ),接下来的combiner block也是定义纹理的应用方式,这个combiner block的命令会
在萤幕显示每一个被执行的动作。

让我们开始了一个着色器的一般结构小回顾:
Shader "MyShaderName" {
Properties {
// ... properties here ...
}
SubShader {
// ... subshader for graphics hardware A ...
Pass {
// ... pass commands ...
}
// ... more passes if needed ...
}
SubShader {
// ... subshader for graphics hardware B ...
}
// ... Optional fallback ...
FallBack "VertexLit"
}
最后,我们在这里引入一个新的命令:
FallBack "VertexLit"
回退命令可用于在着色结束,它告诉它应该使用着色如果从目前的着色没有SubShaders可以运行在
用户的图形硬件。其效果是一样的,包括在年底从后备着色所有SubShaders相同。例如,如果你写
了颠簸映射着色,然后不要写成一个非常基本的非凹凸映射的老显卡你可以回退到subshader内置
VertexLit着色。
该着色的基本构建块,介绍了在第一渲染教程,而性能完整的文件,SubShaders并通过提供。
阿建设SubShaders快速方法是使用证在其他着色器定义。该命令UsePass正是如此,所以你可以重
用一个整洁时尚着色器代码。作为一个例子下面的命令使用的名称,通过“基地”从内置的镜面着色:
UsePass "Specular/BASE"
着色:顶点和片段程序
1
为了UsePass为了工作,这个名字必须考虑的一个传递希望使用。通过名称内的命令给它一个名字:
Name "MyPassName"
顶点和片段方案
我们描述了通过该只使用一个单一的纹理相结合的第一个教程指令。现在是时候证明我们如何能够通
过使用我们的顶点和片段方案。
当您使用顶点和片段程序(即所谓“可编程管线”),大部分的硬编码功能(“固定功能管线”)在图形
硬件已关闭。例如,使用一个顶点程序关闭标准3D变换,灯光和纹理坐标生成完全。同样地,使用
任何一个片段程序替换纹理相结合,将在SetTexture命令定义的模式,因此SetTexture命令是没有必
要的。
写作顶点/片断程序需要一个三维转换,照明和协调空间 - 透彻的认识,因为你必须重写固定功能是
一样的OpenGL的API将自己的建造。另一方面,你可以做更多比内置的!
利用ShaderLab Cg语言
在ShaderLab着色器通常用Cg语言嵌入“Cg的片段着色器中的文本”的编程语言。 Cg的片段被编译成
低级的统一着色器组装编辑,最后着色是在你的游戏的数据中包含的文件只包含这个低层次的组装。
当您选择一个项目视图着色,检查员Cg语言编译后显示,这可能有助于在调试援助着色文本。统一
自动编译的CG OpenGL和Direct3D的片段,所以你的着色器,使用Cg的工作都将只。请注意,因为
企业管治守则是由编辑编译,你不能创建Cg的从脚本在运行时着色器。
一般来说,Cg的片段放在里面通行证块。他们看起来像这样:
Pass {
// ... the usual pass state setup ...
CGPROGRAM
// compilation directives for this snippet, e.g.:
#pragma vertex vert
#pragma fragment frag
// the Cg code itself
2
ENDCG
// ... the rest of pass setup ...
}
下面的例子演示了一个Cg的方案,使得对象的颜色正常人完全着色:
Shader "Tutorial/Display Normals" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_fog_exp2
#include "UnityCG.cginc"
struct v2f {
V2F_POS_FOG;
float3 color : COLOR0;
};
v2f vert (appdata_base v)
{
v2f o;
PositionFog( v.vertex, o.pos, o.fog );
o.color = v.normal * 0.5 + 0.5;
return o;
}
half4 frag (v2f i) : COLOR
{
return half4( i.color, 1 );
}
ENDCG
}
}
Fallback "VertexLit"
}
3
当应用于一个对象,将图像中的结果如下(如果您的图形卡支持顶点和片段的过程中方案):


我们的“平均值显示”着色没有任何属性,包含一个是空的,除了单一的企业管治守则证单
SubShader。最后,向在VertexLit着色器内置的定义后备。让我们解剖了部分企业管治守则的一部
分:
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_fog_exp2
// ... snip ...
ENDCG
整个Cg的片段之间写入CGPROGRAM和ENDCG关键字。在开始编译指令#pragma指令给出:
#pragma vertex name告诉该代码包含在给定的函数(垂直这里顶点方案)。
#pragma fragment name告诉该代码包含在给定的函数有关水土这里(片断程序)。
#pragma fragmentoption name加上一个选项来编译OpenGL的片段方案。在这里,我们添加指数
平方雾支持。
继汇编指令只是普通企业管治守则。我们首先包括一个内置的Cg的文件:
#include UnityCg.cginc
该文件包含常用UnityCg.cginc宣言等的着色器可以保持较小的功能。该文件本身是统一内发现的应
用:/应用程序/统一/ Unity.app /目录/ CGIncludes / UnityCG.cginc。在这里,我们将使用
4
appdata_base结构,V2F_POS_FOG宏观和PositionFog从该文件助手作用。我们可以只定义它们直
接在着色,不包括文件的过程。
接下来,我们要定义一个片段“顶点”结构(这里命名为v2f) - 什么样的信息是从顶点传递到片断程
序。我们通过标准的地位和雾参数和float3颜色参数。颜色将计算出的顶点程序和公正的片段程序的
输出。
我们的出发定义的顶点程序 - 垂直功能。在这里,我们在计算标准方法使用UnityCG.cginc辅助功能
(位置和雾)输入和输出作为一种颜色正常的:
! o.color = v.normal * 0.5 + 0.5;
正常的组成部分是-1 .. 1范围内,而色彩在0 .. 1范围内,所以我们在规模和偏见的代码高于正常。接
下来,我们定义一个片断程序 - 有关水土功能,只是颜色和产出计算为alpha组件1:
half4 frag (v2f i) : COLOR
{
return half4( i.color, 1 );
}
就这样,我们的着色完毕!即使这样简单的着色器是非常有用的可视化网格法线。
当然,这种着色不响应所有灯光,而这其中,事情变得有点复杂,对渲染管线和光衰减有关详细信
息,参考网页阅读。
企业管治守则中使用着色性能
当你定义的着色性能,你给他们一个像_Color或_MainTex名称。要使用Cg语言你他们只需要定义一
个匹配的名称和类型的变量。统一将自动设置Cg的变量的名称与着色性能匹配。
下面是一个完整的着色器显示的颜色调制纹理。当然,你可以很容易地做一个纹理合成调用相同的,
但问题是这里只是为了说明如何使用Cg的属性:
Shader "Tutorial/Textured Colored" {
Properties {
_Color ("Main Color", Color) = (1,1,1,0.5)
_MainTex ("Texture", 2D) = "white" { }
5
}
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_fog_exp2
#include "UnityCG.cginc"
float4 _Color;
sampler2D _MainTex;
struct v2f {
V2F_POS_FOG;
float2 uv : TEXCOORD0;
};
v2f vert (appdata_base v)
{
v2f o;
PositionFog( v.vertex, o.pos, o.fog );
o.uv = TRANSFORM_UV(0);
return o;
}
half4 frag (v2f i) : COLOR
{
half4 texcol = tex2D( _MainTex, i.uv );
return texcol * _Color;
}
ENDCG
}
}
Fallback "VertexLit"
}
6
这种着色结构是在前面的例子一样。在这里,我们定义两个属性,即_Color和_MainTex。企业管治
守则内我们定义相应的变量:
float4 _Color;
sampler2D _MainTex;
访问中看到着色性能更多信息,Cg语言。
顶点和片段程序在这里不做任何幻想;顶点程序使用从UnityCG.cginc的TRANSFORM_UV宏,以确保
质地规模与偏移是正确应用,并片断程序公正样品的质地和颜色属性的繁殖。
请注意,因为我们正在编写我们自己的节目片段在这里,我们不需要任何SetTexture命令。如何纹理
着色器适用于完全控制的片断程序。
摘要
我们已经展示了如何定制着色器程序可以在几个简单的步骤产生。虽然这里的例子所示很简单,没有
什么阻止你写任意复杂的着色器程序!这可以帮助您采取统一充分利用,实现最佳的渲染效果。
完整的ShaderLab参考手册在这里。我们也有一个阴影在forum.unity3d.com论坛,从而去那里得到
你的着色器的帮助!编程快乐,享受团结和Shaderlab权力。


在这个block内我们设定了一个颜色值,并命名为_Color,我们会在后面使用这个颜色
8
在下个命令,我们指定如何混合纹理以及颜色值。我们用Combine命令来混合其他纹理或颜色,
看起来像下面这样:
Combine ColorPart, AlphaPart
在这里ColorPart与AlphaPart定义了混合的颜色(RGB)以及alpha值(A)个别的资料,假如
AlphaPart被省略了,那它将与ColorPart的资料作混合
在我们的VertexLit范例中:
Combine texture * primary DOUBLE, texture * constant
这里的texture来源是当前的纹理(_MainTex),它将与主要的颜色互相搭配(*),主色为照明设备
的颜色,它是由Material计算出来的结果。最终是这两个倍增后的结果会增加照明强度.
aplha值(在逗号以后)是由constantColor倍增而得的结果。另一个常用的混合模式称为previous
(在这个shader未使用),这是所有previous SetTexture的结果,并且可以用来混合多种纹理和颜
色。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2012-12-17 10:05 | 显示全部楼层
非常需要,
谢谢分享。
发表于 2012-12-21 17:24 | 显示全部楼层
{:5_404:}{:5_404:}{:5_404:}{:5_404:}
发表于 2016-11-21 04:02 | 显示全部楼层
感谢分享!
发表于 2016-11-27 20:52 | 显示全部楼层

感谢楼主的无私分享!
发表于 2016-12-28 17:08 | 显示全部楼层
{:5_424:}感觉很不错  要是能增加一些例子就好拉
发表于 2017-1-5 21:42 | 显示全部楼层

感谢楼主的无私分享!
发表于 2017-2-8 19:06 | 显示全部楼层
啦啦啦啦啦
发表于 2017-3-18 23:23 | 显示全部楼层
:(:lol:Q:L:hug::time:
发表于 2017-4-3 09:59 | 显示全部楼层
好帖就是要顶
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-13 09:17 , Processed in 0.136502 second(s), 32 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表