unity shader shaderLab 手册

本文出处:http://blog.csdn.net/lcbcsdn/article/details/46848125

(1)数学函数

函数 功能描述
abs(x) 返回输入参数的绝对值
acos(x) 反余切函数,输入参数范围为[-1,1], 返回[0,π]区间的角度值
all(x) 如果输入参数均不为0,则返回ture; 否则返回flase。&&运算
any(x) 输入参数只要有其中一个不为0,则返回true。
asin(x) 反正弦函数,输入参数取值区间为,返回角度值范围为, 
atan(x) 反正切函数,返回角度值范围为
atan2(y,x) 计算y/x的反正切值。实际上和atan(x)函数功能完全一样,至少输入参数不同。atan(x) = atan2(x, float(1))。
ceil(x) 对输入参数向上取整。例如: ceil(float(1.3)) ,其返回值为2.0
clamp(x,a,b) 如果x值小于a,则返回a;
如果x值大于b,返回b;
否则,返回x。
cos(x) 返回弧度x的余弦值。返回值范围为
cosh(x) 双曲余弦(hyperbolic cosine)函数,计算x的双曲余弦值。
cross(A,B) 返回两个三元向量的叉积(cross product)。注意,输入参数必须是三元向量!
degrees(x) 输入参数为弧度值(radians),函数将其转换为角度值(degrees)
determinant(m) 计算矩阵的行列式因子。
dot(A,B) 返回A和B的点积(dot product)。参数A和B可以是标量,也可以是向量(输入参数方面,点积和叉积函数有很大不同)。
exp(x) 计算的值,e=2.71828182845904523536
exp2(x) 计算的值
floor(x) 对输入参数向下取整。例如floor(float(1.3))返回的值为1.0;但是floor(float(-1.3))返回的值为-2.0。该函数与ceil(x)函数相对应。
fmod(x,y) 返回x/y的余数。如果y为0,结果不可预料。
frac(x) 返回标量或矢量的小数
frexp(x, out i) 将浮点数x分解为尾数和指数,即, 返回m,并将指数存入i中;如果x为0,则尾数和指数都返回0
isfinite(x) 判断标量或者向量中的每个数据是否是有限数,如果是返回true;否则返回false;
isinf(x) 判断标量或者向量中的每个数据是否是无限,如果是返回true;否则返回false;
isnan(x) 判断标量或者向量中的每个数据是否是非数据(not-a-number NaN),如果是返回true;否则返回false;
ldexp(x, n) 计算的值
lerp(a, b, f) 计算或者的值。即在下限a和上限b之间进行插值,f表示权值。注意,如果a和b是向量,则权值f必须是标量或者等长的向量。
lit(NdotL, NdotH, m) N表示法向量;
L表示入射光向量;
H表示半角向量;
m表示高光系数。 
函数计算环境光、散射光、镜面光的贡献,返回的4元向量。 
X位表示环境光的贡献,总是1.0; 
Y位代表散射光的贡献,如果 ,则为0;否则为 
Z位代表镜面光的贡献,如果 或者,则位0;否则为;
W位始终位1.0
log(x) 计算的值,x必须大于0
log2(x) 计算的值,x必须大于0
log10(x) 计算的值,x必须大于0
max(a, b) 比较两个标量或等长向量元素,返回最大值。
min(a,b) 比较两个标量或等长向量元素,返回最小值。
modf(x, out ip) 把x分解成整数和分数两部分,每部分都和x有着相同的符号,整数部分被保存在ip中,分数部分由函数返回
mul(M, N) 矩阵M和矩阵N的积,计算方法如下
mul(M, v) 矩阵M和列向量v的积,公式如下
mul(v, M) 行向量v和矩阵M的积,公式如下
noise(x) 根据它的参数类型,这个函数可以是一元、二元或三元噪音函数。返回的值在0和1之间,并且通常与给定的输入值一样
pow(x, y)  
radians(x) 函数将角度值转换为弧度值
round(x) 返回四舍五入值。
rsqrt(x) x的平方根的倒数,x必须大于0
saturate(x) 把x限制到[0,1]之间
sign(x) 如果则返回1;否则返回0
sin(x) 输入参数为弧度,计算正弦值,返回值范围 为[-1,1]
sincos(float x, out s, out c) 该函数是同时计算x的sin值和cos值,其中s=sin(x),c=cos(x)。该函数用于“同时需要计算sin值和cos值的情况”,比分别运算要快很多!
sinh(x) 计算x的双曲正弦
smoothstep(min, max, x) 值x位于min、max区间中。如果x=min,返回0;如果x=max,返回1;如果x在两者之间,按照下列公式返回数据:
step(a, x) 如果,返回0;否则,返回1
sqrt(x) 求x的平方根,,x必须大于0
tan(x) 计算x正切值
tanh(x) 计算x的双曲线切线
transpose(M) 矩阵M的转置矩阵
如果M是一个AxB矩阵,M的转置是一个BxA矩阵,它的第一列是M的第一行,第二列是M的第二行,第三列是M的第三行,等等

 

(2)几何函数

函数 功能描述
distance(pt1, pt2) 两点之间的欧几里德距离(Euclidean distance)
faceforward(N,I,Ng) 如果,返回N;否则返回-N。
length(v) 返回一个向量的模,即sqrt(dot(v,v))
normalize(v) 返回v向量的单位向量
reflect(I, N) 根据入射光纤方向I和表面法向量N计算反射向量,仅对三元向量有效
refract(I,N,eta) 根据入射光线方向I,表面法向量N和折射相对系数eta,计算折射向量。如果对给定的eta,I和N之间的角度太大,返回(0,0,0)。
只对三元向量有效

 

(3)纹理映射函数

