全局声明宏定义_Unity SRP 8.全局照明

本文是Unity SRP系列的第8篇,讲解如何在Unity中实现静态和动态全局光照。主要内容包括:设置场景以显示间接光照、烘焙光照贴图、采样光照贴图、处理透明表面的光照问题、合并直射光和间接光、自发光材质的创建,以及光照探头和Light Probe Proxy Volumes的使用。文章还涵盖了实时全局照明的实现和点光源、聚光灯的全局光照效果。
摘要由CSDN通过智能技术生成

35f771af788e66e11ed930d0bf33bd86.png

翻译汇总文章:

HipHopBoy:Unity SRP 系列翻译汇总​zhuanlan.zhihu.com

原文链接:

Global Illumination​catlikecoding.com
da033edfea03710220fda98a849ce7ce.png

间接光照

  • 烘焙和采样光照贴图
  • 展示非直接光
  • 创建自发光材质
  • 通过探头和lppv(Light Probe Proxy Volume) 采样灯光
  • 支持预计算实时全局照明

这是Unity SRP系列的第8篇文章。主要关于怎么支持静态和动态全局光照。

这篇教程使用 Unity 2018.3.0f2.

1 光照贴图

实时光只处理了直射光。只有直接暴露在光线下的表面才会被照亮,这是因为缺少了从表面反射到另外的表面最终到摄像机的间接光。这也被称为全局照明。我们可以把间接光烘焙到光照贴图来添加它。Rendering 16, Static Lighting 教程讲解了再unity中烘焙灯光的基础概念,但是对于老的渲染管线只能使用Enlighten lightmapper。

1.1 设置场景

当场景中只有一个直射光没有间接光的时候,可以很容易的看到所有的阴影区域颜色是接近黑色的。

3ade2a6f628dff37366f8173b6cbcdcf.png
只有实时光的场景

大的阴影更加显而易见

87f9e1b047b3f634f488c20607196eb7.png

因为高光环境反射被添加到直射光里,所以我们还能看到阴影里面的物体。如果没有反射探头我们会看到天空盒的反射,这是明亮的。通过把Intensity Multiplier 调整到0来排除天空盒的影响。我们就会看到阴影区域是全黑的。

69f8821c3c79059bca6fef0b7f4e894a.png

634d8868c9db90bc4655a02635fbcc4b.png
全黑环境

1.2 烘焙光照

在场景灯光设置下的 Mixed Lighting 下勾选 Baked Global Illumination 和把Lighting Mode调为Baked Indirect 来开启烘焙间接光。这会让Unity烘焙灯光,但是我们无法直接看到。

889ed1da91153bc0299748214d891d61.png

我会使用默认的Lightmapping 设置,在上面做一些小的改变。默认的使用先进的Lightmapper,我会保留它。因为我有一个小的场景,我会把光照贴图的分辨率从10增加到20.我还禁用了压缩光照贴图选项,为了得到最好的质量,跳过了贴图压缩这一步。改变Directional Model为 Non-Directional ,因为只有使用法线贴图的场景才用到,这里我们不需要。

a0fa93a68eb9ffbea994e85c09e615f6.png
光照贴图设置

烘焙灯光是静态的,所以在运行模式不能改变。只有被标记为lightmap-static的游戏对象才会烘焙它们的间接光贡献。把所有的几何图形都标记为完全静态是最快的。

896399536ea4002f3a2f3ba048d3edf0.png
静态游戏物体

当烘焙时,有uv重叠的话,unity会产生警告。当一个物体的uv展开时在光照贴图中太小,会引起光照信息重叠,就会发生这种情况。你可以通过调整Scale in Lightmap的参数来调整物体的比例。另外对一些默认的物体,比如球体,可以通过开启Stitch Seams 来提升烘焙光照的效果。

6a062646abf1b39008420269f25c78fa.png

最后,为了烘焙最主要贡献的灯光,设置它的模式为Mixed。这就意味着它被用于实时光照,它的间接光照也会被烘焙。

eff31ba32900135f4fd2ea63a27d8b3c.png

在烘焙完成之后,你可以通过Lighting window的Baked Lightmaps标签页来查看贴图。根据贴图的大小和烘焙所有静态物体所需空间的多少,你最终会得到多个贴图。

de6a402344b125c82d6445d7b32fee65.png

1.3 采样光照贴图

为了采样光照贴图,我们需要通知Unity让我们的贴图对我们的shader可用并且在顶点数据里面包含光照贴图的uv坐标。通过MyPipeline.Render里面的 RendererConfiguration.PerObjectLightmaps 标志来完成。就行我们开启反射探头一样。

		drawSettings.rendererConfiguration |=
			RendererConfiguration.PerObjectReflectionProbes |
			RendererConfiguration.PerObjectLightmaps;

