第12章 Forward Renderer源码分析

第12章 Forward Renderer源码分析

理论讲解

12.1 ForwardRenderer.cs核心代码结构

ForwardRenderer是URP中默认的渲染器实现,它采用前向渲染技术,适用于大多数移动和VR平台。ForwardRenderer继承自ScriptableRenderer,实现了具体的渲染逻辑。

ForwardRenderer主要职责

  1. 渲染通道管理:管理一系列预定义的渲染通道
  2. 相机数据处理:处理相机的渲染数据和配置
  3. 渲染特性集成:集成各种渲染特性(如后处理、阴影等)
  4. 资源分配:管理渲染过程中使用的临时资源

ForwardRenderer架构特点

  • 前向渲染:每个物体与所有光源进行光照计算
  • 多Pass处理:通过多个渲染通道处理不同类型的几何体
  • 可扩展性:支持通过Renderer Features扩展功能

12.2 Setup()方法执行流程

Setup()方法是ForwardRenderer的核心方法,负责配置渲染器以准备渲染。

Setup方法主要步骤

  1. 清除现有通道:清空之前的渲染通道队列
  2. 配置相机数据:根据相机数据配置渲染参数
  3. 创建渲染通道:根据配置创建相应的渲染通道
  4. 添加渲染特性:将注册的渲染特性添加到通道队列

Setup方法执行顺序

  • 深度预通道(可选)
  • 主光源阴影通道
  • 附加光源阴影通道
  • 深度贴图通道
  • 不透明几何体通道
  • 透明几何体通道
  • 后处理通道(可选)

12.3 RenderPass的添加与执行顺序

ForwardRenderer通过一系列预定义的RenderPass来实现完整的渲染流程。

主要RenderPass类型

  1. DepthPrepass:深度预通道,用于生成深度纹理
  2. MainLightShadowCasterPass:主光源阴影投射通道
  3. AdditionalLightsShadowCasterPass:附加光源阴影投射通道
  4. OpaquePass:不透明几何体渲染通道
  5. TransparentPass:透明几何体渲染通道
  6. PostProcessPass:后处理通道

RenderPass执行顺序

  • 阴影通道:首先渲染所有阴影贴图
  • 深度通道:生成深度信息(如果需要)
  • 不透明通道:渲染不透明几何体
  • 透明通道:渲染透明几何体
  • 后处理通道:应用后处理效果

12.4 渲染状态管理

ForwardRenderer需要管理复杂的渲染状态,包括渲染目标、深度状态、混合状态等。

渲染状态类型

  • 渲染目标状态:当前的渲染目标和深度目标
  • 深度状态:深度测试、深度写入设置
  • 混合状态:颜色混合模式
  • 光栅化状态:光栅化设置

状态管理策略

  • 状态缓存:缓存当前渲染状态以避免不必要的状态切换
  • 状态验证:在设置新状态前验证是否需要更改
  • 状态恢复:在渲染完成后恢复原始状态

12.5 多Pass协调机制

ForwardRenderer通过精心设计的多Pass协调机制实现高效的渲染流程。

Pass间数据传递

  • 纹理传递:通过渲染纹理在Pass间传递数据
  • 缓冲区共享:共享常量缓冲区和顶点缓冲区
  • 状态继承:后续Pass继承前序Pass的某些状态

协调机制实现

  • 依赖管理:确保Pass按正确的依赖顺序执行
  • 资源管理:合理分配和释放渲染资源
  • 性能优化:最小化Pass间的切换开销

12.6 Forward vs Deferred渲染对比

Forward渲染优势

  • 内存效率:不需要G-Buffer,内存占用较低
  • 透明度支持:天然支持透明物体渲染
  • 简单性:渲染流程相对简单
  • 移动友好:适合移动和VR平台

Forward渲染限制

  • 光源限制:每个物体需要与所有光源计算
  • 性能瓶颈:大量光源时性能下降
  • 复杂光照:难以实现复杂的全局光照

代码示例

12.7 ForwardRenderer核心实现分析

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
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