函数 功能描述
tex1D(sampler1D tex, float s) 一维纹理查询
tex1D(sampler1D tex, float s, float dsdx, float dsdy) 使用导数值(derivatives)查询一维纹理
Tex1D(sampler1D tex, float2 sz) 一维纹理查询,并进行深度值比较
Tex1D(sampler1D tex, float2 sz, float dsdx,float dsdy) 使用导数值(derivatives)查询一维纹理, 并进行深度值比较
Tex1Dproj(sampler1D tex, float2 sq) 一维投影纹理查询
Tex1Dproj(sampler1D tex, float3 szq) 一维投影纹理查询,并比较深度值
Tex2D(sampler2D tex, float2 s) 二维纹理查询
Tex2D(sampler2D tex, float2 s, float2 dsdx, float2 dsdy) 使用导数值(derivatives)查询二维纹理
Tex2D(sampler2D tex, float3 sz) 二维纹理查询,并进行深度值比较
Tex2D(sampler2D tex, float3 sz, float2 dsdx,float2 dsdy) 使用导数值(derivatives)查询二维纹理,并进行深度值比较
Tex2Dproj(sampler2D tex, float3 sq) 二维投影纹理查询
Tex2Dproj(sampler2D tex, float4 szq) 二维投影纹理查询,并进行深度值比较
texRECT(samplerRECT tex, float2 s) 二维非投影矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy) 二维非投影使用导数的矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz) 二维非投影深度比较矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy) 二维非投影深度比较并使用导数的矩形纹理查询(OpenGL独有)
texRECT proj(samplerRECT tex, float3 sq) 二维投影矩形纹理查询(OpenGL独有)
texRECT proj(samplerRECT tex, float3 szq) 二维投影矩形纹理深度比较查询(OpenGL独有)
Tex3D(sampler3D tex, float s) 三维纹理查询
Tex3D(sampler3D tex, float3 s, float3 dsdx, float3 dsdy) 结合导数值(derivatives)查询三维纹理
Tex3Dproj(sampler3D tex, float4 szq) 查询三维投影纹理,并进行深度值比较
texCUBE(samplerCUBE tex, float3 s) 查询立方体纹理
texCUBE (samplerCUBE tex, float3 s, float3 dsdx, float3 dsdy) 结合导数值(derivatives)查询立方体纹理
texCUBEproj (samplerCUBE tex, float4 sq) 查询投影立方体纹理


在这个表中,每个函数第二个参数的名字指明了在执行纹理查询的时候,它的值是如果被使用的:

  • s表示这是一个一元、二元或三元纹理座标。
  • z表示这是一个用来进行阴影贴图查找的深度比较值。
  • q表示这是一个透视值,在进行纹理查找之前,它被用来除以纹理座标(s)。

当你使用的纹理函数允许你指定一个深度比较值的时候,与之相关联的纹理单元必须被设置成深度比较纹理。否则,深度比较实际上不会被执行。 
 

(4)偏导函数

函数 功能描述
ddx(a) 近似a关于屏幕空间x轴的偏导数
ddy(a) 近似a关于屏幕空间y轴的偏导数

 

(5)调试函数

函数 功能描述
void debug(float4 x) 如果在编译时设置了DEBUG,片段着 色程序中调用该函数可以将值x作为COLOR语义的最终输出;否则该函数什么也不做。

 

 

Unity ShaderLab学习总结

Why Bothers?

为什么已经有ShaderForge这种可视化Shader编辑器、为什么Asset Store已经有那么多炫酷的Shader组件可下载,还是有必要学些Shader的编写?

2014-0718-1607-11-33.png

  • 因为上面这些Shader工具/组件最终都是以Shader文件的形式而存在。
  • 需要开发人员/技术美术有能力对Shader进行功能分析、效率评估、选择、优化、兼容、甚至是Debug。
  • 对于特殊的需求,可能还是直接编写Shader比较实际、高效。

总之,Shader编写是重要的;但至于紧不紧急,视乎项目需求。

涉及范围

本文只讨论Unity ShaderLab相关的知识和使用方法。但,

  • 既不讨论渲染相关的基础概念;
    • 基础概念可参考Rendering Pipeline Overview等文章。
    • 作为移动设备GPU和桌面GPU的最大不同点,tile-based deferred rendering (WikiPowerVR/Mali/Adreno)也是重要的概念。
      其大幅减少带宽消耗、会进行Early-Z测试尝试减少Overdraw(依赖于渲染物体提交顺序由前至后)。
      其中PowerVR的Hidden Surface Removal做到像素级别的Overdraw减少(不用依赖于渲染物体提交顺序由前至后)。
  • 也不讨论具体的渲染技巧

参考资源

  • Youtube:https://www.youtube.com/watch?v=hDJQXzajiPg (包括part1-6)。视频是最佳的入门方式没有之一,所以墙裂建议就算不看下文的所有内容,都要去看一下part1。
  • 书籍:《Unity 3D ShaderLab开发实战详解》
  • Unity各种官方文档

使用Shader

2014-0720-1007-25-36.png


如上图,一句话总结:

  1. GameObject里有MeshRenderer,
  2. MeshRenderer里有Material列表,
  3. 每个Material里有且只有一个Shader;
  4. Material在编辑器暴露该Shader的可调属性。

所以关键是怎么编写Shader。

Shader基础

编辑器

使用MonoDevelop这反人类的IDE来编写Shader居然是让人满意的。有语法高亮,无语法提示。
如果习惯VisualStudio,可以如下实现.Shader文件的语法高亮。

  • 下载作者donaldwu自己添加的关键词文件usertype.dat。其包括了Unity ShaderLab的部分关键字,和HLSL的所有关键字。关键字以后持续添加中。
  • 将下载的usertype.dat放到Microsoft Visual Studio xx.x\CommonX\IDE\文件夹下;
  • 打开VS,工具>选项>文本编辑器>文件扩展名,扩展名里填“shader”,编辑器选VC++,点击添加;
  • 重启VS,Done。

Shader


 
  1. Shader "ShaderLab Tutorials/TestShader"

  2. {

  3. // ...

  4. }

2014-0720-1707-17-42.png


Shader的名字会直接决定shader在material里出现的路径

SubShader


 
  1. Shader "ShaderLab Tutorials/TestShader" {

  2. SubShader

  3. {

  4. //...

  5. }

  6. }

一个Shader有多个SubShader。一个SubShader可理解为一个Shader的一个渲染方案。即SubShader是为了针对不同的渲染情况而编写的。每个Shader至少1个SubShader、理论可以无限多个,但往往两三个就足够。
一个时刻只会选取一个SubShader进行渲染,具体SubShader的选取规则包括:

  • 从上到下选取
  • SubShader的标签、Pass的标签
    • 是否符合当前的“Unity渲染路径”
    • 是否符合当前的ReplacementTag
  • SubShader是否和当前的GPU兼容

按此规则第一个被选取的SubShader将会用于渲染,未被选取的SubShader在这次渲染将被忽略。

SubShader的Tag


 
  1. Shader "ShaderLab Tutorials/TestShader" {

  2. SubShader

  3. {

  4. Tags { "Queue"="Geometry+10" "RenderType"="Opaque" }

  5. //...

  6. }

  7. }

