第14章 RenderingData与Context

第14章 RenderingData与Context

理论讲解

14.1 ScriptableRenderContext作用

ScriptableRenderContext是Unity可编程渲染管线中的核心组件,它充当了渲染命令执行的上下文环境。这个上下文管理着渲染管线中的所有渲染操作,包括几何体绘制、阴影投射、光照计算等。

ScriptableRenderContext的主要职责:

  1. 命令执行:执行渲染命令缓冲区中的命令
  2. 资源管理:管理渲染过程中使用的资源
  3. 状态管理:维护渲染状态(如深度测试、混合等)
  4. 批处理:优化渲染调用,减少Draw Call
  5. 同步机制:处理CPU与GPU之间的同步

ScriptableRenderContext的使用场景:

  • 在ScriptableRenderPass的Execute方法中作为参数传入
  • 执行DrawRenderers命令
  • 执行阴影渲染命令
  • 提交渲染命令到GPU

14.2 RenderingData数据结构

RenderingData是URP中封装当前帧渲染所需数据的结构体,它包含了渲染管线各个阶段所需的信息。

RenderingData的主要组成部分:

CameraData:包含相机相关的渲染信息

  • 相机变换矩阵
  • 视锥体参数
  • 渲染目标信息
  • 相机配置参数

LightData:包含光照相关的渲染信息

  • 主光源信息
  • 附加光源信息
  • 光照模式配置
  • 光照烘焙信息

ShadowData:包含阴影相关的渲染信息

  • 阴影贴图配置
  • 阴影投射物体列表
  • 阴影参数设置

CullingResults:包含视锥体裁剪结果

  • 可见物体列表
  • 裁剪参数
  • 可见光源列表

PostProcessData:包含后处理相关的数据

  • 后处理配置
  • 后处理资源
  • 后处理参数

14.3 CameraData、LightData、ShadowData

CameraData详解:

CameraData封装了相机渲染所需的所有信息,是渲染管线中最重要的数据结构之一。

主要属性

  • camera:Unity Camera组件引用
  • isSceneViewCamera:是否为场景视图相机
  • isDefaultViewport:是否使用默认视口
  • isHdrEnabled:是否启用HDR
  • maxShadowDistance:最大阴影距离
  • renderScale:渲染缩放
  • cameraBounds:相机边界
  • cullResults:裁剪结果

LightData详解:

LightData管理场景中的光照信息,包括主光源和附加光源的配置。

主要属性

  • mainLightIndex:主光源索引
  • additionalLightsCount:附加光源数量
  • supportsAdditionalLights:是否支持附加光源
  • supportsMixedLighting:是否支持混合光照
  • lightData:光照数据数组

ShadowData详解:

ShadowData管理阴影渲染的相关配置和数据。

主要属性

  • supportsMainLightShadows:是否支持主光源阴影
  • supportsAdditionalLightShadows:是否支持附加光源阴影
  • mainLightShadowmapWidth/Height:主光源阴影贴图尺寸
  • additionalLightsShadowmapWidth/Height:附加光源阴影贴图尺寸
  • shadowmapDepthBufferBits:阴影贴图深度缓冲位数

14.4 渲染上下文的传递机制

在URP渲染管线中,渲染数据通过特定的机制在各个组件间传递,确保数据的一致性和完整性。

数据传递流程:

  1. 渲染管线入口:在Render方法中创建初始的RenderingData
  2. 相机处理:为每个相机创建CameraData
  3. 光照处理:根据场景光照创建LightData
  4. 阴影处理:根据光源配置创建ShadowData
  5. 裁剪处理:执行视锥体裁剪生成CullingResults
  6. 渲染通道:将完整的RenderingData传递给各个渲染通道

数据传递优化策略:

  • 结构体传递:使用ref参数减少数据复制开销
  • 数据缓存:缓存计算结果避免重复计算
  • 按需计算:只计算当前渲染通道需要的数据

14.5 CommandBuffer的获取与执行

CommandBuffer是Unity中用于记录渲染命令的数据结构,在URP中被广泛使用。

CommandBuffer的使用模式:

获取方式

  • 从CommandBufferPool获取(推荐)
  • 直接创建CommandBuffer实例

执行方式

  • 通过ScriptableRenderContext.ExecuteCommandBuffer执行
  • 在渲染通道中执行

CommandBuffer最佳实践:

  1. 使用池化:使用CommandBufferPool.Get()和Release()管理命令缓冲区
  2. 及时释放:在使用完毕后立即释放到池中
  3. 作用域管理:使用using语句确保资源正确释放
  4. 命令优化:批量执行相关命令减少开销

14.6 渲染状态的保存与恢复

在复杂的渲染管线中,正确管理渲染状态对于确保渲染结果的正确性至关重要。

渲染状态类型:

  • 深度状态:深度测试、深度写入
  • 混合状态:颜色混合模式
  • 光栅化状态:剔除模式、多边形模式
  • 着色器状态:当前激活的着色器和材质

状态管理策略:

  1. 状态缓存:缓存当前渲染状态避免不必要的状态切换
  2. 状态验证:在设置新状态前验证是否需要更改
  3. 状态恢复:在渲染完成后恢复原始状态
  4. 作用域管理:使用状态作用域确保状态正确恢复

