Unity ShaderLab基础、Cg基础
Unity ShaderLab基础、Cg基础
blit n. 位块传送,位块传输
LOD 多层次细节
在大型项目开发中,LOD: (Level of detail)多层次细节,是最常用的游戏优化技术。它按照模型的位置和重要程度决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算。缺点是增加了内存,并且需要模型师为我们多提供一套模型。
多层次细节处理,就是让一个物体,在相机距离不同的情况下,显示不同的模型,从而节省性能的开销 。
游戏对象肯定不止一个,大型游戏可能有一堆,几百个,上千个物体,所以作为开发者,我们无需把一个精度那么高的模型,还放在那里,给CPU GPU增加工作量,这时候我们就可以用 LOD 技术,来对模型进行 分层级显示。
视角离近时,我们让物体显示精细度高的模型;视角离远时,我们让物体显示精细度低的模型,这就是 Level of detail 多层次细节优化。
LOD技术带来性能优化的同时,存在的一个 缺点就是会增大程序包的体积,因为本来一个模型,现在要准备起码2个/3个/4个,打包时自然而然程序包体积就会增大!
————————————————
画家算法、反画家算法;
物体着色片元与屏幕着色点;
3D引擎如何实现反画家算法;
渲染队列机制与作用;
ZTest,ZWrite,Blend详解;
画家算法 |
从远到近,一层层的画/着色,最后把所有物体都画完; 同一个点可能有多个物体,需要多次绘制; Shader中需要多次计算光照,然而很多都是无用的计算; |
反画家算法 |
由近到远,如果近的盖住了远的,远处的就不画了,而只画近处的; 同一个点只画一次,节约算力,提高性能; |
着色点、着色片元 |
屏幕着色点:屏幕上一个像素点; 物体的着色片元:模型→世界→摄像机→投影裁剪变换→片元; 三维模型的三角形面片→屏幕上的投影三角形; |
总结 |
画家算法:由远到近,一层一层网上覆盖,性能不好; 反画家算法:由近到远,不会重复着色,性能好;
|
渲染队列 |
反画家算法的弊端:半透明有问题; 半透明的解决方案:渲染队列; 渲染队列是一个数字,由小到大排列,先渲染小的,后渲染大的; 渲染队列1(2000):物体A,物体B,物体C...(由近到远) 渲染队列2(3000):物体1,物体2,物体3...(由近到远) 渲染队列3(4000):物体a,物体b,物体c...(由近到远) 渲染顺序:队列1(A→B→C)→队列2(1→2→3)→队列3(a→b→c); Unity渲染队列*5: Background 1000,Geometry 2000,Alpha Test 2450,Transparent 3000,Overlay 4000; 渲染队列之间:画家算法(由小到大); 渲染队列内部:反画家算法(由近到远); 因此,要实现一个半透明物体覆盖在透明物体上,就必须用画家算法,也就是两个物体位于不同的渲染队列中,并且半透明物体的队列值要更大;
位置关系 同一个渲染队列 不同的渲染队列 A绿色,在前,靠近摄像机,深度小,半透明;队列1(2000); B蓝色,在后,远离摄像机,深度大,不透明;队列1(2000);
|
同一队列 |
同一个渲染队列: 1、先用天空盒背景初始化缓存,颜色缓存(天空盒颜色)深度缓存(无穷大+∞); 2、A在前,先渲染A中间小方块区域: 由于Za小于天空盒Zsky的+∞,颜色缓存(绿色)深度缓存(Za); 由于A是半透明,此时的显示效果是A与天空盒背景色融合了; 3、B在后,再渲染B大方块区域: 未被A遮挡部分,由于Zb<Zsky的+∞,于是颜色缓存(蓝色),深度缓存(Zb); 被A遮挡部分,Zb>Za,B的深度值大于A的深度值,于是B直接被丢弃; 此时的半透明效果不是我们所希望的,因为A后面不是B,而是天空盒,B消失不见了; |
不同队列 |
现将AB置于不同的渲染队列,且B的队列小于A的队列,Qb<Qa,也就是先渲染B,再渲染A; 1、先初始化天空盒(背景队列),颜色缓存(天空盒颜色)深度缓存(无穷大+∞); 渲染小队列,也就是B所在队列(不透明队列): Zb<Zsky,所以B被渲染出来,并覆盖天空盒; 渲染大队列,也就是A所在队列(透明队列): Za<Zb,所以A被渲染出来,并与B进行融合,而不是与天空盒进行融合; 从而达到A盖在B上,而又能看到B的效果,也就是希望的半透明效果;
|
颜色缓存中有几个颜色?只有一个颜色,计算后或者混合后的当前颜色;
为什么需要颜色缓存?因为可能要做混合效果;
ZTest深度测试(规则) |
规则:当前片元的深度值Z和缓存里面的深度值Zbuffer比较,如果Z<Zbuffer,就绘制,否则就丢弃(这是默认规则); 目的:判断一个片元,是否要着色,还是直接丢弃; 通过测试,就着色,不通过就丢弃; |
ZWrite深度值写入(Bool) |
是否将当前物体/片元的深度值写入深度缓存; |
Blend混合规则(规则) |
如果当前物体/片元通过ZTest,要写入颜色缓存,那么按照那种规则进行写入?就是混合,或者是混合规则;
|
着色三部曲 |
ZTest→做深度测试,通过就着色,否则就丢弃; Blend→进入着色Shader程序片段,计算光照、颜色,然后写入颜色缓存; ZWrite→(通过测试的)是否将深度值写入深度缓存(更新缓存Z); |
反画家算法的实现
缓存 |
每个屏幕着色点,分配一个颜色缓存,分配一个深度缓存; 颜色缓存:当前着色到屏幕着色点的颜色; 深度缓存:着色物体的片元到摄像机的距离; 谁通过测试,并把颜色写进来,就把他的深度值写进来,也就是更新了当前深度值; 模型A→三角形→绘制到屏幕; 片元→光照/颜色→着色到屏幕; 屏幕上着色点→颜色→颜色缓存; 屏幕上着色点→深度/距离→深度缓存;
|
排序 |
游戏引擎对所有渲染物体进行排序; 靠近摄像机的排在前面,远离摄像机的排在后面; |
初始化 |
颜色缓存:天空和的颜色; 深度缓存:无穷远的距离; |
画近的 |
按照渲染序列,先绘制近处物体A; 将A的颜色写入颜色缓存; A的深度写入深度缓存; |
画远的 |
绘制远处物体B→屏幕着色点→范围就是物体B的范围; 着色前先做一个判断:物体B的深度和已经绘制的深度值; 如果小于屏幕值才进行光照就散和着色,否则,直接丢弃; 绘制B→着色蓝色片元→如果被绿色A占据→不计算光照和颜色→直接丢弃; |
Unity渲染队列-ZTest ZWrite
深度 就是该像素点在3d世界中距离摄像机的距离。离摄像机越远,则深度值(Z值)越大。
深度缓存
深度缓存中存储着准备要绘制在屏幕上的像素点的深度值。如果启用了深度缓冲区,在绘制每个像素之前,OpenGL会把该像素的深度值和深度缓存的深度值进行比较。如果新像素深度值<深度缓存深度值,则新像素值会取代原先的;反之,新像素值被遮挡,其颜色值和深度将被丢弃。(深度主要起的是比较的作用)
ZTest(深度测试)
开启后,它会与深度缓存区的深度值进行比较。通过比较则写入到颜色缓存区(这里会经历颜色混合Blend),不通过则丢弃
ZTest Less:深度小于当前缓存则通过
ZTest Greater:深度大于当前缓存则通过
ZTest LEqual:深度小于等于当前缓存则通过
ZTest GEqual:深度大于等于当前缓存则通过
ZTest Equal:深度等于当前缓存则通过
ZTest NotEqual:深度不等于当前缓存则通过
ZTest Always:不论如何都通过
注:ZTest默认值是On(LEqual)
Blend
ZWrite(深度写入)
开启后,若通过ZTest,则会把自己的深度值写入到深度缓存区
ZWrite On:写入深度
ZWrite Off:不写入深度
注:ZWrite默认值是On
Alpha测试(Alphatesting)
语法
AlphaTest Off
渲染所有像素(默认)。
AlphaTest comparison AlphaValue
将 alpha 测试设置为仅渲染 alpha 值在一定范围内的像素。
比较 (Comparison)
比较 (Comparison) 可以选择以下词语:
大于 (Greater) 仅渲染 alpha 值大于 AlphaValue 的像素。
大于等于 (GEqual) 仅渲染 alpha 值大于或等于 AlphaValue 的像素。
小于 (Less) 仅渲染 alpha 值小于 AlphaValue 的像素。
小于等于 (LEqual) 仅渲染 alpha 值小于或等于 AlphaValue 的像素。
等于 (Equal) 仅渲染 alpha 值等于 AlphaValue 的像素。
不等于 (NotEqual) 仅渲染 alpha 值不等于 AlphaValue 的像素。
总是 (Always) 渲染所有像素。这在功能上相当于 Alpha 测试关 (AlphaTest Off)。
永不 (Never) 不渲染任何像素。
AlphaValue
在 0 和 1 之间的浮点数。它也可能是浮动或范围属性的引用变量,这种情况下应该写在标准的方括号内([变量名])。
ZTest:通过则绘制,否则丢弃; |
AlphaTest:Alpha 测试是拒绝将像素写入屏幕的最后机会。 |
1. ZTest Less:深度小于当前缓存则通过 2. ZTest Greater:深度大于当前缓存则通过 3. ZTest LEqual:深度小于等于当前缓存则通过 4. ZTest GEqual:深度大于等于当前缓存则通过 5. ZTest Equal:深度等于当前缓存则通过 6. ZTest NotEqual:深度不等于当前缓存则通过 7. ZTest Always:不论如何都通过 注:ZTest默认值是On(LEqual) |
1. AlphaTest Greater value 仅渲染 alpha 值大于 AlphaValue 的像素。 2. AlphaTest GEqual value仅渲染 alpha 值大于或等于 AlphaValue 的像素。 3. AlphaTest Less value 仅渲染 alpha 值小于 AlphaValue 的像素。 4. AlphaTest LEqual value 仅渲染 alpha 值小于或等于 AlphaValue 的像素。 5. AlphaTest Equal value 仅渲染 alpha 值等于 AlphaValue 的像素。 6. AlphaTest NotEqual value 仅渲染 alpha 值不等于 AlphaValue 的像素。 7. AlphaTest Always 渲染所有像素。相当于 AlphaTest Off。 8. AlphaTest Never 不渲染任何像素。 |
AlphaTest Greater 0.5
_Cutoff ("Alpha cutoff", Range (0,1)) = 0.5
AlphaTest Greater [_Cutoff]
AlphaTest LEqual [_Cutoff]
固定功能shader(Fixed function shader):针对硬件能够执行的基本命令编写的shader.
Shader1.0学习笔记之SetTexture
1.语法
SetTexture [TextureName] {Texture Block}
2.Texture block combine 命令
combine src1 * src2 越乘越暗
combine src1 + src2 越加越亮
combine src1 lerp(src2) src3 插值运算使用src2的alpha值,注意如果alpha值为1,src1被使用;alpha值为0, src3被使用
src可以是m previous,constant,primary 或texture其中之一。
Previous指前一个SetTexture的结果
Primary指灯光计算的颜色
Texture指在SetTexture中指定的TextureName的颜色
Constant指ConstantColor指定的常量颜色值
Unity中物体的渲染顺序
提示:以下是本篇文章正文内容,下面案例可供参考
一、摄像机渲染
Unity中的渲染顺序首先是由摄像机(Camera)确定的,以摄像机为单元进行渲染,最后在根据设置将多个摄像机渲染的画面结合起来。不同物体首先按照摄像机深度进行渲染,深度高将会覆盖深度低的相机画面。
二、划分渲染队列
在同一个摄像机下,Unity以物体材质上的渲染队列(RenderQueue)数值进行了划分,将所有物体分为了两个队列
RenderQueue<2500,Opaque队列,通常是不透明物体
RenderQueue>2500,Transparent队列,通常是透明物体
同一个摄像机下,Unity会先渲染Opaque队列中的不透明物体,然后渲染Transparent队列中的透明物体。
三、不透明物体的渲染(深度决定论(由近到远),开启了ZWrite)
在Opaque队列中的物体,根据包围盒中心距离摄像机的距离,由近到远排序,进行渲染,Opaque队列中物体都是不透明物体,通常开启了ZWrite,由近到远渲染可以做遮挡剔除,减少了OverDraw,Opaque队列中的物体,可以设置SortingLayer,SortingOrder,Shader的RenderQueue等值,但是不会起作用,只会由距离摄像机的深度决定,距离摄像机近的先进行渲染,开启深度写入后,相同位置深度靠后会被裁剪掉。
四、透明物体的渲染(SortingLayer→SortingOrder→RenderQueue→Z(由远到近),关闭了ZWrite)
透明物体的Shader通常关闭了ZWrite,SorintLayer、SortingOrder,RenderQueue这些值的设置会影响显示的顺序,所以透明物体的渲染顺序遵循的规则是
根据SortingLayer层的顺序进行渲染,SortingLayer可以在Edit-projectsettings-Tags&Layer中进行设置,在代码中可以通过render.sortingLayer="layer";这样的代码进行设置。
SortingLayer相同的情况下根据SortingOrder的顺序进行渲染
SortingLayer跟SortingOrder都相同的情况下,根据RenderQueue的顺序进行渲染
都相同的情况下,根据包围盒中心距离摄像机的距离,由远到近进行渲染;
五、UGUI元素的渲染(按照透明物体处理)
UGUI元素使用的UIDefault材质通常是RenderQueue为3000,走的是透明物体的渲染,所以根据SortingLayer -> SortingOrder -> RenderQueue 的顺序进行排序,当以上值都相同时,根据元素在 Hierarchy 视图中的顺序进行。
渲染顺序总结
Unity对于渲染顺序并没有那么细的划分,只是以2500为界限划分了两次渲染过程:第一次渲染,2500及以下按照sort layer—>sort order—>render queue优先级排序;第二次渲染,2500以上按照sort layer—>sort order—>render queue优先级排序; 因为2500及以下shader往往开启深度写入,所以sortlayer、sort order及render queue造成的渲染顺序改变对于显示顺序并无影响;
1、不同的物体首先由摄像机的深度Z(Depth)决定,深度值越大优先级越高。
2、同摄像机渲染顺序先渲染不透明的物体,后渲染透明物体,透明物体的渲染层级更高。
3、同摄像机不透明物体渲染顺序由对象上的Z值决定。不透明物体由近到远排序优先。
4、同摄像机下透明物体
SortingLayer
SortingLayer 属性我们前面介绍过,它是我们渲染对象的排序层级,在编辑面板中越靠后的层级越高,越往后渲染。当两个渲染对象的SortingLayer一致的时候,比较Order In Layer的数值,数值越大越靠后渲染,层级越高。
RenderQueue
当上面的条件都一致的时候,我们判断RenderQueue的值,值越大,越靠后渲染,层级越高。
深度排序
透明物体由远到近排序优先。
————————————————
Unity渲染队列:渲染队列数字小于2500的对象认为是完全不透明(从前往后渲染),高于2500的被认为是半透明物体(从后往前渲染)。
“Queue” = “Background”值1000,此队列最先渲染。
“Queue” = “Geometry”值2000,通常是不透明物体。
“Queue” = “AlphaTest”值2450,透贴,要么完全透明,要么完全不透明。
“Queue” = “Transparent”值3000,常用于半透明对象,要混合的对象。
“Queue” = “Overlay”值4000,最后渲染,用于叠加效果。
What are Light Probes?光照探针/探测器,获取光照数据,用于运动物体
You’re already storing data about how light hits the different surfaces in your scene in a lightmap. You can use Light Probes to measure (or probe) data about the light that passes through the empty spaces in your scene. At runtime, data from the nearest Light Probe is used to estimate the light that should hit any moving GameObjects in your scene.
Why are they useful?更逼真、更高效、
You can use Light Probes to make your baked lighting much more realistic. They are also relatively efficient to use at runtime compared to real-time lights, if you place them with care.
Although Light Probes are generally useful to address issues with baked lighting that you might encounter when lighting dynamic objects, they are also very useful for areas in a scene where there are significant changes in the lighting. If users don’t see dynamic objects respond to lighting in the way that they expect in these areas, it can negatively impact their immersion in an experience.
realistic英[ˌriːəˈlɪstɪk] 美[ˌriːəˈlɪstɪk]adj. 现实的;实际的;明智的;逼真的;
address 英[əˈdres]美[əˈdres]n.住址; 通信处; vt.演说; 演讲;设法解决;address issues
immersion 英[ɪˈmɜːʃn]美[ɪˈmɜːrʒn]n. 浸没; 浸; 沉浸; 专心; 陷入;
beneath 英[bɪˈniːθ]美[bɪˈniːθ]prep.在下方; 在(或往)…下面; adv.在下面; 在底下;
snapshot 英[ˈsnæpʃɒt]美[ˈsnæpʃɑːt]n.快照; 简介; 简要说明;vt.给…拍快照;
probe英[prəʊb]美[proʊb]n. 探究; 详尽调查; (不载人)航天探测器; (医生用的)探针; 探测仪;
Light Probes=光照探测器
当您烘焙光照贴图时,您会将光照静态表面的快照存储在场景中。场景中的灯光不会继续在这些表面上投射更多的光。当一个动态对象(如您的球体)通过烘焙光时,渲染器需要有关通过动态对象行进的空白空间的光的信息,以便能够正确地照亮它。
Unity 有一个工具可以解决这个问题:Light Probes 。您已经在光照贴图中存储了有关光线如何照射场景中不同表面的数据。您可以使用 Light Probes 测量(或探测)有关穿过场景中空白空间的光的数据。在运行时,来自最近的 Light Probe 的数据用于估计应该击中场景中任何移动游戏对象的光线。
Light Probes 通常可用于解决您在为动态对象照明时可能遇到的烘焙照明问题,但它们对于场景中照明发生显着变化的区域也非常有用;
Blend Mode混合模式
- 什么是混合
混合是什么呢?混合就是把两种颜色混在一起。具体一点,就是把某一像素位置原来的颜色和将要画上去的颜色,通过某种方式混在一起,从而实现特殊的效果。
假设我们需要绘制这样一个场景:透过红色的玻璃去看绿色的物体,那么可以先绘制绿色的物体,再绘制红色玻璃。在绘制红色玻璃的时候,利用“混合”功能,把将要绘制上去的红色和原来的绿色进行混合,于是得到一种新的颜色,看上去就好像玻璃是半透明的。
- 在OpenGL中使用Blend
2.1 初始化说明
要使用OpenGL的混合功能,只需要调用:glEnable(GL_BLEND);即可。
要关闭OpenGL的混合功能,只需要调用:glDisable(GL_BLEND);即可。
注意:只有在RGBA模式下,才可以使用混合功能,颜色索引模式下是无法使用混合功能的。
混合需要把原来的颜色和将要画上去的颜色找出来,经过某种方式处理后得到一种新的颜色。这里把将要画上去的颜色称为“源颜色”,把原来的颜色称为“目标颜色”。
2.2 公式说明
数学公式来表达一下这个运算方式。
假设源颜色的四个分量(指红色,绿色,蓝色,alpha值)是 (Rs, Gs, Bs, As),
目标颜色的四个分量是(Rd, Gd, Bd, Ad),
又设源因子为(Sr, Sg, Sb, Sa),
目标因子为 (Dr, Dg, Db, Da)。
则混合产生的新颜色可以表示为:
源颜色 |
(Rs, Gs, Bs, As) |
(Red source,Green source,Blue source,Alpha source) |
源因子 |
(Sr, Sg, Sb, Sa) |
(Source red,Source green,Source blue,Source alpha) |
目标颜色 |
(Rd, Gd, Bd, Ad) |
(Red dest,Green dest,Blue dest,Alpha dest) |
目标因子 |
(Dr, Dg, Db, Da) |
(Dest red,Dest green,Dest blue,Dest alpha) |
计算公式(默认Add)
(Rs*Sr+Rd*Dr, Gs*Sg+Gd*Dg, Bs*Sb+Bd*Db, As*Sa+Ad*Da)
如果颜色的某一分量超过了1.0,则它会被自动截取为1.0,不需要考虑越界的问题。
2.3 在OpenGL中的使用
选择源混合因子和目标混合因子的方式:
第一种方式是调用函数glBlendFunc(),并指定两个混合因子, 其中第一个参数为源RGBA的混合因子, 第二个参数为目标RGBA的混合因子.
第二种方法是调用glBlendFuncSeparate()并指定4个混合因子, 这样可以用不同的方式来混合RGB和alpha值
第二种方式就不在说了,说下第一种当时中的混合因子的枚举表:
GL_DST_ALPHA |
( Ad , Ad , Ad , Ad ) |
GL_DST_COLOR |
( Rd , Gd , Bd , Ad ) |
GL_ONE |
(1,1,1,1) |
GL_ONE_MINUS_DST_ALPHA |
(1,1,1,1) - (Ad,Ad,Ad,Ad) |
GL_ONE_MINUS_DST_COLOR |
(1,1,1,1) - (Rd,Gd,Bd,Ad) |
GL_ONE_MINUS_SRC_ALPHA |
(1,1,1,1) - (As,As,As,As) |
GL_SRC_ALPHA |
( As , As , As , As ) |
GL_SRC_ALPHA_SATURATE |
(f,f,f,1) : f = min(As,1-Ad) |
GL_ZERO |
( 0 , 0 , 0 , 0 ) |
- unity中的说明
3.1 unity中混合简介
在所有着色器执行完毕,所有纹理都被应用,所有像素准备被呈现到屏幕之后,使用Blend命令来操作这些像素进行混合。
3.2 blend的语法Blend Off:关闭blend混合(默认值)
Blend SrcFactor DstFactor :配置并启动混合。产生的颜色被乘以SrcFactor. 已存在于屏幕的颜色乘以DstFactor,并且两者将被叠加在一起。
Blend SrcFactor DstFactor, SrcFactorA DstFactorA:同上,但是使用不同的要素来混合alpha通道
BlendOpBlendOpValue:不是添加混合颜色在一起,而是对它们做不同的操作。
BlendOpOpColor, OpAlpha:同上,但是使用不同的操作来处理alpha通道
AlphaToMaskOn:里面新添加的,常用在开启多重渲染(MSAA)的地表植被的渲染。
混合指令 Blend |
当前对象的颜色 将要画上去的颜色 混合系数 |
屏幕上已存在的颜色 某一像素位置原来的颜色 混合系数 |
通过不同的混合系数,得到不同的混合值,从而实现特殊的视觉效果 |
Blend |
One |
One |
线性减淡;粒子常用,如火焰粒子。 |
Blend |
SrcAlpha |
OneMinusSrcAlpha |
透明混合;正常的透明效果。 |
Blend |
OneMinusDstColor |
One |
滤色 |
Blend |
DstColor |
Zero |
正片叠底 |
Blend |
DstColor |
SrcColor |
类似X光片效果 |
Blend |
One |
OneMinusSrcAlpha |
透明度混合;当前色×当前α+(1-当前α)×缓存颜色 |
Unity中的混合因子(和OpenGL的差不多):
One |
值为1,使用此设置来让源或是目标颜色完全的通过。 |
Zero |
值为0,使用此设置来删除源或目标值。 |
SrcColor |
此阶段的值是乘以源颜色的值。 |
SrcAlpha |
此阶段的值是乘以源alpha的值。 |
DstColor |
此阶段的值是乘以帧缓冲区源颜色的值。 |
DstAlpha |
此阶段的值是乘以帧缓冲区源alpha的值。 |
OneMinusSrcColor |
此阶段的值是乘以(1 - source color) |
OneMinusSrcAlpha |
此阶段的值是乘以(1 - source alpha) |
OneMinusDstColor |
此阶段的值是乘以(1 - destination color) |
OneMinusDstAlpha |
此阶段的值是乘以(1 - destination alpha) |
混合的操作符(Blend operations)
Add |
Add source and destination together. |
Sub |
Subtract destination from source. |
RevSub |
Subtract source from destination. |
Min |
Use the smaller of source and destination. |
Max |
Use the larger of source and destination. |
LogicalClear |
Logical operation: Clear (0) DX11.1 only. |
LogicalSet |
Logical operation: Set (1) DX11.1 only. |
LogicalCopy |
Logical operation: Copy (s) DX11.1 only. |
LogicalCopyInverted |
Logical operation: Copy inverted (!s) DX11.1 only. |
LogicalNoop |
Logical operation: Noop (d) DX11.1 only. |
LogicalInvert |
Logical operation: Invert (!d) DX11.1 only. |
LogicalAnd |
Logical operation: And (s & d) DX11.1 only. |
LogicalNand |
Logical operation: Nand !(s & d) DX11.1 only. |
LogicalOr |
Logical operation: Or (s | d) DX11.1 only. |
LogicalNor |
Logical operation: Nor !(s | d) DX11.1 only. |
LogicalXor |
Logical operation: Xor (s ^ d) DX11.1 only. |
LogicalEquiv |
Logical operation: Equivalence !(s ^ d) DX11.1 only. |
LogicalAndReverse |
Logical operation: Reverse And (s & !d) DX11.1 only. |
LogicalAndInverted |
Logical operation: Inverted And (!s & d) DX11.1 only. |
LogicalOrReverse |
Logical operation: Reverse Or (s | !d) DX11.1 only. |
LogicalOrInverted |
Logical operation: Inverted Or (!s | d) DX11.1 only |
下列是最经常使用的混合类型
Blend SrcAlpha OneMinusSrcAlpha // Alphablending alpha混合
Blend One One // Additive 相加混合
Blend One OneMinusDstColor // Soft Additive柔和相加混合
Blend DstColor Zero // Multiplicative 相乘混合
BlendDstColor SrcColor // 2x Multiplicative 2倍相乘混合
Alpha Test和Alpha Blending
Alpha Test和Alpha Blending是两种处理透明的方法。
Alpha Test采用一种很霸道极端的机制,只要一个像素的alpha不满足条件,那么它就会被fragment shader舍弃,“我才不要你类!”。被舍弃的fragments不会对后面的各种Tests产生影响;否则,就会按正常方式写入到缓存中,并进行正常的深度检验等等,也就是说,Alpha Test是不需要关闭ZWrite的。Alpha Test产生的效果也很极端,要么完全透明,即看不到,要么完全不透明。
而Alpha Blending则是一种中庸的方式,它使用当前fragment的alpha作为混合因子,来混合之前写入到缓存中颜色值。但Alpha Blending麻烦的一点就是它需要关闭ZWrite,并且要十分小心物体的渲染顺序。如果不关闭ZWrite,那么在进行深度检测的时候,它背后的物体本来是可以透过它被我们看到的,但由于深度检测时大于它的深度就被剔除了,从而我们就看不到它后面的物体了。因此,我们需要保证物体的渲染顺序是从后往前,并且关闭该半透明对象的ZWrite。
注意:Alpha Blending只是关闭ZWrite,人家可没有关闭ZTest哦!这意味着,在输出一个Alpha Blending的fragment时,它还是会判断和当前Color Buffer中的fragment的深度关闭,如果它比当前的fragment深度更远,那么它就不会再做后续的混合操作;否则,它就会和当前的fragment进行混合,但是不会把自己的深度信息写入Depth Buffer中。这是非常重要的,这一点决定了,即便一个不透明物体出现在一个透明物体的前面,不透明物体仍可以正常的遮挡住透明物体!也就说说,对于Alpha Blending来说,Depth Buffer是只读的。
————————————————
1、什么是深度?
深度其实就是该像素点在3d世界中距离摄象机的距离,深度值Zbuffer(Z值)越大,则离摄像机越远。
2、什么是深度缓存?
深度缓存中存储着每个像素点(绘制在屏幕上的)的深度值!如果启用了深度缓冲区,在绘制每个像素之前,OpenGL会把它的深度值和已经存储在这个像素的深度值进行比较。新像素深度值<原先像素深度值,则新像素值会取代原先的;反之,新像素值被遮挡,其颜色值和深度将被丢弃,最终屏幕显示的就是深度缓存中深度对应的像素点的颜色!(深度主要起的是比较的作用)
3、什么是深度测试?
在深度测试中,默认情况是将要绘制的新像素的z值与深度缓冲区中对应位置的z值进行比较,如果比深度缓存中的值小,那么用新像素的颜色值更新深度缓存中对应像素的颜色值。
if( z_new<z_buffer) write2buffer(z_new) else //do nothing
4、为什么需要深度?
在不使用深度测试的时候,如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这样的效果并不是我们所希望的。而有了深度缓冲以后,绘制物体的顺序就不那么重要了,都能按照远近(Z值)正常显示,这很关键。(越后绘制的东西,距离相机就越近)
那么,在unity中,如果知道了渲染队列,ZWrite,ZTest,如何确定哪个物体先显示呢?
首先,unity先将渲染队列中较前的进行渲染,然后再执行ZWrite,ZTest
ZWrite可以取的值为:On/Off,默认值为On,代表是否要将像素的深度写入深度缓存中;
ZTest可以取的值为:Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never/Off,默认值为LEqual;
代表如何将像素的颜色写入深度缓存中,例如当取默认值的情况下,如果将要绘制的新像素的z值小于等于深度缓存中的值,则将用新像素的颜色值更新深度缓存中对应像素的颜色值。需要注意的是,当ZTest取值为Off时,表示的是关闭深度测试,等价于取值为Always,而不是Never!Always指的是直接将当前像素颜色(不是深度)写进颜色缓冲区中;而Never指的是不要将当前像素颜色写进颜色缓冲区中,相当于消失。
因为ZWrite默认值为On,ZTest默认值为LEqual,所以这很好地解释了为什么在unity中,距离相机近的东西会阻挡住距离相机远的东西。如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这时我们可以通过修改ZWrite和ZTest来改变物体的遮挡关系!
ZTest ZWrite
深度Z→比较ZTest→写入ZWrite→ZBuffer
深度:就是该像素点在3d世界中距离摄像机的距离。离摄像机越远,则深度值(Z值)越大。
深度缓存:深度缓存中存储着准备要绘制在屏幕上的像素点的深度值。如果启用了深度缓冲区,在绘制每个像素之前,OpenGL会把该像素的深度值和深度缓存的深度值进行比较。如果新像素深度值<深度缓存深度值,则新像素值会取代原先的;反之,新像素值被遮挡,其颜色值和深度将被丢弃。(深度主要起的是比较的作用)
SubShader
{
//ZWrite表示是否将深度写入GBuffer
//ZTest表示是否将颜色写入GBuffer
ZWrite On
//与前面Alpha测试和模版测试相同,ZTest是要渲染的物体的深度和Gbuffer中的深度作比较,符合要求则渲染,否则不渲染
//Less | Greater | LEqual | GEqual | Equal | NotEqual | Always
ZTest Greater
Pass
{
Color(1,0,0,1)
}
}
ZTest 深度测试
|
开启后,它会与深度缓存区的深度值进行比较。通过比较则写入到颜色缓存区(这里会经历颜色混合Blend),不通过则丢弃 ZTest Less:深度小于当前缓存则通过 ZTest Greater:深度大于当前缓存则通过 ZTest LEqual:深度小于等于当前缓存则通过 ZTest GEqual:深度大于等于当前缓存则通过 ZTest Equal:深度等于当前缓存则通过 ZTest NotEqual:深度不等于当前缓存则通过 ZTest Always:不论如何都通过 注:ZTest默认值是On(LEqual) |
ZWrite 深度写入
|
开启后,若通过ZTest,则会把自己的深度值写入到深度缓存区; ZWrite On:写入深度 ZWrite Off:不写入深度 注:ZWrite默认值是On |
RenderingPath*3:VertexLit,Forward,Deferred Lighting;
LightMode:Vertex,ForwardBase,ForwardAdd,PepassBase,PrepassFinal等;
deferred英[dɪ'fɜ:d] 美[dɪ'fɜd]adj. 延期的,缓召的v. 拖延,延缓,推迟
前向渲染(Forward)延迟渲染(deferred)
前向渲染 Forward Rendering
|
它的实现最贴合我们的思维逻辑,当我们渲染模型时,只需要关心画模型然后直接处理光照,让它自己去做深度测试,最后深度测试过的都显示在屏幕上。 1、对要渲染的物体进行遍历渲染出shadowmap 2、再遍历一遍上面要渲染的物体,根据shadowmap对每一个物体的像素进行光照计算 优点 很明显,就是简单,并且可以针对每个物体指定它的材质,因为每个物体都是独立渲染的。 缺点 1、由于依赖深度测试,如果物体是乱序的,可能会出现大量的像素光照计算都是浪费的。 2、不能支持光源数量较多的情况。所以我们一般有两种做法来处理多光源的情况,一种是一遍渲染多个光源,所有光照运算都在一个着色器中进行。另一种是多遍渲染多个光源,意思就是每多一盏灯,就多渲染一次模型,所以性能消耗也比较大。 |
延迟渲染 Deferred Rendering |
它的做法是在第一遍渲染模型的时候,不进行光照计算,直接将位置、法线深度、颜色等存到G-Buffer。很多人第一次接触G-Buffer这个名词都是一头雾水,其实就是创建多张和屏幕一样大的纹理,然后每张纹理的像素值分别用来存上面提到的这些数据。也就是说一次渲染,需要输出多张纹理,这跟前向渲染是不同的, 前向渲染只渲染到一张纹理上,这张纹理最终会渲染在屏幕上。而延迟渲染这多张纹理都不是最终结果,可以理解为只是用几张贴图存储一堆中间数据。 第二遍再根据G-Buffer的数据,进行光照计算,写入帧缓冲区 优点 处理完G-Buffer之后,其实每盏灯光就可以通过一个Drawcall的消耗去执行光照计算。第一遍处理完的G-Buffer是深度测试过的,不像前向渲染一样,有那么多光照计算的浪费。 缺点 1、最终的光照计算方式只能是一种,也就是其他文章提到的只允许一个材质,因为最终计算的时候只剩下一堆数据,不知道它们分别是谁的,所以只能无差别对待。而前向渲染可以每个模型一种计算方式。 2、不允许使用透明物件,因为最终G-Buffer只剩一个像素了,无法进行混合。不过可以在第二遍渲染完之后,用前向渲染的方式渲染透明物体。 3、不支持抗锯齿,意味着不能用MSAA,不过可以用FXAA进行后期处理 4、有些硬件不支持MRT(Multiple Render Targets 多重纹理目标),也就是输出到多张纹理上实现G-Buffer的功能 5、G-Buffer需要比较大的带宽,有些硬件不具备这个能力 6、由于光照计算本身性能消耗也不低,延迟渲染的光照计算其实等同于在做一次全屏的后处理,后处理其实对手机来说过于昂贵。而如果只有一盏灯的话,其实前向渲染省了这次额外的渲染。所以移动设备上延迟渲染的性能会比前向渲染的性能要差一些 |
- 前向:先计算,再丢弃;
- 延迟:先丢弃,再计算;
G-buffer,Geometric Buffer,几何缓冲区
Deferred Rendering可以将延迟渲染( Deferred Rendering)理解为先将所有物体都先绘制到屏幕空间的缓冲(即G-buffer,Geometric Buffer,几何缓冲区)中,再逐光源对该缓冲进行着色的过程,从而避免了因计算被深度测试丢弃的⽚元的着色而产⽣的不必要的开销。也就是说延迟渲染基本思想是,先执行深度测试,再进行着色计算,将本来在物空 间(三维空间)进行光照计算放到了像空间(二维空间)进行处理。
延迟渲染利:解决了前向渲染不能使用大量灯光的问题。
延迟渲染弊:不能使用半透明对象。
需要显卡支持多目标渲染(Multiple Render Targets,多目标渲染在后面进行解释)。
没有抗锯齿。阴影依赖于光照的数量。
————————————————
几何空间
空间 |
Unity变换 |
Shader变换 |
模型空间 Model Space |
transform.worldToLocalMatrix.MultiplyPoint transform.worldToLocalMatrix.MultiplyVector |
左乘_World2Object |
世界空间 World Space |
transform.localToWorldMatrix.MultiplyPoint transform.localToWorldMatrix.MultiplyVector |
左乘_Object2World |
视空间 View Space |
Camera.worldToCameraMatrix Camera.cameraToWorldMatrix |
UNITY_MATRIX_MV (model→view) |
剪切空间-投影 Projection Space |
Camera.projectionMatrix |
UNITY_MATRIX_MVP (model→view→projection) |
pivot英[ˈpɪvət] 美[ˈpɪvət]n. 原点;中心点,中枢
vertex英[ˈvɜ:teks] 美[ˈvɜrteks]n. 最高点;顶点;(三角形、多边形等的)角的顶点
Material class in UnityEngine/继承自:Object
GetColor 获取指定的颜色值。 GetColorArray 获取指定的颜色数组。 GetFloat 获取指定的浮点值。 GetFloatArray 获取指定的浮点数组。 GetInt This method is deprecated. Use GetFloat or GetInteger instead. GetInteger 获取指定的整数值。 GetMatrix 从着色器获取指定的矩阵值。 GetMatrixArray 获取指定的矩阵数组。 GetPassName 返回索引 pass 处的着色器通道的名称。 GetShaderPassEnabled 检查此材质上是否启用了给定的着色器通道。 GetTag 获取材质着色器标记的值。 GetTexture 获取指定的纹理。 GetTextureOffset 获取纹理 propertyName 的位置偏移。 GetTexturePropertyNameIDs 返回此材质上公开的所有纹理属性的名称 ID。 GetTexturePropertyNames 返回此材质上公开的所有纹理属性的名称。 GetTextureScale 获取纹理 propertyName 的位置缩放。 GetVector 获取指定的向量值。 GetVectorArray 获取指定的向量数组。 |
SetBuffer Sets a named buffer value. SetColor 设置指定的颜色值。 SetColorArray 设置颜色数组属性。 SetConstantBuffer Sets a ComputeBuffer or GraphicsBuffer as a named constant buffer for the material. SetFloat 设置指定的浮点值。 SetFloatArray 设置浮点数组属性。 SetInt This method is deprecated. Use SetFloat or SetInteger instead. SetInteger 设置指定的整数值。 SetKeyword Sets the state of a local shader keyword for this material. SetMatrix 为着色器设置指定的矩阵。 SetMatrixArray 设置矩阵数组属性。 SetOverrideTag 对材质设置重写标记/值。 SetPass 激活给定的 pass 以进行渲染。 SetShaderPassEnabled 在每个材质级别上启用或禁用着色器通道。 SetTexture 设置指定的纹理。 SetTextureOffset 设置纹理 propertyName 的位置偏移。 SetTextureScale 设置纹理 propertyName 的位置缩放。 SetVector 设置指定的向量值。 SetVectorArray 设置向量数组属性。 |
渲染队列Queue
背景 |
普通几何体 |
阿尔法测试 |
透明体 |
覆盖 |
Background |
Geometry |
Alpha Test |
Transparent |
Overlay |
1000 |
2000 |
2450 |
3000 |
4000 |
Tags{“Queue”=”Geometry+1314”}
渲染类型Render Type
背景 |
普通几何体 |
透明裁切 |
透明体 |
覆盖 |
Background |
Opaque |
TransparentCutout |
Transparent |
Overlay |
光照模式Light Mode
Always |
不管使用哪种渲染路径,该 Pass总是会被渲染,但不会计算任何光照。 |
ForwardBase |
用于前向渲染。该Pass会计算环境光、最重要的平行光、逐顶点/SH光源和Lightmaps。 |
ForwardAdd |
用于前向渲染。该Pass会计算额外的逐像素光源。每个Pass对应一个光源。 |
Deferred |
用于延迟渲染。该Pass会渲染G缓冲(G-buffer)。 |
ShadowCaster |
把物体的深度信息渲染到阴影映射纹理(shadowmap)或一张深度纹理中。 |
PrepassBase |
用于遗留的延迟渲染。该 Pass 会渲染发现和高光反射的指数部分。 |
PrepassFinal |
用于遗留的延迟渲染。该Pass通过合并纹理、光照和自发光来渲染得到最后的颜色。 |
顶点 |
Vertex、VertexLMRGBM 和 VertexLM : 用于遗留的顶点照明渲染。 |
渲染路径Render Path
前项渲染 |
延迟渲染 |
顶点光照 |
Forward Rendering |
Deferred Rendering |
Vertex Lit |
Shader常用语义
在Unity Shader中,语义是一种用于指定变量或属性的用途或含义的标记。在Shader中使用语义可以告诉Unity引擎如何使用这些变量或属性。下面是一些常见的Shader语义及其含义:
Shader语义 |
作用和意义 |
示例 |
POSITION |
定义了每个顶点的位置。它必须在顶点着色器的输出中使用。 |
float4 pos : POSITION |
NORMAL |
定义了每个顶点的法向量。法向量是垂直于表面的向量,用于计算光照和阴影效果。 |
float3 normal : NORMAL |
COLOR |
定义了每个顶点的颜色。可以用它来表示材质的颜色或在顶点着色器中计算出的其他颜色。 |
float4 color : COLOR |
TEXCOORD0-3 |
定义了每个顶点在纹理图像中的位置,以便将纹理贴到表面上。 |
float2 uv : TEXCOORD0 |
TANGENT |
定义了每个顶点的切线向量。切线向量是表面切线方向的向量,用于计算法线贴图。 |
float3 tangent : TANGENT |
BINORMAL |
定义了每个顶点的副切线向量。副切线向量是表面副切线方向的向量,用于计算法线贴图。 |
float3 binormal : BINORMAL |
SV_POSITION |
定义了像素在屏幕空间中的位置。用于像素着色器的输出。 |
float4 pos : SV_POSITION |
UNITY_FOG_COORDS |
定义了雾坐标。用于计算雾效果。 |
float fogCoord : UNITY_FOG_COORDS |
UNITY_VERTEX_ID |
定义了顶点的索引。用于访问顶点缓冲区中的顶点数据。 |
uint vertexID : UNITY_VERTEX_ID |
UNITY_BASEVERTEX |
顶点缓冲区的基本索引 |
|
UNITY_MATRIX_MVP |
定义了世界空间到裁剪空间的变换矩阵。 |
float4x4 MVP : UNITY_MATRIX_MVP
|
UNITY_LIGHTMODEL_AMBIENT |
定义了环境光颜色。用于计算全局光照。 |
float4 ambient : UNITY_LIGHTMODEL_AMBIENT |
UNITY_LIGHTMODEL_DIRECTION |
定义了灯光模型的方向。用于计算方向光照。 |
float3 direction : UNITY_LIGHTMODEL_DIRECTION |
UNITY_LIGHTMODEL_AMBIENT_COLOR |
环境光颜色 |
|
UNITY_LIGHT_ATTENUATION |
定义了光照的衰减值。用于计算点光源和聚光灯的光照衰减。 |
float3 attenuation : UNITY_LIGHT_ATTENUATION |
UNITY_LIGHT_COOKIE |
定义了灯光的贴图。用于在灯光上添加纹理效果。 |
sampler2D cookie :
|
UNITY_TEXEL_DENSITY |
纹理像素密度 |
|
UNITY_SPECCUBE_BOX_MINMAX |
立方体贴图的包围盒最小值和最大值 |
|
UNITY_LIGHT_FALLOFF_EXPONENT |
光照的衰减指数 |
|
UNITY_LIGHT_SPOT_DIR |
聚光灯的方向 |
|
UNITY_LIGHT_SPOT_ATTENUATION |
聚光灯的衰减值 |
|
UNITY_LIGHT_ATTEN_PARAM |
灯光的衰减参数 |
|
UNITY_LIGHT_SHADOW_BIAS |
阴影的偏移值 |
|
UNITY_LIGHT_SHADOW_MAP_TEXTURE |
阴影贴图的纹理 |
|
UNITY_LIGHT_SHADOW_DITHER_CONSTANT |
阴影抖动的常数 |
|
UNITY_LIGHT_SHADOW_BIAS_PARAMS |
阴影偏移的参数 |
|
UNITY_SHOULD_WRITE_DEPTH_CLIP |
是否写入深度剪辑 |
|
UNITY_WORLD_SPACE_VIEW_PROJ |
世界空间视图投影矩阵 |
|
UNITY_MATRIX_V_INV |
视图矩阵的逆矩阵 |
|
UNITY_MATRIX_P_INV |
投影矩阵的逆矩阵 |
|
UNITY_MATRIX_VP_INV |
视图投影矩阵的逆矩阵 |
|
UNITY_MATRIX_MV_INV |
模型视图矩阵的逆矩阵 |
|
UNITY_MATRIX_IT_MV_INV |
模型视图矩阵逆转置矩阵的逆矩阵 |
|
atten n.衰减器,衰减系数;LightAtten;
atten=attenuation英[əˌtenjʊ'eɪʃn] 美[əˌtenjʊ'eɪʃn]n. 变薄;弄细;稀薄化;减少;衰减、衰减系数;
Shader语义是一种用于指定着色器输入和输出的标识符,它们定义了顶点和像素着色器中输入和输出变量的含义和用途。每个语义都有一个特定的含义,告诉着色器要接收或输出什么样的数据。例如,POSITION语义指示顶点位置,NORMAL语义指示法向量,TEXCOORD0-3语义指示纹理坐标,SV_POSITION语义指示像素在屏幕上的位置等等。
举个例子,当我们需要在顶点着色器中将顶点的位置输出到像素着色器中,我们可以在顶点着色器中使用POSITION语义声明顶点的位置,并将其作为输出参数传递给像素着色器。在像素着色器中,我们可以使用SV_POSITION语义指示像素在屏幕上的位置,并将其作为像素着色器的输出。
另一个例子是使用TEXCOORD语义指定纹理坐标。在顶点着色器中,我们可以使用TEXCOORD语义声明顶点的纹理坐标,并将其作为输出参数传递给像素着色器。在像素着色器中,我们可以使用同样的TEXCOORD语义指示像素的纹理坐标,并用于将纹理贴到表面上。
————————————————
uniform着色器统一值
属性是每个顶点位置,表面法线和纹理坐标等都需要的,而统一值则用于为整个图元批次向保持不变的着色器传递数据。对于顶点着色器来说,可能最普遍的统一值就是变换矩阵。
一个统一值在一个图元的绘制过程中是不变的,所以其值不能在glBegin和glEnd之间设置的
uniform限定了表示一个变量的值将由应用程序在着色器执行之前指定,并且在图元的处理过程中不会发生变化。
uniform变量是由顶点着色器和片段着色器共享的,他们必须声明为全局变量。
uniform变量特点:
- 由应用程序赋值;
- 渲染过程中不会发生变化;
全局变量,顶点着色器和片段着色器共享;
ShaderLab和CG变量的对应关系
|
ShaderLab属性类型 CG变量类型 Color, Vector float4, half4, fixed4 Range, Float float, half, fixed 2D sampler2D Cube samplerCube 3D sampler3D |
UnityCG的一些常用结构体 |
名称 描述 包含变量 appdata_base 顶点着色器的输入 顶点位置、顶点法线、第一组纹理坐标 appdata_tan 顶点着色器的输入 顶点位置、顶点切线、顶点法线、第一组纹理坐标 appdata_full 顶点着色器的输入 顶点位置、顶点切线、顶点法线、四组(或更多)纹理坐标 appdata_img 顶点着色器的输入 顶点位置、第一组纹理坐标 v2f_img 顶点着色器的输出 裁剪空间中的位置、纹理坐标 |
UnityCG的空间变换函数 |
函数名 描述 float3 WorldSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向 float3 ObjSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回模型空间中从该点到摄像机的观察方向 float3 WorldSpaceLightDir(float4 v) 输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向,没有被归一化。仅可用于前向渲染中。 float3 ObjSpaceLightDir(float4 v) 输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向,没有被归一化。仅可用于前向渲染中。 float3 UnityObjectToWorldNormal(float3 norm) 把法线方向从模型空间转换到世界空间中。 float3 UnityObjectToWorldDir(in float3 dir) 把方向矢量从模型空间变换到世界空间中。 float3 UnityWorldToObjectDir(float3 dir) 把方向矢量从世界空间变换到模型空间中。 |
顶点着色器输入数据的语义(Unity所支持的)
|
语义 描述 POSITION 模型空间中的顶点位置,通常是float4类型 NORMAL 顶点法线,通常是float3类型 TANGENT 顶点切线,通常是float4类型 TEXCOORDn 该顶点的纹理坐标,TEXCOORD0表示第一组纹理坐标,以此类推。通常是float2或者float4类型 COLOR 顶点颜色,通常是fixed4或者float4类型 |
顶点着色器的输出数据的语义(Unity所支持的)
|
语义 描述 SV_POSITION 裁剪空间中的顶点坐标,结构体中必须包含一个用该语义修饰的变量。等同于DX9中的POSITION,但最好使用SV_POSITION COLOR0 通常用于输出第一组顶点颜色,但不是必需的 COLOR1 通常用于输出第二组顶点颜色,但不是必需的 TEXCOORD0~TEXCOORD7 通常用于输出纹理坐标,但不是必需的 |
|
|
Unity向Shader传递参数
GetComponent<Render>().material.SetVector(“_SecondColor”,new Vector(1,0,0,1));
属性和变量数据类型对应关系
贴图→采样器 |
2D→sampler2D,Cube→samplerCube,3D→sampler3D |
颜色→向量 |
Color,Vector→float4,half4,fixed4 |
浮点数 |
Range,Float→float,half,fixed(float1,half1,fixed) |
appdata_base,appdata_tan,appdata_full,appdata_img,v2f_img表示Application Data
应用程序能够自动提供的数据,根据需求的不同,可以使用不同版本的appdata 结构体
appdata将作为
struct appdata_base { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct appdata_tan { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; |
struct appdata_full { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 texcoord1 : TEXCOORD1; float4 texcoord2 : TEXCOORD2; float4 texcoord3 : TEXCOORD3; fixed4 color : COLOR; UNITY_VERTEX_INPUT_INSTANCE_ID }; |
struct appdata_img { float4 vertex : POSITION; half2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f_img { float4 pos : SV_POSITION; half2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; |
pixel英[ˈpɪksl] 美[ˈpɪksəl, -ˌsɛl]n. (显示器或电视机图像的)像素
texture-pixel纹理像素
Texel英[ˈteksəl] 美[ˈtɛksəl, ˈtɛsəl] 图素; 纹元、纹素; 纹理元; 纹理元素、纹理像素、纹理单元;
纹理元素(Texel,Texture Element)是计算机图形学中纹理空间的基本单位。纹理由一组纹理组成,就像图片由一组像素组成一样。但是,在谈到3d图形和3d再现的大部分内容时,texel和pixel是有区别的。
纹理元素(Texel,Texture Element)是计算机图形学中纹理空间的基本单位。纹理由一组纹理组成,就像图片由一组像素组成一样。但是,在谈到 3d 图形和 3d 再现的大部分内容时,texel 和 pixel 是有区别的。纹理元素也称为纹理像素。
Texel是一种三维网格纹理压缩(texture compression)技术,是亚洲服务器到客户端(ASTC)压缩技术的一个实现。它可以将纹理数据压缩到较小的字节以节省存储空间并提高数据传输速度。
Texel可用于各种应用,如虚拟现实(VR),游戏和视频。Texel技术非常适合于3D模型的纹理压缩,这些模型的纹理压缩过程普遍复杂而费时。Texel技术是一种快速的纹理压缩技术,可以确保模型和纹理表示的真实度和逼真程度,同时有效减少压缩文件体积。
Texel压缩算法具有几个关键特征。首先它支持熵编码,可以有效减少纹理文件的体积,但不会降低真实度和逼真度。然后它支持用户自定义的像素格式,可以自定义像素,以及像素对齐模式,可以增加灵活性和易用性。
Texel使用一套程式化编码了特征。与其它技术不同的是,它的哈希格局采用了变量程序模型,以便为用户提供更强大的控制,从而更好地控制纹理压缩效果。
Texel在三维网格纹理压缩技术中起到了重要作用。它可以快速和有效地完成纹理压缩,帮助开发者在较短的时间内完成复杂的三维模型表示。然而,Texel分辨率和尺寸有限,可能会影响模型表示的真实度和逼真度。
首先为什么要用贴图?其实主要是为了压缩数据、节省运算资源,因为如果直接使用3D扫描结果的话会导致一个小玩意就有特别多的面,导致CPU,显卡爆炸。
贴图分类*6
颜色贴图、凹凸贴图、反射贴图、结构贴图、光照与环境贴图、其他贴图;
颜色贴图*3 主要为Diffuse、Albedo、Base Color三种 |
Diffuse 光照模型在Lambertian(兰伯特材质球)着色器中会把颜色贴图叫做Diffuse Map(也叫颜色贴图),通常在绘制这张Diffuse Map的时候会把物体的结构阴影信息也绘制进去。在传统工作流中,Diffuse Map是带着光影信息的。 Diffuse Map(漫反射颜色)应该表示物体表面的颜色,在Unity中叫做Albedo。 |
Albedo 主要体现模型的纹理和颜色。Unity的Shader(着色器)中,把颜色贴图叫做Albedo。 |
|
Base Color Base Color是把颜色贴图剔除光影变化后,我们看到的最基础的颜色。在PBR工作流中颜色贴图叫做Base Color, 其中包含了电介质的反射颜色和金属的反射率值这两种类型的数据。因为Base Color Map中带了金属的反射率值,所以需要配合上Metallic Map一起使用的。 |
|
Gradient&Ramp、ColorLUT Gradient&Ramp Map(渐变图)和ColorLUT(颜色查找表)也可以认为是颜色贴图的一种,这类贴图通过在一维或二维的方式将一种颜色映射到另一种颜色。且通常作为全局资源使用(不是特定于某一模型)。
|
|
凹凸贴图*3 主要为Bump、Normal和Displacement三种,三种贴图都是为模型提供更多的细节。其中Displacement有时用于改变模型的顶点位置,而Bump和Normal则不会改变模型的顶点位置。 凹凸贴图对比 就实现复杂度/质量与性能开销而言,Dispalcement>Normal>Bump(>Reflection)。
|
Bump Map(凹凸贴图 )是一个类似于法线贴图的概念,有时也称为Height(高度图)。但是凹凸贴图只包含高度信息而不包含角度信息。凹凸贴图的优点是可以很直观地看出模型表面的凹凸情况(颜色越浅表明该位置的表面越像外凸起,反之亦然),但是计算更复杂,因此更性能开销更大。高度图通常与法线贴图结合使用,用于给出表面凹凸的额外信息。 |
Normal Map(法线贴图)是凹凸映射技术的另一种应用。法线贴图包含角度信息而不包含任何高度信息,其R、G、B三个通道储存的信息表示了斜面的方向和陡峭程度。使用法线贴图和高度贴图可以确保光照和位移是一致的,能够带来更真实的效果。 由于法线贴图存储的是表面的法线方向,而方向是相对于坐标空间而言的。因此存在三种不同的空间法线贴图:Tangent切线空间、Object对象空间、World世界空间,三种法线贴图都有各自的优缺点且能达到相同的效果,只是计算方式有所不同。 |
|
Displacement Displacement Map(置换贴图,也叫移位贴图)可以改变模型对象的几何形状,但要达到较好的置换效果需要提高模型本身的顶点数,通常结合曲面细分使用。因此在提供最真实的效果的同时也会大幅增加渲染性能的开销。 置换贴图的另一个用途是作为Parallax Map(视差贴图,也称为Virtual Displacement Map虚拟置换贴图)使用。 Steep Parallax Map Steep Parallax Map(陡峭视差贴图/映射)是视差贴图的改进版。通过增加采样数量来提高准确性(普通视差贴图仅使用一个样本),因此在陡峭高度变化较大的地方也能显示出正确效果。 Parallax Occlusion Map(视差遮蔽贴图/映射)与陡峭视差贴图的原理基本相同,但在不同的样本之间进行了线性插值,因此能在一定程度上解决陡峭视差贴图存在的问题。 Relief Map(浮雕贴图)能够实现比陡峭视差贴图更深的凹凸深度,并能实现很好的自阴影和遮挡效果,但其性能开销也比陡峭视差贴图高。 Vector Displacement Map(矢量置换贴图)是高度贴图的扩展,与传统Displacement(置换贴图)不同的是矢量置换贴图记录了模型上各点的高度和方向信息,并储存为16/32位浮点颜色信息。 |
|
反射贴图 与颜色贴图中的Diffuse和Base Color一样,反射贴图中根据工作流的不同也有不一样的贴图类型。
|
Metallic(金属贴图)起到类似于蒙版的作用,区分固有色贴图中的金属和绝缘体数据。在金属性贴图中,0(黑色-0 sRGB)表示绝缘体,而1(白-255 sRGB)表示金属。 金属贴图 金属贴图的运行方式类似于掩码的运作方式,因为该贴图向着色器阐释如何分析基础色中的数据。金属感对象的光泽度由粗糙度控制。 材质越粗糙,其光泽度就会越低, 而缺少粗糙度将使金属显得非常有光泽。 Roughness(粗糙度贴图)定义材质得粗糙度信息,0(黑色-0 sRGB)表示光滑,1(白-255 sRGB)表示粗糙。粗粗糙度是指造成光漫射的表面不规则状况,反射方向根据表面粗糙度自由变化。这改变了光的方向,但是光强度保持恒定不变。表面越粗糙,高光越散越暗。表面越光滑,高光反射集中,尽管反射的光的总量是一点的,表面也会更亮,光会更强。 粗糙度贴图采样得来的粗糙度数值会影响一个表面的微平面统计学上的取向度。一个比较粗糙的表面会得到更宽阔更模糊的镜面反射(高光),而一个比较光滑的表面则会得到集中而清晰的镜面反射。 Roughness粗糙度贴图 与Glossiness Map光泽度贴图是相反的。Roughness 反向就变成Glossiness Map 。 |
Specular - Glossiness 高光反射/光泽度工作流 在高光反射/光泽度工作流中,使用的反射贴图为Specular和Glossiness。 Specular(高光贴图)表示高光得范围、强度、颜色,在Specular工作流中,颜色越亮高光越强,黑色表示没有高光。 高光反射规定了金属的反射率值和非金属的F0。使用RGB贴图可以在贴图中创建不同反射率的电介质材质。 高光度也可影响材质的光泽度。 将“高光度(Specular)”值调整到接近1时,将使材质的反射和反射高光显得特别强特别显眼, 而将该值减小到接近0会弱化反射及反射高光,直到它们几乎不存在为止。 高光度(Specular)也深受粗糙度影响。 即使“高光度(Specular)”输入设置为1,通过将“粗糙度(Roughness)”的值设置为1,也可以取消高光度效果。 另外,如果启用了金属感,那么调整高光度不会影响材质。 Glossiness(缩写Gloss,光泽度贴图),定义材质得粗糙度信息,跟Roughness相反,0(黑色-0 sRGB)表示粗糙,1(白-255 sRGB)表示光滑。 光泽度无非是指表面反射光线的能力。 表面能够反射的光线越多,光泽度越高。 表面能够反射的光线越少,光泽度越低。 表面反射光线的能力受环境中各种因素的影响,例如落在对象上的那些非常小颗粒的灰尘,以及接触对象时从手上沾染到对象上的油污, 所有这一切都会影响表面反射光线的能力。 Anisotropic Map(各向异性贴图)是一种特殊的反射贴图。拉丝金属通常具有各向异性的高光,这是由表面的微划痕引起的。有时使用各项异性贴图去制作拉丝金属的效果。 |
|
结构贴图*5 |
Ambient Occlusion Ambient Occlusion(AO,环境光遮蔽贴图)描述了较大尺度的光线遮蔽信息,通常由高模烘培得到。指表面某点能获得多少环境中的光,用来模拟物体之间所产生的阴影,在不打光的时候增加体积感。 |
Cavity Map(缝隙图)描述了比AO图更小尺度的光线遮蔽信息,通常由高模或者法线贴图烘培得到。 缝隙图只包含模型对象表面的凹面区域而不包括凸面区域,因此缝隙图通常大部分都是白色的,只有凹陷区域是深色的。与AO图不同的是,缝隙图影响不仅会影响漫反射,还会影响高光反射部分。 |
|
Bent Normal Map(环境法线贴图)有助于减少照明构建之后发生的漏光现象。 环境法线贴图能够和AO图结合使用以改善漫反射间接照明,通过将环境发现代替法线用于间接照明来使漫反射间接照明更接近于全局光照。 |
|
Curvature(曲率贴图)是存储网格的凸度/凹度的纹理,可用于遮盖表面会出现更多磨损的地方或可能发生次表面散射的地方(凸面),可能积累更多污垢(凹面)的地方,以检查表面的连续性等。 |
|
Thickness(厚度贴图)记录了表面厚度信息,可以用于辅助制作表面散射(SSS,简称3S材质)材质,或直接扩散/反照率假装SSS的效果。 |
|
光照与环境贴图
|
Light Map(光照贴图)用来存储预渲染的光照信息,用于静态模型上的间接光照,解决实时动态光源效果不好且消耗性能的问题。 |
Spherical Environment Map(球面环境贴图)是最简单的反射映射技术之一。球面环境贴图将环境光存储在球面上,然后用环境光去渲染整个的物体。 |
|
Cube Map(立方体贴图)是环境映射的一种实现方法。环境映射可以模拟物体周围的环境,而使用了环境映射的物体可以看起来像镀了层金属一样反射出周围的环境。 |
|
Radiosity Normal Map(辐射度法线贴图)是光贴图和法线贴图的特殊混合。可以将照明作为一组三个光照贴图进行烘焙,以存储照明矢量,而不仅仅是亮度/颜色。这使表面法线贴图可以接收定向照明,因此,通过烘焙的照明信息可以更准确地照明凹凸。 |
|
其他贴图
|
ID/Mask Map(ID、遮罩贴图)用于选择不同的区域,进行分别绘制。 |
Emissive Map(自发光贴图)控制表面发射光的颜色和亮度。当场景中使用了自发光材质时,它看起来像一个可见光。物体将呈现发光效果。 自发光材质通常用于某些部位应该从内部照亮的物体上,例如监视器屏幕、高速制动的汽车盘式制动器、控制面板上的发光按钮,或黑暗中仍然可见的怪物眼睛。简单的自发光材质可以通过一个颜色和亮度来定义。 |
|
Opacity(透明贴图)定义贴图的不透明度,用于裁剪表面的一部分。黑色是透明的部分,白色为不透明的部分,灰色为半透明的部分。 当材质使用不透明度贴图时,它将充当遮罩,该遮罩将隐藏对象的某些部分。例如可以将“不透明度”贴图用于剪切树叶形状,穿孔表面和网格等。 |
|
Position Map(位置贴图)使用R/G/B三个通道描述X/Y/Z轴上顶点对应的位置。 通常位置贴图来实现模型底部到顶部的渐变效果等,如墙壁底部的污渍、石块底部的青苔。 |
|
Detail(细节贴图)是用于平铺的局部贴图纹理,以相对较低的成本,内存和性能来增加表面细节(微观和宏观)。 |
|
Flow Map(流动贴图)存储的是向量场数据,可以用来制作流动的水面效果。 |
|
DuDv贴图是使用一种纹理扭曲另一种纹理的像素的一种简单方法。常用于火上的热雾、涟漪折射的水面等。 DuDv贴图与法线贴图类似,都是将方向信息存储在纹理中,但DuDv贴图仅用到了R通道和G通道。 DuDv的工作方式与视差贴图扭曲曲面的方式类似,只是DuDv不考虑视角(无视差)。从DuDv贴图中获取Du和Dv,对反射贴图中的每个像素,将Du添加到反射贴图的U纹理坐标,并将Dv添加到其V坐标。最后偏移反射贴图像素,从而产生失真。 |
diffuse英[dɪˈfjuːs , dɪˈfjuːz] 美[dɪˈfjuːs , dɪˈfjuːz]adj. 分散的,弥漫的;
albedo英[æl'bɪdəʊ] 美[æl'bɪdoʊ]n. (星体)反照率,主色;
gradient英[ˈgreɪdiənt] 美[ˈɡrediənt]n. [物]梯度,陡度;渐变、逐渐变化;(道路的)倾斜度,坡度
parallax英[ˈpærəlæks] 美[ˈpærəlæks]n. 视差(量),视差角度
metallic英[məˈtælɪk] 美[məˈtælɪk]adj. 金属的;金属性的;金属制的;含金属的
glossiness英['glɒsɪnɪs] 美['glɒsɪnɪs]n. 有光泽的;光泽度
specular英['spekjʊlə] 美['spekjələ]adj. 镜的;镜子似的;高光的;
anisotropic英[ænˌaɪsə'trɒpɪk] 美[ˌænaɪsə'trɒpɪk]adj. 各向异性的
Ambient 英/ˈæmbiənt/美/ˈæmbiənt/adj.环境的,周围的;
occlusion英[ə'klu:ʒn] 美[ə'kluʒn]n. 遮蔽,闭塞,锢囚锋;咬合;堵塞
cavity英[ˈkævəti] 美[ˈkævəti]n. 缝隙,洞,腔;〈牙科〉龋洞
curvature英[ˈkɜːvətʃə(r)] 美[ˈkɜːrvətʃər]n. 弯曲;弯曲部分;曲率;曲度
spherical英[ˈsferɪkl] 美[ˈsfɪrɪkəl, ˈsfɛr-]adj. 球形的,球面的;天体的,天空的
radiosity英['reɪdi:əʊsɪtɪ] 美['reɪdioʊsɪtɪ]n. 发光,辐射度
opacity英[əʊˈpæsəti] 美[oʊˈpæsəti]n. 不透明性;费解;难懂;模糊
opaque英[əʊˈpeɪk] 美[oʊˈpeɪk]adj. 不透明的;无光泽的,晦暗的;
emissive英[ɪ'mɪsɪv] 美[ɪ'mɪsɪv]adj. 发射的,放射性的,发光的;
#pragma target 2.0 //默认值,指定硬件平台Shader Model 2.0 on Direct3D 9;
profile
一个Cg profile定义了一个“被特定图形硬件或API所支持的Cg语言子集”,任意一种shader language都是基于可编程图形硬件的(寄存器、指令集等),这也就意味着:不同的图形硬件和标准库函数;profile还定义了数据类型的精度,并且指定数据类型是否全部或仅部分支持。profile按照功能可以划分为顶点profile和片段profile,而顶点profile和片段profile又基于OpenGL和DirectX的不同版本或扩展,划分为各种版本。从某种意义上而言OpenGL和DirectX的发展历程成就了Cg语言;
Unity内置Shader
Unlit不发光,只取贴图;最简单;一般用于UI;
VertexLit顶点光照,只计算顶点值;
Diffuse漫反射;
Normal mapped法线贴图;
Specular高光;
Normal Mapped Specular高光、法线、贴图;
Parallax Normal mapped 视差法线贴图;
Parallax Normal Mapped Specular 视差高光法线贴图;
ShaderLab基本结构
shader “name”
{
[Properties] 属性块
SubShaders 子块,可以有多个,但只执行一个;越往后的越简单,性能要求越低;
[FallBack] 兜底块,所有SubShader都不行的时候,就用这个兜底的;性能要求最低;
}
Unity Shader分类
surface shaders |
表面着色器,是对vert和frag的一种包装; 不需要写pass通道,可以为我们生成代码; |
vertex and fragment shaders
|
顶点片元着色器 |
fixed function shaders |
固定功能着色器,最简单最快; 只能用ShaderLab编写,不能用Cg或HLSL; ShaderLab语法中,不需要分号; |
表面着色器
Shader name { Properties { _Color(“Color”,Color)=(1,1,1,1) _MainTex(“Albedo (RGB)”,2D)=”white”{} _Glossiness(“Smoothness”,Range(0,1))=0.5 _Metallic(“Metallic”,Range(0,1))=0.0 } SubShader { Tags{“RenderType”=”Opaque”} LOD 200 CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0 sampler2D _MainTex; half _Glossiness; half _Metallic; fixed4 _Color; struct Input{float uv_MainTex;}; void surf (Input IN,inout SurfaceOutputStandard o) { fixed4 c=tex2D(_MainTex,IN.uv_MainTex)*_Color; o.Albedo=c.rgb; o.Metallic=_Metallic; o.Smoothness=_Glossiness; o.Alpha=c.a; } ENDCG } }
|
metallic英[məˈtælɪk] 美[məˈtælɪk]adj. 金属的;金属性的;金属制的;含金属的
albedo英[æl'bɪdəʊ] 美[æl'bɪdoʊ]n. RGB颜色;
smoothness英[smu:ðnəs] 美[ˈsmuðnɪs]n. 平滑;流畅;平静;平稳
glossiness英['glɒsɪnɪs] 美['glɒsɪnɪs]n. 有光泽的;光泽度
Alpha n. 透明(度);
texture英[ˈtekstʃə(r)] 美[ˈtekstʃər]n. 纹理、质地;结构;本质
swizzle英['swɪzl] 美['swɪzəl]n.取出向量中的分量,float4 a=float4(1,1,0,0);float4 b=float4(a.wzyx);float4 c=float4(a.xxxx);
float4 d=float4(a.rgb,b.w);
wrap英[ræp] 美[ræp]v. 重复,平铺重复
流程控制:支持if else,不支持switch case;
循环控制:支持while,do while,for;
函数:要在使用之前进行定义;如果非要在使用后定义,那么必须在使用前进行声明(同C++);如果在使用前定义,可以省略声明;
函数声明时,不仅要指定形参类型,同时要指定形参名称;void Func(float4 f4);Cg参数总是通过值传递方式(值拷贝);
Cg内置函数:数学函数、稽核函数、纹理函数、导数函数;
Sampler采样器:
_MainTex(“MainTex”,2D)=””{ }
sampler2D _MainTex;
float2 uv=float2(0.5f,0.5f);
fixed4 color=tex2D(_MainTex,uv);
tex2D返回值:float4,采样所得到的颜色;
参数1:(2D→sampler2D)采样源图片,从哪个图片上采样;
参数2:float2,贴图的UV坐标值,采样位置,从图片上的哪个位置采样;
TEXCOORD=纹理坐标=texture coordinate=UV坐标;
平铺和偏移tiling offset
float _MainTex_ST; S=scale缩放; T=transmit平移; |
S |
float tiling_x; float tiling_y; |
T |
float offset_x; float offset_y; |
Cg支持类型定义#typedef,支持宏#define;
#define TRANSFORM_TEX(tex,name)(tex.xy*name##_ST.xy+name##_ST.zw)
#define TRANSFORM_UV(idx) v.texcoord.xy
光照贴图,没有环境光源的情况下,也能正常显示;
Cg语言数据类型
浮点型 |
float:32位浮点数;half:16位浮点数;fixed:12位浮点数;0.5f,0.5h,0.5x; float4,float3,float2,float1,其中float1等价于float; half4,half3,half2,half1,其中half1等价于half; fixed4,fixed3,fixed2,fixed1,其中fixed1等价于fixed; |
整形 |
Int:32位整形数据,int4,int3,int2,int1,其中int1等价于int; |
布尔 |
bool; 0为假,非0为真;bool4,bool3,bool2,bool1,其中bool1等价于bool; bool b1=true;bool b2=false; |
采样器 |
Sampler:sampler1D,sampler2D,sampler3D,samplerCUBE和samplerRECT |
向量 |
向量:一共拥有4种长度的向量,1 - 4之间,不得小于1不得大于4; 例如:float3 a; half4 h; fixed2 m; int1 d; 向量初始化或赋值:float4 a = float4(1,2,3,4); float3 b; b = float3(0,2,3); 注意:对于向量的赋值和初始化,我们必须保证值向量的纬度一定要和变量向 float1等价于float,half1等价于half,fixed1等价于fixed; |
矩阵 |
矩阵:矩阵的行和列的长度不得小于1,不得大于4; 例如: float2x4 a;// 表示这是一个2行4列的矩阵; half3x3 m;// 表示是一个3 X 3的方阵; 矩阵赋值和初始化 float2x2 rtX = {sin@, 0, 0, cos@};// 注意,矩阵在赋值的时候一定要人为的分开行与行之间的关系,但是程序只认识顺序的赋值; 注意:CG中向量,矩阵和数组是完全不同的,向量和矩阵是内置的数据类型,而数组则是一种数据结构,不是内置数据类型。 |
数组 |
因为Cg是显卡操作语言,他没有相应的内存,所以对于Cg语言来讲就不可能存在空间申请,那么Cg的数组就必须在定义的时候指定大小,除非数组出现在函数的行参当中,我们可以不指定数组大小; 一维数组: 类型(数据类型,向量,矩阵类型) 数组名[数组的个数]; 二维数组: 类型(数据类型,向量,矩阵类型) 数组名[数组的行数][数组的列数]; 数组的赋值:float a[2] = {1, 2}; float a[2][2] = PW_1,2}, {3, 4; 一维数组的赋值一定要和矩阵分开,他们不是同一种关系; 数组可以获取长度;float2 b[2];int arrayLen = b.length; // 结果2 float m[3][4];arrayLen = m.length;// 结果是3; arrayLen = m[1].length;// 结果是4; |
结构体 |
结构体是一种自定义数据类型,他可以把所有的数据类型进行集合式的包装,起到了数据封装的作用; 结构体中可以定义任意类型的变量,变量在定义的时候可以同时初始化。与高级语言不通,Cg没有修饰词,所以struct中的所有变量和函数都是公共的; struct appdata_full { float normal:NORMAL; }; |
CG表达式与控制语句 |
关系操作符:<,>,<=,>=,!=,==;if(logocolor.a == 0) 逻辑操作符:&&,||,!;数学操作符:+,—,*,/,% 移位操作符:>>; Swizzle操作符:float a=1.0,float4 b = a.xxxx;这种用法我们有时候会用到 控制流语句:if ,if-else,while ,for,break; |
点操作符 |
点操作符只能针对Cg的:向量和结构体;向量点操作: 对于向量他可以按照坐标顺序和色彩顺序访问向量中的每个元素: xyzw, rgba; 注意:他和向量的维度有关,绝对不能超过向量的维度进行访问; float2 a = float2(1,2); float3 b = a.xyx; float4 m = a.yyyy; float3 m1 = a.xyz;// 这是错误的!因为超出了维度的访问范围; 结构的点操作:v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);和普通编译语言是一样的; |
行参修饰词 |
行参修饰词: in: 表示当前行参是只能输入的; out:表示当前行参用来输出数据的; inout: 表示可以进行输入和输出; |
语义 |
为了表达当前变量是指定的数据范围,我们提出语义的概念。语义可以作为输入也可以作为输出。语义的定义只能存在于入口函数的行参和返回值上。 常用的语义: POSITION : 表示当前这个变量表示的是坐标,我们需要使用float4向量来作为变量的类型; COLOR: 表示当前这个变量是颜色表示,我们需要使用float4/ half4 / fixed4 来表示颜色信息; NORMAL: 表示当前这个变量是法线坐标,因为法线描述的是一个点的特性,所以他没有坐标系关系,那么我们就可以使用float3向量; TEXCOORD0 – TEXCOORD7: 这样的语义可以表示任意的数据类型,但是我们经常使用 TEXCOORD0来表示贴图UV坐标用float4向量; TANGENT:表示顶点角的正切值,用float3传递; 语义的输入性和输出性,需要和行参中的修饰词结合表示,in 表示当前语义是输入,out 表示当前语义是输出型的,inout表示支持输入和输出; 语义的写法: (1) 作为行参来实现: [in|out|inout] <数据类型> <行参名> [: <语义词>] (2) 作为返回值来实现: <返回值类型不能是void> <入口函数名>([行参列表]) [: <语义词>] {} (3) 作为结构体来实现: float3 worldLightDir:TEXCOORD1; |
入口函数 |
Cg语言的入口函数: 因为Cg语言是一种特殊的显卡语言,他需要同时处理显卡的两个工作部分,一个是点的位置描述,另外一个是点的颜色值描述。所以Cg语言有两个入口函数,他们分别是:顶点程序、片段/片装源/像素程序; 其它的函数我们称为内部函数。 注意:Cg的入口函数没有特定的函数面,我们都是后期自己制定出来的,所以如果我们想让某个函数成为入口函数就一定要通知引擎这个函数的名字; 入口函数的特性: (1)顶点入口函数:顶点入口函数是唯一可以和引擎沟通的函数,所以语义数据的传入都需要在顶点入口函数中完成。顶点入口函数必须履行向光栅硬件传递变换后的坐标,所以顶点入口函数必须有一个返回型的语义,而且必须是POSITION类型的语义。同时他可以向我们片段入口函数传递响应的数据。 (2)片段入口函数:片段程序的主要责任是给当前这个像素点设定颜色的,所以我们需要在片段程序中返回一个颜色语义,类型必须是COLOR,而且只能向外输出COLOR,因为他是最后一道程序,所以其他的语义抛出是无任何意义的。入口函数中传回来 POSITION, NORMAL, TANGENT等语义,片段程序不能读也不能写,对于COLOR0 – COLOR1 和 TEXCOORD0 – TEXCOORD7这样的语义片段程序可以读写; 三、 |
ShaderLab+Cg |
Unity3D引擎中ShaderLab语言与Cg的结合 因为Cg属于可编程着色器程序,所以在SubShader必须用Pass过程块; 在着色器中,我们需要两个特定的命令夹住Cg语言,这样ShaderLab才认识你的Cg代码: CGPROGRAM。。。ENDCG 因为Cg语言的入口函数没有特定名称,所以我们需要通知ShaderLab哪两个入口函数是我们的顶点和片段的入口函数。我们需要借助以下命令: // 顶点入口函数的设定 pragma vertex 入口函数名 // 片段入口函数的设定 pragma fragment 入口函数名 注意:可编程着色器只要写了入口函数就一定要按照同样的名字来实现入口函数; Cg语言也支持对于第三方的代码调用,如果需要调用第三方的代码,我们需要使用: #include “需要包含的代码文件.cginc” 这样的关键字; 对于Unity引擎,他为我们提供了两个cginc文件,方便了我们与引擎的沟通; UnityCG.cginc :当前文件提供了Unity引擎中大部分的位置坐标和方向的内容; Lighting.cginc:当前文件提供了Unity引擎中灯光的操作; 当我们Cg需要使用我们ShaderLab语言的属性时,我们必须借助 uniform这个关键字。需要注意,uniform变量的名字必须和我们属性的名字一模一样; 对于Cg语言来说,如果我们直接定义uniform变量,而不在我们的ShaderLab属性列表中定义,那么我们的Unity引擎同样也可以向这个变量传递数据。但是这个变量在我们的Inspector面中无法显示出来; 1.从应用程序传递到GPU的数据,分为图元信息数据(在GPU处理的基本数据如顶点位置信息等)和其他的离散数据(在GPU运行流程中不会发生变化,如材质对光的反射、折射信息),这两种输入数据如何区分? Cg 语言提供了一组语义词,用以表明参数是由顶点的哪些数据初始化的,Uniform 修辞一个参数,表示该参数的值由外部应用程序初始化并传入 2.从应用程序传递到GPU中的图元信息如何区分类型,即,顶点程序怎么知道一个数据是位置数据,而不是法向量数据? 语义词,表示输入图元的数据含义(是位置信息,还是法向量信息),也表明这些图元数据存放的硬件资源(寄存器或者纹理缓冲区)。顶点着色程序和片段着色程序中 Varying inputs 类型的输入,必须和一个语义词相绑定 3.顶点着色程序与片段着色程序之间的数据传递如何进行? 根据输入语义,图形处理器从某个寄存器取数据;然后再将处理好的数据,根据输出语义,放到指定的寄存器,语义,是两个处理阶段(顶点程序、片段程序)之间的输入\ 输出数据和寄存器之间的桥梁,同时语义通常也表示数据的含义,POSITION 一般表示参数种存放的数据是顶点位置 |
三大 Shader 编程语言(CG/HLSL/GLSL)
Shader Language的发展方向是设计出在便携性方面可以和C++、Java等相比的高级语言,“赋予程序员灵活而方便的编程方式”,并“尽可能的控制渲染过程”同时“利用图形硬件的并行性,提高算法效率”。
Shader Language目前主要有3种语言:
- 基于 OpenGL 的 OpenGL Shading Language,简称 GLSL;
- 基于 DirectX 的 High Level Shading Language,简称 HLSL;
- 还有 NVIDIA 公司的 C for Graphic,简称 Cg 语言。
Shader定义,Shader中文翻译为着色器,是一种较为短小的程序片段,用于告诉图形硬件如何计算和输出图像,过去由汇编语言来编写,现在也可以使用高级语言来编写。一句话,Shader是可编程图形管线的算法片段;Shader主要分为两类,Vertex Shader和Fragment Shader;
Shader、材质、贴图的关系
Shader(着色器)实际上就是一小段程序,它负责将输入的顶点数据以指定的方式和输入的贴图或者颜色等组合起来,然后输出。绘图单元可以依据这个输出来将图像绘制到屏幕上。
输入的贴图或者颜色等,加上对应的Shader,以及对Shader的特定参数设置,将这些内容打包存储在一起,得到的就是一个材质(Material);之后,可以将材质赋值给三维物体进行渲染(输出)了;
材质好比最终商品,Shader好比生产商品的方法,贴图好比原材料;
Shader是渲染管线中可编程的程序片段;
渲染管线是生成计算机图像的程序;
材质是商品、Shader是方法,贴图是材料;
材质>着色器>纹理/贴图
使用透明的3要点:
1、用上#pragma xxx alpha:打开alpha混合;
2、alpha 值要合理设置,0表示完全透明(消失不见),1表示完全不透明;
3、一定让透明的物体在不透明物体后⾯面渲染Tags { "Queue" = "Transparent" }
贴图分类:二维贴图、立方体贴图、视频贴图、渲染贴图、程序贴图;
cube map=reflection map=立方体贴图=反射贴图,用于制作反射周围环境的效果;
normal map 法线贴图,不增加模型复杂度的情况下,增加模型立体效果;
Cull/culling 英/kʌl/美/kʌl/v.裁剪、消除、剔除;Cull Back,Cull Front;
backface culling 隐面消除、背面剔除、背面消隐;
blend/blending英[blend] 美[blend]v. (使)混合;融合;
texture英[ˈtekstʃə(r)] 美[ˈtekstʃər]n.纹理;质地;MainTex 主纹理;
specular英['spekjʊlə] 美['spekjələ]adj. 镜的;镜子似的;
tint英[tɪnt] 美[tɪnt]n. 色彩,色泽;MainTint 主色调;
incident light[光] 入射光;incident 英/ˈɪnsɪdənt/美/ˈɪnsɪdənt/adj.入射的;
bump 英[bʌmp]美[bʌmp]n. 凸块; 肿块(常因击打所致); 隆起;bump map凹凸图;
Albedo颜色RGB通道;Alpha透明度通道α;
四种常见光照模型
Lambert Lighting——兰伯特光照模型
Half-Lambert Lighting—半兰伯特光照模型
Phong Lighting——冯氏光照模型
- Blinn-Phong Lighting——布林-冯光照模型
- Shader是Material的一部分;
同一个Shader可以用于多个Material;
CG、HLSL:CGPROGRAM 和 ENDCG
GLSL:GLSLPROGRAM 和 ENDGLSL
语言 |
公司 |
全称 |
其他-Unity首选Cg |
Cg |
NVIDIA |
C for Graphics |
Cg运行在GLSL、HLSL之上; |
GLSL |
OpenGL |
OpenGL Shading Language |
跨平台 |
HLSL |
微软 |
High Level Shader Language |
Direct X,基于C++,只支持微软平台 |
Cg语言(C for Graphics)是为GPU编程设计的高级着色器语言,由NVIDIA公司开发。Cg极力保留C语言的大部分语义,并让开发者从硬件细节中解脱出来,Cg同时也有一个高级语言的其他好处,如代码的易重用性,可读性得到提高,编译器代码优化。最新版本为3.1,当前已不再被积极开发与支持.
GLSL OpenGL着色语言(OpenGL Shading Language)是用来在OpenGL中着色编程的语言,也即开发人员写的短小的自定义程序,他们是在图形卡的GPU (Graphic Processor Unit图形处理单元)上执行的,代替了固定的渲染管线的一部分,使渲染管线中不同层次具有可编程性。
GLSL的代码文件一般包括顶点着色器程序(.vert)和片元着色器程序(.frag)。
HLSL高阶着色器语言(High Level Shader Language,简称HLSL),由微软拥有及开发的一种语言,HLSL 独立的工作在 Windows 平台上,只能供微软的Direct3D使用。
soft vegetation 松软植被
Emission 自发光
Shiness 高光反射
Diffuse 漫反射
Specular 镜面光
Ambient 环境光
fallback英[ˈfɔːlbæk]美[ˈfɔːlbæk]n. 应变计划; 退路;
Bump Map(凹凸贴图)(凹凸映射)
Fresnel美 [frəˈnɛl]英 [freiˈnel] 菲涅耳;菲涅尔;
在光学里,菲涅耳数(Fresnel number)是一个时常出现于衍射理论的无量纲量。菲涅耳数是因法国物理学者奥古斯丁·菲涅耳而命名。
Fresnel英[freiˈnel] 美[freˈnɛl]菲涅耳(Augustin Jean,1788-1827,法国物理学家)
这种随着距离变化而产生的反射效果/清晰度的变化,就是菲涅尔。
入射角有两个重要的特性:
1、 随着观察距离的变化而变化:距离越近,入射角越大;距离越远,入射角越小;
2、 入射角大小影响反射效果:入射角越大,反射效果越弱;入射角越小,反射效果越强。
- 湖边人在观察塔尖的倒影时,入射角更大,所以反射效果更弱;
- 湖边人在观察塔底的倒影时,入射角更小,所以反射效果更强;
反射效果越弱,水体看起来越透明,像空气;
反射效果越强,水体看起来越光滑,像镜子。
- 塔尖反射效果弱→塔尖的倒影看起来不清晰,甚至看不到倒影;
- 塔底反射效果强→塔底的倒影像镜子一般清晰。
HDR高动态范围成像(英语:High Dynamic Range Imaging,简称HDRI或HDR),在计算机图形学与电影摄影术中,是用来实现比普通数位图像技术更大曝光动态范围(即更大的明暗差别)的一组技术。高动态范围成像的目的就是要正确地表示真实世界中从太阳光直射到最暗的阴影这样大的范围亮度。
纹理Texture、材质Material、着色器Shader
mesh英[meʃ] 美[mɛʃ]n. 网孔,网眼,网状物;
albedo 美[æl'bɪdoʊ] 英[æl'bɪdəʊ]就是颜色RGB,但不包含A通道;
OpenGL(英语:Open Graphics Library,译名:开放图形库或者“开放式图形库”)是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)。这个接口由近350个不同的函数调用组成,用来绘制从简单的图形到比较复杂的三维景象。而另一种程序接口系统是仅用于Microsoft Windows上的Direct3D。OpenGL常用于CAD、虚拟现实、科学可视化程序和电子游戏开发。
Cg语言(C for Graphics)是为GPU编程设计的高级着色器语言,由NVIDIA公司开发。Cg极力保留C语言的大部分语义,并让开发者从硬件细节中解脱出来,Cg同时也有一个高级语言的其他好处,如代码的易重用性,可读性得到提高,编译器代码优化。