SubShader内部可以有标签(Tags)的定义。Tag指定了这个SubShader的渲染顺序(时机),以及其他的一些设置。

  • "RenderType"标签。Unity可以运行时替换符合特定RenderType的所有Shader。Camera.RenderWithShaderCamera.SetReplacementShader配合使用。Unity内置的RenderType包括:
    • "Opaque":绝大部分不透明的物体都使用这个;
    • "Transparent":绝大部分透明的物体、包括粒子特效都使用这个;
    • "Background":天空盒都使用这个;
    • "Overlay":GUI、镜头光晕都使用这个;
    • 用户也可以定义任意自己的RenderType这个标签所取的值。
    • 应注意,Camera.RenderWithShaderCamera.SetReplacementShader不要求标签只能是RenderTypeRenderType只是Unity内部用于Replace的一个标签而已,你也可以自定义自己全新的标签用于Replace。
      比如,你为自己的ShaderA.SubShaderA1(会被Unity选取到的SubShader,常为Shader文件中的第一个SubShader)增加Tag为"Distort"="On",然后将"Distort"作为参数replacementTag传给函数。此时,作为replacementShader实参的ShaderB.SubShaderB1中若有也有一模一样的"Distort"="On",则此SubShaderB1将代替SubShaderA1用于本次渲染。
    • 具体可参考Rendering with Replaced Shaders
  • "Queue"标签。定义渲染顺序。预制的值为
    • "Background"。值为1000。比如用于天空盒。
    • "Geometry"。值为2000。大部分物体在这个队列。不透明的物体也在这里。这个队列内部的物体的渲染顺序会有进一步的优化(应该是从近到远,early-z test可以剔除不需经过FS处理的片元)。其他队列的物体都是按空间位置的从远到近进行渲染。
    • "AlphaTest"。值为2450。已进行AlphaTest的物体在这个队列。
    • "Transparent"。值为3000。透明物体。
    • "Overlay"。值为4000。比如镜头光晕。
    • 用户可以定义任意值,比如"Queue"="Geometry+10"
  • "ForceNoShadowCasting",值为"true"时,表示不接受阴影。
  • "IgnoreProjector",值为"true"时,表示不接受Projector组件的投影。

另,关于渲染队列和Batch的非官方经验总结是,一帧的渲染队列的生成,依次决定于每个渲染物体的:

  • Shader的RenderType tag,
  • Renderer.SortingLayerID,
  • Renderer.SortingOrder,
  • Material.renderQueue(默认值为Shader里的"Queue"),
  • Transform.z(ViewSpace)(默认为按z值从前到后,但当Queue是“Transparent”的时候,按z值从后到前)。

这个渲染队列决定了之后(可能有dirty flag的机制?)渲染器再依次遍历这个渲染队列,“同一种”材质的渲染物体合到一个Batch里。

Pass


 
  1. Shader "ShaderLab Tutorials/TestShader" {

  2. SubShader {

  3. Pass

  4. {

  5. //...

  6. }

  7. }

  8. }

一个SubShader(渲染方案)是由一个个Pass块来执行的。每个Pass都会消耗对应的一个DrawCall。在满足渲染效果的情况下尽可能地减少Pass的数量。

Pass的Tag


 
  1. Shader "ShaderLab Tutorials/TestShader" {

  2. SubShader {

  3. Pass

  4. {

  5. Tags{ "LightMode"="ForwardBase" }

  6. //...

  7. }

  8. }

  9. }

和SubShader有自己专属的Tag类似,Pass也有Pass专属的Tag。
其中最重要Tag是 "LightMode",指定Pass和Unity的哪一种渲染路径(“Rendering Path”)搭配使用。除最重要的ForwardBaseForwardAdd外,这里需额外提醒的Tag取值可包括:

  • Always,永远都渲染,但不处理光照
  • ShadowCaster,用于渲染产生阴影的物体
  • ShadowCollector,用于收集物体阴影到屏幕座标Buff里。

其他渲染路径相关的Tag详见下面章节“Unity渲染路径种类”。
具体所有Tag取值,可参考ShaderLab syntax: Pass Tags

FallBack


 
  1. Shader "ShaderLab Tutorials/TestShader"{

  2. SubShader { Pass {} }

  3.  
  4. FallBack "Diffuse" // "Diffuse"即Unity预制的固有Shader

  5. // FallBack Off //将关闭FallBack

  6. }

当本Shader的所有SubShader都不支持当前显卡,就会使用FallBack语句指定的另一个Shader。FallBack最好指定Unity自己预制的Shader实现,因其一般能够在当前所有显卡运行。

Properties


 
  1. Shader "ShaderLab Tutorials/TestShader"

  2. {

  3. Properties {

  4. _Range ("My Range", Range (0.02,0.15)) = 0.07 // sliders

  5. _Color ("My Color", Color) = (.34, .85, .92, 1) // color

  6. _2D ("My Texture 2D", 2D) = "" {} // textures

  7. _Rect("My Rectangle", Rect) = "name" { }

  8. _Cube ("My Cubemap", Cube) = "name" { }

  9. _Float ("My Float", Float) = 1

  10. _Vector ("My Vector", Vector) = (1,2,3,4)

  11.  
  12. // Display as a toggle.

  13. [Toggle] _Invert ("Invert color?", Float) = 0

  14. // Blend mode values

  15. [Enum(UnityEngine.Rendering.BlendMode)] _Blend ("Blend mode", Float) = 1

  16. //setup corresponding shader keywords.

  17. [KeywordEnum(Off, On)] _UseSpecular ("Use Specular", Float) = 0

  18. }

  19.  
  20. // Shader

  21. SubShader{

  22. Pass{

  23. //...

  24. uniform float4 _Color;

  25. //...

  26. float4 frag() : COLOR{ return fixed4(_Color); }

  27. //...

  28. #pragma multi_compile __ _USESPECULAR_ON

  29. }

  30. }

  31.  
  32. //fixed pipeline

  33. SubShader {

  34. Pass{

  35. Color[_Color]

  36. }

  37. }

  38. }

  • Shader在Unity编辑器暴露给美术的参数,通过Properties来实现。
  • 所有可能的参数如上所示。主要也就Float、Vector和Texture这3类。
  • 除了通过编辑器编辑Properties,脚本也可以通过Material的接口(比如SetFloatSetTexture编辑)
  • 之后在Shader程序通过[name](固定管线)或直接name(可编程Shader)访问这些属性。
  • 在每一个Property前面也能类似C#那样添加Attribute,以达到额外UI面板功能。详见MaterialPropertyDrawer.html

Shader中的数据类型

有3种基本数值类型:floathalffixed
这3种基本数值类型可以再组成vector和matrix,比如half3是由3个half组成、float4x4是由16个float组成。

  • float:32位高精度浮点数。
  • half:16位中精度浮点数。范围是[-6万, +6万],能精确到十进制的小数点后3.3位。
  • fixed:11位低精度浮点数。范围是[-2, 2],精度是1/256。

