unity multithreadedunity rendering modepath要不要开启

扫一扫,访问微社区
后使用快捷导航没有帐号?
签到成功!您今天第{todayrank}个签到,签到排名竞争激烈,记得每天都来签到哦!已连续签到:{constant}天,累计签到:{days}天
关注:1917
当前位置: &
__________________________________________________________________________________
开发者干货区版块规则:
  1、文章必须是图文形式。(至少2幅图)
& && &2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
& && &3、本版块只支持在游戏蛮牛原创首发,不支持转载。
& && &4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
& && &5、......
__________________________________________________________________________________
查看: 905|回复: 2
Thinking in Unity3D:渲染管线中的Rendering Path
9排名<font color="#FF昨日变化10主题帖子积分
在线时间10 小时
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
才可以下载或查看,没有帐号?
本帖最后由 麒麟子 于
20:09 编辑
[img][/img]
关于《Thinking in 》
笔者在研究和使用Unity3D的过程中,获得了一些Unity3D方面的信息,同时也感叹Unity3D设计之精妙。不得不说,笔者最近几年的引擎研发工作中,早已习惯性的从Unity3D中寻找解决方案。
Unity3D虽比不上UE那么老练沉稳,气势磅礴。也比不上CE那样炫丽多姿,盛气凌人。但它的发展势如破竹,早已遍地生花!故而在此记录一些自己的心得体会,供大家参详交流。若有欠妥之处,还望各位及时指正。
Thinking in Unity3D由一系列文章组成,文章列表地址:/geniusalex/p/5321545.html
Unity3D发展至今,已经是5.x版本了。对于一个引擎迭代来说,特性、效果、效率的提升,无不波及到渲染管线的改动。而与渲染管线最为紧密挂钩的就是材质系统和渲染流程,但由于材质系统和渲染流程涉及的范围和内容更广。我们将用单独的篇幅来描述。本文主要目标是渲染管线中的Rendering Path。
由于历史发展,以及各种平台、机型、版本兼容的原因。Unity3D中,目前保存了4种Rending Path.
1、Deferred Shading Rendering Path(延迟渲染)
2、Forward Rendering Path(前向渲染)
3、Lagacy Deferred Lighting Rendering Path(延迟光照)
4、Vertex Lit Rendering Path(顶点光照)
Forward Rendering Path(前向渲染)
官方文档:http://docs..com/Manual/RenderTech-ForwardRendering.html
传统的前向着色渲染方式是一种简单粗暴的方式。就是一次性将一个物体绘制完再绘制下一个。光照计算也是如此。前向着色最主要的就是光照问题。当光源过多的时候,就需要进行处理。 而Unity3D在光源处理方面,也结合了像素光照(per-pixel lighting) ,顶点光照(per-vertex lighting),球谐光照(Spherical Harmonics lighting)等多种方案,其复杂程度可见一斑。
Unity3D中前向渲染的光源策略
前向着色渲染由于效率和寄存器限制等原因。不可能老老实实地去处理所有的光源。因此,需要根据光源的远近,范围,重要程度等因子决定计算方式。
1、如果一个光源的RenderMode没有设置为重要(Important),那么它将永远是逐顶点或者球谐光照计算方式。
2、最亮的(Brightest)方向光源会做为逐像素光照计算。
3、如果一个光源的RenderMode设置为重要(Important),那么它将会采用逐像素光照计算方式
4、如果上面的结果中的用于逐像素计算的光源数目小于了Project Settings-&Quality面板中的Pixel Light Count值。 为了减少亮度误差,有一些光源会被当作像素光源计算(PS:非像素光源无法完全计算阴影关系。会导致场景偏亮)。
5、Unity3D对顶点光照,像素光照做了最大限制。 分别为4个。而场景中不可能只有这么多光源。因此,使用了一个优先级判定。
[img][/img]
左:光源位置图 右:光源分配图
从图中我们可以看到。 D参与了像素和顶点光照。 G参与了顶点光照和球谐光照。 这样的处理应该是为了做一个光照信息的平滑衔接,不至于变得很突兀。
Unity3D中前向渲染的光照的计算过程
前向渲染中,光照计算被分成了多个PASS。通常它们由1*FarwardBase Pass + N*FarwardAdd Pass组成。可以看出,光源的数目在前向渲染管线中是一个致命的效率杀手。
1、Base Pass 提交一个逐像素方向光和所有的逐顶点光照和球谐光照。
2、Additional Pass 提交一个逐像素的光照计算。 如果一个物体受更多的光源影响。那么就会有许多PASS需要进行绘制。
注:在Shader中。可以指定FarwardBase来关掉Additional 功能。
注:在前向渲染中,只能有一个方向光实时阴影。
Unity3D中的球谐光照
球谐光照是一个CPU光照算法。它可以处理大规模的光源信息,非常适合一些很小的动态点光源。但是它存在以下几个问题。
1、球谐光照是基于物体顶点的算法,并非像素级。这就意味着它不能使用一些像素级的效果增强手段。比如法线贴图。
2、基于效率的考虑,球谐光照的更新频率非常低。如果光源移动过快,就会穿邦。
3、球谐光照是基于全局空间的计算,当一个面离点光源或者聚光灯很近时,效果是错的。
Deferred Shading Rendering Path(延迟渲染)
官方文档:/Manual/RenderTech-DeferredShading.html
延迟渲染技术简介
延迟渲染技术已经是一个成熟且稳定的技术。已经广泛用于各种商业引擎中。它主要解决的是当光源数目过多时带来的复杂光照计算的开销。 在传统前向渲染中,假设一个场景中有M个物体,N个光源。 那么理论上进行的光照计算次数为 M*N。 而DS管线可以使其变为M+N。
但是DS管线并非万能的。有以下情况需要注意
延迟渲染技术缺陷
1、DS需要多渲染目标(MRT)的支持、深度纹理、双面模板缓存。
& &&&这个特性,需要显卡支持SM3.0的API。2006年以后的PC显卡应该不成问题。比如GeForce 8xxxx,AMD Radeon X2400,Intel G45以后的显卡。
2、DS管线会消耗更多的显存,用于缓存G-Buffer。同时,会要求显卡拥有更大的位宽(bit counts)。
& &&&在手机上目前(2016年)还不实现。
3、DS管线无法处理半透明物体。
& &&&半透明物体需要退回到传统前向渲染中进行
4、硬件抗锯齿(MSAA)无法使用。
& &&&只能使用一些后期算法,如FXAA等。
5、这句话中的内容目前未测试,故无法准确体会其中的意思:There is also no support for the Mesh Renderer’s Receive Shadows flag and culling masks are only supported in a limited way. You can only use up to four culling masks. That is, your culling layer mask must at least contain all layers minus four arbitrary layers, so 28 of the 32 layers must be set. Otherwise you will get graphical artefacts.
延迟渲染技术在Unity3D中的实现方案
Unity3D中,延迟渲染管线为分两个阶段进行。G-Buffer阶段和光照计算(Lighting)阶段。
G-Buffer阶段
Unity3D渲染所有的非透明对象到各个RT中,RT的内容分布见 G-Buffer内容。Unity3D将各个RT做成了全局变量,方面Shader中进行操作。像这样:CameraGBufferTexture0 .. CameraGBufferTexture3
光照计算阶段
这个阶段的主要目的就是根据G-Buffer的内容进行光照计算。由于是屏幕空间的计算,显然要比之前的前向渲染来得容易得多。
注:实时阴影的计算是在光照计算之前的。 DS管线并不能减少实时阴影的开销。应该怎么整还得怎么整。最后,每个物体受到的实时阴影的影响会叠加到RT3中。一些特殊的爆光效果,Lightmap光影贴图效果等都会进入RT3。 参见G-Buffer内容
G-Buffer内容
oRT0, ARGB32 format: Diffuse color (RGB), occlusion (A).
oRT1, ARGB32 format: Specular color (RGB), roughness (A).
oRT2, ARGB2101010 format: World space normal (RGB), unused (A).
oRT3, ARGB2101010 (non-HDR) or ARGBHalf (HDR) format: Emission + lighting + lightmaps + reflection probes buffer.
oDepth+Stencil buffer.
注:为了减少显存和渲染开销。当前场景的摄像机开启了HDR模式时,RT3将不会被创建。而是直接使用摄像机的HDR RT。
自定义DS管线
Unity3D中,标准的DS管线是Standard系列。如果你想修改某一个部分。你可以新建一个自己的Shader。然后替换掉默认的即可。
替换的位置在Edit-&Project Settings-&Graphics面板中。把Deferred属性下拉框变成Custom,就可以进行替换操作了。
[img][/img]
Lagacy Deferred Lighting Rendering Path(延迟光照)
官方文档:/Manual/RenderTech-DeferredLighting.html
技术文章:/blog/deferred-lighting-approaches/
注:从5.0开始,DL渲染已经不被Unity3D推荐,Unity3D更推荐大家新项目使用DS管线方式。因为DL方式不好实现基于PBR着色的Standard材质,以及场景反射。
注:如果摄像机设置为了正交投影。会强制退回前向渲染
注:DL也不会降低实时阴影的开销
和DS渲染管线一样,DL的出现同样是为了解决光照计算的复杂度问题。然后不同的是,DL仅仅把光照计算拿出去了。简单说来,DL管线工作流程如下。
步骤一、渲染场景中的对象,输出光照计算需要的RT(深度、法线、高光信息)
步骤二、使用上面的RT进行光照计算
步骤三、再次渲染场景中的对象,并与计算机来的光照信息结合。
不难看出,DL相比DS而言,不需要大量的G-Buffer支持。甚至不需要MRT的支持。但是对深度图的要求是必须的。如果遇上无法访问深度BUFFER的情况。那就需要做一次Pre-Depth Pass渲染。
比起DS而言,DL由于不需要MRT的支持。在硬件特性需求和位宽上,少了许多开销。
2、PC:GeForce FX、Radeon X1300、Intel 965 / GMA X3100
3、Mobile:所有支持OpenGL ES 3.0的设备,部分支持OpenGL ES 2.0的设备。
Vertex Lit Rendering Path(顶点光照)
官方文档:/Manual/RenderTech-VertexLit.html
注:这不是一个通用的技术名词,只有Unity3D中有。
注:主机平台这个不顶用。
注:不支持实时阴影和高精度高光计算。
Vertex Lit Rendering就是指,所有的光照计算都通过顶点进行。而在Unity3D中,它的主要目的是为了支持那些没有可编程管线的设备。VL也提供了几种方法,用于支持不同的材质类型。
1、Vertex 使用Blinn-Phong进行光照处理,针对没有lightmap的对象使用。
2、VertexLMRGBM 针对lightmap贴图使用RGBM加密(PC和主机平台)的对象, 没有额外的光照计算。
3、VertexLMM 针对lightmap贴图使用double-LDR加密(移动平台)的对象,没有额外的光照计算。
Unity3D对几种渲染管线的统一处理
在上面我描述中,我们发现,不管哪一种管线。都会涉及到几个部分。 1、光照计算 2、透明渲染 3、阴影计算 4、图像输出。 那Unity3D又是如何对这些进行统一流程控制的呢。我们看下面的图就明白了。
[img][/img]
从图中我们可以看到。Unity3D的传统渲染管线和延迟渲染管线,在非透明物体渲染和光照阶段是分离的。当处理完以后,紧接着处理非透明图像效果-&天空盒-&透明物体渲染-&后期效果。
总的来说,Unity3D的渲染管线还算稳定和易用,其的渲染管线包含了常见的三种方案。最主要目的还是在想着光照计算和效果显示的处理。同时保持对上层透明。其Graphics Commander Buffer提供了扩展管线的能力。而Graphics设置面板里,也提供了自定义延迟管线Shader的功能。然而也有诸多的美中不足,比如,正交摄像机模式下,不能使用延迟渲染技术。 延迟光照下无法实现PBR和实时环境反射抽取等等。
/Manual/SL-RenderPipeline.html/Manual/RenderingPaths.html/Manual/GraphicsCommandBuffers.html
蛮牛币 +50
每日推荐:
71704/5000排名<font color="#FF昨日变化1主题帖子积分
日久生情, 积分 1704, 距离下一级还需 3296 积分
日久生情, 积分 1704, 距离下一级还需 3296 积分
在线时间499 小时
每日推荐:
61258/1500排名<font color="#FF昨日变化1主题帖子积分
蛮牛粉丝, 积分 1258, 距离下一级还需 242 积分
蛮牛粉丝, 积分 1258, 距离下一级还需 242 积分
蛮牛币2698
在线时间330 小时
学习。MARK
每日推荐:
游戏蛮牛给予质量较高、影响力较大的unity相关技术开发者的荣誉称号
经过游戏蛮牛认证的蛮牛小翻译
Facebook相关行业专家现场解析国外游戏市场现状及开发者游戏出海大方向。1.先来一段单张纹理贴图的shader示例代码:
1 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
3 Shader "Custom/MyShader"{
4 Properties{
//外部可调属性
_MainTex ("Main Tex", 2D) = "white" {}
8 SubShader
<span style="color: #
//设置使用本Subshader所需要满足的渲染路径等参数,如果满足,即使用本shader
<span style="color: #
Tags {"Queue"="Transparent""RenderType"="Transparent"}
<span style="color: #
<span style="color: #
<span style="color: #
//设置该pass 的渲染状态和标签
<span style="color: #
Tags { "LightMode"="ForwardBase" }
<span style="color: #
//开始cg代码片段
<span style="color: #
<span style="color: #
//该代码的编译指令,
<span style="color: #
#pragma vertex vert//设置顶点着色器的函数名称
<span style="color: #
#pragma fragment frag//设置片段着色器的函数名称
<span style="color: #
#include "Lighting.cginc"//包含库文件
<span style="color: #
<span style="color: #
struct a2v {
<span style="color: #
float4 vertex : POSITION;//当前要渲染的顶点坐标
<span style="color: #
float4 texcoord : TEXCOORD0;//当前要渲染的顶点的第一套纹理坐标
<span style="color: #
<span style="color: #
<span style="color: #
struct v2f {
<span style="color: #
float4 pos : SV_POSITION;//
<span style="color: #
float2 uv : TEXCOORD0;
<span style="color: #
<span style="color: #
sampler2D _MainT
<span style="color: #
float4 _MainTex_ST;
<span style="color: #
<span style="color: #
v2f vert(a2v v)
<span style="color: #
<span style="color: #
<span style="color: #
o.pos=UnityObjectToClipPos(v.vertex);//将顶点坐标变换到裁剪空间中
<span style="color: #
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);//变换uv坐标
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
fixed4 frag(v2f i):SV_Target
<span style="color: #
<span style="color: #
fixed4 c = tex2D (_MainTex, i.uv);//对纹理坐标进行采样
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
//SubShader
<span style="color: #
<span style="color: #
//如果不满足第一个subshader所需要的条件,那么再来检测是否满足第二subshader 的条件。
<span style="color: #
<span style="color: #
<span style="color: # FallBack "Diffuse"
<span style="color: # }
MyShader.shader
Shader "ShaderLab Tutorials/TestShader" {
一个Shader有多个SubShader。一个SubShader可理解为一个Shader的一个渲染方案。即SubShader是为了针对不同的渲染情况而编写的。每个Shader至少1个SubShader、理论可以无限多个,但往往两三个就足够。一个时刻只会选取一个SubShader进行渲染,具体SubShader的选取规则包括:
从上到下选取
SubShader的标签、Pass的标签
是否符合当前的“Unity渲染路径”
是否符合当前的ReplacementTag
SubShader是否和当前的GPU兼容
按此规则第一个被选取的SubShader将会用于渲染,未被选取的SubShader在这次渲染将被忽略。
SubShader的Tag
Shader "ShaderLab Tutorials/TestShader" {
Tags { "Queue"="Geometry+10" "RenderType"="Opaque" }
shader内部可以有标签(Tags)的定义。Tag指定了这个SubShader的渲染顺序(时机),以及其他的一些设置。
"RenderType"标签。Unity可以运行时替换符合特定RenderType的所有Shader。或配合使用。Unity内置的RenderType包括:
"Opaque":绝大部分不透明的物体都使用这个;
"Transparent":绝大部分透明的物体、包括粒子特效都使用这个;
"Background":天空盒都使用这个;
"Overlay":GUI、镜头光晕都使用这个;
用户也可以定义任意自己的RenderType这个标签所取的值。
应注意,或不要求标签只能是RenderType,RenderType只是Unity内部用于Replace的一个标签而已,你也可以自定义自己全新的标签用于Replace。比如,你为自己的ShaderA.SubShaderA1(会被Unity选取到的SubShader,常为Shader文件中的第一个SubShader)增加Tag为"Distort"="On",然后将"Distort"作为参数replacementTag传给函数。此时,作为replacementShader实参的ShaderB.SubShaderB1中若有也有一模一样的"Distort"="On",则此SubShaderB1将代替SubShaderA1用于本次渲染。
具体可参考
"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里。
Shader "ShaderLab Tutorials/TestShader" {
SubShader {
一个SubShader(渲染方案)是由一个个Pass块来执行的。每个Pass都会消耗对应的一个DrawCall。在满足渲染效果的情况下尽可能地减少Pass的数量。
Shader "ShaderLab Tutorials/TestShader" {
SubShader {
Tags{ "LightMode"="ForwardBase" }
shader有自己专属的Tag类似,Pass也有Pass专属的Tag。
其中最重要Tag是 "LightMode",指定Pass和Unity的哪一种渲染路径(“Rendering Path”)搭配使用。除最重要的ForwardBase、ForwardAdd外,这里需额外提醒的Tag取值可包括:
Always,永远都渲染,但不处理光照
ShadowCaster,用于渲染产生阴影的物体
ShadowCollector,用于收集物体阴影到屏幕坐标Buff里。
其他渲染路径相关的Tag详见下面章节“Unity渲染路径种类”。具体所有Tag取值,可参考。
Shader "ShaderLab Tutorials/TestShader"{
SubShader { Pass {} }
FallBack "Diffuse" // "Diffuse"即Unity预制的固有Shader
// FallBack Off //将关闭FallBack
当本Shader的所有SubShader都不支持当前显卡,就会使用FallBack语句指定的另一个Shader。FallBack最好指定Unity自己预制的Shader实现,因其一般能够在当前所有显卡运行。
Properties
1 Shader "ShaderLab Tutorials/TestShader"
Properties {
_Range ("My Range", Range (<span style="color: #.02,<span style="color: #.15)) = <span style="color: #.07 // sliders
_Color ("My Color", Color) = (.<span style="color: #, .<span style="color: #, .<span style="color: #, <span style="color: #) // color
_2D ("My Texture 2D", 2D) = "" {} // textures
_Rect("My Rectangle", Rect) = "name" { }
_Cube ("My Cubemap", Cube) = "name" { }
_Float ("My Float", Float) = <span style="color: #
<span style="color: #
_Vector ("My Vector", Vector) = (<span style="color: #,<span style="color: #,<span style="color: #,<span style="color: #)
<span style="color: #
<span style="color: #
// Display as a toggle.
<span style="color: #
[Toggle] _Invert ("Invert color?", Float) = <span style="color: #
<span style="color: #
// Blend mode values
<span style="color: #
[Enum(UnityEngine.Rendering.BlendMode)] _Blend ("Blend mode", Float) = <span style="color: #
<span style="color: #
//setup corresponding shader keywords.
<span style="color: #
[KeywordEnum(Off, On)] _UseSpecular ("Use Specular",
Float) = <span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
SubShader{
<span style="color: #
<span style="color: #
<span style="color: #
uniform float4 _C
<span style="color: #
<span style="color: #
float4 frag() : COLOR{ return fixed4(_Color); }
<span style="color: #
<span style="color: #
#pragma multi_compile __ _USESPECULAR_ON
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
//fixed pipeline
<span style="color: #
<span style="color: #
<span style="color: #
Color[_Color]
<span style="color: #
<span style="color: #
<span style="color: # }
Shader在Unity编辑器暴露给美术的参数,通过Properties来实现。
所有可能的参数如上所示。主要也就Float、Vector和Texture这3类。
除了通过编辑器编辑Properties,脚本也可以通过Material的接口(比如SetFloat、SetTexture编辑)
之后在Shader程序通过[name](固定管线)或直接name(可编程Shader)访问这些属性。
在每一个Property前面也能类似C#那样添加Attribute,以达到额外UI面板功能。详见。
Shader中的数据类型
有3种基本数值类型:float、half和fixed。这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]。/的访问接口都是Row-Major,比如MyMatrix[3]返回的是第3行;的访问接口是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中各个Space的坐标系
一般情况下,从Vertex Buff输入顶点到Vertex Shader,
该顶点为左手坐标系Model Space中的顶点vInModel,其用w=1的Homogenous Cooridniates(故等效于Cartesian Coordinates)表达vInModel = float4(xm, ym, zm, 1);
vInWrold = mul(_Object2World , vInModel)后,得出左手坐标系World Space中的vInWorld,其为w=1的Homogenous Cooridniates(故等效于Cartesian Coordinates)vInWorld = float4(xw, yw, zw, 1);
vInView = mul(UNITY_MATRIX_V , vInWrold)后,得出右手坐标系View Space中的vInView,其为w=1的Homogenous Cooridniates(故等效于Cartesian Coordinates)vInWorld = float4(xv, yv, zv, 1);
vInClip = mul(UNITY_MATRIX_P , vInView)后,得出左手坐标系Clip Space中的vInClip,其为w往往不等于1的Homogenous Cooridniates(故往往不等效于Cartesian Coordinates)vInClip = float4(xc, yc, zc, wc);设r、l、t、b、n、f的长度绝对值如下图:
注意View Space中摄像机前方的z值为负数、-z为正数。则GL/DX/Metal的Clip Space坐标为:
xc=(2nx+rz+lz)/(r-l);
yc=(2ny+tz+bz)/(t-b);
zc=(-fz-nz-2nf)/(f-n);
xc=(2nx+rz+lz)/(r-l);
yc=(2ny+tz+bz)/(t-b);
zc=(-fz-nf)/(f-n);
vInNDC = vInClip / vInClip.w后,得出左手坐标系Normalized Device Coordinates中的vInNDC,其为w=1的Homogenous Cooridniates(故等效于Cartesian Coordinates)vInNDC = float4(xn, yn, zn, 1)。xn和yn的取值范围为[-1,1]。
GL: zn=zc/wc=(fz+nz+2nf)/((f-n)z);
DX/Metal: zn=zc/wc=(fz+nf)/((f-n)z);
在Unity中,zn的取值范围可以这样决定:
如果UNITY_REVERSED_Z已定义,zn的取值范围是[UNITY_NEAR_CLIP_VALUE, 0],即[1,0]
如果UNITY_REVERSED_Z未定义,zn的取值范围是[UNITY_NEAR_CLIP_VALUE, 1]
如果SHADER_API_D3D9/SHADER_API_D3D11_9X定义了,即[0,1]
否则,即OpenGL情况,即[-1,1]
1 v2f vert (appdata v)
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
// 1 、2、3是等价的,和4是不等价的
// 因为是M在左、V在右,所以是Column Vector
// 因为是HLSL/CG语言,所以是访问方式是Row-Major
o.rootInView = mul(UNITY_MATRIX_MV, float4(<span style="color: #, <span style="color: #, <span style="color: #, <span style="color: #)); // 1
o.rootInView = float4(UNITY_MATRIX_MV[<span style="color: #].w, UNITY_MATRIX_MV[<span style="color: #].w, UNITY_MATRIX_MV[<span style="color: #].w, <span style="color: #); // 2
<span style="color: #
o.rootInView = UNITY_MATRIX_MV._m03_m13_m23_m33;
<span style="color: #
//o.rootInView = UNITY_MATRIX_MV[3]; // 4
<span style="color: #
<span style="color: #
<span style="color: # }
<span style="color: #
<span style="color: # fixed4 frag (v2f i) : SV_Target
<span style="color: # {
<span style="color: #
// 因为是ViewSpace是右手坐标系,所以当root在view前面的时候,z是负数,所以需要-z才能正确显示颜色
<span style="color: #
fixed4 col = fixed4(i.rootInView.x, i.rootInView.y, -i.rootInView.z, <span style="color: #);
<span style="color: #
<span style="color: # }
<span style="color: #
<span style="color: # struct appdata
<span style="color: # {
<span style="color: #
float4 vertex : POSITION;
<span style="color: # };
<span style="color: # struct v2f
<span style="color: # {
<span style="color: #
float4 rootInView : TEXCOORD0;
<span style="color: #
float4 vertex : SV_POSITION;
<span style="color: # };
Shader形态
Shader形态之1:固定管线
固定管线是为了兼容老式显卡。都是顶点光照。之后固定管线可能是被Unity抛弃的功能,所以最好不学它、当它不存在。特征是里面出现了形如下面Material块、没有CGPROGRAM和ENDCG块。
1 Shader "ShaderLab Tutorials/TestShader"
Properties {
_Color ("My Color", Color) = (.<span style="color: #, .<span style="color: #, .<span style="color: #, <span style="color: #) // color
// Fixed Pipeline
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
Diffuse [_Color]
<span style="color: #
Ambient [_Color]
<span style="color: #
<span style="color: #
<span style="color: #
Lighting On
<span style="color: #
<span style="color: #
<span style="color: # }
Shader形态之2:可编程Shader
1 Shader "ShaderLab Tutorials/TestShader"
Properties {}
// ... the usual pass state setup ...
<span style="color: #
<span style="color: #
<span style="color: #
// compilation directives for this snippet, e.g.:
<span style="color: #
#pragma vertex vert
<span style="color: #
#pragma fragment frag
<span style="color: #
<span style="color: #
// the Cg/HLSL code itself
<span style="color: #
float4 vert(float4 v:POSITION) : SV_POSITION{
<span style="color: #
return mul(UNITY_MATRIX_MVP, v);
<span style="color: #
<span style="color: #
float4 frag() : COLOR{
<span style="color: #
return fixed4(<span style="color: #.0, <span style="color: #.0, <span style="color: #.0, <span style="color: #.0);
<span style="color: #
<span style="color: #
<span style="color: #
// ... the rest of pass setup ...
<span style="color: #
<span style="color: #
<span style="color: # }
功能最强大、最自由的形态。
特征是在Pass里出现CGPROGRAM和ENDCG块
编译指令#pragma。详见。其中重要的包括:
编译指令示例/含义
#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了。其他库详见。
ShaderLab内置值。Unity给Shader程序提供了便捷的、常用的值,比如下面例子中的UNITY_MATRIX_MVP就代表了这个时刻的MVP矩阵。详见。
Shader输入输出参数语义(Semantics)。在管线流程中每个阶段之间(比如Vertex Shader阶段和FragmentShader阶段之间)的输入输出参数,通过语义字符串,来指定参数的含义。常用的语义包括:COLOR、SV_Position、TEXCOORD[n]。完整的参数语义可见(由于是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"
Properties {
// Surface Shader
SubShader {
Tags { "RenderType" = "Opaque" }
#pragma surface surf Lambert
<span style="color: #
struct Input {
<span style="color: #
float4 color : COLOR;
<span style="color: #
<span style="color: #
void surf (Input IN, inout SurfaceOutput o) {
<span style="color: #
o.Albedo = <span style="color: #;
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
FallBack "Diffuse"
<span style="color: # }
SurfaceShader可以认为是一个光照Shader的语法糖、一个光照VS/FS的生成器。减少了开发者写重复代码的需要。
在手游,由于对性能要求比较高,所以不建议使用SurfaceShader。因为SurfaceShader是一个比较“通用”的功能,而通用往往导致性能不高。
特征是在SubShader里出现CGPROGRAM和ENDCG块。(而不是出现在Pass里。因为SurfaceShader自己会编译成多个Pass。)
编译指令是:#pragma surface surfaceFunction lightModel [optionalparams]
surfaceFunction:surfaceShader函数,形如void surf (Input IN, inout SurfaceOutput o)
lightModel:使用的光照模式。包括Lambert(漫反射)和BlinnPhong(镜面反射)。
也可以自己定义光照函数。比如编译指令为#pragma surface surf MyCalc
在Shader里定义half4 LightingMyCalc (SurfaceOutput s, 参数略)函数进行处理(函数名在签名加上了“Lighting”)。
你定义输入数据结构(比如上面的Input)、编写自己的Surface函数处理输入、最终输出修改过后的SurfaceOutput。SurfaceOutput的定义为
struct SurfaceOutput {
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"
Properties {...}
SubShader {
// Stats for Vertex shader:
gles : 14 avg math (11..19), 1 avg texture (1..2)
metal : 14 avg math (11..17)
<span style="color: #
// Stats for Fragment shader:
<span style="color: #
metal : 14 avg math (11..19), 1 avg texture (1..2)
<span style="color: #
<span style="color: #
Program "vp" // vertex program
<span style="color: #
<span style="color: #
SubProgram "gles" {
<span style="color: #
// Stats: 11 math, 1 textures
<span style="color: #
Keywords{...} // keywords for shader variants ("uber shader")
<span style="color: #
<span style="color: #
//shader codes in string
<span style="color: #
<span style="color: #
#ifdef VERTEX
<span style="color: #
vertex shader codes
<span style="color: #
<span style="color: #
<span style="color: #
// Note, on gles, fragment shader stays here inside Program "vp"
<span style="color: #
#ifdef FRAGMENT
<span style="color: #
fragment shader codes
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
SubProgram "metal"
<span style="color: #
some setup
<span style="color: #
Keywords{...}
<span style="color: #
<span style="color: #
//vertex shader codes in string
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
Program "fp" // fragment program
<span style="color: #
<span style="color: #
SubProgram "gles" {
<span style="color: #
Keywords{...}
<span style="color: #
"// shader disassembly not supported on gles" //(because gles fragment shader codes are in Program "vp")
<span style="color: #
<span style="color: #
<span style="color: #
SubProgram "metal" {
<span style="color: #
common setup
<span style="color: #
Keywords{...}
<span style="color: #
<span style="color: #
//fragment shader codes in string
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: # }
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描述
"PrepassBase"
渲染物体信息。即把法向量、高光度到一张ARGB32的物体信息纹理上,把深度信息保存在Z-Buff上。
Lighting Pass
无对应可编程Pass
根据Base Pass得出的物体信息,在屏幕坐标系下,使用BlinnPhong光照模式,把光照信息渲染到ARGB32的光照信息纹理上(RGB表示diffuse颜色值、A表示高光度)
Final Pass
"PrepassFinal"
根据光照信息纹理,物体再渲染一次,将光照信息、纹理信息和自发光信息最终混合。LightMap也在这个Pass进行。
Forward Rendering
渲染路径内部子阶段对应的LightMode描述
"ForwardBase"
渲染:最亮一个的方向光光源(像素级)和对应的阴影、所有顶点级光源、LightMap、所有LightProbe的SH光源(Sphere Harmonic,球谐函数,效率超高的低频光)、环境光、自发光。
Additional Passes
"ForwardAdd"
其他需要像素级渲染的的光源
注意到的是,在Forward Rendering中,光源可能是像素级光源、顶点级光源或SH光源。其判断标准是:
配制成“Not Important”的光源都是顶点级光源和SH光源
最亮的方向光永远都是像素级光源
配置成“Important”的都是像素级光源
上面2种情况加起来的像素级光源数目小于“Quality Settings”里面的“Pixel Light Count”的话,会把第1种情况的光源补为额外的像素级光源。
另外,配置成“Auto”的光源有更复杂的判断标注,截图如下:
07-31-40.png
具体可参考。
Vertex Lit
渲染路径内部子阶段对应的LightMode描述
渲染无LightMap物体
VertexLMRGBM
"VertexLMRGBM"
渲染有RGBM编码的LightMap物体
"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。
移动设备GPU架构简述
《The Mali GPU: An Abstract Machine》系列以Arm Mali GPU为例子给出了全面的讨论,现简述如下:
Application/Geometry/Fragment三阶段组成,三者中最大才是瓶颈
OpenGL的同步API是个“illusion”,事实上是CommandQueue(直到遇到Fence会被强制同步),以减少CPU/GPU之间的互相等待
Pipeline Throttle,为了更低的延迟,当GPU累积了多帧(往往是3帧,以eglSwapBuffers()或Present()来区分帧)的Command时,OS会通过eglSwapBuffers()或Present()来阻塞CPU让其进入idle,从而防止更多后续Command的提交
tile-based deferred rendering (,//)是重要的概念。其将Fragment一帧处理多个比如16x16的单元,并为Shader集成一个小但快的cache,从而大幅避免Shader和主内存之间带宽消耗(电量消耗)
GPU包含数个(当前常见为4-8个)Unified Shading Core,可动态分配用于Vertex Shader、Fragment Shader或Compute Kernel
每个Unified Shader Core包含数个(当前常见为2个)用于SIMD计算的运算器Arithmetic Pipeline(A-pipe),1个用于纹理采样的Texutre Pipeline(T-pipe),1个用于非纹理类的内存读写的Load/Store Pipeline(LS-pipe)比如顶点属性写读、变量访问等
会进行Early-ZS测试尝试减少Overdraw(依赖于渲染物体提交顺序由前至后)
Arm的和PowerVR的Hidden Surface Removal做到像素级别的Overdraw减少(不用依赖于渲染物体提交顺序由前至后)
当Shader使用discard或clip、在Fragment Shader里修改深度值、半透明,将不能进行Early-ZS,只好使用传统的Late-ZS
2016年的新型号,对架构作出了优化
Youtube: (包括part1-6)。视频是最佳的入门方式没有之一,所以墙裂建议就算不看下文的所有内容,都要去看一下part1。
书籍:《Unity 3D ShaderLab开发实战详解》
Unity各种官方文档
作者:DonaldW链接:/p/7b來源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
阅读(...) 评论()}

我要回帖

更多关于 unity dotween path 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信