代码示例

14.7 RenderingData访问与使用

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
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class RenderingDataAnalyzer : MonoBehaviour
{
[Header("Analysis Settings")]
public bool enableAnalysis = true;
public bool logCameraData = true;
public bool logLightData = true;
public bool logShadowData = true;

[Header("Performance Thresholds")]
public int warningVisibleLights = 10;
public int warningVisibleRenderers = 50;
public float warningMaxShadowDistance = 50f;

private RenderingData m_CurrentRenderingData;
private CameraData m_CurrentCameraData;
private LightData m_CurrentLightData;
private ShadowData m_CurrentShadowData;

[System.Serializable]
public class RenderingStats
{
public int visibleLights;
public int visibleRenderers;
public int visibleShadowCasters;
public float maxShadowDistance;
public bool isHdrEnabled;
public bool supportsMainLightShadows;
public bool supportsAdditionalLightShadows;
public int additionalLightsCount;
public float renderScale;
}

public RenderingStats currentStats = new RenderingStats();

void Start()
{
if (enableAnalysis)
{
RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering;
RenderPipelineManager.endCameraRendering += OnEndCameraRendering;
}
}

void OnDestroy()
{
if (enableAnalysis)
{
RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering;
RenderPipelineManager.endCameraRendering -= OnEndCameraRendering;
}
}

private void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
{
if (!enableAnalysis) return;

// 这里我们无法直接访问RenderingData,但可以分析相机数据
AnalyzeCamera(camera);
}

private void OnEndCameraRendering(ScriptableRenderContext context, Camera camera)
{
if (!enableAnalysis) return;

// 在相机渲染结束后进行分析
LogAnalysisResults();
}

private void AnalyzeCamera(Camera camera)
{
// 分析相机数据
var urpData = camera.GetUniversalAdditionalCameraData();
if (urpData != null)
{
currentStats.isHdrEnabled = urpData.allowHDR;
currentStats.renderScale = urpData.renderScale;
}

// 分析光照数据(通过场景中的光源)
var lights = FindObjectsOfType<Light>();
currentStats.visibleLights = lights.Length;
currentStats.additionalLightsCount = Mathf.Max(0, lights.Length - 1); // 假设一个主光源

// 分析阴影数据
var shadowLights = System.Array.FindAll(lights, l => l.shadows != LightShadows.None);
currentStats.supportsMainLightShadows = shadowLights.Length > 0;
currentStats.supportsAdditionalLightShadows = shadowLights.Length > 1;
currentStats.maxShadowDistance = camera.farClipPlane;

// 分析渲染器数据
var renderers = FindObjectsOfType<Renderer>();
currentStats.visibleRenderers = renderers.Length;

// 分析阴影投射器
var shadowCasters = System.Array.FindAll(renderers, r => r.shadowCastingMode != ShadowCastingMode.Off);
currentStats.visibleShadowCasters = shadowCasters.Length;

// 性能检查
CheckPerformanceThresholds();
}

private void CheckPerformanceThresholds()
{
var warnings = new System.Collections.Generic.List<string>();

if (currentStats.visibleLights > warningVisibleLights)
{
warnings.Add($"Too many visible lights: {currentStats.visibleLights} (threshold: {warningVisibleLights})");
}

if (currentStats.visibleRenderers > warningVisibleRenderers)
{
warnings.Add($"Too many visible renderers: {currentStats.visibleRenderers} (threshold: {warningVisibleRenderers})");
}

if (currentStats.maxShadowDistance > warningMaxShadowDistance)
{
warnings.Add($"Large shadow distance: {currentStats.maxShadowDistance:F1} (threshold: {warningMaxShadowDistance})");
}

if (warnings.Count > 0 && logCameraData)
{
foreach (var warning in warnings)
{
Debug.LogWarning($"[Rendering Analysis] {warning}");
}
}
}

private void LogAnalysisResults()
{
if (!logCameraData) return;

var log = new System.Text.StringBuilder();
log.AppendLine("=== Rendering Data Analysis ===");
log.AppendLine($"Visible Lights: {currentStats.visibleLights}");
log.AppendLine($"Visible Renderers: {currentStats.visibleRenderers}");
log.AppendLine($"Visible Shadow Casters: {currentStats.visibleShadowCasters}");
log.AppendLine($"Additional Lights Count: {currentStats.additionalLightsCount}");
log.AppendLine($"HDR Enabled: {currentStats.isHdrEnabled}");
log.AppendLine($"Render Scale: {currentStats.renderScale:F2}");
log.AppendLine($"Supports Main Light Shadows: {currentStats.supportsMainLightShadows}");
log.AppendLine($"Supports Additional Light Shadows: {currentStats.supportsAdditionalLightShadows}");

Debug.Log(log.ToString());
}

// 获取当前渲染统计信息
public RenderingStats GetCurrentStats()
{
return currentStats;
}

// 重置统计信息
public void ResetStats()
{
currentStats = new RenderingStats();
}

// 获取性能建议
public string GetPerformanceRecommendations()
{
var recommendations = new System.Collections.Generic.List<string>();

if (currentStats.visibleLights > warningVisibleLights)
{
recommendations.Add("Reduce number of active lights or use light probes for static objects");
}

if (currentStats.visibleRenderers > warningVisibleRenderers)
{
recommendations.Add("Implement LOD system or occlusion culling to reduce visible geometry");
}

if (currentStats.supportsAdditionalLightShadows && currentStats.additionalLightsCount > 4)
{
recommendations.Add("Consider reducing shadow-casting additional lights for better performance");
}

return recommendations.Count > 0 ? string.Join("\n", recommendations) : "No performance recommendations";
}
}