数据类型影响性能

  • 精度够用就好。
    • 颜色和单位向量,使用fixed
    • 其他情况,尽量使用half(即范围在[-6万, +6万]内、精确到小数点后3.3位);否则才使用float

ShaderLab中的Matrix

当提到“Row-Major”、“Column-Major”,根据不同的场合,它们可能指不同的意思:

  • 数学上的,主要是指矢量V是Row Vector、还是Column Vector。引用自[Game Engine Architecture 2nd Edition, 183]。留意到V和M的乘法,当是Row Vector的时候,数学上写作VM,Matrix在右边,Matrix的最下面一行表示Translate;当是Column Vector的时候,数学上写作MtVt,Matrix在左边并且需要转置,Matrix最右面一列表示Translate。
  • 访问接口上的:Row-Major即MyMatrix[Row][Column]、Column-Major即MyMatrix[Column][Row]。HLSL/CG的访问接口都是Row-Major,比如MyMatrix[3]返回的是第3行;GLSL的访问接口是Column-Major,比如MyMatrix[3]返回的是第3列。
  • 寄存器存储上的:每个元素是按行存储在寄存器中、还是按列存储在寄存器中。需要关注它的一般情况举例是,float2x3的MyMatrix,到底是占用2个寄存器(Row-Major)、还是3个寄存器(Column-Major)。在HLSL里,可以通过#pragmapack_matrix设定row_major或者column_major。

上述情况,互不相干。
然后,ShaderLab中,数学上是Column Vector、访问接口上是Row-Major、存储上是(尚未查明)。另外,ShaderLab在World Space是左手座标系、View Space是右手座标系、在Normalized Device Coordinates里是左手座标系。


 
  1. v2f vert (appdata v)

  2. {

  3. v2f o;

  4. o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);

  5. // 1 、2、3是等价的,和4是不等价的

  6. // 因为是M在左、V在右,所以是Column Vector

  7. // 因为是HLSL/CG语言,所以是访问方式是Row-Major

  8. o.rootInView = mul(UNITY_MATRIX_MV, float4(0, 0, 0, 1)); // 1

  9. o.rootInView = float4(UNITY_MATRIX_MV[0].w, UNITY_MATRIX_MV[1].w, UNITY_MATRIX_MV[2].w, 1); // 2

  10. o.rootInView = UNITY_MATRIX_MV._m03_m13_m23_m33; // 3

  11. //o.rootInView = UNITY_MATRIX_MV[3]; // 4

  12.  
  13. return o;

  14. }

  15.  
  16. fixed4 frag (v2f i) : SV_Target

  17. {

  18. // 因为是ViewSpace是右手座标系,所以当root在view前面的时候,z是负数,所以需要-z才能正确显示颜色

  19. fixed4 col = fixed4(i.rootInView.x, i.rootInView.y, -i.rootInView.z, 1);

  20. return col;

  21. }

  22.  
  23. struct appdata

  24. {

  25. float4 vertex : POSITION;

  26. };

  27. struct v2f

  28. {

  29. float4 rootInView : TEXCOORD0;

  30. float4 vertex : SV_POSITION;

  31. };

Shader形态

Shader形态之1:固定管线

固定管线是为了兼容老式显卡。都是顶点光照。之后固定管线可能是被Unity抛弃的功能,所以最好不学它、当它不存在。特征是里面出现了形如下面Material块、没有CGPROGRAMENDCG块。


 
  1. Shader "ShaderLab Tutorials/TestShader"

  2. {

  3. Properties {

  4. _Color ("My Color", Color) = (.34, .85, .92, 1) // color

  5. }

  6.  
  7. // Fixed Pipeline

  8. SubShader

  9. {

  10. Pass

  11. {

  12. Material{

  13. Diffuse [_Color]

  14. Ambient [_Color]

  15. }

  16.  
  17. Lighting On

  18. }

  19. }

  20. }

Shader形态之2:可编程Shader


 
  1. Shader "ShaderLab Tutorials/TestShader"

  2. {

  3. Properties {}

  4.  
  5. SubShader

  6. {

  7. Pass

  8. {

  9. // ... the usual pass state setup ...

  10.  
  11. CGPROGRAM

  12. // compilation directives for this snippet, e.g.:

  13. #pragma vertex vert

  14. #pragma fragment frag

  15.  
  16. // the Cg/HLSL code itself

  17. float4 vert(float4 v:POSITION) : SV_POSITION{

  18. return mul(UNITY_MATRIX_MVP, v);

  19. }

  20. float4 frag() : COLOR{

  21. return fixed4(1.0, 0.0, 0.0, 1.0);

  22. }

  23. ENDCG

  24. // ... the rest of pass setup ...

  25. }

  26. }

  27. }

  • 功能最强大、最自由的形态。
  • 特征是在Pass里出现CGPROGRAMENDCG
  • 编译指令#pragma。详见官网Cg snippets。其中重要的包括:
编译指令 示例/含义
#pragma vertex name
#pragma fragment name
替换name,来指定Vertex Shader函数、Fragment Shader函数。
#pragma target name 替换name(为2.03.0等)。设置编译目标shader model的版本。
#pragma only_renderers name name ...
#pragma exclude_renderers name name...
#pragma only_renderers gles gles3
#pragma exclude_renderers d3d9 d3d11 opengl
只为指定渲染平台(render platform)编译
  • 引用库。通过形如#include "UnityCG.cginc"引入指定的库。常用的就是UnityCG.cginc了。其他库详见官网Built-in shader include files
  • ShaderLab内置值。Unity给Shader程序提供了便捷的、常用的值,比如下面例子中的UNITY_MATRIX_MVP就代表了这个时刻的MVP矩阵。详见官网ShaderLab built-in values
  • Shader输入输出参数语义(Semantics)。在管线流程中每个阶段之间(比如Vertex Shader阶段和FragmentShader阶段之间)的输入输出参数,通过语义字符串,来指定参数的含义。常用的语义包括:COLORSV_PositionTEXCOORD[n]。完整的参数语义可见HLSL Semantic(由于是HLSL的连接,所以可能不完全在Unity里可以使用)。
  • 特别地,因为Vertex Shader的的输入往往是管线的最开始,Unity为此内置了常用的数据结构:
数据结构 含义
appdata_base vertex shader input with position, normal, one texture coordinate.
appdata_tan vertex shader input with position, normal, tangent, one texture coordinate.
appdata_full vertex shader input with position, normal, tangent, vertex color and two texture coordinates.
appdata_img vertex shader input with position and one texture coordinate.

