第5章 URP光照系统

第5章 URP光照系统

理论讲解

实时光照与烘焙光照混合

在URP中,光照系统是渲染管线的核心组成部分之一。URP支持多种光照模式,包括实时光照、烘焙光照以及两者的混合使用。理解这些光照模式的工作原理对于创建高质量的视觉效果至关重要。

实时光照(Real-time Lighting)

实时光照是指在运行时动态计算的光照效果。在URP中,实时光照包括:

  1. 主光源(Main Light):通常是场景中最主要的定向光源,如太阳光
  2. 附加光源(Additional Lights):包括点光源、聚光灯等其他光源
  3. 环境光(Ambient Light):来自环境的间接光照

实时光照的优势:

  • 动态变化:光源可以移动、改变颜色和强度
  • 交互性:光源可以对场景中的物体产生实时影响
  • 灵活性:可以随时调整光照参数

实时光照的局限性:

  • 性能开销:每帧都需要计算光照效果
  • 光源数量限制:过多的光源会影响性能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using UnityEngine;
using UnityEngine.Rendering.Universal;

public class RealTimeLightingController : MonoBehaviour
{
[Header("Main Light Configuration")]
public Light mainLight;
public float mainLightIntensity = 1.0f;
public Color mainLightColor = Color.white;

[Header("Additional Lights")]
public Light[] additionalLights;
public float additionalLightIntensity = 0.5f;

[Header("Environment Lighting")]
public float ambientIntensity = 0.2f;
public Color ambientColor = Color.gray;

private UniversalRenderPipelineAsset urpAsset;

void Start()
{
SetupRealTimeLighting();
}

void SetupRealTimeLighting()
{
// 配置主光源
if(mainLight != null)
{
mainLight.type = LightType.Directional;
mainLight.intensity = mainLightIntensity;
mainLight.color = mainLightColor;
mainLight.lightmapBakeType = LightmapBakeType.Realtime;
}

// 配置附加光源
foreach(var light in additionalLights)
{
if(light != null)
{
light.intensity = additionalLightIntensity;
light.lightmapBakeType = LightmapBakeType.Realtime;
}
}

// 配置环境光
RenderSettings.ambientIntensity = ambientIntensity;
RenderSettings.ambientLight = ambientColor;
RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Trilight; // 或其他模式
}

// 动态调整光照
public void AdjustMainLightIntensity(float intensity)
{
if(mainLight != null)
{
mainLight.intensity = intensity;
}
}

public void AdjustMainLightColor(Color color)
{
if(mainLight != null)
{
mainLight.color = color;
}
}

// 切换光照模式
public void SetLightMode(LightmapBakeType bakeType)
{
if(mainLight != null)
{
mainLight.lightmapBakeType = bakeType;
}

foreach(var light in additionalLights)
{
if(light != null)
{
light.lightmapBakeType = bakeType;
}
}
}
}

烘焙光照(Baked Lighting)

烘焙光照是预先计算并存储在光照贴图中的光照信息。在URP中,烘焙光照通过Unity的光照烘焙系统生成。

烘焙光照的优势:

  • 性能高效:运行时不需要计算复杂的光照效果
  • 视觉质量:可以实现高质量的间接光照效果
  • 一致性:光照效果在不同设备上保持一致

烘焙光照的局限性:

  • 静态性:烘焙后的光照无法动态变化
  • 预处理时间:需要较长的烘焙时间
  • 内存占用:需要存储光照贴图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
using UnityEngine;
using UnityEngine.Rendering.Universal;

public class BakedLightingController : MonoBehaviour
{
[Header("Baked Lighting Configuration")]
public bool enableBakedLighting = true;
public Light[] staticLights;
public Renderer[] staticObjects;

[Header("Lightmap Settings")]
public float lightmapScale = 1.0f;

void Start()
{
ConfigureBakedLighting();
}

void ConfigureBakedLighting()
{
if(enableBakedLighting)
{
// 设置静态光源
foreach(var light in staticLights)
{
if(light != null)
{
light.lightmapBakeType = LightmapBakeType.Baked;
light.gameObject.isStatic = true;
}
}

// 设置静态物体
foreach(var obj in staticObjects)
{
if(obj != null)
{
var meshRenderer = obj.GetComponent<MeshRenderer>();
if(meshRenderer != null)
{
meshRenderer.lightmapScaleOffset = new Vector4(
lightmapScale,
lightmapScale,
0, 0
);
}
}
}
}
}

// 检查对象是否适合烘焙
public bool IsObjectBakeable(Renderer renderer)
{
if(renderer == null) return false;

// 检查是否为静态对象
if(!renderer.gameObject.isStatic) return false;

// 检查材质是否支持光照贴图
var material = renderer.sharedMaterials;
foreach(var mat in material)
{
if(mat.HasProperty("_MainTex"))
{
// 检查UV设置
if(renderer.lightmapIndex == -1) return false;
}
}

return true;
}
}

混合光照(Mixed Lighting)

混合光照结合了实时光照和烘焙光照的优点,允许某些光照效果实时计算,而其他效果烘焙到光照贴图中。

在URP中,混合光照模式包括:

  • Baked Indirect:间接光照烘焙,直接光照实时计算
  • Subtractive:烘焙光照作为基础,实时光照减去环境光
  • Shadowmask:烘焙阴影遮蔽,实时光照计算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
using UnityEngine;
using UnityEngine.Rendering.Universal;