// 这是一个模拟的ForwardRenderer实现,用于演示核心概念
public class CustomForwardRenderer : ScriptableRenderer
{
// 渲染器配置
private ForwardRendererData m_RendererData;
private List<ScriptableRenderPass> m_ActiveRenderPassQueue = new List<ScriptableRenderPass>();
private List<RendererFeature> m_RendererFeatures = new List<RendererFeature>();

// 渲染资源
private RenderTargetHandle m_CameraColorTarget;
private RenderTargetHandle m_CameraDepthTarget;
private RenderTargetHandle m_DepthTexture;
private RenderTargetHandle m_OpaqueColor;

// 状态管理
private bool m_CreateDepthTexture;
private bool m_CreateOpaqueTexture;
private bool m_SupportsDynamicBatching;
private bool m_SupportsMixedLighting;

public CustomForwardRenderer(ForwardRendererData data) : base(data)
{
m_RendererData = data;
m_CreateDepthTexture = data.depthTextureFormat != DepthTextureFormat.None;
m_CreateOpaqueTexture = data.opaqueDownsampling != OpaqueTextureDownsampling.None;
m_SupportsDynamicBatching = data.supportsDynamicBatching;
m_SupportsMixedLighting = data.supportsMixedLighting;

// 初始化渲染目标句柄
m_CameraColorTarget.Init("_CameraColorTexture");
m_CameraDepthTarget.Init("_CameraDepthTexture");
m_DepthTexture.Init("_CameraDepthAttachment");
m_OpaqueColor.Init("_AfterOpaqueTexture");
}

public override void Setup(ScriptableRenderContext context, ref RenderingData renderingData)
{
// 清空之前的渲染通道队列
m_ActiveRenderPassQueue.Clear();

// 配置相机数据
var cameraData = renderingData.cameraData;
var lightData = renderingData.lightData;
var shadowData = renderingData.shadowData;

// 创建渲染通道
ConfigureRenderPasses(ref renderingData);

// 添加渲染特性
AddRendererFeatures(ref renderingData);

// 配置相机渲染目标
ConfigureCameraTarget(
m_CameraColorTarget.Identifier(),
m_DepthTexture.Identifier()
);
}

private void ConfigureRenderPasses(ref RenderingData renderingData)
{
var cameraData = renderingData.cameraData;
var lightData = renderingData.lightData;
var shadowData = renderingData.shadowData;

// 1. 深度预通道(如果需要)
if (m_CreateDepthTexture && cameraData.captureActions == null)
{
var depthPrepass = CreateDepthPrepass();
if (depthPrepass != null)
{
m_ActiveRenderPassQueue.Add(depthPrepass);
}
}

// 2. 主光源阴影通道
if (shadowData.supportsMainLightShadows)
{
var mainShadowPass = CreateMainLightShadowPass(ref renderingData);
if (mainShadowPass != null)
{
m_ActiveRenderPassQueue.Add(mainShadowPass);
}
}

// 3. 附加光源阴影通道
if (shadowData.supportsAdditionalLightShadows)
{
var additionalShadowPass = CreateAdditionalLightShadowPass(ref renderingData);
if (additionalShadowPass != null)
{
m_ActiveRenderPassQueue.Add(additionalShadowPass);
}
}

// 4. 不透明渲染通道
var opaquePass = CreateOpaquePass(ref renderingData);
if (opaquePass != null)
{
m_ActiveRenderPassQueue.Add(opaquePass);
}

// 5. 透明渲染通道
var transparentPass = CreateTransparentPass(ref renderingData);
if (transparentPass != null)
{
m_ActiveRenderPassQueue.Add(transparentPass);
}

// 6. 后处理通道(如果启用)
if (renderingData.postProcessingData.IsEnabled())
{
var postProcessPass = CreatePostProcessPass(ref renderingData);
if (postProcessPass != null)
{
m_ActiveRenderPassQueue.Add(postProcessPass);
}
}
}

private ScriptableRenderPass CreateDepthPrepass()
{
// 创建深度预通道,用于生成深度纹理
var depthPrepass = new DepthOnlyPass(
RenderPassEvent.BeforeRenderingOpaques,
m_DepthTexture,
new RenderStateMask()
);

return depthPrepass;
}

private ScriptableRenderPass CreateMainLightShadowPass(ref RenderingData renderingData)
{
// 创建主光源阴影通道
var shadowSettings = new ShadowDrawingSettings(renderingData.cullResults, 0);
var mainShadowPass = new MainLightShadowCasterPass(
RenderPassEvent.BeforeRenderingShadows,
shadowSettings
);

return mainShadowPass;
}

private ScriptableRenderPass CreateAdditionalLightShadowPass(ref RenderingData renderingData)
{
// 创建附加光源阴影通道
var additionalShadowPass = new AdditionalLightsShadowCasterPass(
RenderPassEvent.BeforeRenderingPrePasses,
renderingData.lightData.additionalLightsVisibilityIndex
);

return additionalShadowPass;
}

private ScriptableRenderPass CreateOpaquePass(ref RenderingData renderingData)
{
// 创建不透明渲染通道
var opaquePass = new CustomOpaquePass(
RenderPassEvent.BeforeRenderingOpaques,
m_CameraColorTarget,
m_CameraDepthTarget,
renderingData.cameraData.requiresDepthTexture,
renderingData.cameraData.requiresOpaqueTexture
);

return opaquePass;
}

private ScriptableRenderPass CreateTransparentPass(ref RenderingData renderingData)
{
// 创建透明渲染通道
var transparentPass = new CustomTransparentPass(
RenderPassEvent.BeforeRenderingTransparents,
m_CameraColorTarget,
renderingData.cameraData.requiresDepthTexture
);

return transparentPass;
}

private ScriptableRenderPass CreatePostProcessPass(ref RenderingData renderingData)
{
// 创建后处理通道
var postProcessPass = new CustomPostProcessPass(
RenderPassEvent.AfterRenderingPostProcessing,
renderingData.postProcessingData
);

return postProcessPass;
}

private void AddRendererFeatures(ref RenderingData renderingData)
{
// 添加渲染特性到队列
foreach (var feature in m_RendererFeatures)
{
if (feature?.isActive != false)
{
feature.AddRenderPasses(this, ref renderingData);
}
}
}

public override void EnqueuePass(ScriptableRenderPass pass)
{
if (pass != null)
{
m_ActiveRenderPassQueue.Add(pass);
}
}

public override void SetupLights(ScriptableRenderContext context, ref RenderingData renderingData)
{
// 设置光照数据
base.SetupLights(context, ref renderingData);
}

public override void SetupCullingParameters(ref ScriptableCullingParameters cullingParameters, ref CameraData cameraData)
{
// 设置裁剪参数
base.SetupCullingParameters(ref cullingParameters, ref cameraData);
}

public override void Render(ScriptableRenderContext renderContext, ref RenderingData renderingData)
{
// 执行所有渲染通道
for (int i = 0; i < m_ActiveRenderPassQueue.Count; i++)
{
var pass = m_ActiveRenderPassQueue[i];
pass.Execute(renderContext, ref renderingData);
}

// 清理渲染通道
for (int i = 0; i < m_ActiveRenderPassQueue.Count; i++)
{
var pass = m_ActiveRenderPassQueue[i];
pass.FrameCleanup(ref renderingData);
}
}

// 添加渲染特性
public void AddRendererFeature(RendererFeature feature)
{
if (feature != null)
{
m_RendererFeatures.Add(feature);
feature.Create();
}
}

// 移除渲染特性
public void RemoveRendererFeature(RendererFeature feature)
{
if (feature != null)
{
m_RendererFeatures.Remove(feature);
}
}

// 清空所有渲染特性
public void ClearRendererFeatures()
{
m_RendererFeatures.Clear();
}
}