14.8 自定义渲染上下文管理器

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
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class RenderContextManager : MonoBehaviour
{
[Header("Context Management")]
public bool enableContextPooling = true;
public bool enableStateTracking = true;
public bool logContextOperations = false;

[Header("Performance Settings")]
public int maxCommandBuffersInPool = 20;
public float stateChangeThreshold = 0.1f; // 避免频繁状态切换的阈值

private Queue<CommandBuffer> m_CommandBufferPool = new Queue<CommandBuffer>();
private List<CommandBuffer> m_ActiveCommandBuffers = new List<CommandBuffer>();

// 渲染状态跟踪
private Dictionary<string, object> m_RenderStates = new Dictionary<string, object>();
private Dictionary<string, float> m_LastStateChangeTime = new Dictionary<string, float>();

// 上下文作用域管理
private Stack<RenderContextScope> m_ContextScopes = new Stack<RenderContextScope>();

[System.Serializable]
public class RenderContextScope
{
public string name;
public RenderTargetIdentifier currentRenderTarget;
public RenderTextureDescriptor currentDescriptor;
public int commandCount;
public float startTime;

public RenderContextScope(string scopeName)
{
name = scopeName;
startTime = Time.realtimeSinceStartup;
commandCount = 0;
}
}

void Start()
{
InitializeContextManager();
}

private void InitializeContextManager()
{
// 初始化命令缓冲区池
if (enableContextPooling)
{
for (int i = 0; i < maxCommandBuffersInPool; i++)
{
var cmdBuffer = new CommandBuffer();
cmdBuffer.name = $"Pooled Command Buffer {i}";
m_CommandBufferPool.Enqueue(cmdBuffer);
}
}
}

// 获取命令缓冲区
public CommandBuffer GetCommandBuffer(string name = "Default")
{
CommandBuffer cmdBuffer;

if (enableContextPooling && m_CommandBufferPool.Count > 0)
{
cmdBuffer = m_CommandBufferPool.Dequeue();
}
else
{
cmdBuffer = new CommandBuffer();
}

cmdBuffer.name = name;
cmdBuffer.Clear();
m_ActiveCommandBuffers.Add(cmdBuffer);

if (logContextOperations)
{
Debug.Log($"[RenderContextManager] Acquired command buffer: {name}");
}

return cmdBuffer;
}

// 释放命令缓冲区
public void ReleaseCommandBuffer(CommandBuffer cmdBuffer)
{
if (cmdBuffer == null) return;

if (enableContextPooling && m_CommandBufferPool.Count < maxCommandBuffersInPool)
{
cmdBuffer.Clear();
m_CommandBufferPool.Enqueue(cmdBuffer);
}
else
{
cmdBuffer.Dispose();
}

m_ActiveCommandBuffers.Remove(cmdBuffer);

if (logContextOperations)
{
Debug.Log($"[RenderContextManager] Released command buffer");
}
}

// 开始渲染上下文作用域
public void BeginContextScope(string scopeName)
{
var scope = new RenderContextScope(scopeName);
m_ContextScopes.Push(scope);

if (logContextOperations)
{
Debug.Log($"[RenderContextManager] Begin scope: {scopeName}");
}
}

// 结束渲染上下文作用域
public void EndContextScope()
{
if (m_ContextScopes.Count > 0)
{
var scope = m_ContextScopes.Pop();
var duration = Time.realtimeSinceStartup - scope.startTime;

if (logContextOperations)
{
Debug.Log($"[RenderContextManager] End scope: {scope.name}, Duration: {duration:F3}s, Commands: {scope.commandCount}");
}
}
}

// 设置渲染状态
public void SetRenderState(string stateName, object value)
{
if (!enableStateTracking) return;

// 检查状态是否真的需要改变
if (m_RenderStates.ContainsKey(stateName))
{
if (AreEqual(m_RenderStates[stateName], value))
{
// 状态相同,无需改变
return;
}
}

// 检查上次改变时间,避免频繁改变
float currentTime = Time.realtimeSinceStartup;
if (m_LastStateChangeTime.ContainsKey(stateName))
{
if (currentTime - m_LastStateChangeTime[stateName] < stateChangeThreshold)
{
// 改变太频繁,跳过
return;
}
}

m_RenderStates[stateName] = value;
m_LastStateChangeTime[stateName] = currentTime;

if (logContextOperations)
{
Debug.Log($"[RenderContextManager] Set state: {stateName} = {value}");
}
}

// 获取渲染状态
public T GetRenderState<T>(string stateName, T defaultValue = default(T))
{
if (enableStateTracking && m_RenderStates.ContainsKey(stateName))
{
try
{
return (T)m_RenderStates[stateName];
}
catch
{
return defaultValue;
}
}
return defaultValue;
}

// 检查两个对象是否相等(用于状态比较)
private bool AreEqual(object a, object b)
{
if (a == null && b == null) return true;
if (a == null || b == null) return false;

// 特殊处理向量类型
if (a is Vector3 && b is Vector3)
{
return ((Vector3)a == (Vector3)b);
}

if (a is Vector4 && b is Vector4)
{
return ((Vector4)a == (Vector4)b);
}

if (a is Matrix4x4 && b is Matrix4x4)
{
return ((Matrix4x4)a == (Matrix4x4)b);
}

// 一般比较
return a.Equals(b);
}

// 执行命令缓冲区
public void ExecuteCommandBuffer(ScriptableRenderContext context, CommandBuffer cmdBuffer)
{
if (cmdBuffer == null) return;

// 更新作用域中的命令计数
if (m_ContextScopes.Count > 0)
{
var currentScope = m_ContextScopes.Peek();
currentScope.commandCount++;
}

context.ExecuteCommandBuffer(cmdBuffer);
cmdBuffer.Clear(); // 清除已执行的命令

if (logContextOperations)
{
Debug.Log($"[RenderContextManager] Executed command buffer: {cmdBuffer.name}");
}
}

// 提交渲染上下文
public void SubmitRenderContext(ScriptableRenderContext context)
{
context.Submit();

if (logContextOperations)
{
Debug.Log("[RenderContextManager] Submitted render context");
}
}

// 获取上下文统计信息
public string GetContextStats()
{
var stats = new System.Text.StringBuilder();
stats.AppendLine("=== Render Context Statistics ===");
stats.AppendLine($"Command Buffer Pool Size: {m_CommandBufferPool.Count}");
stats.AppendLine($"Active Command Buffers: {m_ActiveCommandBuffers.Count}");
stats.AppendLine($"Max Pool Size: {maxCommandBuffersInPool}");
stats.AppendLine($"Active Scopes: {m_ContextScopes.Count}");
stats.AppendLine($"Tracked States: {m_RenderStates.Count}");

return stats.ToString();
}

// 清理所有资源
public void CleanupAllResources()
{
// 清理命令缓冲区
foreach (var cmdBuffer in m_ActiveCommandBuffers)
{
cmdBuffer.Dispose();
}
m_ActiveCommandBuffers.Clear();

while (m_CommandBufferPool.Count > 0)
{
var cmdBuffer = m_CommandBufferPool.Dequeue();
cmdBuffer.Dispose();
}

// 清理状态
m_RenderStates.Clear();
m_LastStateChangeTime.Clear();

// 清理作用域
m_ContextScopes.Clear();

if (logContextOperations)
{
Debug.Log("[RenderContextManager] All resources cleaned up");
}
}

void OnDestroy()
{
CleanupAllResources();
}
}