public class MixedLightingController : MonoBehaviour
{
[Header("Mixed Lighting Configuration")]
public Light[] mixedLights;
public MixedLightingMode mixedMode = MixedLightingMode.BakedIndirect;

[Header("Light Probes")]
public LightProbeGroup lightProbeGroup;
public bool useLightProbes = true;

void Start()
{
SetupMixedLighting();
}

void SetupMixedLighting()
{
foreach(var light in mixedLights)
{
if(light != null)
{
light.lightmapBakeType = LightmapBakeType.Mixed;
light.mixedLightingMode = mixedMode;

// 配置光源参数以适应混合模式
if(mixedMode == MixedLightingMode.Subtractive)
{
light.shadowType = LightShadows.Soft;
}
else if(mixedMode == MixedLightingMode.BakedIndirect)
{
light.bounceIntensity = 1.0f;
}
}
}

// 配置Light Probes
if(lightProbeGroup != null && useLightProbes)
{
// Light Probes会自动应用于未烘焙的动态物体
var dynamicObjects = FindObjectsOfType<Renderer>();
foreach(var obj in dynamicObjects)
{
if(obj.GetComponent<LightProbeProxyVolume>() == null)
{
obj.probeAnchor = lightProbeGroup.transform;
}
}
}
}

// 切换混合光照模式
public void SwitchMixedMode(MixedLightingMode newMode)
{
mixedMode = newMode;

foreach(var light in mixedLights)
{
if(light != null)
{
light.mixedLightingMode = newMode;
}
}
}

// 获取当前混合光照信息
public string GetMixedLightingInfo()
{
string info = "Mixed Lighting Configuration:\n";
info += $"Mode: {mixedMode}\n";
info += $"Light Count: {mixedLights.Length}\n";
info += $"Light Probes: {(lightProbeGroup != null ? "Enabled" : "Disabled")}\n";

return info;
}
}

Light Layers与Rendering Layers

Light Layers是URP中用于控制光照影响范围的功能,允许开发者指定哪些光源可以照亮哪些物体。

Light Layers工作原理

Light Layers通过位掩码(bitmask)的方式工作,每个光源和每个渲染器都可以分配到不同的层中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
using UnityEngine;
using UnityEngine.Rendering.Universal;

public class LightLayersController : MonoBehaviour
{
[Header("Light Layers Configuration")]
public Light[] lights;
public Renderer[] renderers;

[System.Serializable]
public class LightLayerAssignment
{
public Light light;
public int layerMask = 1; // 默认在Layer 0
}

public LightLayerAssignment[] lightLayerAssignments;

void Start()
{
ConfigureLightLayers();
}

void ConfigureLightLayers()
{
// 配置光源层
foreach(var assignment in lightLayerAssignments)
{
if(assignment.light != null)
{
// 在URP中,光源层通过Light组件的参数控制
// 这里我们使用自定义方式来模拟层分配
SetLightLayer(assignment.light, assignment.layerMask);
}
}

// 配置渲染器层
foreach(var renderer in renderers)
{
if(renderer != null)
{
// 在URP中,渲染器的层通常通过材质属性或Shader属性控制
SetRendererLightLayer(renderer, 1); // 示例:设置为层0
}
}
}

void SetLightLayer(Light light, int layerMask)
{
// 在实际URP中,这通常通过材质属性或自定义Shader实现
// 这里我们只是演示概念
Debug.Log($"Setting light {light.name} to layer mask: {layerMask}");
}

void SetRendererLightLayer(Renderer renderer, int layerMask)
{
// 在实际URP中,这通常通过材质属性控制
// 例如:renderer.material.SetInt("_LightLayer", layerMask);
Debug.Log($"Setting renderer {renderer.name} to light layer: {layerMask}");
}

// 创建光源-物体配对
public void CreateLightObjectPair(Light light, GameObject[] objects, int layerMask)
{
// 为指定对象设置光照层
foreach(var obj in objects)
{
var renderer = obj.GetComponent<Renderer>();
if(renderer != null)
{
SetRendererLightLayer(renderer, layerMask);
}
}

// 设置光源影响的层
SetLightLayer(light, layerMask);
}
}

光照模式:Baked、Realtime、Mixed

URP支持三种主要的光照模式,每种模式都有其特定的用途和性能特征:

1. Baked Mode(烘焙模式)

在烘焙模式下,所有光照信息都被预先计算并存储在光照贴图中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using UnityEngine;

public class BakedLightModeController : MonoBehaviour
{
[Header("Baked Light Configuration")]
public Light[] bakedLights;
public GameObject[] staticObjects;

[Header("Baking Parameters")]
public float indirectIntensity = 1.0f;
public float lightmapResolution = 40.0f;

void ConfigureBakedLights()
{
foreach(var light in bakedLights)
{
if(light != null)
{
light.lightmapBakeType = LightmapBakeType.Baked;
light.bounceIntensity = indirectIntensity;

// 烘焙光源通常是静态的
light.gameObject.isStatic = true;
}
}

foreach(var obj in staticObjects)
{
if(obj != null)
{
obj.isStatic = true;

var renderer = obj.GetComponent<MeshRenderer>();
if(renderer != null)
{
renderer.lightmapScaleOffset = Vector4.one;
}
}
}
}

// 检查是否满足烘焙要求
public bool CheckBakingRequirements()
{
bool allStatic = true;
bool hasUVs = true;

foreach(var obj in staticObjects)
{
if(!obj.isStatic) allStatic = false;

var meshFilter = obj.GetComponent<MeshFilter>();
var meshRenderer = obj.GetComponent<MeshRenderer>();

if(meshFilter != null && meshRenderer != null)
{
var mesh = meshFilter.sharedMesh;
if(mesh != null && mesh.uv.Length == 0) hasUVs = false;
}
}

return allStatic && hasUVs;
}
}