// 自定义不透明渲染通道
public class CustomOpaquePass : ScriptableRenderPass
{
private FilteringSettings m_FilteringSettings;
private List<ShaderTagId> m_ShaderTagIdList = new List<ShaderTagId>();
private RenderTargetHandle m_ColorAttachmentHandle;
private RenderTargetHandle m_DepthAttachmentHandle;
private bool m_RequiresDepthTexture;
private bool m_RequiresOpaqueTexture;

public CustomOpaquePass(
RenderPassEvent renderPassEvent,
RenderTargetHandle colorAttachment,
RenderTargetHandle depthAttachment,
bool requiresDepthTexture,
bool requiresOpaqueTexture)
{
this.renderPassEvent = renderPassEvent;
m_ColorAttachmentHandle = colorAttachment;
m_DepthAttachmentHandle = depthAttachment;
m_RequiresDepthTexture = requiresDepthTexture;
m_RequiresOpaqueTexture = requiresOpaqueTexture;

// 添加常用的Shader标签
m_ShaderTagIdList.Add(new ShaderTagId("SRPDefaultUnlit"));
m_ShaderTagIdList.Add(new ShaderTagId("UniversalForward"));
m_ShaderTagIdList.Add(new ShaderTagId("LightweightForward"));

// 设置过滤条件
m_FilteringSettings = new FilteringSettings(RenderQueueRange.opaque);
}

public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
// 配置渲染通道
if (m_RequiresOpaqueTexture)
{
ConfigureTarget(m_ColorAttachmentHandle.Identifier(), m_DepthAttachmentHandle.Identifier());
}
else
{
ConfigureTarget(cameraTextureDescriptor.colorFormat, cameraTextureDescriptor.depthBufferFormat);
}

ConfigureClear(ClearFlag.All, Color.black);
}

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var drawingSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, SortingCriteria.CommonOpaque);
var filterSettings = m_FilteringSettings;

context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref filterSettings);
}

public override void FrameCleanup(ref RenderingData renderingData)
{
// 清理帧资源
}
}

// 自定义透明渲染通道
public class CustomTransparentPass : ScriptableRenderPass
{
private FilteringSettings m_FilteringSettings;
private List<ShaderTagId> m_ShaderTagIdList = new List<ShaderTagId>();
private RenderTargetHandle m_ColorAttachmentHandle;
private bool m_RequiresDepthTexture;

public CustomTransparentPass(
RenderPassEvent renderPassEvent,
RenderTargetHandle colorAttachment,
bool requiresDepthTexture)
{
this.renderPassEvent = renderPassEvent;
m_ColorAttachmentHandle = colorAttachment;
m_RequiresDepthTexture = requiresDepthTexture;

// 添加透明Shader标签
m_ShaderTagIdList.Add(new ShaderTagId("SRPDefaultUnlit"));
m_ShaderTagIdList.Add(new ShaderTagId("UniversalForward"));
m_ShaderTagIdList.Add(new ShaderTagId("LightweightForward"));

// 设置透明渲染的过滤条件
m_FilteringSettings = new FilteringSettings(RenderQueueRange.transparent);
}

public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
ConfigureTarget(m_ColorAttachmentHandle.Identifier(), m_RequiresDepthTexture ? BuiltinRenderTextureType.CurrentActive : BuiltinRenderTextureType.None);
ConfigureClear(ClearFlag.None, Color.black);
}

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var drawingSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, SortingCriteria.CommonTransparent);
var filterSettings = m_FilteringSettings;

context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref filterSettings);
}

public override void FrameCleanup(ref RenderingData renderingData)
{
// 清理透明渲染通道资源
}
}