14.9 RenderingData扩展分析器

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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class ExtendedRenderingDataAnalyzer : MonoBehaviour
{
[Header("Extended Analysis")]
public bool enableExtendedAnalysis = true;
public bool analyzePerObjectData = true;
public bool analyzePerLightData = true;
public bool logDetailedStats = false;

[Header("Analysis Settings")]
public float analysisUpdateInterval = 0.5f;
public int maxObjectsToAnalyze = 1000;

private float m_LastAnalysisTime = 0f;
private Dictionary<Renderer, RendererAnalysisData> m_RendererAnalysisData = new Dictionary<Renderer, RendererAnalysisData>();
private Dictionary<Light, LightAnalysisData> m_LightAnalysisData = new Dictionary<Light, LightAnalysisData>();

[System.Serializable]
public class RendererAnalysisData
{
public Renderer renderer;
public Material[] materials;
public int triangleCount;
public bool castsShadows;
public ShadowCastingMode shadowMode;
public bool receivesShadows;
public float distanceToCamera;
public int renderQueue;
public bool isStatic;
public string shaderName;
}

[System.Serializable]
public class LightAnalysisData
{
public Light light;
public LightType type;
public float range;
public float intensity;
public Color color;
public bool castsShadows;
public LightShadows shadowType;
public float innerSpotAngle;
public float outerSpotAngle;
public bool enabled;
public float distanceToCamera;
}

[System.Serializable]
public class SceneAnalysisSummary
{
public int totalRenderers;
public int totalLights;
public int shadowCastingRenderers;
public int shadowReceivingRenderers;
public int lightsWithShadows;
public float averageRendererDistance;
public float averageLightIntensity;
public int dynamicBatchableRenderers;
public int staticBatchableRenderers;
}

public SceneAnalysisSummary summary = new SceneAnalysisSummary();

void Update()
{
if (enableExtendedAnalysis && Time.time - m_LastAnalysisTime >= analysisUpdateInterval)
{
PerformExtendedAnalysis();
m_LastAnalysisTime = Time.time;
}
}

private void PerformExtendedAnalysis()
{
if (analyzePerObjectData)
{
AnalyzeRenderers();
}

if (analyzePerLightData)
{
AnalyzeLights();
}

GenerateSummary();

if (logDetailedStats)
{
LogDetailedAnalysis();
}
}

private void AnalyzeRenderers()
{
var renderers = FindObjectsOfType<Renderer>();
m_RendererAnalysisData.Clear();

int analyzedCount = 0;
foreach (var renderer in renderers)
{
if (analyzedCount >= maxObjectsToAnalyze) break;

var analysisData = new RendererAnalysisData
{
renderer = renderer,
materials = renderer.sharedMaterials,
triangleCount = GetRendererTriangleCount(renderer),
castsShadows = renderer.shadowCastingMode != ShadowCastingMode.Off,
shadowMode = renderer.shadowCastingMode,
receivesShadows = renderer.receiveShadows,
distanceToCamera = GetDistanceToMainCamera(renderer),
renderQueue = GetRendererRenderQueue(renderer),
isStatic = renderer.gameObject.isStatic,
shaderName = GetRendererShaderName(renderer)
};

m_RendererAnalysisData[renderer] = analysisData;
analyzedCount++;
}
}

private void AnalyzeLights()
{
var lights = FindObjectsOfType<Light>();
m_LightAnalysisData.Clear();

foreach (var light in lights)
{
var analysisData = new LightAnalysisData
{
light = light,
type = light.type,
range = light.range,
intensity = light.intensity,
color = light.color,
castsShadows = light.shadows != LightShadows.None,
shadowType = light.shadows,
innerSpotAngle = light.innerSpotAngle,
outerSpotAngle = light.spotAngle,
enabled = light.enabled,
distanceToCamera = GetDistanceToMainCamera(light)
};

m_LightAnalysisData[light] = analysisData;
}
}

private void GenerateSummary()
{
summary.totalRenderers = m_RendererAnalysisData.Count;
summary.totalLights = m_LightAnalysisData.Count;

summary.shadowCastingRenderers = 0;
summary.shadowReceivingRenderers = 0;
summary.averageRendererDistance = 0f;

foreach (var kvp in m_RendererAnalysisData)
{
var data = kvp.Value;
if (data.castsShadows) summary.shadowCastingRenderers++;
if (data.receivesShadows) summary.shadowReceivingRenderers++;
summary.averageRendererDistance += data.distanceToCamera;
}

if (summary.totalRenderers > 0)
{
summary.averageRendererDistance /= summary.totalRenderers;
}

summary.lightsWithShadows = 0;
summary.averageLightIntensity = 0f;

foreach (var kvp in m_LightAnalysisData)
{
var data = kvp.Value;
if (data.castsShadows) summary.lightsWithShadows++;
summary.averageLightIntensity += data.intensity;
}

if (summary.totalLights > 0)
{
summary.averageLightIntensity /= summary.totalLights;
}

// 分析批处理能力
summary.dynamicBatchableRenderers = 0;
summary.staticBatchableRenderers = 0;

foreach (var kvp in m_RendererAnalysisData)
{
var data = kvp.Value;
if (data.isStatic)
{
summary.staticBatchableRenderers++;
}
else
{
// 简单判断是否适合动态批处理(顶点数小于300且使用相同材质)
if (data.triangleCount * 3 < 300) // 3个顶点组成一个三角形
{
summary.dynamicBatchableRenderers++;
}
}
}
}

private int GetRendererTriangleCount(Renderer renderer)
{
var meshFilter = renderer.GetComponent<MeshFilter>();
if (meshFilter != null && meshFilter.sharedMesh != null)
{
return meshFilter.sharedMesh.triangles.Length / 3; // 每个三角形有3个顶点
}

// 对于其他类型的渲染器,返回估算值
return 100; // 默认值
}

private float GetDistanceToMainCamera(Component component)
{
var mainCamera = Camera.main;
if (mainCamera != null)
{
return Vector3.Distance(component.transform.position, mainCamera.transform.position);
}
return 0f;
}

private int GetRendererRenderQueue(Renderer renderer)
{
if (renderer.sharedMaterials.Length > 0 && renderer.sharedMaterials[0] != null)
{
return renderer.sharedMaterials[0].renderQueue;
}
return 2000; // 默认渲染队列
}

private string GetRendererShaderName(Renderer renderer)
{
if (renderer.sharedMaterials.Length > 0 && renderer.sharedMaterials[0] != null)
{
return renderer.sharedMaterials[0].shader.name;
}
return "Default";
}

private void LogDetailedAnalysis()
{
var log = new System.Text.StringBuilder();
log.AppendLine("=== Extended Rendering Data Analysis ===");
log.AppendLine($"Total Renderers: {summary.totalRenderers}");
log.AppendLine($"Total Lights: {summary.totalLights}");
log.AppendLine($"Shadow Casting Renderers: {summary.shadowCastingRenderers}");
log.AppendLine($"Shadow Receiving Renderers: {summary.shadowReceivingRenderers}");
log.AppendLine($"Lights with Shadows: {summary.lightsWithShadows}");
log.AppendLine($"Average Renderer Distance: {summary.averageRendererDistance:F2}");
log.AppendLine($"Average Light Intensity: {summary.averageLightIntensity:F2}");
log.AppendLine($"Dynamic Batchable Renderers: {summary.dynamicBatchableRenderers}");
log.AppendLine($"Static Batchable Renderers: {summary.staticBatchableRenderers}");

// 输出前几个渲染器的详细信息
log.AppendLine("\nTop Renderers by Triangle Count:");
var sortedRenderers = new List<RendererAnalysisData>(m_RendererAnalysisData.Values);
sortedRenderers.Sort((a, b) => b.triangleCount.CompareTo(a.triangleCount));

for (int i = 0; i < Mathf.Min(5, sortedRenderers.Count); i++)
{
var data = sortedRenderers[i];
log.AppendLine($" {data.renderer.name}: {data.triangleCount} triangles, " +
$"Shadows: {data.castsShadows}, Distance: {data.distanceToCamera:F1}");
}

// 输出光源信息
log.AppendLine("\nLights Analysis:");
foreach (var kvp in m_LightAnalysisData)
{
var data = kvp.Value;
log.AppendLine($" {data.light.name}: {data.type}({data.intensity} intensity), " +
$"Shadows: {data.castsShadows}, Distance: {data.distanceToCamera:F1}");
}

Debug.Log(log.ToString());
}

// 获取特定渲染器的分析数据
public RendererAnalysisData GetRendererAnalysisData(Renderer renderer)
{
if (m_RendererAnalysisData.ContainsKey(renderer))
{
return m_RendererAnalysisData[renderer];
}
return null;
}

// 获取特定光源的分析数据
public LightAnalysisData GetLightAnalysisData(Light light)
{
if (m_LightAnalysisData.ContainsKey(light))
{
return m_LightAnalysisData[light];
}
return null;
}

// 获取渲染器分析数据列表
public List<RendererAnalysisData> GetRendererAnalysisDataList()
{
return new List<RendererAnalysisData>(m_RendererAnalysisData.Values);
}

// 获取光源分析数据列表
public List<LightAnalysisData> GetLightAnalysisDataList()
{
return new List<LightAnalysisData>(m_LightAnalysisData.Values);
}

// 获取场景分析摘要
public SceneAnalysisSummary GetSceneSummary()
{
return summary;
}

// 获取性能建议
public List<string> GetPerformanceSuggestions()
{
var suggestions = new List<string>();

if (summary.shadowCastingRenderers > 50)
{
suggestions.Add($"High number of shadow casting renderers ({summary.shadowCastingRenderers}). Consider reducing shadow casters for performance.");
}

if (summary.lightsWithShadows > 8)
{
suggestions.Add($"High number of shadow casting lights ({summary.lightsWithShadows}). Consider using baked lighting.");
}

if (summary.dynamicBatchableRenderers > 0 && summary.dynamicBatchableRenderers < summary.totalRenderers * 0.5f)
{
suggestions.Add("Low dynamic batching efficiency. Check materials and mesh sizes.");
}

if (summary.averageLightIntensity > 2.0f)
{
suggestions.Add($"High average light intensity ({summary.averageLightIntensity:F2}). Consider reducing intensities for better performance.");
}

return suggestions;
}
}