2. Realtime Mode(实时模式)

在实时模式下,所有光照效果都在运行时动态计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using UnityEngine;
using UnityEngine.Rendering.Universal;

public class RealtimeLightModeController : MonoBehaviour
{
[Header("Realtime Light Configuration")]
public Light[] realtimeLights;
public GameObject[] dynamicObjects;

[Header("Realtime Parameters")]
public float maxRealtimeLights = 4;
public bool enableShadows = true;

void ConfigureRealtimeLights()
{
int lightCount = 0;

foreach(var light in realtimeLights)
{
if(light != null && lightCount < maxRealtimeLights)
{
light.lightmapBakeType = LightmapBakeType.Realtime;
light.shadows = enableShadows ? LightShadows.Soft : LightShadows.None;

lightCount++;
}
}
}

// 动态调整实时光源
public void AdjustRealtimeLighting(float intensityMultiplier)
{
foreach(var light in realtimeLights)
{
if(light != null)
{
light.intensity *= intensityMultiplier;
}
}
}

// 获取实时光源信息
public string GetRealtimeLightInfo()
{
int activeLights = 0;
float totalIntensity = 0f;

foreach(var light in realtimeLights)
{
if(light != null && light.isActiveAndEnabled)
{
activeLights++;
totalIntensity += light.intensity;
}
}

return $"Active Realtime Lights: {activeLights}\n" +
$"Max Allowed: {maxRealtimeLights}\n" +
$"Total Intensity: {totalIntensity:F2}";
}
}

3. Mixed Mode(混合模式)

混合模式结合了烘焙和实时光照的优点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using UnityEngine;

public class MixedLightModeController : MonoBehaviour
{
[Header("Mixed Light Configuration")]
public Light[] mixedLights;
public MixedLightingMode mixedMode = MixedLightingMode.BakedIndirect;

[Header("Mixed Parameters")]
public float indirectIntensity = 1.0f;
public bool useShadowmask = false;

void ConfigureMixedLights()
{
foreach(var light in mixedLights)
{
if(light != null)
{
light.lightmapBakeType = LightmapBakeType.Mixed;
light.mixedLightingMode = mixedMode;
light.bounceIntensity = indirectIntensity;

// 根据混合模式配置阴影
if(mixedMode == MixedLightingMode.Shadowmask || useShadowmask)
{
light.lightShadowCasterMode = LightShadowCasterMode.Everything;
}
}
}
}

// 切换混合模式
public void SetMixedMode(MixedLightingMode newMode)
{
mixedMode = newMode;
ConfigureMixedLights();
}

// 获取混合光照统计
public string GetMixedLightStats()
{
int bakedIndirect = 0;
int subtractive = 0;
int shadowmask = 0;

foreach(var light in mixedLights)
{
if(light != null)
{
switch(light.mixedLightingMode)
{
case MixedLightingMode.BakedIndirect:
bakedIndirect++;
break;
case MixedLightingMode.Subtractive:
subtractive++;
break;
case MixedLightingMode.Shadowmask:
shadowmask++;
break;
}
}
}

return $"Mixed Light Statistics:\n" +
$"Baked Indirect: {bakedIndirect}\n" +
$"Subtractive: {subtractive}\n" +
$"Shadowmask: {shadowmask}";
}
}

Reflection Probes在URP中的使用

Reflection Probes(反射探针)用于捕获场景中的环境反射信息,在URP中它们的工作方式与传统管线类似,但需要考虑URP的特殊性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using UnityEngine;
using UnityEngine.Rendering.Universal;

public class ReflectionProbesController : MonoBehaviour
{
[Header("Reflection Probes Configuration")]
public ReflectionProbe[] reflectionProbes;
public Renderer[] reflectiveObjects;

[Header("Probe Settings")]
public float refreshMode = 0f; // 0=On Awake, 1=Every N frames, 2=Via Scripting
public int frameUpdateFrequency = 10;
public float intensity = 1.0f;

void Start()
{
SetupReflectionProbes();
}

void SetupReflectionProbes()
{
foreach(var probe in reflectionProbes)
{
if(probe != null)
{
// 配置反射探针
probe.mode = UnityEngine.Rendering.ReflectionProbeMode.Realtime;
probe.refreshMode = UnityEngine.Rendering.ReflectionProbeRefreshMode.ViaScripting;
probe.timeSlicingMode = UnityEngine.Rendering.ReflectionProbeTimeSlicingMode.AllFacesAtOnce;
probe.intensity = intensity;

// 设置探针的大小和位置
probe.size = Vector3.one * 10f; // 10x10x10的区域
probe.center = Vector3.zero;
}
}

// 配置使用反射的材质
foreach(var renderer in reflectiveObjects)
{
if(renderer != null)
{
var materials = renderer.sharedMaterials;
foreach(var material in materials)
{
// 确保材质支持反射
if(material.HasProperty("_SpecularHighlights"))
{
material.EnableKeyword("_SPECGLOSSMAP");
}
}
}
}
}

// 手动更新反射探针
public void UpdateReflectionProbes()
{
foreach(var probe in reflectionProbes)
{
if(probe != null)
{
probe.RenderProbe();
}
}
}

// 根据时间更新反射探针
void Update()
{
if(Time.frameCount % frameUpdateFrequency == 0)
{
UpdateReflectionProbes();
}
}

// 获取反射探针信息
public string GetReflectionProbesInfo()
{
string info = "Reflection Probes Information:\n";
info += $"Probe Count: {reflectionProbes.Length}\n";
info += $"Reflective Objects: {reflectiveObjects.Length}\n";
info += $"Update Frequency: Every {frameUpdateFrequency} frames\n";
info += $"Intensity: {intensity:F2}\n";

return info;
}
}