Shader形态之3:SurfaceShader


 
  1. Shader "ShaderLab Tutorials/TestShader"

  2. {

  3. Properties { }

  4.  
  5. // Surface Shader

  6. SubShader {

  7. Tags { "RenderType" = "Opaque" }

  8. CGPROGRAM

  9. #pragma surface surf Lambert

  10. struct Input {

  11. float4 color : COLOR;

  12. };

  13. void surf (Input IN, inout SurfaceOutput o) {

  14. o.Albedo = 1;

  15. }

  16. ENDCG

  17. }

  18. FallBack "Diffuse"

  19. }

  • SurfaceShader可以认为是一个光照Shader的语法糖、一个光照VS/FS的生成器。减少了开发者写重复代码的需要。
  • 在手游,由于对性能要求比较高,所以不建议使用SurfaceShader。因为SurfaceShader是一个比较“通用”的功能,而通用往往导致性能不高。
  • 特征是在SubShader里出现CGPROGRAMENDCG块。(而不是出现在Pass里。因为SurfaceShader自己会编译成多个Pass。)
  • 编译指令是:
    #pragma surface surfaceFunction lightModel [optionalparams]
    • surfaceFunction:surfaceShader函数,形如void surf (Input IN, inout SurfaceOutput o)
    • lightModel:使用的光照模式。包括Lambert(漫反射)和BlinnPhong(镜面反射)。
      • 也可以自己定义光照函数。比如编译指令为#pragma surface surf MyCalc
  • 你定义输入数据结构(比如上面的Input)、编写自己的Surface函数处理输入、最终输出修改过后的SurfaceOutput。SurfaceOutput的定义为
    
     
    1. struct SurfaceOutput {

    2. half3 Albedo; // 纹理颜色值(r, g, b)

    3. half3 Normal; // 法向量(x, y, z)

    4. half3 Emission; // 自发光颜色值(r, g, b)

    5. half Specular; // 镜面反射度

    6. half Gloss; // 光泽度

    7. half Alpha; // 不透明度

    8. };

Shader形态之4:Compiled Shader

点击a.shader文件的“Compile and show code”,可以看到该文件的“编译”过后的ShaderLab shader文件,文件名形如Compiled-a.shader
其依然是ShaderLab文件,其包含最终提交给GPU的shader代码字符串。
先就其结构进行简述如下,会发现和上述的编译前ShaderLab结构很相似。


 
  1. // Compiled shader for iPhone, iPod Touch and iPad, uncompressed size: 36.5KB

  2. // Skipping shader variants that would not be included into build of current scene.

  3. Shader "ShaderLab Tutorials/TestShader"

  4. {

  5. Properties {...}

  6. SubShader {

  7. // Stats for Vertex shader:

  8. // gles : 14 avg math (11..19), 1 avg texture (1..2)

  9. // metal : 14 avg math (11..17)

  10. // Stats for Fragment shader:

  11. // metal : 14 avg math (11..19), 1 avg texture (1..2)

  12. Pass {

  13. Program "vp" // vertex program

  14. {

  15. SubProgram "gles" {

  16. // Stats: 11 math, 1 textures

  17. Keywords{...} // keywords for shader variants ("uber shader")

  18.  
  19. //shader codes in string

  20. "

  21. #ifdef VERTEX

  22. vertex shader codes

  23. #endif

  24.  
  25. // Note, on gles, fragment shader stays here inside Program "vp"

  26. #ifdef FRAGMENT

  27. fragment shader codes

  28. #endif

  29. "

  30. }

  31.  
  32. SubProgram "metal" {

  33. some setup

  34. Keywords{...}

  35.  
  36. //vertex shader codes in string

  37. "..."

  38. }

  39. }

  40.  
  41. Program "fp" // fragment program

  42. {

  43. SubProgram "gles" {

  44. Keywords{...}

  45. "// shader disassembly not supported on gles" //(because gles fragment shader codes are in Program "vp")

  46. }

  47.  
  48. SubProgram "metal" {

  49. common setup

  50. Keywords{...}

  51.  
  52. //fragment shader codes in string

  53. "..."

  54. }

  55. }

  56. }

  57. }

  58.  
  59. ...

  60. }

Unity渲染路径(Rendering Path)种类

概述

开发者可以在Unity工程的PlayerSettings设置对渲染路径进行3选1:

  • Deferred Lighting,延迟光照路径。3者中最高质量地还原光照阴影。光照性能只与最终像素数目有关,光源数量再多都不会影响性能。
  • Forward Rendering,顺序渲染路径。能发挥出Shader全部特性的渲染路径,当然也就支持像素级光照。最常用、功能最自由,性能与光源数目*受光照物体数目有关,具体性能视乎其具体使用到的Shader的复杂度。
  • Vertex Lit,顶点光照路径。顶点级光照。性能最高、兼容性最强、支持特性最少、品质最差。

渲染路径的内部阶段和Pass的LightMode标签

每个渲染路径的内部会再分为几个阶段。
然后,Shader里的每个Pass,都可以指定为不同的LightMode。而LightMode实际就是说:“我希望这个Pass在这个XXX渲染路径的这个YYY子阶段被执行”。

Deferred Ligting

渲染路径内部子阶段 对应的LightMode 描述
Base Pass "PrepassBase" 渲染物体信息。即把法向量、高光度到一张ARGB32的物体信息纹理上,把深度信息保存在Z-Buff上。
Lighting Pass 无对应可编程Pass 根据Base Pass得出的物体信息,在屏幕座标系下,使用BlinnPhong光照模式,把光照信息渲染到ARGB32的光照信息纹理上(RGB表示diffuse颜色值、A表示高光度)
Final Pass "PrepassFinal" 根据光照信息纹理,物体再渲染一次,将光照信息、纹理信息和自发光信息最终混合。LightMap也在这个Pass进行。

Forward Rendering

渲染路径内部子阶段 对应的LightMode 描述
Base Pass "ForwardBase" 渲染:最亮一个的方向光光源(像素级)和对应的阴影、所有顶点级光源、LightMap、所有LightProbe的SH光源(Sphere Harmonic,球谐函数,效率超高的低频光)、环境光、自发光。
Additional Passes "ForwardAdd" 其他需要像素级渲染的的光源

注意到的是,在Forward Rendering中,光源可能是像素级光源、顶点级光源或SH光源。其判断标准是:

  • 配制成“Not Important”的光源都是顶点级光源和SH光源
  • 最亮的方向光永远都是像素级光源
  • 配置成“Important”的都是像素级光源
  • 上面2种情况加起来的像素级光源数目小于“Quality Settings”里面的“Pixel Light Count”的话,会把第1种情况的光源补为额外的像素级光源。