14.10 渲染状态管理器

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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

public class RenderStateManager : MonoBehaviour
{
[Header("State Management")]
public bool enableStateValidation = true;
public bool logStateChanges = false;
public bool enableStateCaching = true;

[Header("State Settings")]
public float stateChangeDebounceTime = 0.01f; // 防抖时间

// 当前渲染状态
private Dictionary<string, object> m_CurrentStates = new Dictionary<string, object>();
private Dictionary<string, float> m_LastStateChangeTime = new Dictionary<string, float>();

// 状态历史记录
private Dictionary<string, Queue<object>> m_StateHistory = new Dictionary<string, Queue<object>>();
private int m_HistorySize = 10;

// 状态作用域栈
private Stack<RenderStateScope> m_StateScopes = new Stack<RenderStateScope>();

[System.Serializable]
public class RenderStateScope
{
public string name;
public Dictionary<string, object> savedStates = new Dictionary<string, object>();
public float enterTime;

public RenderStateScope(string scopeName)
{
name = scopeName;
enterTime = Time.realtimeSinceStartup;
}
}

[System.Serializable]
public class StateChange
{
public string stateName;
public object oldValue;
public object newValue;
public float time;

public StateChange(string name, object oldVal, object newVal)
{
stateName = name;
oldValue = oldVal;
newValue = newVal;
time = Time.realtimeSinceStartup;
}
}

private List<StateChange> m_StateChanges = new List<StateChange>();

void Start()
{
InitializeStateManager();
}

private void InitializeStateManager()
{
// 初始化一些默认状态
SetState("DepthTest", CompareFunction.Less);
SetState("DepthWrite", true);
SetState("ColorWrite", true);
SetState("CullMode", CullMode.Back);
}

// 设置渲染状态
public bool SetState(string stateName, object value)
{
if (enableStateValidation && !ValidateStateChange(stateName, value))
{
if (logStateChanges)
{
Debug.LogWarning($"[RenderStateManager] Invalid state change: {stateName} = {value}");
}
return false;
}

// 检查防抖时间
float currentTime = Time.realtimeSinceStartup;
if (m_LastStateChangeTime.ContainsKey(stateName))
{
if (currentTime - m_LastStateChangeTime[stateName] < stateChangeDebounceTime)
{
return false; // 防抖,不执行改变
}
}

object oldValue = null;
bool stateExists = m_CurrentStates.ContainsKey(stateName);

if (stateExists)
{
oldValue = m_CurrentStates[stateName];

// 如果值相同,不执行改变
if (AreEqual(oldValue, value))
{
return false;
}
}

// 记录状态改变
m_CurrentStates[stateName] = value;
m_LastStateChangeTime[stateName] = currentTime;

// 添加到历史记录
if (!m_StateHistory.ContainsKey(stateName))
{
m_StateHistory[stateName] = new Queue<object>();
}

var history = m_StateHistory[stateName];
history.Enqueue(value);
if (history.Count > m_HistorySize)
{
history.Dequeue();
}

// 记录状态改变
m_StateChanges.Add(new StateChange(stateName, oldValue, value));
if (m_StateChanges.Count > 100) // 限制历史记录大小
{
m_StateChanges.RemoveAt(0);
}

if (logStateChanges)
{
Debug.Log($"[RenderStateManager] State changed: {stateName} = {value} (was: {oldValue})");
}

return true;
}

// 获取渲染状态
public T GetState<T>(string stateName, T defaultValue = default(T))
{
if (m_CurrentStates.ContainsKey(stateName))
{
try
{
return (T)m_CurrentStates[stateName];
}
catch
{
if (logStateChanges)
{
Debug.LogWarning($"[RenderStateManager] Type mismatch for state: {stateName}");
}
return defaultValue;
}
}
return defaultValue;
}

// 开始状态作用域
public void BeginStateScope(string scopeName)
{
var scope = new RenderStateScope(scopeName);

// 保存当前状态
foreach (var kvp in m_CurrentStates)
{
scope.savedStates[kvp.Key] = kvp.Value;
}

m_StateScopes.Push(scope);

if (logStateChanges)
{
Debug.Log($"[RenderStateManager] Begin state scope: {scopeName}");
}
}

// 结束状态作用域
public void EndStateScope()
{
if (m_StateScopes.Count > 0)
{
var scope = m_StateScopes.Pop();

// 恢复之前保存的状态
var statesToRestore = new Dictionary<string, object>(scope.savedStates);

// 先移除当前作用域中新增的状态
var statesToRemove = new List<string>();
foreach (var kvp in m_CurrentStates)
{
if (!scope.savedStates.ContainsKey(kvp.Key))
{
statesToRemove.Add(kvp.Key);
}
}

foreach (var state in statesToRemove)
{
m_CurrentStates.Remove(state);
if (m_LastStateChangeTime.ContainsKey(state))
{
m_LastStateChangeTime.Remove(state);
}
if (m_StateHistory.ContainsKey(state))
{
m_StateHistory.Remove(state);
}
}

// 恢复保存的状态
foreach (var kvp in scope.savedStates)
{
m_CurrentStates[kvp.Key] = kvp.Value;
}

if (logStateChanges)
{
Debug.Log($"[RenderStateManager] End state scope: {scope.name}");
}
}
}

// 验证状态改变的有效性
private bool ValidateStateChange(string stateName, object value)
{
switch (stateName)
{
case "DepthTest":
return value is CompareFunction;
case "DepthWrite":
return value is bool;
case "ColorWrite":
return value is bool || value is ColorWriteMask;
case "CullMode":
return value is CullMode;
case "BlendSrc":
case "BlendDst":
return value is BlendMode;
case "ZTest":
return value is CompareFunction;
default:
return true; // 默认允许所有状态改变
}
}

// 检查两个对象是否相等
private bool AreEqual(object a, object b)
{
if (a == null && b == null) return true;
if (a == null || b == null) return false;

// 特殊处理向量类型
if (a is Vector3 && b is Vector3)
{
return ((Vector3)a - (Vector3)b).magnitude < 0.001f;
}

if (a is Vector4 && b is Vector4)
{
return ((Vector4)a - (Vector4)b).magnitude < 0.001f;
}

if (a is Matrix4x4 && b is Matrix4x4)
{
return ((Matrix4x4)a == (Matrix4x4)b);
}

// 一般比较
return a.Equals(b);
}

// 获取状态历史
public object[] GetStateHistory(string stateName)
{
if (m_StateHistory.ContainsKey(stateName))
{
return m_StateHistory[stateName].ToArray();
}
return new object[0];
}

// 获取最近的状态改变
public StateChange[] GetRecentStateChanges(int count = 10)
{
int startIndex = Mathf.Max(0, m_StateChanges.Count - count);
var changes = new StateChange[m_StateChanges.Count - startIndex];

for (int i = startIndex; i < m_StateChanges.Count; i++)
{
changes[i - startIndex] = m_StateChanges[i];
}

return changes;
}

// 重置所有状态
public void ResetAllStates()
{
m_CurrentStates.Clear();
m_LastStateChangeTime.Clear();
m_StateHistory.Clear();
m_StateChanges.Clear();

// 重新初始化默认状态
InitializeStateManager();

if (logStateChanges)
{
Debug.Log("[RenderStateManager] All states reset");
}
}

// 获取当前状态统计
public string GetStateStats()
{
var stats = new System.Text.StringBuilder();
stats.AppendLine("=== Render State Statistics ===");
stats.AppendLine($"Current States: {m_CurrentStates.Count}");
stats.AppendLine($"State Scopes: {m_StateScopes.Count}");
stats.AppendLine($"Recent State Changes: {m_StateChanges.Count}");
stats.AppendLine($"History Size Limit: {m_HistorySize}");

if (m_CurrentStates.Count > 0)
{
stats.AppendLine("\nCurrent States:");
foreach (var kvp in m_CurrentStates)
{
stats.AppendLine($" {kvp.Key}: {kvp.Value}");
}
}

return stats.ToString();
}

// 应用状态到CommandBuffer
public void ApplyStatesToCommandBuffer(CommandBuffer cmd)
{
// 应用深度测试状态
if (m_CurrentStates.ContainsKey("DepthTest"))
{
var depthTest = GetState<CompareFunction>("DepthTest", CompareFunction.Less);
cmd.SetGlobalInt("_ZTest", (int)depthTest);
}

// 应用深度写入状态
if (m_CurrentStates.ContainsKey("DepthWrite"))
{
var depthWrite = GetState<bool>("DepthWrite", true);
cmd.SetGlobalInt("_ZWrite", depthWrite ? 1 : 0);
}

// 应用颜色写入状态
if (m_CurrentStates.ContainsKey("ColorWrite"))
{
if (m_CurrentStates["ColorWrite"] is bool)
{
var colorWrite = GetState<bool>("ColorWrite", true);
cmd.SetGlobalInt("_ColorWrite", colorWrite ? 0xF : 0x0); // RGBA all channels
}
else if (m_CurrentStates["ColorWrite"] is ColorWriteMask)
{
var colorWriteMask = GetState<ColorWriteMask>("ColorWrite", ColorWriteMask.All);
cmd.SetGlobalInt("_ColorWrite", (int)colorWriteMask);
}
}

// 应用剔除模式状态
if (m_CurrentStates.ContainsKey("CullMode"))
{
var cullMode = GetState<CullMode>("CullMode", CullMode.Back);
cmd.SetGlobalInt("_CullMode", (int)cullMode);
}
}
}