Light Cookies与IES配置文件

Light Cookies(光照贴图)和IES配置文件用于创建复杂的光照效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
using UnityEngine;
using UnityEngine.Rendering.Universal;

public class LightCookiesController : MonoBehaviour
{
[Header("Light Cookies Configuration")]
public Light[] cookieLights;
public Texture2D[] cookieTextures;
public Texture2D[] iesProfiles;

[Header("Cookie Settings")]
public float cookieSize = 10f;
public float cookieOffset = 0f;

void Start()
{
SetupLightCookies();
}

void SetupLightCookies()
{
int cookieIndex = 0;

foreach(var light in cookieLights)
{
if(light != null && cookieIndex < cookieTextures.Length)
{
// 设置光照贴图
light.cookie = cookieTextures[cookieIndex];
light.cookieSize = cookieSize;

cookieIndex++;
}
}
}

// 切换光照贴图
public void SwitchCookieTexture(int lightIndex, int textureIndex)
{
if(lightIndex < cookieLights.Length && textureIndex < cookieTextures.Length)
{
cookieLights[lightIndex].cookie = cookieTextures[textureIndex];
}
}

// 应用IES配置文件
public void ApplyIESProfile(int lightIndex, int iesIndex)
{
if(lightIndex < cookieLights.Length && iesIndex < iesProfiles.Length)
{
// IES配置文件通常通过特定的Shader或插件应用
// 这里我们只是演示概念
Debug.Log($"Applying IES profile {iesProfiles[iesIndex].name} to light {cookieLights[lightIndex].name}");
}
}

// 获取光照贴图信息
public string GetCookiesInfo()
{
string info = "Light Cookies Information:\n";
info += $"Cookie Lights: {cookieLights.Length}\n";
info += $"Available Textures: {cookieTextures.Length}\n";
info += $"IES Profiles: {iesProfiles.Length}\n";
info += $"Cookie Size: {cookieSize:F2}\n";

return info;
}
}

体积光与光照优化策略

体积光(Volumetric Lighting)在URP中可以通过自定义Renderer Feature实现,同时需要考虑光照优化策略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class VolumetricLightingController : MonoBehaviour
{
[Header("Volumetric Lighting Configuration")]
public Light[] volumetricLights;
public float scatteringCoefficient = 0.1f;
public float absorptionCoefficient = 0.05f;
public Color lightColor = Color.white;

[Header("Optimization Settings")]
public int volumeResolution = 64;
public bool useTemporalReprojection = true;
public float temporalReprojectionStrength = 0.9f;

private Material volumetricMaterial;
private RenderTexture volumeTexture;

void Start()
{
SetupVolumetricLighting();
}

void SetupVolumetricLighting()
{
// 创建体积光照材质
Shader volumetricShader = Shader.Find("Universal Render Pipeline/Custom/VolumetricLighting");
if(volumetricShader != null)
{
volumetricMaterial = new Material(volumetricShader);
volumetricMaterial.SetFloat("_ScatteringCoeff", scatteringCoefficient);
volumetricMaterial.SetFloat("_AbsorptionCoeff", absorptionCoefficient);
volumetricMaterial.SetColor("_LightColor", lightColor);
}

// 配置光源
foreach(var light in volumetricLights)
{
if(light != null)
{
// 体积光通常需要特殊的光源配置
light.type = LightType.Directional; // 或 Point/Spot
light.cookie = null; // 体积光通常不使用cookie
}
}
}

// 光照优化策略
public void ApplyLightingOptimizations()
{
// 1. 光源剔除优化
CullDistantLights();

// 2. 光源合并(如果适用)
MergeSimilarLights();

// 3. 动态光源管理
ManageDynamicLights();
}

void CullDistantLights()
{
Camera mainCamera = Camera.main;
if(mainCamera == null) return;

Vector3 cameraPos = mainCamera.transform.position;
float maxLightDistance = 50f; // 可配置的最大光照距离

foreach(var light in volumetricLights)
{
if(light != null)
{
float distance = Vector3.Distance(light.transform.position, cameraPos);
if(distance > maxLightDistance)
{
light.enabled = false; // 或者调整强度
}
else
{
light.enabled = true;
// 根据距离调整强度
float intensityFactor = Mathf.Clamp01(1.0f - (distance / maxLightDistance));
light.intensity = intensityFactor;
}
}
}
}

void MergeSimilarLights()
{
// 简单的光源合并逻辑(实际实现会更复杂)
for(int i = 0; i < volumetricLights.Length; i++)
{
for(int j = i + 1; j < volumetricLights.Length; j++)
{
if(volumetricLights[i] != null && volumetricLights[j] != null)
{
float distance = Vector3.Distance(
volumetricLights[i].transform.position,
volumetricLights[j].transform.position
);

// 如果两个光源距离很近且特性相似,可以考虑合并
if(distance < 2.0f)
{
Debug.Log($"Lights {i} and {j} are close, consider merging");
}
}
}
}
}

void ManageDynamicLights()
{
// 动态管理光源数量
int maxActiveLights = 4; // 根据性能预算调整
int activeCount = 0;

foreach(var light in volumetricLights)
{
if(light != null)
{
if(activeCount < maxActiveLights)
{
light.enabled = true;
activeCount++;
}
else
{
light.enabled = false;
}
}
}
}

// 获取体积光照信息
public string GetVolumetricLightingInfo()
{
string info = "Volumetric Lighting Configuration:\n";
info += $"Volumetric Lights: {volumetricLights.Length}\n";
info += $"Scattering Coeff: {scatteringCoefficient:F3}\n";
info += $"Absorption Coeff: {absorptionCoefficient:F3}\n";
info += $"Volume Resolution: {volumeResolution}\n";
info += $"Temporal Reprojection: {useTemporalReprojection}\n";

return info;
}

void OnDestroy()
{
if(volumetricMaterial != null)
{
DestroyImmediate(volumetricMaterial);
}

if(volumeTexture != null)
{
RenderTexture.ReleaseTemporary(volumeTexture);
}
}
}