另外,配置成“Auto”的光源有更复杂的判断标注,截图如下:

2014-0720-1607-31-40.png


具体可参考Forward Rendering Path Details

Vertex Lit

渲染路径内部子阶段 对应的LightMode 描述
Vertex "Vertex" 渲染无LightMap物体
VertexLMRGBM "VertexLMRGBM" 渲染有RGBM编码的LightMap物体
VertexLM "VertexLM" 渲染有双LDR编码的LightMap物体

不同LightMode的Pass的被选择

一个工程的渲染路径是唯一的,但一个工程里的Shader是允许配有不同LightMode的Pass的。
在Unity,策略是“从工程配置的渲染路径模式开始,按Deferred、Forward、VertxLit的顺序,搜索最匹配的LightMode的一个Pass”。
比如,在配置成Deferred路径时,优先选有Deferred相关LightMode的Pass;找不到才会选Forward相关的Pass;还找不到,才会选VertexLit相关的Pass。
再比如,在配置成Forward路径时,优先选Forward相关的Pass;找不到才会选VertexLit相关的Pass。

 

 

 

原文链接:http://www.jianshu.com/p/7b9498e58659

 

 

************转http://www.tuicool.com/articles/ABNbyi*******************

因为Unity中基础的固定功能Shader的知识点基本上讲完,下期开始就要准备讲表面着色器(Surface Shader)了,所以在文章开头,让我们复习和更深入了解一下Unity中Shader的三种形态。

在Unity中,Shader便可以分成如下三种基本类型:

1. 固定功能着色器(FixedFunction Shader)

2. 表面着色器(SurfaceShader)

3. 顶点着色器&片段着色器(Vertex Shader & Fragment Shader)

顾名思义,其中的固定功能着色器便是我们所说的固定功能渲染管线(fixed-functionrenderingpipelines)的具体表现,而表面着色器、顶点着色器以及片段着色器便属于可编程渲染管线。下面分别对其进行简单的介绍。

1.1   Unity中的Shader形态之一:固定功能Shader

这里的固定功能着色器可以说是Unity为Shader的书写自带的一层壳,Unity已经在内部为我们做了大量的工作,我们只要稍微记住一些关键字、一些规范就可以实现出很多不错的效果。固定功能着色器是我们初学Unity Shader的最近几篇文章中的主要学习对象。而后面的表面着色器、顶点着色器以及片段着色器就是在固定功能着色器的基础上嵌套了CG语言的代码而成的更加复杂的着色器。我们来看看他们的一些基本概念。

固定管线是为了兼容老式显卡。都为顶点光照,就是我们前四篇文章加上这篇文章中讲到的内容。

其特征是里面的核心是下面Material材质属性块、没有CGPROGRAM和ENDCG块,以及各种顶点着色和片段着色的宏命令。

一个光照材质完备版的固定功能Shader示例如下:

Shader "浅墨Shader编程/Volume5/固定功能的Shader示例"   
{  
  //-------------------------------【属性】-----------------------------------------  
  Properties   
  {  
    _Color ("主颜色", Color) = (1,1,1,0)  
    _SpecColor ("高光颜色", Color) = (1,1,1,1)  
    _Emission ("自发光颜色", Color) = (0,0,0,0)  
    _Shininess ("光泽度", Range (0.01, 1)) = 0.7  
    _MainTex ("基本纹理", 2D) = "white" {}  
  }  
  //--------------------------------【子着色器】--------------------------------  
  SubShader  
  {  
    //----------------通道---------------  
    Pass  
    {  
      //-----------材质------------  
      Material  
      {  
        //可调节的漫反射光和环境光反射颜色  
        Diffuse [_Color]  
        Ambient [_Color]  
        //光泽度  
        Shininess [_Shininess]  
        //高光颜色  
        Specular [_SpecColor]  
        //自发光颜色  
        Emission [_Emission]  
      }  
      //开启光照  
      Lighting On  
      //开启独立镜面反射  
      SeparateSpecular On  
      //设置纹理并进行纹理混合  
      SetTexture [_MainTex]   
      {  
        Combine texture * primary DOUBLE, texture * primary  
      }  
    }  
  }  
}

  1.2 Unity中的Shader形态之二:表面着色器SurfaceShader

这部分算是Unity微创新自创的一套着色器标准。

表面着色器(Surface Shader)这个概念更多的只是在Unity中听说,可以说是Unity自己发扬光大的一项使Shader的书写门槛降低和更易用的技术。我们会在接下来的学习中逐渐意识到Unity是如何为我们把Shader的复杂性包装起来,使其书写的过程更便捷和易用

的。一些特性如下:

•      SurfaceShader可以认为是一个光照Shader的语法块、一个光照VS/FS的生成器。减少了开发者写重复代码的需要。

•      特征是在SubShader里出现CGPROGRAM和ENDCG块。(而不是出现在Pass里。因为SurfaceShader自己会编译成多个Pass。)

•      编译指令是:

#pragma surface surfaceFunction lightModel[optionalparams]

o     surfaceFunction:surfaceShader函数,形如void surf (Input IN, inoutSurfaceOutput o)

o     lightModel:使用的光照模式。包括Lambert(漫反射)和BlinnPhong(镜面反射)。

     也可以自己定义光照函数。比如编译指令为#pragma surface surf MyCalc

     在Shader里定义half4 LightingMyCalc (SurfaceOutputs, 参数略)函数进行处理(函数名在签名加上了“Lighting”)。

•      我们自己定义输入数据结构(比如上面的Input)、编写自己的Surface函数处理输入、最终输出修改过后的SurfaceOutput。而SurfaceOutput的定义为:

struct SurfaceOutput
{
 	half3 Albedo; // 纹理颜色值(r, g, b)
 	half3 Normal; // 法向量(x, y, z)
 	half3 Emission; // 自发光颜色值(r, g, b)
 	half Specular; // 镜面反射度
 	half Gloss; // 光泽度
 	half Alpha; // Alpha不透明度
};

上面是一些特性总结,让我们看一个具体Shader示例:

Shader "浅墨Shader编程/Volume5/表面Shader示例 "   
{  
  //-------------------------------【属性】-----------------------------------------  
  Properties   
  {  
    _MainTex ("【纹理】Texture", 2D) = "white" {}  
    _BumpMap ("【凹凸纹理】Bumpmap", 2D) = "bump" {}  
    _RimColor ("【边缘颜色】Rim Color", Color) = (0.17,0.36,0.81,0.0)  
    _RimPower ("【边缘颜色强度】Rim Power", Range(0.6,9.0)) = 1.0  
  }  
  //----------------------------【开始一个子着色器】---------------------------  
  SubShader   
  {  
    //渲染类型为Opaque,不透明  
    Tags { "RenderType" = "Opaque" }  
    //-------------------开始CG着色器编程语言段-----------------  
    CGPROGRAM  
    //使用兰伯特光照模式  
    #pragma surface surf Lambert  
    //输入结构  
    struct Input   
    {  
      float2 uv_MainTex;//纹理贴图  
      float2 uv_BumpMap;//法线贴图  
      float3 viewDir;//观察方向  
    };  
    //变量声明  
    sampler2D _MainTex;//主纹理  
    sampler2D _BumpMap;//凹凸纹理  
    float4 _RimColor;//边缘颜色  
    float _RimPower;//边缘颜色强度  
    //表面着色函数的编写  
    void surf (Input IN, inout SurfaceOutput o)  
    {  
      //表面反射颜色为纹理颜色  
      o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;  
      //表面法线为凹凸纹理的颜色  
      o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));  
      //边缘颜色  
      half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));  
      //边缘颜色强度  
      o.Emission = _RimColor.rgb * pow (rim, _RimPower);  
    }  
    //-------------------结束CG着色器编程语言段------------------  
    ENDCG  
  }   
  //“备胎”为普通漫反射  
  Fallback "Diffuse"  
}

  1.3 Unity中的Shader形态之三:可编程Shader

可编程Shader其实就是顶点着色器和片段着色器,这一部分和DirectX系的HLSL和CG着色器语言联系紧密。其实就是Unity给HLSL和CG报了一个ShaderLab的壳。

研究过Direct3D和OpenGL着色器编程的童鞋们一定对顶点着色器和片段着色器不陌生。我们来简单介绍一下他们的用途。

顶点着色器:产生纹理座标,颜色,点大小,雾座标,然后把它们传递给裁剪阶段。

片段着色器:进行纹理查找,决定什么时候执行纹理查找,是否进行纹理查找,及把什么作为纹理座标。

可编程Shader的特点为:

    • 功能最强大、最自由的形态。
    • 特征是在Pass里出现CGPROGRAM和ENDCG块
    • 编译指令#pragma。详见 官网Cg snippets 。其中重要的包括:

 

编译指令

示例/含义

#pragma vertex name #pragma fragment name

替换name,来指定Vertex Shader函数、Fragment Shader函数。

#pragma target name

替换name(为2.0、3.0等)。设置编译目标shader model的版本。

#pragma only_renderers name name ... #pragma exclude_renderers name name...

#pragma only_renderers gles gles3, #pragma exclude_renderers d3d9 d3d11 opengl, 只为指定渲染平台(render platform)编译

    • 关于引用库。通过形如#include "UnityCG.cginc"引入指定的库。常用的就是UnityCG.cginc了。其他库详见 官网Built-in shader include files 。
    • ShaderLab内置值。Unity给Shader程序提供了便捷的、常用的值,比如下面例子中的UNITY_MATRIX_MVP就代表了这个时刻的MVP矩阵。详见 官网ShaderLab built-in values 。
    • Shader输入输出参数语义(Semantics)。在管线流程中每个阶段之间(比如Vertex Shader阶段和FragmentShader阶段之间)的输入输出参数,通过语义字符串,来指定参数的含义。常用的语义包括:COLOR、SV_Position、TEXCOORD[n]。完整的参数语义可见 HLSL Semantic (由于是HLSL的连接,所以可能不完全在Unity里可以使用)。
    • 特别地,因为Vertex Shader的的输入往往是管线的最开始,Unity为此内置了常用的数据结构:

 

 

数据结构

含义

appdata_base

顶点着色器 输入位置、法线以及一个纹理座标。

appdata_tan

顶点着色器 输入位置、法线、切线以及一个纹理座标。

appdata_full

顶点着色器 输入位置、法线、切线、顶点颜色以及两个纹理座标。

appdata_img

顶点着色器 输入位置以及一个纹理座标。

 

让我们用一个可编程着色器Shader示例结束此部分的讲解:

Shader "浅墨Shader编程/Volume5/可编程Shader示例" 
{
  //-------------------------------【属性】--------------------------------------
  Properties 
  {
    _Color ("Color", Color) = (1.0,1.0,1.0,1.0)
    _SpecColor ("Specular Color", Color) = (1.0,1.0,1.0,1.0)
    _Shininess ("Shininess", Float) = 10
  }

  //--------------------------------【子着色器】--------------------------------
  SubShader 
  {
    //-----------子着色器标签----------
    Tags { "LightMode" = "ForwardBase" }

    //----------------通道---------------
    Pass 
    {
      //-------------------开始CG着色器编程语言段-----------------  
      CGPROGRAM
      #pragma vertex vert
      #pragma fragment frag
      
      //---------------声明变量--------------
      uniform float4 _Color;
      uniform float4 _SpecColor;
      uniform float _Shininess;
      
      //--------------定义变量--------------
      uniform float4 _LightColor0;
      
      //--------------顶点输入结构体-------------
      struct vertexInput 
      {
        float4 vertex : POSITION;
        float3 normal : NORMAL;
      };

      //--------------顶点输出结构体-------------
      struct vertexOutput 
      {
        float4 pos : SV_POSITION;
        float4 col : COLOR;
      };
      
      //--------------顶点函数--------------
      vertexOutput vert(vertexInput v)
      {
        vertexOutput o;
        
        //一些方向
        float3 normalDirection = normalize( mul( float4(v.normal, 0.0), _World2Object ).xyz );
        float3 viewDirection = normalize( float3( float4( _WorldSpaceCameraPos.xyz, 1.0) - mul(_Object2World, v.vertex).xyz ) );
        float3 lightDirection;
        float atten = 1.0;
        
        //光照
        lightDirection = normalize(_WorldSpaceLightPos0.xyz);
        float3 diffuseReflection = atten * _LightColor0.xyz * max( 0.0, dot( normalDirection, lightDirection ) );
        float3 specularReflection = atten * _LightColor0.xyz * _SpecColor.rgb * max( 0.0, dot( normalDirection, lightDirection ) ) * pow( max( 0.0, dot( reflect( -lightDirection, normalDirection ), viewDirection ) ), _Shininess );
        float3 lightFinal = diffuseReflection + specularReflection + UNITY_LIGHTMODEL_AMBIENT;
        
        //计算结果
        o.col = float4(lightFinal * _Color.rgb, 1.0);//颜色
        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//位置
        return o;
      }
      
      //--------------片段函数---------------
      float4 frag(vertexOutput i) : COLOR
      {
        return i.col;
      }

      //-------------------结束CG着色器编程语言段------------------
      ENDCG
    }
  }
  //备胎
  Fallback "Diffuse"
  
}

 

 