当一个物体在光照贴图中被渲染时,Unity会提供需要的数据并且选一个有LIGHTMAPON关键字shader变体。所以我们必须添加一个muti-complie 在我们的shader中。

			#pragma multi_compile _ _SHADOWS_SOFT
			#pragma multi_compile _ LIGHTMAP_ON

通过在Lit.hlsl中添加 unity_Lightmap和和它配对使用的采样器声明来使光照贴图可用

TEXTURE2D(unity_Lightmap);
SAMPLER(samplerunity_Lightmap);

光照贴图的坐标通过第二个uv通道提供,所以在VertexInput中添加

struct VertexInput {
	float4 pos : POSITION;
	float3 normal : NORMAL;
	float2 uv : TEXCOORD0;
	float2 lightmapUV : TEXCOORD1;
	UNITY_VERTEX_INPUT_INSTANCE_ID
};

我们也必须将它们添加到VertexOutput中,但这仅在使用灯光贴图时才需要。

struct VertexOutput {
	float4 clipPos : SV_POSITION;
	float3 normal : TEXCOORD0;
	float3 worldPos : TEXCOORD1;
	float3 vertexLighting : TEXCOORD2;
	float2 uv : TEXCOORD3;
	#if defined(LIGHTMAP_ON)
		float2 lightmapUV : TEXCOORD4;
	#endif
	UNITY_VERTEX_INPUT_INSTANCE_ID
};

光照贴图也有缩放和偏移,但是不应用在整个贴图中。相反,他们用来指定一个物体展开的uv在光照贴图上的位置。定义unity_LightmapST 作为UnityPerDraw buffer的一部分。因为它不符合TRANSFORM_TEX所期望的命名约定,如果需要,我们必须自己转换LitPassVertex中的坐标

CBUFFER_START(UnityPerDraw)
	…
	float4 unity_LightmapST;
CBUFFER_END

…

VertexOutput LitPassVertex (VertexInput input) {
	…
	output.uv = TRANSFORM_TEX(input.uv, _MainTex);
	#if defined(LIGHTMAP_ON)
		output.lightmapUV =
			input.lightmapUV * unity_LightmapST.xy + unity_LightmapST.zw;
	#endif
	return output;
}

让我们创建一个单独的SampleLightmap函数,在给定一些UV坐标的情况下对光照贴图进行采样。在里面我们将调用Core EntityLighting文件里面的SampleSingleLightmap 函数。我们提供贴图,采样器声明和uv坐标,前两个通过TEXTURE2D_PARAM 宏传递。

float3 SampleLightmap (float2 uv) {
	return SampleSingleLightmap(
		TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap), uv
	);
}

SampleSingleLightmap需要更多的参数。下一个是UV坐标的尺度偏移变换。但是我们已经在顶点程序中做过了,所以这里我们要提供一个恒等变换。

	return SampleSingleLightmap(
		TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap), uv,
		float4(1, 1, 0, 0)
	);

然后是一个布尔值,指示是否需要对光照贴图中的数据进行解码。这依赖于目标平台。如果unity使用HDR 光照贴图那么解码就不是必须的。这是UNITY_LIGHTMAP_FULL_HDR定义时的情况。

	return SampleSingleLightmap(
		TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap), uv,
		float4(1, 1, 0, 0),
		#if defined(UNITY_LIGHTMAP_FULL_HDR)
			false
		#else
			true
		#endif
	);

最后,我们需要提供解码指令,使照明在正确的范围。我们需要使用float4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0, 0.0)。

	return SampleSingleLightmap(
		TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap), uv,
		float4(1, 1, 0, 0),
		#if defined(UNITY_LIGHTMAP_FULL_HDR)
			false,
		#else
			true,
		#endif
		float4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0, 0.0)
	);

我们对光照贴图进行采样,因为我们想要添加全局光照。我们为此创建一个全局光照函数,在这个函数里面处理细节。给它一个VertexOutput参数,这意味着需要为他定义一个结构体。如果有光照贴图,采样它,否则返回0。

struct VertexOutput {
	…
};

float3 GlobalIllumination (VertexOutput input) {
	#if defined(LIGHTMAP_ON)
		return SampleLightmap(input.lightmapUV);
	#endif
	return 0;
}

在LitPassFragment的末尾调用这个函数,最初替换所有其他的照明,这样我们就可以单独看到它了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值