代码示例

完整的光照管理系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
using UnityEngine;
using UnityEngine.Rendering.Universal;
using System.Collections.Generic;

public class AdvancedLightingSystem : MonoBehaviour
{
[System.Serializable]
public class LightConfiguration
{
public string configName;
public LightType lightType = LightType.Directional;
public LightmapBakeType bakeType = LightmapBakeType.Realtime;
public MixedLightingMode mixedMode = MixedLightingMode.BakedIndirect;
public float intensity = 1.0f;
public Color color = Color.white;
public bool enableShadows = true;
public LightShadows shadowType = LightShadows.Soft;
}

[Header("Light Management")]
public List<LightConfiguration> lightConfigs = new List<LightConfiguration>();
public Light[] managedLights;

[Header("Environment Settings")]
public float ambientIntensity = 0.2f;
public Color ambientColor = Color.gray;
public float reflectionIntensity = 1.0f;

[Header("Performance Settings")]
public int maxRealtimeLights = 8;
public float lightCullDistance = 100f;
public bool enableLightProbes = true;

private Dictionary<string, LightConfiguration> configMap = new Dictionary<string, LightConfiguration>();
private int activeLightCount = 0;

void Start()
{
InitializeLightingSystem();
}

void InitializeLightingSystem()
{
// 构建配置映射
foreach(var config in lightConfigs)
{
if(!configMap.ContainsKey(config.configName))
{
configMap[config.configName] = config;
}
}

// 配置管理的光源
ConfigureManagedLights();

// 设置环境参数
SetupEnvironment();
}

void ConfigureManagedLights()
{
activeLightCount = 0;

foreach(var light in managedLights)
{
if(light != null && activeLightCount < maxRealtimeLights)
{
ApplyLightConfiguration(light, GetDefaultConfiguration());
activeLightCount++;
}
}
}

void SetupEnvironment()
{
// 设置环境光
RenderSettings.ambientIntensity = ambientIntensity;
RenderSettings.ambientLight = ambientColor;
RenderSettings.reflectionIntensity = reflectionIntensity;

// 设置环境模式
RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Trilight;
}

LightConfiguration GetDefaultConfiguration()
{
if(lightConfigs.Count > 0)
{
return lightConfigs[0];
}

// 返回默认配置
return new LightConfiguration
{
configName = "Default",
lightType = LightType.Directional,
bakeType = LightmapBakeType.Realtime,
intensity = 1.0f,
color = Color.white,
enableShadows = true
};
}

public void ApplyLightConfiguration(Light light, LightConfiguration config)
{
if(light == null || config == null) return;

// 设置光源类型
light.type = config.lightType;

// 设置烘焙类型
light.lightmapBakeType = config.bakeType;

// 设置混合模式(如果是混合光照)
if(config.bakeType == LightmapBakeType.Mixed)
{
light.mixedLightingMode = config.mixedMode;
}

// 设置强度和颜色
light.intensity = config.intensity;
light.color = config.color;

// 设置阴影
if(config.enableShadows)
{
light.shadows = config.shadowType;
}
else
{
light.shadows = LightShadows.None;
}

// 根据光源类型设置特定参数
switch(config.lightType)
{
case LightType.Spot:
light.spotAngle = 30f; // 默认聚光灯角度
light.range = 10f; // 默认范围
break;

case LightType.Point:
light.range = 10f; // 默认范围
break;

case LightType.Directional:
// 定向光不需要设置范围和角度
break;
}
}

public void ApplyConfigurationByName(Light light, string configName)
{
if(configMap.ContainsKey(configName))
{
ApplyLightConfiguration(light, configMap[configName]);
}
}

// 动态创建光源
public Light CreateDynamicLight(LightConfiguration config, Vector3 position, Quaternion rotation)
{
if(activeLightCount >= maxRealtimeLights)
{
Debug.LogWarning("Maximum realtime lights reached!");
return null;
}

GameObject lightObj = new GameObject($"DynamicLight_{config.configName}");
lightObj.transform.position = position;
lightObj.transform.rotation = rotation;

Light light = lightObj.AddComponent<Light>();
ApplyLightConfiguration(light, config);

// 添加到管理列表
System.Array.Resize(ref managedLights, managedLights.Length + 1);
managedLights[managedLights.Length - 1] = light;

activeLightCount++;

return light;
}

// 光源性能优化
public void OptimizeLights(Camera camera)
{
if(camera == null) return;

Vector3 cameraPos = camera.transform.position;

foreach(var light in managedLights)
{
if(light != null)
{
float distance = Vector3.Distance(light.transform.position, cameraPos);

// 距离过远的光源可以降低质量或禁用
if(distance > lightCullDistance)
{
// 降低阴影质量或完全禁用阴影
if(light.shadows != LightShadows.None)
{
light.shadows = LightShadows.Soft;
light.shadowResolution = LightShadowResolution.Low;
}
}
else
{
// 距离较近的光源保持高质量
if(light.shadows == LightShadows.Soft)
{
light.shadowResolution = LightShadowResolution.Medium;
}
}
}
}
}

// 获取光照系统统计信息
public string GetLightingSystemInfo()
{
int realtimeLights = 0;
int bakedLights = 0;
int mixedLights = 0;

foreach(var light in managedLights)
{
if(light != null)
{
switch(light.lightmapBakeType)
{
case LightmapBakeType.Realtime:
realtimeLights++;
break;
case LightmapBakeType.Baked:
bakedLights++;
break;
case LightmapBakeType.Mixed:
mixedLights++;
break;
}
}
}

return $"Lighting System Statistics:\n" +
$"Total Managed Lights: {managedLights.Length}\n" +
$"Active Realtime: {realtimeLights}\n" +
$"Baked: {bakedLights}\n" +
$"Mixed: {mixedLights}\n" +
$"Max Realtime Limit: {maxRealtimeLights}\n" +
$"Ambient Intensity: {ambientIntensity:F2}\n" +
$"Reflection Intensity: {reflectionIntensity:F2}";
}

// 切换光照配置
public void SwitchLightingConfiguration(string configName)
{
if(!configMap.ContainsKey(configName))
{
Debug.LogError($"Configuration '{configName}' not found!");
return;
}

var config = configMap[configName];

// 应用到所有管理的光源
foreach(var light in managedLights)
{
if(light != null)
{
ApplyLightConfiguration(light, config);
}
}

Debug.Log($"Switched to lighting configuration: {configName}");
}

// 添加新的光照配置
public void AddLightConfiguration(LightConfiguration config)
{
if(!configMap.ContainsKey(config.configName))
{
lightConfigs.Add(config);
configMap[config.configName] = config;
}
}

void Update()
{
// 在运行时持续优化光源
if(Camera.main != null)
{
OptimizeLights(Camera.main);
}
}
}