OK,下面我们来看本次文章的主角——blending操作。

二、混合操作(Blending)

我们直奔主题吧。混合操作最常见的用途便是用来制作透明物体、或者是进行纹理的混合。它是Shader渲染的最后一步:

如上图所示,正被渲染的像素经过顶点光照、顶点着色器、剔除和深度测试,雾效、Alpha测试等一系列操作之后,最后一步便是混合操作。这个时候计算结果即将被输出到帧缓冲中。而混合操作,就是管理如何将这些像素输出到帧缓存中的这样一个过程——是直接替换原来的,是一加一的混合,还是有Alpha参与的不等比地混合等等。

混合操作有两个对象:源和目标,因此也有两个对应的因子,即源因子和目标因子(对应于下面讲解的Blend SrcFactor DstFactor操作)。

而如果我们把RGB颜色通道和Alpha通道分开来操作的话,混合就有了4个操作对象(对应于下面讲解的Blend SrcFactor DstFactor,SrcFactorA DstFactorA操作)。

2.1 混合操作相关的句法

Blend Off

Turn off blending 关闭混合

Blend  SrcFactorDstFactor

基本的配置并启动混操作。对产生的颜色乘以SrcFactor.对 已存在于屏幕的颜色乘以DstFactor,并且两者将被叠加在一起。

Blend  SrcFactorDstFactor, SrcFactorA DstFactorA

同上,但是使用不同的要素来混合alpha通道,也就是有了4个操作对象

BlendOp  Add / Min | Max | Sub | RevSub

此操作不是Blend操作一样添加混合颜色在一起,而是对它们做不同的操作。

而如下便是常用混合操作符(blend operations)的含义列举:

 

Add

将源像素和目标像素相加.

Sub

用源像素减去目标像素

RevSub

用目标像素减去源像素

Min

取目标像素和源像素颜色的较小者作为结果

Max

取目标像素和源像素颜色的较大者作为结果

 

2.2 混合因子(Blend factors)列举

以下所有的属性都可作为SrcFactor或DstFactor。其中,Source指的是被计算过的颜色,Destination是已经在屏幕上的颜色。

 

One 值为1,使用此因子来让帧缓冲区源颜色或是目标颜色完全的通过。
Zero 值为0,使用此因子来删除帧缓冲区源颜色或目标颜色的值。
SrcColor 使用此因子为将当前值乘以帧缓冲区源颜色的值
SrcAlpha 使用此因子为将当前值乘以帧缓冲区源颜色Alpha的值。
DstColor 使用此因子为将当前值乘以帧缓冲区源颜色的值。
DstAlpha 使用此因子为将当前值乘以帧缓冲区源颜色Alpha分量的值。
OneMinusSrcColor 使用此因子为将当前值乘以(1 -帧缓冲区源颜色值)
OneMinusSrcAlpha 使用此因子为将当前值乘以(1 -帧缓冲区源颜色Alpha分量的值)
OneMinusDstColor 使用此因子为将当前值乘以(1 –目标颜色值)
OneMinusDstAlpha 使用此因子为将当前值乘以(1 –目标Alpha分量的值)

2.3 常见的混合操作句法示例

上面都是一些句法和列表的列举,往往会令人一头雾水,下面这是一些示例,用其中的任何一句加在Pass中就可以实现对应的混合操作了:

Blend SrcAlpha OneMinusSrcAlpha    // Alpha混合
Blend One One                       // 相加
Blend One OneMinusDstColor         // 比较柔和的相加(SoftAdditive)
Blend DstColor Zero                  // 乘法
Blend DstColor SrcColor              // 2倍乘法

三、QianMo's Toolkit升级到v1.3

这次QianMo's Toolkit又迎来了新的特性——飞翔。

将脚本赋给Controller,并调整相应的速度,(并可以先禁掉之前的鼠标视角控制相关脚本)然后点运行,并可以在天空中自由地飞翔了。

其中用W、A、S、D控制前后左右,R、F控制上升下降。

其代码如下:


 
  1. //-----------------------------------------------【脚本说明】-------------------------------------------------------

  2. // 脚本功能: 控制Contorller在场景中飞翔

  3. // 使用语言: C#

  4. // 开发所用IDE版本:Unity4.5 06f 、Visual Studio 2010

  5. // 2014年12月 Created by 浅墨

  6. // 更多内容或交流,请访问浅墨的博客:http://blog.csdn.net/poem_qianmo

  7. //---------------------------------------------------------------------------------------------------------------------

  8. //-----------------------------------------------【使用方法】-------------------------------------------------------

  9. // 第一步:在Unity中拖拽此脚本到场景的Controller之上,或在Inspector中[Add Component]->[浅墨's Toolkit]->[SetMaxFPS]

  10. // 第二步:在面板中设置相关鼠标速度

  11. //---------------------------------------------------------------------------------------------------------------------

  12. using UnityEngine;

  13. using System.Collections;

  14. //添加组件菜单

  15. [AddComponentMenu("浅墨's Toolkit/FlyController")]

  16. public class FlyController : MonoBehaviour

  17. {

  18. //参数定义

  19. public float lookSpeed = 5.0f;

  20. public float moveSpeed = 1.0f;

  21. public float rotationX = 0.0f;

  22. public float rotationY = 0.0f;

  23. void Update()

  24. {

  25. //获取鼠标偏移量

  26. rotationX += Input.GetAxis("Mouse X") * lookSpeed;

  27. rotationY += Input.GetAxis("Mouse Y") * lookSpeed;

  28. rotationY = Mathf.Clamp(rotationY, -90, 90);

  29. //鼠标控制视角

  30. transform.localRotation = Quaternion.AngleAxis(rotationX, Vector3.up);

  31. transform.localRotation *= Quaternion.AngleAxis(rotationY, Vector3.left);

  32. transform.position += transform.forward * moveSpeed * Input.GetAxis("Vertical");

  33. transform.position += transform.right * moveSpeed * Input.GetAxis("Horizontal");

  34. //I键,向上平移

  35. if (Input.GetKey(KeyCode.R))

  36. transform.position += transform.up * moveSpeed;

  37. //K键,向下平移

  38. if (Input.GetKey(KeyCode.F))

  39. transform.position -= transform.up * moveSpeed;

  40. }

  41. }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章