- 【Unity3D技术文档翻译】第3.6.7篇 反射探针概述(R
- 【Unity3D技术文档翻译】第3.4.3篇 使用灯光
- 【Unity3D技术文档翻译】第3.6.6.1篇 光照探针:技术
- 【Unity3D技术文档翻译】第3.6.6篇 光照探针概述 (L
- 【Unity3D技术文档翻译】第3.4.1篇 灯光类型
- 【Unity3D技术文档翻译】第3.4篇 灯光资源概述(Ligh
- Unity3D技术文档翻译】第3.6.6.6篇 Light Pr
- 【Unity3D技术文档翻译】第3.6.4篇 烘焙环境遮蔽(Ba
- 【Unity3D技术文档翻译】第3.6.2.4篇 自定义光衰减(
- 【Unity3D技术文档翻译】第3.6.5篇 LOD与烘焙光照贴

上一章:【Unity3D技术文档翻译】第3.6.6.5篇 光照探针与 Mesh Renderer 组件
本章原文所在章节:【Unity Manual】→【Graphics】→【Graphics Overview】→【Lighting】→【Global Illumination】→【Light Probes】→【Light Probe Proxy Volume component】
Light Probe Proxy Volume 组件

Light Probe Proxy Volume(LPPV) 组件允许你为那些无法使用烘焙光照贴图的大型动态游戏对象(例如,大型粒子系统或者蒙皮网格)使用更多的光照信息。
默认情况下,一个 probe-lit 渲染器从一个单独的从周围其他光照探针做插值处理的光照探针接收光照。因此游戏对象的表面具有不变的环境光照。该光照具有一个角度梯度,因为它使用了球谐函数(spherical harmonics,简称 SH),但是它缺少一个空间梯度。在大型游戏对象或者粒子系统上,这个问题会很明显。遍布游戏对象的光照匹配的是它的锚点,而如果游戏对象跨越了一个光照过渡,对象的部分地方将看起来不正确。
Light Probe Proxy Volume(LPPV) 组件在一个包围体内部生成了一个插值光照探针的3D网格。你可以在组件的 UI 中指定该网格的分辨率。插值光照探针的球谐函数系数(SH)将被上传至3D纹理。然后包含了 SH 的3D纹理将在渲染时被采样,以计算对漫反射环境光照的贡献。这就为 probe-lit 游戏对象提供了一个空间梯度。
标准着色器(Standard Shader)支持该特性。如果想将该特性添加到自定义着色器中,需要使用 ShadeSHPerPixel
函数。想要学习如果实现该函数,请查看本节底部的粒子系统采样着色器的代码示例。
什么时候使用
Unity 中的大多数渲染器(Renderer)组件都包含了光照探针(Light Probes)。光照探针具有三个可选项:
- Off:渲染器不会使用任何插值光照探针。
- Blend Probes(默认选项):每个渲染器使用一个插值光照探针。
- Use Proxy Volume:渲染器使用了插值光照探针的3D网格。
当你将 Light Probes 属性设置为 Use Proxy Volume,游戏对象就必须包含 Light Probe Proxy Volume(LPPV) 组件。你可以在相同的游戏对象上添加一个 LPPV 组件,也可以使用来自另一个使用了 Proxy Volume Override 属性的游戏对象上的 LPPV 组件。如果 Unity 在当前游戏对象或者 Proxy Volume Override 游戏对象上没有找到 LPPV 组件,在渲染器的底部将会出现一个警告信息。

示例

在上图场景中,地面上有两个使用了自发光材质的平面。注意:
- 当使用一个 LPPV 组件时,环境光照随着几何体渐变。在几何体的两边各使用了一个插值光照探针,以创建不变的颜色。
- 几何体没有使用静态光照贴图,图中球体代表了插值光照探针。它们是 Gizmo Renderer 的一部分。
如何使用组件
使用插值光照探针3D网格的区域的生成受 Bounding Box Mode 属性的影响。

共有三个可选项:
Bounding Box Mode | 作用 |
---|---|
Automatic Local*(默认选项) | 一个本地空间边界盒被计算。插值光照探针位置被生成在该边界盒内部。如果一个渲染器组件没有被添加到游戏对象上,那么一个默认的边界盒将被生成。边界盒计算围绕当前的渲染器,然后对所有子层级中拥有 Light Probes 属性的渲染器设置 Use Proxy Volume 选项。 |
Automatic World | 边界盒计算围绕当前的渲染器,然后对所有子层级中拥有 Light Probes 属性的渲染器设置 Use Proxy Volume 选项。边界盒是世界对齐的。 |
Custom | 一个自定义边界盒被使用。边界盒被指定用于游戏对象的本地空间。边界盒编辑工具被开启。你可以通过调整 UI 中的 Size 和 Origin 值来手动编辑边界盒体积。 |

Automatic Local 和 Automatic World 之间主要的不同点是,在 Automatic Local 模式下,当一个大型游戏对象的层级在使用来自父对象的相同 LPPV 组件时,边界盒在计算时更加资源敏感。当然,边界盒的尺寸可能更小,这意味着光照数据将更加简洁。
来自边界体积的光照探针插值的数量受 Proxy Volume Resolution 属性的影响。它共有两个选项:
- ** Automatic**(默认值):每个轴上的分辨率,由你指定的每单元插值光照探针数,以及边界盒的尺寸计算得出。
- Custom:允许你为每个轴指定一个不同的分辨率。如下图所示:

注意:每个轴最终的分辨率必须是2的倍数,最大值是 32。
Probe Position Mode 指定了一个插值光照探针相对于中心方格的位置。该选项对于穿过墙面的一些插值光照探针,以及其他会导致光照渗透的几何体很有用。下面的例子展示了 在一个2D视图中 Cell Corner 和 Cell Center 的区别,使用的是 4*4 网格分辨率:

图面对比
- 一个简单的使用了标准着色器的 Mesh Renderer:


- 使用了标准着色器的蒙皮 Mesh Renderer:


使用 ShadeSHPerPixel 函数的粒子系统示例着色器
Shader "Particles/AdditiveLPPV" {
Properties {
_MainTex ("Particle Texture", 2D) = "white" {}
_TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
}
Category {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
Blend SrcAlpha One
ColorMask RGB
Cull Off Lighting Off ZWrite Off
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_particles
#pragma multi_compile_fog
// Specify the target
#pragma target 3.0
#include "UnityCG.cginc"
// You must include this header to have access to ShadeSHPerPixel
#include "UnityStandardUtils.cginc"
fixed4 _TintColor;
sampler2D _MainTex;
struct appdata_t {
float4 vertex : POSITION;
float3 normal : NORMAL;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_FOG_COORDS(1)
float3 worldPos : TEXCOORD2;
float3 worldNormal : TEXCOORD3;
};
float4 _MainTex_ST;
v2f vert (appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.color = v.color;
o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
half3 currentAmbient = half3(0, 0, 0);
half3 ambient = ShadeSHPerPixel(i.worldNormal, currentAmbient, i.worldPos);
fixed4 col = _TintColor * i.color * tex2D(_MainTex, i.texcoord);
col.xyz += ambient;
UNITY_APPLY_FOG_COLOR(i.fogCoord, col, fixed4(0,0,0,0)); // fog towards black due to our blend mode
return col;
}
ENDCG
}
}
}
}
如果本文对你有帮助的话,点个赞或者评论一下吧!
网友评论