实践练习

14.11 练习1:RenderingData访问分析

目标:创建一个工具来分析RenderingData中的各种数据

步骤

  1. 创建RenderingDataAnalyzer类
  2. 实现相机数据访问
  3. 实现光照数据分析
  4. 实现阴影数据统计
  5. 测试分析工具的功能

实现要点

  • 使用RenderPipelineManager事件
  • 分析各种渲染数据
  • 生成性能报告

14.12 练习2:渲染上下文管理

目标:实现渲染上下文的管理和优化

步骤

  1. 创建RenderContextManager类
  2. 实现命令缓冲区池化
  3. 实现上下文作用域管理
  4. 实现状态跟踪功能
  5. 测试性能优化效果

关键技术

  • CommandBuffer池化
  • 作用域管理
  • 状态跟踪

14.13 练习3:扩展数据分析师

目标:创建详细的场景数据分析师

步骤

  1. 实现渲染器数据分析
  2. 实现光源数据分析
  3. 生成场景摘要
  4. 提供性能建议
  5. 优化分析性能

分析维度

  • 几何体复杂度
  • 光照配置
  • 阴影设置
  • 批处理能力

14.14 练习4:渲染状态管理

目标:实现渲染状态的有效管理

步骤

  1. 创建RenderStateManager
  2. 实现状态设置和获取
  3. 实现状态作用域
  4. 实现状态验证
  5. 测试状态管理效果