// 自定义后处理通道
public class CustomPostProcessPass : ScriptableRenderPass
{
private PostProcessData m_PostProcessData;
private RenderTargetHandle m_Source;
private RenderTargetHandle m_Destination;

public CustomPostProcessPass(RenderPassEvent renderPassEvent, PostProcessData postProcessData)
{
this.renderPassEvent = renderPassEvent;
m_PostProcessData = postProcessData;

m_Source.Init("_PostProcessSource");
m_Destination.Init("_PostProcessDest");
}

public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
ConfigureTarget(m_Destination.Identifier(), BuiltinRenderTextureType.None);
ConfigureClear(ClearFlag.None, Color.black);
}

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
// 执行后处理逻辑
if (renderingData.cameraData.postProcessEnabled)
{
// 这里会执行实际的后处理效果
// 具体实现会根据启用的后处理效果而定
}
}

public override void FrameCleanup(ref RenderingData renderingData)
{
// 清理后处理资源
}
}

12.8 ForwardRenderer配置分析器

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

public class ForwardRendererAnalyzer : MonoBehaviour
{
[Header("Analyzer Settings")]
public bool enableAnalysis = true;
public bool logConfiguration = true;
public bool validateSetup = true;

[Header("Performance Thresholds")]
public float warningSetupTime = 5.0f; // 毫秒
public int maxRenderPasses = 20;
public int maxRendererFeatures = 10;

private Dictionary<string, object> rendererConfig = new Dictionary<string, object>();
private List<string> analysisLogs = new List<string>();
private float setupStartTime;

void Start()
{
if (enableAnalysis)
{
AnalyzeCurrentRenderer();
}
}

public void AnalyzeCurrentRenderer()
{
analysisLogs.Clear();

// 获取当前渲染管线
var currentPipeline = RenderPipelineManager.currentPipeline;
if (currentPipeline == null)
{
analysisLogs.Add("No active render pipeline found");
return;
}

analysisLogs.Add("=== Forward Renderer Analysis ===");
analysisLogs.Add($"Render Pipeline Type: {currentPipeline.GetType().Name}");

// 分析相机数据
AnalyzeCameraData();

// 分析渲染器配置
AnalyzeRendererConfiguration();

// 分析渲染通道
AnalyzeRenderPasses();

// 分析渲染特性
AnalyzeRendererFeatures();

// 输出分析结果
if (logConfiguration)
{
foreach (var log in analysisLogs)
{
Debug.Log(log);
}
}
}

private void AnalyzeCameraData()
{
var cameras = FindObjectsOfType<Camera>();
analysisLogs.Add($"\nCamera Analysis:");
analysisLogs.Add($"Number of Cameras: {cameras.Length}");

foreach (var camera in cameras)
{
var urpData = camera.GetUniversalAdditionalCameraData();
if (urpData != null)
{
analysisLogs.Add($" Camera '{camera.name}':");
analysisLogs.Add($" - Renderer Index: {urpData.rendererIndex}");
analysisLogs.Add($" - Render Type: {urpData.renderType}");
analysisLogs.Add($" - Requires Depth Texture: {urpData.requiresDepthTexture}");
analysisLogs.Add($" - Requires Opaque Texture: {urpData.requiresOpaqueTexture}");
analysisLogs.Add($" - Allow HDR: {urpData.allowHDR}");
analysisLogs.Add($" - Allow MSAA: {urpData.allowMSAA}");
analysisLogs.Add($" - Allow Dynamic batching: {urpData.allowDynamicBatching}");
}
}
}

private void AnalyzeRendererConfiguration()
{
analysisLogs.Add($"\nRenderer Configuration Analysis:");

// 获取ForwardRendererData(如果可用)
var rendererAssets = FindObjectsOfType<ForwardRendererData>();
if (rendererAssets.Length > 0)
{
var rendererData = rendererAssets[0]; // 使用第一个找到的
analysisLogs.Add($"Found {rendererAssets.Length} ForwardRendererData assets");
analysisLogs.Add($"Renderer Data Name: {rendererData.name}");
analysisLogs.Add($"Depth Texture Format: {rendererData.depthTextureFormat}");
analysisLogs.Add($"Opaque Downsampling: {rendererData.opaqueDownsampling}");
analysisLogs.Add($"Supports Dynamic Batching: {rendererData.supportsDynamicBatching}");
analysisLogs.Add($"Supports Mixed Lighting: {rendererData.supportsMixedLighting}");
analysisLogs.Add($"Renderer Features Count: {rendererData.rendererFeatures.Count}");
}
else
{
analysisLogs.Add("No ForwardRendererData assets found in scene");
}
}

private void AnalyzeRenderPasses()
{
analysisLogs.Add($"\nRender Passes Analysis:");

// 这里我们模拟分析渲染通道
// 在实际应用中,需要访问渲染器的内部状态
analysisLogs.Add("Render Passes: Cannot directly access from outside renderer");
analysisLogs.Add($"Max Render Passes Threshold: {maxRenderPasses}");

if (maxRenderPasses > 15)
{
analysisLogs.Add("WARNING: High number of render passes may impact performance");
}
}

private void AnalyzeRendererFeatures()
{
analysisLogs.Add($"\nRenderer Features Analysis:");

var rendererAssets = FindObjectsOfType<ForwardRendererData>();
if (rendererAssets.Length > 0)
{
var rendererData = rendererAssets[0];
var features = rendererData.rendererFeatures;

analysisLogs.Add($"Number of Renderer Features: {features.Count}");
analysisLogs.Add($"Max Renderer Features Threshold: {maxRendererFeatures}");

for (int i = 0; i < features.Count; i++)
{
var feature = features[i];
if (feature != null)
{
analysisLogs.Add($" Feature {i}: {feature.name} (Type: {feature.GetType().Name}, Active: {feature.isActive})");
}
}

if (features.Count > maxRendererFeatures)
{
analysisLogs.Add($"WARNING: Too many renderer features ({features.Count} > {maxRendererFeatures})");
}
}
}

// 验证渲染器设置
public bool ValidateRendererSetup()
{
if (!validateSetup) return true;

var isValid = true;
var validationLogs = new List<string>();

// 验证渲染器特性数量
var rendererAssets = FindObjectsOfType<ForwardRendererData>();
if (rendererAssets.Length > 0)
{
var features = rendererAssets[0].rendererFeatures;
if (features.Count > maxRendererFeatures)
{
validationLogs.Add($"Too many renderer features: {features.Count} > {maxRendererFeatures}");
isValid = false;
}
}

// 输出验证结果
if (validationLogs.Count > 0)
{
foreach (var log in validationLogs)
{
Debug.LogWarning($"[Renderer Validation] {log}");
}
}
else
{
Debug.Log("[Renderer Validation] Setup is valid");
}

return isValid;
}

// 获取渲染器统计信息
public string GetRendererStats()
{
var stats = new System.Text.StringBuilder();

stats.AppendLine("=== Forward Renderer Statistics ===");

// 相机统计
var cameras = FindObjectsOfType<Camera>();
stats.AppendLine($"Active Cameras: {cameras.Length}");

// 渲染器特性统计
var rendererAssets = FindObjectsOfType<ForwardRendererData>();
if (rendererAssets.Length > 0)
{
var features = rendererAssets[0].rendererFeatures;
stats.AppendLine($"Renderer Features: {features.Count}");
}

// 性能相关设置
stats.AppendLine($"SRP Batcher: {GraphicsSettings.useScriptableRenderPipelineBatching}");
stats.AppendLine($"LOD Bias: {QualitySettings.lodBias}");
stats.AppendLine($"Anisotropic Filtering: {QualitySettings.anisotropicFiltering}");

return stats.ToString();
}

// 性能分析
public void PerformanceAnalysis()
{
var startTime = Time.realtimeSinceStartup;

// 模拟渲染器设置操作
var rendererAssets = FindObjectsOfType<ForwardRendererData>();
if (rendererAssets.Length > 0)
{
// 这里可以测量实际的设置时间
System.Threading.Thread.Sleep(1); // 模拟处理时间
}

var setupTime = (Time.realtimeSinceStartup - startTime) * 1000f; // 转换为毫秒

if (setupTime > warningSetupTime)
{
Debug.LogWarning($"[Performance] Renderer setup took {setupTime:F2}ms (threshold: {warningSetupTime}ms)");
}
else
{
Debug.Log($"[Performance] Renderer setup took {setupTime:F2}ms");
}
}
}