实践练习

练习1:创建动态光照切换系统

目标:创建一个可以根据时间或事件动态切换不同光照配置的系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
using UnityEngine;
using UnityEngine.Rendering.Universal;
using System.Collections;

public class DynamicLightingSwitcher : MonoBehaviour
{
[System.Serializable]
public class TimeBasedLightingConfig
{
public string configName;
public float timeOfDay = 12.0f; // 24小时制时间
public LightConfiguration lightConfig;
public float transitionDuration = 2.0f;
public AnimationCurve transitionCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
}

[Header("Dynamic Lighting Configuration")]
public TimeBasedLightingConfig[] timeBasedConfigs;
public Light[] targetLights;

[Header("Time Control")]
public bool useRealTime = false;
public float timeScale = 1.0f;
private float currentTime = 8.0f; // 默认早上8点

[Header("Current State")]
private TimeBasedLightingConfig currentConfig;
private TimeBasedLightingConfig targetConfig;
private float transitionProgress = 0f;
private bool isTransitioning = false;

void Start()
{
InitializeDynamicLighting();
}

void InitializeDynamicLighting()
{
if(timeBasedConfigs.Length > 0)
{
currentConfig = timeBasedConfigs[0];
ApplyConfiguration(currentConfig.lightConfig);
}
}

void Update()
{
if(useRealTime)
{
currentTime += Time.deltaTime * timeScale / 3600f; // 转换为小时
if(currentTime >= 24f) currentTime -= 24f;
}
else
{
// 演示用途:手动增加时间
currentTime += Time.deltaTime * 0.1f;
if(currentTime >= 24f) currentTime -= 24f;
}

CheckAndApplyTimeBasedChanges();

if(isTransitioning)
{
UpdateTransition();
}
}

void CheckAndApplyTimeBasedChanges()
{
TimeBasedLightingConfig nextConfig = GetNextConfig();

if(nextConfig != null && nextConfig != targetConfig)
{
StartConfigurationTransition(nextConfig);
}
}

TimeBasedLightingConfig GetNextConfig()
{
// 找到下一个时间点的配置
TimeBasedLightingConfig nextConfig = null;
float minDistance = float.MaxValue;

foreach(var config in timeBasedConfigs)
{
float distance = CalculateTimeDistance(currentTime, config.timeOfDay);
if(distance < minDistance && distance < 1.0f) // 1小时内的变化
{
minDistance = distance;
nextConfig = config;
}
}

return nextConfig;
}

float CalculateTimeDistance(float from, float to)
{
float distance = Mathf.Abs(to - from);
// 处理跨越24点的情况
if(distance > 12f)
{
distance = 24f - distance;
}
return distance;
}

void StartConfigurationTransition(TimeBasedLightingConfig newConfig)
{
if(newConfig == null) return;

targetConfig = newConfig;
isTransitioning = true;
transitionProgress = 0f;
}

void UpdateTransition()
{
transitionProgress += Time.deltaTime / targetConfig.transitionDuration;

if(transitionProgress >= 1.0f)
{
transitionProgress = 1.0f;
isTransitioning = false;
currentConfig = targetConfig;
}

// 在当前配置和目标配置之间插值
InterpolateBetweenConfigs(currentConfig, targetConfig,
targetConfig.transitionCurve.Evaluate(transitionProgress));
}

void InterpolateBetweenConfigs(TimeBasedLightingConfig from,
TimeBasedLightingConfig to, float t)
{
foreach(var light in targetLights)
{
if(light != null)
{
// 插值强度
float intensity = Mathf.Lerp(from.lightConfig.intensity,
to.lightConfig.intensity, t);
light.intensity = intensity;

// 插值颜色
Color color = Color.Lerp(from.lightConfig.color,
to.lightConfig.color, t);
light.color = color;

// 插值其他属性...
}
}
}

void ApplyConfiguration(LightConfiguration config)
{
foreach(var light in targetLights)
{
if(light != null)
{
// 应用配置
light.intensity = config.intensity;
light.color = config.color;

if(config.enableShadows)
{
light.shadows = config.shadowType;
}
else
{
light.shadows = LightShadows.None;
}
}
}
}

// 手动切换到特定配置
public void SwitchToConfig(string configName)
{
foreach(var config in timeBasedConfigs)
{
if(config.configName == configName)
{
StartConfigurationTransition(config);
return;
}
}
}

// 获取当前时间
public float GetCurrentTime()
{
return currentTime;
}

// 获取光照系统信息
public string GetLightingInfo()
{
return $"Current Time: {currentTime:F2}h\n" +
$"Current Config: {currentConfig?.configName ?? "None"}\n" +
$"Target Config: {targetConfig?.configName ?? "None"}\n" +
$"Transition Progress: {transitionProgress * 100:F1}%\n" +
$"Lights Count: {targetLights.Length}";
}
}