管理功能

  • 状态缓存
  • 防抖机制
  • 作用域恢复

14.15 练习5:性能监控与优化

目标:实现渲染性能的全面监控

步骤

  1. 集成所有分析工具
  2. 实现实时性能监控
  3. 生成性能报告
  4. 提供优化建议
  5. 验证优化效果

监控指标

  • 渲染状态变化
  • 命令缓冲区使用
  • 绘制调用统计

总结

第14章深入探讨了RenderingData与Context的概念,这是URP渲染管线中数据传递和上下文管理的核心机制。RenderingData封装了渲染所需的所有数据,而ScriptableRenderContext提供了执行渲染命令的环境。

关键要点总结:

  1. 数据结构:RenderingData包含CameraData、LightData、ShadowData等组件
  2. 上下文管理:ScriptableRenderContext管理渲染命令的执行
  3. 数据传递:通过ref参数高效传递渲染数据
  4. 状态管理:正确管理渲染状态确保渲染正确性
  5. 资源管理:CommandBuffer池化和作用域管理

理解RenderingData与Context的机制对于开发高效的渲染功能至关重要,它确保了渲染管线中数据的一致性和执行的正确性。通过合理的状态管理和资源管理,可以显著提升渲染性能。

下一章将分析光照与阴影的源码实现,深入了解URP中光照系统的内部工作原理。