码迷,mamicode.com
首页 > 编程语言 > 详细

翻译5 Unity Advanced Lighting

时间:2020-01-31 17:17:35      阅读:126      评论:0      收藏:0      [点我收藏+]

标签:raw   dad   setting   ram   dba   ott   back   新建   splay   

使用多个光源渲染
支持多光源类型
使用光照信息
计算顶点光照
了解球谐函数

上部分介绍了Unity的基本单个光源,现在学习多个光源参与渲染物体,使用Unity5.6.6f2

1 Include Files

为了给Shader增加支持多个光源,我们需要增加更多Pass通道。但是这些Pass最终包含了几乎完全相似的代码,为了避免代码的重复性,我们可以通过把着色器代码移动到一个CG文件,然后在Shader代码中引用该文件

在文件目录中手动创建一个MyLighting.cginc文件,再把FirstLighting.shader内从#pragma以下到ENDCG以上区间内代码拷贝进.cginc文件。这样我们不直接在shader中写这些重复的代码,通过include引用使用它。

注意,.cginc文件也提供了类似的避免重复定义,#define XXX_INCLUDED,再把整个文件内容放置在预处理文件块中。

#if !defined(MY_LIGHTING_INCLUDED)
#define MY_LIGHTING_INCLUDED
//…
#endif

 

2 第二光源-Drection

新建两个方向光对象,参数设置如下图:

技术图片 技术图片

2-1. 两个光源参数

现在场景中有两个光,但是每个物体看起来没有什么区别。现在我们一次只激活一个光源,看看有什么变化。

技术图片 技术图片

2-2. 左main光源,右minor光源

2.1 增加第二个Pass

当前场景内只能看见一个光源效果,这是由于MyMultiLightShader只有一个Pass且只计算了一个光源。Pass光照标签ForwardBase只计算主光源, 为了渲染额外的光源,需要增加一个Pass且指定光照标签为ForwardAdd方可计算额外的光源

SubShader
{
    Pass
    {
	Tags { "LightMode" = "ForwardBase" }
	CGPROGRAM
	#pragma target 3.0
	#pragma vertex MyVertexProgram
	#pragma fragment MyFragmentProgram
	#include "MyLighting.cginc"
	ENDCG
    }
    Pass
    {
	Tags { "LightMode" = "ForwardAdd" }
	CGPROGRAM
	#pragma target 3.0
	#pragma vertex MyVertexProgram
	#pragma fragment MyFragmentProgram
	#include "MyLighting.cginc"
	ENDCG
    }
}

现在虽然计算了两个光源,但是ForwardAdd计算结果会直接覆盖ForwardBase的结果。我们需要把这两个光照效果结合起来,需要在ForwardAdd Pass内使用混合。

UnityShader的Blend函数:如何通过定义两个因子来合并新旧数据? 新旧数据分别与Blend函数的因子相乘然后相加,得到最终结果。如果Pass内没有Blend默认不混合=Blend One Zero。每个Pass计算后的数据会写入帧缓冲区中,也就会替换之前任何写入该缓冲区的内容。为了把新旧数据都能加到帧缓冲区,我们可以需要指示GPU使用Blend one one模式。

Pass
{
	Tags { "LightMode" = "ForwardAdd" }
	Blend One One
	//...
}

技术图片 技术图片

2-3. 左无混合, 右one one混合

Z-buffer\GPU`s depth buffer:一个物体第一次被渲染,GPU就会检查该片元是否会渲染在其他已经渲染过的像素的前面,这些距离信息就存储在该缓冲区中。因此每个像素都有颜色和深度信息,该深度表示从相机到最近表面的每个像素的距离。

ForwardBase中,如果要渲染的片元前面没有任何内容(深度值最小),它就是最靠近摄像机的表面。GPU也会继续运行fragment程序,生成新的颜色和记录新的深度。如果要渲染的片元的深度值最终比已经存在的大,说明它前面有东西,它就不会被渲染也不能看见。在forward add中重复计算minor光时,要添加到已经存在的灯光,再次运行fragment程序时,因为针对的是同一个对象,最终记录了完全相同的深度值。因此两次写入相同的深度信息是没必要的,用ZWrite off关闭它。

	Blend One One
	ZWrite Off

2.2 Draw Call Batches

在Game视图右上角打开Stats窗口,可以更好地了解运行时发生的事情。查看Batches、Saved by batching数据。先只激活main光源。

技术图片

2-4. Batches数据6,总共7

场景内有5个对象,应该是5个Batches。见下图图技术图片

2-5. 实际Batches

通过FrameDebugger分析,实际是5个draw mesh加上3个内置阴影render函数,一共8个Batches。但是由于启用了动态批处理dynamic batching,所以有一个Saved by batching统计。

那现在来消除这3个阴影渲染函数调用,打开Edit/Project Settings/Quality。Shadows选择Disable Shadows. Clear先无视它这个系统清屏函数。

技术图片 技术图片

2-6. 去掉了阴影渲染函数

激活minor光源,如下图:

技术图片 技术图片

2-7. 10 + 1 = 11

10个Batches? 因为这5个对象被渲染了两次,最终为10个批次,而不是上面的4个。 动态批处理失效了!Unity规定动态批处理最多只支持一个方向光作用的物体对象。

2.3 Frame Debugger

通过Window / Frame Debugger打开可以清楚了解屏幕画面是如何被渲染出来的,5.6版本。

技术图片

2-8 Frame Debugger调试

通过选择光条可单步调试渲染,窗口会自动显示每一步的细节。按照上面的顺序,优先画出了靠近相机的不透明物体,这个front-to-back从前到后的渲染顺序是有效的,得益于depth-buffer深度缓冲,隐藏的片元就会被跳过不渲染。如果使用back-to-front从后到前的顺序,就会覆写远处的像素,发生overdraw。

Unity渲染顺序是front-to-back,同时Unity喜欢把相似的物体分组。例如,sphere和cube分开,可避免在不同mesh网格间切换;或者把使用相同的material分组。

3 Point Lights

翻译5 Unity Advanced Lighting

标签:raw   dad   setting   ram   dba   ott   back   新建   splay   

原文地址:https://www.cnblogs.com/baolong-chen/p/12245910.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!