12.9 渲染通道性能监控器

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

public class RenderPassPerformanceMonitor : MonoBehaviour
{
[System.Serializable]
public class RenderPassStats
{
public string name;
public int executionCount;
public float totalTime;
public float averageTime;
public float maxTime;
public int drawCallCount;
public int triangleCount;
public bool isActive;
}

[Header("Performance Monitoring")]
public bool enableMonitoring = true;
public float monitoringInterval = 1.0f;
public bool logPerformanceData = true;

[Header("Performance Thresholds")]
public float warningPassTime = 5.0f; // 毫秒
public int warningDrawCalls = 50;
public int warningTriangles = 10000;

private Dictionary<string, RenderPassStats> passStats = new Dictionary<string, RenderPassStats>();
private float lastMonitoringTime = 0f;
private List<string> performanceWarnings = new List<string>();

void Update()
{
if (enableMonitoring && Time.time - lastMonitoringTime >= monitoringInterval)
{
AnalyzePerformance();
lastMonitoringTime = Time.time;
}
}

public void RecordPassExecution(string passName, float executionTime, int drawCalls = 0, int triangles = 0)
{
if (!enableMonitoring) return;

if (!passStats.ContainsKey(passName))
{
passStats[passName] = new RenderPassStats
{
name = passName,
executionCount = 0,
totalTime = 0f,
averageTime = 0f,
maxTime = 0f,
drawCallCount = 0,
triangleCount = 0,
isActive = true
};
}

var stats = passStats[passName];
stats.executionCount++;
stats.totalTime += executionTime;
stats.averageTime = stats.totalTime / stats.executionCount;
if (executionTime > stats.maxTime) stats.maxTime = executionTime;
stats.drawCallCount += drawCalls;
stats.triangleCount += triangles;
}

private void AnalyzePerformance()
{
performanceWarnings.Clear();

foreach (var kvp in passStats)
{
var stats = kvp.Value;

// 检查执行时间
if (stats.maxTime > warningPassTime)
{
performanceWarnings.Add($"Pass '{stats.name}' max time {stats.maxTime:F2}ms > threshold {warningPassTime}ms");
}

// 检查平均每帧时间
if (stats.averageTime > warningPassTime / 2)
{
performanceWarnings.Add($"Pass '{stats.name}' avg time {stats.averageTime:F2}ms is high");
}

// 检查绘制调用
if (stats.drawCallCount > warningDrawCalls)
{
performanceWarnings.Add($"Pass '{stats.name}' draw calls {stats.drawCallCount} > threshold {warningDrawCalls}");
}
}

// 输出性能数据
if (logPerformanceData)
{
OutputPerformanceData();
}

// 输出警告
if (performanceWarnings.Count > 0)
{
foreach (var warning in performanceWarnings)
{
Debug.LogWarning($"[Render Pass Performance] {warning}");
}
}
}

private void OutputPerformanceData()
{
var output = new System.Text.StringBuilder();
output.AppendLine("=== Render Pass Performance Data ===");

foreach (var kvp in passStats)
{
var stats = kvp.Value;
output.AppendLine($"Pass: {stats.name}");
output.AppendLine($" Executions: {stats.executionCount}");
output.AppendLine($" Total Time: {stats.totalTime:F2}ms");
output.AppendLine($" Average Time: {stats.averageTime:F2}ms");
output.AppendLine($" Max Time: {stats.maxTime:F2}ms");
output.AppendLine($" Total Draw Calls: {stats.drawCallCount}");
output.AppendLine($" Total Triangles: {stats.triangleCount}");
output.AppendLine("");
}

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

// 获取特定通道的统计信息
public RenderPassStats GetPassStats(string passName)
{
if (passStats.ContainsKey(passName))
{
return passStats[passName];
}
return null;
}

// 重置所有统计信息
public void ResetAllStats()
{
passStats.Clear();
performanceWarnings.Clear();
}

// 重置特定通道的统计信息
public void ResetPassStats(string passName)
{
if (passStats.ContainsKey(passName))
{
passStats.Remove(passName);
}
}

// 获取性能报告
public string GetPerformanceReport()
{
var report = new System.Text.StringBuilder();

report.AppendLine("=== Render Pass Performance Report ===");
report.AppendLine($"Monitoring Interval: {monitoringInterval}s");
report.AppendLine($"Total Passes Monitored: {passStats.Count}");

if (passStats.Count > 0)
{
// 按执行时间排序
var sortedPasses = new List<RenderPassStats>();
foreach (var kvp in passStats)
{
sortedPasses.Add(kvp.Value);
}
sortedPasses.Sort((a, b) => b.averageTime.CompareTo(a.averageTime));

report.AppendLine("\nTop Performance Impacting Passes:");
foreach (var stats in sortedPasses)
{
report.AppendLine($" {stats.name}: {stats.averageTime:F2}ms avg, {stats.maxTime:F2}ms max");
}
}

return report.ToString();
}

// 检查是否存在性能问题
public bool HasPerformanceIssues()
{
return performanceWarnings.Count > 0;
}

// 获取性能问题摘要
public string GetPerformanceIssuesSummary()
{
if (performanceWarnings.Count == 0)
{
return "No performance issues detected";
}

return string.Join("\n", performanceWarnings);
}
}

12.10 ForwardRenderer优化建议器

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

public class ForwardRendererOptimizer : MonoBehaviour
{
[Header("Optimization Analysis")]
public bool enableOptimizationAnalysis = true;
public bool suggestBatchingOptimizations = true;
public bool suggestShaderOptimizations = true;
public bool suggestLODOptimizations = true;

[Header("Optimization Thresholds")]
public int highDrawCallThreshold = 100;
public int highBatchThreshold = 100;
public float highFrameTimeThreshold = 16.6f; // 60 FPS

[System.Serializable]
public class OptimizationSuggestion
{
public string category;
public string description;
public string solution;
public int priority; // 0 = High, 1 = Medium, 2 = Low
public bool isCritical;
}

private List<OptimizationSuggestion> suggestions = new List<OptimizationSuggestion>();
private List<Renderer> allRenderers = new List<Renderer>();
private List<ParticleSystem> allParticleSystems = new List<ParticleSystem>();

void Start()
{
if (enableOptimizationAnalysis)
{
AnalyzeOptimizationOpportunities();
}
}

public void AnalyzeOptimizationOpportunities()
{
suggestions.Clear();
CollectSceneObjects();

// 分析各种优化机会
AnalyzeDrawCallOptimizations();
AnalyzeBatchingOptimizations();
AnalyzeShaderOptimizations();
AnalyzeLODOptimizations();
AnalyzeLightingOptimizations();
AnalyzeTextureOptimizations();

// 输出优化建议
OutputOptimizationSuggestions();
}

private void CollectSceneObjects()
{
allRenderers.Clear();
allParticleSystems.Clear();

// 收集所有渲染器
var renderers = FindObjectsOfType<Renderer>();
allRenderers.AddRange(renderers);

// 收集所有粒子系统
var particleSystems = FindObjectsOfType<ParticleSystem>();
allParticleSystems.AddRange(particleSystems);
}

private void AnalyzeDrawCallOptimizations()
{
int drawCalls = UnityEngine.Rendering.UnityRenderPipeline.activeRenderPassCount;

if (drawCalls > highDrawCallThreshold)
{
var suggestion = new OptimizationSuggestion
{
category = "Draw Calls",
description = $"High draw call count: {drawCalls} (threshold: {highDrawCallThreshold})",
solution = "Combine meshes, use texture atlasing, reduce material variants",
priority = 0,
isCritical = true
};
suggestions.Add(suggestion);
}
}

private void AnalyzeBatchingOptimizations()
{
if (suggestBatchingOptimizations)
{
// 分析静态批处理机会
var staticRenderers = allRenderers.FindAll(r => !r.CompareTag("EditorOnly") && r.gameObject.isStatic);
if (staticRenderers.Count > 10)
{
var suggestion = new OptimizationSuggestion
{
category = "Batching",
description = $"Potential for static batching with {staticRenderers.Count} static objects",
solution = "Enable static batching for static geometry",
priority = 1,
isCritical = false
};
suggestions.Add(suggestion);
}

// 分析动态批处理机会
var dynamicRenderers = allRenderers.FindAll(r => !r.CompareTag("EditorOnly") && !r.gameObject.isStatic);
var smallDynamicRenderers = dynamicRenderers.FindAll(r =>
{
var meshFilter = r.GetComponent<MeshFilter>();
return meshFilter != null &&
meshFilter.sharedMesh != null &&
meshFilter.sharedMesh.vertexCount < 300; // Unity动态批处理限制
});

if (smallDynamicRenderers.Count > 10)
{
var suggestion = new OptimizationSuggestion
{
category = "Batching",
description = $"Potential for dynamic batching with {smallDynamicRenderers.Count} small dynamic objects",
solution = "Ensure small objects use same material for dynamic batching",
priority = 1,
isCritical = false
};
suggestions.Add(suggestion);
}
}
}

private void AnalyzeShaderOptimizations()
{
if (suggestShaderOptimizations)
{
// 分析复杂Shader使用
var complexShaders = new List<string>();
foreach (var renderer in allRenderers)
{
foreach (var material in renderer.sharedMaterials)
{
if (material != null && IsComplexShader(material.shader))
{
if (!complexShaders.Contains(material.shader.name))
{
complexShaders.Add(material.shader.name);
}
}
}
}

if (complexShaders.Count > 0)
{
var suggestion = new OptimizationSuggestion
{
category = "Shaders",
description = $"Using complex shaders: {string.Join(", ", complexShaders)}",
solution = "Consider using simpler shaders for mobile/VR platforms",
priority = 1,
isCritical = false
};
suggestions.Add(suggestion);
}
}
}

private void AnalyzeLODOptimizations()
{
if (suggestLODOptimizations)
{
// 分析LOD使用情况
var lodGroups = FindObjectsOfType<LODGroup>();
if (lodGroups.Length == 0)
{
var renderersWithMeshes = allRenderers.FindAll(r => r.GetComponent<MeshFilter>() != null);
if (renderersWithMeshes.Count > 20)
{
var suggestion = new OptimizationSuggestion
{
category = "LOD",
description = $"No LOD groups in scene with {renderersWithMeshes.Count} mesh renderers",
solution = "Implement LOD groups for distant objects",
priority = 1,
isCritical = false
};
suggestions.Add(suggestion);
}
}
}
}

private void AnalyzeLightingOptimizations()
{
// 分析光源数量
var lights = FindObjectsOfType<Light>();
var realTimeLights = lights.FindAll(l => l.lightmapMode == LightmapMode.Realtime);

if (realTimeLights.Count > 8) // 移动平台建议
{
var suggestion = new OptimizationSuggestion
{
category = "Lighting",
description = $"High number of real-time lights: {realTimeLights.Count}",
solution = "Use baked lighting or light probes instead of real-time lights",
priority = 0,
isCritical = true
};
suggestions.Add(suggestion);
}
}

private void AnalyzeTextureOptimizations()
{
// 分析纹理使用
var materials = new List<Material>();
foreach (var renderer in allRenderers)
{
materials.AddRange(renderer.sharedMaterials);
}

var largeTextures = new List<string>();
foreach (var material in materials)
{
if (material != null)
{
var textureNames = GetTextureProperties(material.shader);
foreach (var textureName in textureNames)
{
var texture = material.GetTexture(textureName);
if (texture != null && IsLargeTexture(texture))
{
largeTextures.Add($"{material.name}.{textureName}({texture.width}x{texture.height})");
}
}
}
}

if (largeTextures.Count > 0)
{
var suggestion = new OptimizationSuggestion
{
category = "Textures",
description = $"Using large textures: {string.Join(", ", largeTextures)}",
solution = "Optimize texture sizes, use texture compression",
priority = 1,
isCritical = false
};
suggestions.Add(suggestion);
}
}

private bool IsComplexShader(Shader shader)
{
// 简单的复杂度判断 - 实际项目中可能需要更复杂的判断
var shaderName = shader.name.ToLower();
return shaderName.Contains("complex") ||
shaderName.Contains("advanced") ||
shaderName.Contains("high") ||
shaderName.Contains("compute");
}

private List<string> GetTextureProperties(Shader shader)
{
var textureProperties = new List<string>();
int propertyCount = ShaderUtil.GetPropertyCount(shader);

for (int i = 0; i < propertyCount; i++)
{
if (ShaderUtil.GetPropertyType(shader, i) == ShaderUtil.ShaderPropertyType.TexEnv)
{
textureProperties.Add(ShaderUtil.GetPropertyName(shader, i));
}
}

return textureProperties;
}

private bool IsLargeTexture(Texture texture)
{
return texture.width > 1024 || texture.height > 1024;
}

private void OutputOptimizationSuggestions()
{
if (suggestions.Count == 0)
{
Debug.Log("[Optimizer] No optimization suggestions found");
return;
}

// 按优先级排序
suggestions.Sort((a, b) => a.priority.CompareTo(b.priority));

Debug.Log($"[Optimizer] Found {suggestions.Count} optimization opportunities:");

foreach (var suggestion in suggestions)
{
var logLevel = suggestion.isCritical ? LogType.Warning : LogType.Log;
var priorityText = suggestion.priority == 0 ? "HIGH" :
suggestion.priority == 1 ? "MEDIUM" : "LOW";

Debug.Log($"[{priorityText}] {suggestion.category}: {suggestion.description}");
Debug.Log($" Solution: {suggestion.solution}");
}
}

// 获取优化建议
public List<OptimizationSuggestion> GetOptimizationSuggestions()
{
return new List<OptimizationSuggestion>(suggestions);
}

// 获取特定类别的建议
public List<OptimizationSuggestion> GetSuggestionsByCategory(string category)
{
return suggestions.FindAll(s => s.category == category);
}

// 获取高优先级建议
public List<OptimizationSuggestion> GetHighPrioritySuggestions()
{
return suggestions.FindAll(s => s.priority == 0);
}

// 应用优化建议(示例方法)
public void ApplyOptimization(string suggestionDescription)
{
var suggestion = suggestions.Find(s => s.description == suggestionDescription);
if (suggestion != null)
{
Debug.Log($"[Optimizer] Applying optimization: {suggestion.solution}");
// 这里可以实现具体的优化应用逻辑
}
}
}

实践练习

12.11 练习1:分析ForwardRenderer结构

目标:深入理解ForwardRenderer的内部结构

步骤