练习2:创建光照性能分析工具

目标:创建一个工具来分析和优化场景中的光照性能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
using UnityEngine;
using UnityEngine.Rendering.Universal;
using System.Collections.Generic;
using System.Linq;

public class LightingPerformanceAnalyzer : MonoBehaviour
{
[Header("Analysis Settings")]
public bool autoAnalyze = true;
public float analysisInterval = 5.0f;
private float lastAnalysisTime = 0f;

[Header("Performance Thresholds")]
public int maxRecommendedLights = 8;
public float maxLightRange = 50f;
public float maxShadowDistance = 30f;
public LightShadows maxShadowQuality = LightShadows.Soft;

[Header("Results")]
public bool hasPerformanceIssues = false;
public List<Light> problematicLights = new List<Light>();

private Dictionary<Light, LightPerformanceData> lightPerformanceData =
new Dictionary<Light, LightPerformanceData>();

[System.Serializable]
public class LightPerformanceData
{
public float lastFrameTime;
public int shadowResolution;
public float range;
public bool hasIssues;
public List<string> issues = new List<string>();
}

void Update()
{
if(autoAnalyze && Time.time - lastAnalysisTime >= analysisInterval)
{
AnalyzeLightingPerformance();
lastAnalysisTime = Time.time;
}
}

public void AnalyzeLightingPerformance()
{
Light[] allLights = FindObjectsOfType<Light>();

problematicLights.Clear();
lightPerformanceData.Clear();
hasPerformanceIssues = false;

foreach(var light in allLights)
{
if(light == null) continue;

var data = new LightPerformanceData();
data.range = light.type == LightType.Directional ? 0 : light.range;
data.shadowResolution = (int)light.shadowResolution;

// 检查潜在的性能问题
CheckLightPerformanceIssues(light, data);

lightPerformanceData[light] = data;

if(data.hasIssues)
{
problematicLights.Add(light);
hasPerformanceIssues = true;
}
}

DebugAnalysisResults();
}

void CheckLightPerformanceIssues(Light light, LightPerformanceData data)
{
// 检查光源数量
Light[] allLights = FindObjectsOfType<Light>();
if(allLights.Length > maxRecommendedLights)
{
data.issues.Add($"Too many lights in scene ({allLights.Length} > {maxRecommendedLights})");
data.hasIssues = true;
}

// 检查光源范围
if(light.type != LightType.Directional && light.range > maxLightRange)
{
data.issues.Add($"Light range too large ({light.range:F1} > {maxLightRange:F1})");
data.hasIssues = true;
}

// 检查阴影距离
var urpAsset = GraphicsSettings.renderPipelineAsset as UniversalRenderPipelineAsset;
if(urpAsset != null && urpAsset.shadowDistance > maxShadowDistance)
{
data.issues.Add($"Shadow distance too large ({urpAsset.shadowDistance:F1} > {maxShadowDistance:F1})");
data.hasIssues = true;
}

// 检查阴影质量
if(light.shadows > maxShadowQuality)
{
data.issues.Add($"Shadow quality too high ({light.shadows} > {maxShadowQuality})");
data.hasIssues = true;
}

// 检查光源类型分布
var lights = FindObjectsOfType<Light>();
var spotLights = lights.Where(l => l.type == LightType.Spot).ToList();
var pointLights = lights.Where(l => l.type == LightType.Point).ToList();

if(spotLights.Count > allLights.Length * 0.7f)
{
data.issues.Add("Too many spot lights, consider using fewer, higher-quality lights");
data.hasIssues = true;
}
}

void DebugAnalysisResults()
{
if(!hasPerformanceIssues)
{
Debug.Log("✅ Lighting performance looks good!");
return;
}

Debug.LogWarning($"⚠️ Found {problematicLights.Count} lights with performance issues:");

foreach(var light in problematicLights)
{
if(lightPerformanceData.ContainsKey(light))
{
var data = lightPerformanceData[light];
Debug.LogWarning($"Light '{light.name}' issues:");
foreach(var issue in data.issues)
{
Debug.LogWarning($" - {issue}");
}
}
}
}

// 获取优化建议
public string GetOptimizationSuggestions()
{
if(!hasPerformanceIssues)
{
return "No performance issues detected. Lighting performance is optimal.";
}

var suggestions = new List<string>();

// 光源数量建议
Light[] allLights = FindObjectsOfType<Light>();
if(allLights.Length > maxRecommendedLights)
{
suggestions.Add($"Reduce light count from {allLights.Length} to {maxRecommendedLights} or fewer");
}

// 阴影优化建议
var shadowLights = allLights.Where(l => l.shadows != LightShadows.None).ToList();
if(shadowLights.Count > 0)
{
suggestions.Add($"Consider reducing shadow resolution or disabling shadows for distant lights");
}

// 距离优化建议
var highRangeLights = allLights.Where(l =>
l.type != LightType.Directional && l.range > maxLightRange * 0.8f).ToList();
if(highRangeLights.Count > 0)
{
suggestions.Add($"Reduce range of {highRangeLights.Count} lights to improve performance");
}

return "Performance Optimization Suggestions:\n" +
string.Join("\n", suggestions.Select(s => "• " + s));
}

// 应用性能优化
public void ApplyPerformanceOptimizations()
{
Light[] allLights = FindObjectsOfType<Light>();

// 降低远处光源的阴影质量
foreach(var light in allLights)
{
if(light.shadows == LightShadows.Soft && light.range > maxLightRange * 0.7f)
{
light.shadows = LightShadows.Hard;
Debug.Log($"Reduced shadow quality for light: {light.name}");
}
}

// 减少光源数量(禁用最不重要的光源)
var lightsByImportance = allLights
.OrderByDescending(l => l.intensity * (l.type == LightType.Directional ? 2 : 1))
.ToList();

for(int i = maxRecommendedLights; i < lightsByImportance.Count; i++)
{
lightsByImportance[i].enabled = false;
Debug.Log($"Disabled light for performance: {lightsByImportance[i].name}");
}

Debug.Log("Applied performance optimizations");
}

// 获取详细分析报告
public string GetDetailedAnalysisReport()
{
var report = new System.Text.StringBuilder();

Light[] allLights = FindObjectsOfType<Light>();

report.AppendLine("=== Lighting Performance Analysis Report ===");
report.AppendLine($"Total Lights: {allLights.Length}");
report.AppendLine($"Problematic Lights: {problematicLights.Count}");
report.AppendLine();

// 按类型统计
int directionalCount = allLights.Count(l => l.type == LightType.Directional);
int pointCount = allLights.Count(l => l.type == LightType.Point);
int spotCount = allLights.Count(l => l.type == LightType.Spot);

report.AppendLine("Light Type Distribution:");
report.AppendLine($" Directional: {directionalCount}");
report.AppendLine($" Point: {pointCount}");
report.AppendLine($" Spot: {spotCount}");
report.AppendLine();

// 性能统计
float totalIntensity = allLights.Sum(l => l.intensity);
float avgIntensity = allLights.Length > 0 ? totalIntensity / allLights.Length : 0;

report.AppendLine("Intensity Statistics:");
report.AppendLine($" Total Intensity: {totalIntensity:F2}");
report.AppendLine($" Average Intensity: {avgIntensity:F2}");
report.AppendLine();

// 阴影统计
int shadowLightsCount = allLights.Count(l => l.shadows != LightShadows.None);
report.AppendLine($"Lights with Shadows: {shadowLightsCount}");

return report.ToString();
}
}

总结

本章详细介绍了URP光照系统的各个方面,包括实时光照与烘焙光照的混合使用、Light Layers与Rendering Layers、三种光照模式(Baked、Realtime、Mixed)的特点和应用、Reflection Probes的使用、Light Cookies与IES配置文件,以及体积光和光照优化策略。

通过理论讲解、代码示例和实践练习,我们学习了:

  1. 光照模式:理解了实时光照、烘焙光照和混合光照的工作原理和适用场景,掌握了如何在不同模式间切换和配置。

  2. Light Layers:学会了如何使用Light Layers来控制光源对特定物体的影响,实现更精细的光照控制。

  3. 反射探针:掌握了Reflection Probes在URP中的配置和使用方法,用于实现高质量的环境反射效果。

  4. 光照优化:学习了多种光照性能优化策略,包括光源剔除、动态管理、质量分级等。

  5. 实践应用:通过创建动态光照切换系统和性能分析工具,将理论知识转化为实际可用的解决方案。

URP光照系统提供了灵活而强大的光照解决方案,正确配置和优化光照系统对于创建高质量的视觉效果和保持良好性能至关重要。在下一章中,我们将深入探讨URP阴影系统,了解阴影的生成原理和优化方法。