  1. 查看Unity的ForwardRenderer源码
  2. 分析Setup方法的执行流程
  3. 理解各种RenderPass的作用
  4. 记录渲染通道的执行顺序
  5. 总结ForwardRenderer的设计模式

分析要点

  • Setup方法的参数和返回值
  • RenderPass的创建和配置
  • 渲染状态的管理

12.12 练习2:实现自定义渲染通道

目标:创建自定义的渲染通道并集成到ForwardRenderer

步骤

  1. 继承ScriptableRenderPass创建自定义通道
  2. 实现Configure和Execute方法
  3. 将自定义通道添加到ForwardRenderer
  4. 测试自定义通道的功能
  5. 优化通道性能

实现要求

  • 遵循ScriptableRenderPass接口
  • 正确管理渲染资源
  • 实现性能监控

12.13 练习3:渲染器性能分析

目标:创建ForwardRenderer性能分析工具

步骤

  1. 开发渲染通道监控器
  2. 记录各通道的执行时间
  3. 分析性能瓶颈
  4. 生成性能报告
  5. 提出优化建议

监控指标

  • 通道执行时间
  • 绘制调用数量
  • 内存使用情况

12.14 练习4:渲染状态管理

目标:理解并优化渲染状态管理

步骤

  1. 分析当前渲染状态
  2. 识别不必要的状态切换
  3. 实现状态缓存机制
  4. 测试性能改进
  5. 验证渲染结果正确性

优化策略

  • 状态排序
  • 状态缓存
  • 批处理优化

12.15 练习5:多Pass协调优化

目标:优化多Pass间的协调机制

步骤

  1. 分析Pass间的依赖关系
  2. 识别资源竞争问题
  3. 优化资源分配策略
  4. 测试协调效率
  5. 验证渲染质量

协调优化

  • 依赖管理
  • 资源复用
  • 执行顺序优化

总结

第12章深入分析了ForwardRenderer的源码实现,这是URP中最重要的渲染器组件。ForwardRenderer采用前向渲染技术,通过一系列精心设计的渲染通道实现完整的渲染流程。

关键要点总结:

  1. 架构设计:ForwardRenderer的模块化设计和职责分离
  2. 渲染流程:从Setup到Render的完整执行流程
  3. 通道管理:各种RenderPass的创建、配置和执行
  4. 状态管理:渲染状态的有效管理和优化
  5. 性能优化:渲染器性能监控和优化策略

ForwardRenderer的设计体现了可编程渲染管线的灵活性和效率,通过合理的架构设计实现了高效的渲染流程。理解其内部实现对于优化渲染性能和扩展渲染功能至关重要。

下一章将深入探讨ScriptableRenderPass的实现细节,了解如何创建和管理自定义渲染通道。