第22章 移动平台优化

第22章 移动平台优化

理论讲解

22.1 移动端URP配置策略

移动平台与桌面平台在硬件性能、内存容量、功耗限制等方面存在显著差异,因此需要针对移动端特性进行专门的URP配置优化。

移动端硬件特点:

  • GPU性能相对较弱
  • 内存容量有限
  • 电池续航考虑
  • 发热控制需求
  • 不同设备性能差异大

URP移动端优化策略:

  1. 渲染质量调整:降低阴影分辨率、减少后处理效果
  2. 光照简化:使用烘焙光照替代部分实时光照
  3. 纹理压缩:使用适合移动端的纹理格式
  4. LOD系统:根据距离和性能动态调整细节级别

URP Asset移动端配置:

  • 渲染质量:降低阴影、抗锯齿、后处理质量
  • 光照设置:优先使用烘焙光照,限制实时光源数量
  • 阴影设置:降低阴影分辨率和级联数量
  • 后处理:禁用或简化复杂后处理效果

22.2 LOD与距离剔除

LOD(Level of Detail)系统是移动端性能优化的关键技术,通过根据对象与摄像机的距离动态调整模型和材质的细节级别来节省性能。

LOD系统原理:

  • 根据距离切换不同细节级别的模型
  • 动态调整材质复杂度
  • 优化纹理分辨率
  • 调整光照计算精度

距离剔除机制:

  • 超出距离阈值的对象不进行渲染
  • 减少远距离对象的计算开销
  • 优化渲染批次管理

LOD实现策略:

  1. 几何LOD:使用不同复杂度的网格
  2. 材质LOD:简化材质属性和着色器
  3. 光照LOD:调整光照计算精度
  4. 纹理LOD:使用Mipmap和压缩格式

22.3 Shader变体管理

Shader变体是影响移动端性能的重要因素,过多的变体会导致内存占用增加和加载时间延长。

Shader变体生成机制:

  • 条件编译指令生成不同变体
  • 多个关键字组合产生指数级变体
  • 运行时根据材质属性选择变体

变体管理策略:

  1. 减少关键字数量:合并相似功能
  2. 使用LOD关键字:根据平台性能选择变体
  3. 预加载必要变体:避免运行时编译
  4. 剔除无用变体:移除不使用的变体组合

移动端Shader优化:

  • 简化计算复杂度
  • 减少纹理采样次数
  • 优化分支逻辑
  • 使用适合移动端的指令

22.4 纹理压缩格式选择

纹理是移动端内存占用的主要来源之一,选择合适的压缩格式对性能优化至关重要。

移动端常用纹理格式:

  1. ASTC:适用于iOS和Android,质量高,压缩率可变
  2. ETC2:Android标准格式,兼容性好
  3. PVRTC:iOS专用格式,压缩效率高
  4. DXT/BC:桌面平台格式,移动端不适用

纹理优化策略:

  • 根据平台选择合适格式
  • 调整压缩质量参数
  • 使用适当的纹理尺寸
  • 合理设置Mipmap

纹理内存管理:

  • 异步加载纹理
  • 按需加载和卸载
  • 使用纹理图集减少Draw Call
  • 优化纹理采样器使用

22.5 光照与阴影简化

移动端的光照和阴影计算需要特别优化,以平衡视觉效果和性能开销。

光照优化策略:

  1. 烘焙光照优先:使用Lightmap替代实时光照
  2. 限制光源数量:减少每像素光照计算
  3. 简化光照模型:使用简化的BRDF计算
  4. 光照烘焙优化:优化UV展开和光照贴图分辨率

阴影优化策略:

  1. 降低阴影分辨率:减少阴影贴图大小
  2. 限制阴影距离:只对近距离对象投射阴影
  3. 简化阴影计算:使用简化的阴影算法
  4. 阴影级联优化:调整级联数量和分布

移动端光照技术:

  • Light Probes:用于动态对象的间接光照
  • Reflection Probes:简化反射计算
  • Light Layers:优化光照分配
  • 混合光照:结合烘焙和实时光照

22.6 性能分析工具使用

移动端性能分析是优化工作的基础,需要使用专业工具监控关键性能指标。

Unity性能分析工具:

  1. Profiler:CPU/GPU性能分析
  2. Frame Debugger:渲染过程调试
  3. GPU Profiler:GPU性能监控
  4. Memory Profiler:内存使用分析

关键性能指标:

  • FPS:帧率稳定性
  • Draw Calls:绘制调用数量
  • Batching:批处理效果
  • Memory Usage:内存占用
  • GPU Utilization:GPU利用率

性能优化流程:

  1. 基线测量:建立性能基准
  2. 瓶颈识别:找出性能瓶颈
  3. 优化实施:应用优化策略
  4. 效果验证:验证优化效果
  5. 持续监控:保持性能稳定

代码示例

22.7 移动端优化管理器

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
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using System;

public class MobileOptimizationManager : MonoBehaviour
{
[Header("Performance Settings")]
public bool enableMobileOptimizations = true;
public bool autoAdjustQuality = true;
public float qualityAdjustInterval = 1.0f;

[Header("LOD Settings")]
public int maxLODLevel = 2;
public float lodBias = 1.0f;
public float distanceScale = 1.0f;

[Header("Culling Settings")]
public float cullingDistance = 100f;
public float cullingUpdateInterval = 0.5f;

[Header("Shader Optimization")]
public bool enableShaderVariantReduction = true;
public bool useMobileShaders = true;
public string[] mobileShaderKeywords = new string[0];

[Header("Texture Optimization")]
public bool enableTextureStreaming = true;
public int textureQuality = 1;
public FilterMode textureFilterMode = FilterMode.Bilinear;

[Header("Lighting Optimization")]
public bool preferBakedLighting = true;
public int maxRealtimeLights = 2;
public int shadowResolution = 512;
public float shadowDistance = 50f;

[Header("Memory Management")]
public float memoryCheckInterval = 2.0f;
public long maxMemoryUsage = 500000000; // 500MB
public bool enableMemoryOptimization = true;

private float m_LastQualityAdjustTime = 0f;
private float m_LastCullingUpdateTime = 0f;
private float m_LastMemoryCheckTime = 0f;
private int m_CurrentLODLevel = 0;
private List<Renderer> m_CulledRenderers = new List<Renderer>();
private List<Light> m_RealtimeLights = new List<Light>();

[System.Serializable]
public class MobilePerformanceData
{
public float averageFPS;
public int drawCalls;
public int batches;
public long memoryUsage;
public float gpuUtilization;
public int realtimeLightsCount;
public float shadowResolutionScale;
public bool isOptimal;
public System.DateTime lastUpdate;
}

[System.Serializable]
public class MobileOptimizationSettings
{
public int lodLevel;
public float shadowDistance;
public int maxRealtimeLights;
public bool useBakedLighting;
public FilterMode textureFilterMode;
public bool enablePostProcessing;
public bool enableShadows;
public bool enableMSAA;
public System.DateTime lastUpdate;
}

public MobilePerformanceData performanceData = new MobilePerformanceData();
public MobileOptimizationSettings optimizationSettings = new MobileOptimizationSettings();

void Start()
{
if (enableMobileOptimizations)
{
InitializeMobileOptimizations();
}
}

void Update()
{
if (enableMobileOptimizations)
{
if (autoAdjustQuality && Time.time - m_LastQualityAdjustTime >= qualityAdjustInterval)
{
AdjustQualitySettings();
m_LastQualityAdjustTime = Time.time;
}

if (Time.time - m_LastCullingUpdateTime >= cullingUpdateInterval)
{
UpdateCulling();
m_LastCullingUpdateTime = Time.time;
}

if (enableMemoryOptimization && Time.time - m_LastMemoryCheckTime >= memoryCheckInterval)
{
CheckMemoryUsage();
m_LastMemoryCheckTime = Time.time;
}
}
}

private void InitializeMobileOptimizations()
{
// 设置LOD参数
QualitySettings.maximumLODLevel = maxLODLevel;
QualitySettings.lodBias = lodBias;

// 获取所有实时灯光
UpdateRealtimeLights();

// 应用纹理设置
ApplyTextureOptimizations();

// 应用光照设置
ApplyLightingOptimizations();

Debug.Log("[MobileOptimizationManager] Initialized mobile optimizations");
}

private void UpdateRealtimeLights()
{
m_RealtimeLights.Clear();
var lights = FindObjectsOfType<Light>();
foreach (var light in lights)
{
if (light != null && light.enabled && light.type != LightType.Baked)
{
m_RealtimeLights.Add(light);
}
}

// 限制实时灯光数量
if (m_RealtimeLights.Count > maxRealtimeLights)
{
for (int i = maxRealtimeLights; i < m_RealtimeLights.Count; i++)
{
m_RealtimeLights[i].enabled = false;
}
}
}

private void ApplyTextureOptimizations()
{
// 设置纹理质量
QualitySettings.masterTextureLimit = Mathf.Clamp(3 - textureQuality, 0, 2);

// 设置纹理过滤模式
var renderers = FindObjectsOfType<Renderer>();
foreach (var renderer in renderers)
{
if (renderer != null && renderer.sharedMaterials != null)
{
foreach (var material in renderer.sharedMaterials)
{
if (material != null)
{
var textures = GetMaterialTextures(material);
foreach (var texture in textures)
{
if (texture != null)
{
// 在运行时无法直接修改纹理属性,但可以记录设置
// 实际纹理优化应在资源导入时设置
}
}
}
}
}
}
}

private void ApplyLightingOptimizations()
{
// 应用光照设置
var urpAsset = GraphicsSettings.renderPipelineAsset as UniversalRenderPipelineAsset;
if (urpAsset != null)
{
// 限制实时灯光数量
// 这里可以进一步优化URP设置
}

// 设置阴影距离
if (QualitySettings.shadowDistance != shadowDistance)
{
QualitySettings.shadowDistance = shadowDistance;
}

// 设置阴影分辨率
QualitySettings.shadowResolution = (ShadowResolution)Mathf.Clamp(shadowResolution / 512, 0, 3);
}

private List<Texture> GetMaterialTextures(Material material)
{
var textures = new List<Texture>();
var propertyCount = ShaderUtil.GetPropertyCount(material.shader);

for (int i = 0; i < propertyCount; i++)
{
if (ShaderUtil.GetPropertyType(material.shader, i) == ShaderUtil.ShaderPropertyType.TexEnv)
{
var texture = material.GetTexture(ShaderUtil.GetPropertyName(material.shader, i));
if (texture != null)
{
textures.Add(texture);
}
}
}

return textures;
}

private void AdjustQualitySettings()
{
// 获取当前性能数据
var currentFPS = 1.0f / Time.unscaledDeltaTime;
var drawCalls = UnityEngine.Rendering.Profiling.Profiler.GetStat(UnityEngine.Rendering.Profiling.CustomSamplerId.DrawCalls).value;

// 根据性能调整设置
if (currentFPS < 30f) // 性能不足,降低质量
{
AdjustToLowQuality();
}
else if (currentFPS > 55f) // 性能良好,可以提高质量
{
AdjustToHighQuality();
}

// 更新性能数据
UpdatePerformanceData(currentFPS, drawCalls);
}

private void AdjustToLowQuality()
{
if (QualitySettings.maximumLODLevel < maxLODLevel)
{
QualitySettings.maximumLODLevel++;
}

if (QualitySettings.shadowDistance > 20f)
{
QualitySettings.shadowDistance = Mathf.Max(20f, QualitySettings.shadowDistance * 0.8f);
}

// 限制实时灯光数量
if (m_RealtimeLights.Count > 1)
{
for (int i = 1; i < m_RealtimeLights.Count; i++)
{
if (m_RealtimeLights[i] != null)
{
m_RealtimeLights[i].enabled = false;
}
}
}
}

private void AdjustToHighQuality()
{
if (QualitySettings.maximumLODLevel > 0)
{
QualitySettings.maximumLODLevel--;
}

if (QualitySettings.shadowDistance < shadowDistance)
{
QualitySettings.shadowDistance = Mathf.Min(shadowDistance, QualitySettings.shadowDistance * 1.1f);
}

// 恢复一些实时灯光
if (m_RealtimeLights.Count > 1)
{
for (int i = 1; i < Mathf.Min(maxRealtimeLights, m_RealtimeLights.Count); i++)
{
if (m_RealtimeLights[i] != null)
{
m_RealtimeLights[i].enabled = true;
}
}
}
}

private void UpdateCulling()
{
var allRenderers = FindObjectsOfType<Renderer>();
m_CulledRenderers.Clear();

foreach (var renderer in allRenderers)
{
if (renderer != null && renderer.enabled)
{
var distance = Vector3.Distance(renderer.transform.position, Camera.main.transform.position);
if (distance > cullingDistance)
{
renderer.enabled = false;
m_CulledRenderers.Add(renderer);
}
else
{
if (m_CulledRenderers.Contains(renderer))
{
renderer.enabled = true;
m_CulledRenderers.Remove(renderer);
}
}
}
}
}

private void CheckMemoryUsage()
{
var memoryUsage = System.GC.GetTotalMemory(false);
if (memoryUsage > maxMemoryUsage)
{
// 触发内存优化
TriggerMemoryOptimization();
}
}

private void TriggerMemoryOptimization()
{
// 强制垃圾回收
System.GC.Collect();

// 卸载未使用的资源
Resources.UnloadUnusedAssets();

// 降低纹理质量
if (QualitySettings.masterTextureLimit < 2)
{
QualitySettings.masterTextureLimit++;
}

// 降低LOD级别
if (QualitySettings.maximumLODLevel < maxLODLevel)
{
QualitySettings.maximumLODLevel++;
}
}

private void UpdatePerformanceData(float currentFPS, int currentDrawCalls)
{
performanceData.averageFPS = currentFPS;
performanceData.drawCalls = currentDrawCalls;
performanceData.batches = UnityEngine.Rendering.Profiling.Profiler.GetStat(UnityEngine.Rendering.Profiling.CustomSamplerId.Batches).value;
performanceData.memoryUsage = System.GC.GetTotalMemory(false);
performanceData.gpuUtilization = GetGPUUtilization(); // 需要平台特定实现
performanceData.realtimeLightsCount = m_RealtimeLights.Count;
performanceData.shadowResolutionScale = (float)QualitySettings.shadowResolution / 3f;
performanceData.isOptimal = currentFPS >= 30f && currentDrawCalls < 1000;
performanceData.lastUpdate = System.DateTime.Now;
}

private float GetGPUUtilization()
{
// 这里需要根据具体平台获取GPU利用率
// Unity没有直接的API,可能需要使用特定平台的工具
return -1f; // 未实现
}

// 获取当前优化设置
public MobileOptimizationSettings GetCurrentSettings()
{
optimizationSettings.lodLevel = QualitySettings.maximumLODLevel;
optimizationSettings.shadowDistance = QualitySettings.shadowDistance;
optimizationSettings.maxRealtimeLights = maxRealtimeLights;
optimizationSettings.useBakedLighting = preferBakedLighting;
optimizationSettings.textureFilterMode = textureFilterMode;
optimizationSettings.enablePostProcessing = true; // 需要检查PostProcessVolume
optimizationSettings.enableShadows = QualitySettings.shadows != ShadowQuality.Disable;
optimizationSettings.enableMSAA = QualitySettings.antiAliasing > 0;
optimizationSettings.lastUpdate = System.DateTime.Now;

return optimizationSettings;
}

// 获取性能数据
public MobilePerformanceData GetPerformanceData()
{
return performanceData;
}

// 强制应用优化设置
public void ApplyOptimizations()
{
ApplyTextureOptimizations();
ApplyLightingOptimizations();
UpdateRealtimeLights();
}

// 设置LOD级别
public void SetLODLevel(int level)
{
QualitySettings.maximumLODLevel = Mathf.Clamp(level, 0, maxLODLevel);
}

// 设置阴影距离
public void SetShadowDistance(float distance)
{
QualitySettings.shadowDistance = Mathf.Clamp(distance, 10f, 200f);
}

// 设置实时灯光数量
public void SetMaxRealtimeLights(int count)
{
maxRealtimeLights = Mathf.Clamp(count, 0, 8);
UpdateRealtimeLights();
}

// 获取优化建议
public string GetOptimizationRecommendations()
{
var recommendations = new System.Text.StringBuilder();

if (performanceData.averageFPS < 30f)
{
recommendations.AppendLine("• 帧率过低,建议降低渲染质量");
}

if (performanceData.drawCalls > 1000)
{
recommendations.AppendLine("• Draw Calls过多,建议优化批处理");
}

if (performanceData.memoryUsage > maxMemoryUsage * 0.8f)
{
recommendations.AppendLine("• 内存使用过高,建议优化资源");
}

if (m_RealtimeLights.Count > maxRealtimeLights)
{
recommendations.AppendLine("• 实时光源过多,建议使用烘焙光照");
}

return recommendations.ToString();
}

// 获取性能摘要
public string GetPerformanceSummary()
{
return $"FPS: {performanceData.averageFPS:F1}, " +
$"Draw Calls: {performanceData.drawCalls}, " +
$"Memory: {performanceData.memoryUsage / 1024 / 1024:F1}MB, " +
$"Realtime Lights: {performanceData.realtimeLightsCount}";
}

void OnDestroy()
{
m_CulledRenderers.Clear();
m_RealtimeLights.Clear();
}
}

22.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
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
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
using System.Collections.Generic;
using UnityEngine;
using System;

public class MobileTextureOptimizer : MonoBehaviour
{
[Header("Texture Streaming Settings")]
public bool enableTextureStreaming = true;
public int streamingTextureCount = 50;
public float textureStreamingUpdateInterval = 0.1f;

[Header("Compression Settings")]
public TextureFormat targetFormat = TextureFormat.ASTC_6x6;
public int compressionQuality = 80;
public bool useMipmap = true;
public FilterMode filterMode = FilterMode.Bilinear;

[Header("Resolution Settings")]
public int maxTextureResolution = 1024;
public int textureQualityLevel = 1; // 0=Low, 1=Medium, 2=High

[Header("Memory Management")]
public long maxTextureMemory = 100000000; // 100MB
public float memoryCheckInterval = 1.0f;

private float m_LastStreamingUpdateTime = 0f;
private float m_LastMemoryCheckTime = 0f;
private Dictionary<Texture, TextureOptimizationData> m_TextureData = new Dictionary<Texture, TextureOptimizationData>();
private List<Texture> m_TexturePool = new List<Texture>();

[System.Serializable]
public class TextureOptimizationData
{
public string name;
public int originalSize;
public int optimizedSize;
public TextureFormat originalFormat;
public TextureFormat optimizedFormat;
public int resolution;
public bool useMipmap;
public FilterMode filterMode;
public long memoryUsage;
public bool isOptimized;
public System.DateTime lastUpdate;
}

[System.Serializable]
public class TextureOptimizationMetrics
{
public int totalTextures;
public int optimizedTextures;
public long totalMemoryUsage;
public long optimizedMemoryUsage;
public float memoryReductionPercentage;
public int texturesExceedingLimit;
public bool isWithinMemoryLimit;
public System.DateTime lastUpdate;
}

public TextureOptimizationMetrics metrics = new TextureOptimizationMetrics();

void Start()
{
InitializeTextureOptimization();
}

void Update()
{
if (enableTextureStreaming && Time.time - m_LastStreamingUpdateTime >= textureStreamingUpdateInterval)
{
UpdateTextureStreaming();
m_LastStreamingUpdateTime = Time.time;
}

if (Time.time - m_LastMemoryCheckTime >= memoryCheckInterval)
{
CheckTextureMemoryUsage();
m_LastMemoryCheckTime = Time.time;
}
}

private void InitializeTextureOptimization()
{
// 收集场景中的纹理
CollectSceneTextures();

// 初始化纹理数据
InitializeTextureData();

Debug.Log("[MobileTextureOptimizer] Initialized texture optimization system");
}

private void CollectSceneTextures()
{
m_TexturePool.Clear();

// 从所有渲染器收集纹理
var renderers = FindObjectsOfType<Renderer>();
foreach (var renderer in renderers)
{
if (renderer != null && renderer.sharedMaterials != null)
{
foreach (var material in renderer.sharedMaterials)
{
if (material != null)
{
var textures = GetMaterialTextures(material);
foreach (var texture in textures)
{
if (texture != null && !m_TexturePool.Contains(texture))
{
m_TexturePool.Add(texture);
}
}
}
}
}
}

// 从UI元素收集纹理
var canvases = FindObjectsOfType<Canvas>();
foreach (var canvas in canvases)
{
var images = canvas.GetComponentsInChildren<UnityEngine.UI.Image>();
foreach (var image in images)
{
if (image != null && image.sprite != null && image.sprite.texture != null)
{
var texture = image.sprite.texture;
if (!m_TexturePool.Contains(texture))
{
m_TexturePool.Add(texture);
}
}
}
}
}

private List<Texture> GetMaterialTextures(Material material)
{
var textures = new List<Texture>();
var propertyCount = ShaderUtil.GetPropertyCount(material.shader);

for (int i = 0; i < propertyCount; i++)
{
if (ShaderUtil.GetPropertyType(material.shader, i) == ShaderUtil.ShaderPropertyType.TexEnv)
{
var texture = material.GetTexture(ShaderUtil.GetPropertyName(material.shader, i));
if (texture != null)
{
textures.Add(texture);
}
}
}

return textures;
}

private void InitializeTextureData()
{
m_TextureData.Clear();

foreach (var texture in m_TexturePool)
{
if (texture != null)
{
var data = new TextureOptimizationData
{
name = texture.name,
originalSize = CalculateTextureSize(texture),
optimizedSize = CalculateTextureSize(texture),
originalFormat = GetTextureFormat(texture),
optimizedFormat = GetTextureFormat(texture),
resolution = Mathf.Max(texture.width, texture.height),
useMipmap = texture.mipmapCount > 1,
filterMode = texture.filterMode,
memoryUsage = CalculateTextureMemory(texture),
isOptimized = false,
lastUpdate = System.DateTime.Now
};

m_TextureData[texture] = data;
}
}

UpdateMetrics();
}

private int CalculateTextureSize(Texture texture)
{
if (texture == null) return 0;
return texture.width * texture.height * GetFormatBytesPerPixel(GetTextureFormat(texture));
}

private TextureFormat GetTextureFormat(Texture texture)
{
if (texture is Texture2D tex2D)
{
return tex2D.format;
}
else if (texture is RenderTexture rt)
{
return GetRenderTextureFormat(rt);
}
// 其他纹理类型...
return TextureFormat.RGBA32;
}

private TextureFormat GetRenderTextureFormat(RenderTexture rt)
{
// 根据RenderTexture的格式返回对应的TextureFormat
switch (rt.format)
{
case RenderTextureFormat.ARGB32:
return TextureFormat.RGBA32;
case RenderTextureFormat.ARGBHalf:
return TextureFormat.RGBAHalf;
case RenderTextureFormat.ARGBFloat:
return TextureFormat.RGBAFloat;
default:
return TextureFormat.RGBA32;
}
}

private int GetFormatBytesPerPixel(TextureFormat format)
{
switch (format)
{
case TextureFormat.RGBA32:
case TextureFormat.ARGB32:
return 4;
case TextureFormat.RGB24:
return 3;
case TextureFormat.Alpha8:
return 1;
case TextureFormat.RGBAHalf:
return 8;
case TextureFormat.RGBAFloat:
return 16;
default:
return 4; // 默认4字节
}
}

private long CalculateTextureMemory(Texture texture)
{
if (texture == null) return 0;

long size = texture.width * texture.height;
size *= GetFormatBytesPerPixel(GetTextureFormat(texture));

if (texture.mipmapCount > 1)
{
// 计算Mipmap内存使用
int mipWidth = texture.width;
int mipHeight = texture.height;
while (mipWidth > 1 || mipHeight > 1)
{
mipWidth = Mathf.Max(1, mipWidth / 2);
mipHeight = Mathf.Max(1, mipHeight / 2);
size += mipWidth * mipHeight * GetFormatBytesPerPixel(GetTextureFormat(texture));
}
}

return size;
}

private void UpdateTextureStreaming()
{
// 简化的纹理流式传输逻辑
// 实际实现需要更复杂的距离和优先级计算

foreach (var texture in m_TexturePool)
{
if (texture != null)
{
// 根据距离和重要性调整纹理质量
// 这里简化处理,实际需要根据摄像机距离等因素
AdjustTextureStreaming(texture);
}
}
}

private void AdjustTextureStreaming(Texture texture)
{
if (m_TextureData.ContainsKey(texture))
{
var data = m_TextureData[texture];

// 根据纹理大小和质量级别调整
int targetResolution = maxTextureResolution;
switch (textureQualityLevel)
{
case 0: // 低质量
targetResolution = Mathf.Min(512, maxTextureResolution);
break;
case 1: // 中等质量
targetResolution = Mathf.Min(1024, maxTextureResolution);
break;
case 2: // 高质量
targetResolution = maxTextureResolution;
break;
}

// 如果纹理分辨率过高,考虑降级
if (data.resolution > targetResolution)
{
// 这里可以触发纹理重新采样或使用更低分辨率的版本
// 实际实现需要异步处理
}
}
}

private void CheckTextureMemoryUsage()
{
long totalMemory = 0;
foreach (var kvp in m_TextureData)
{
totalMemory += kvp.Value.memoryUsage;
}

metrics.totalMemoryUsage = totalMemory;
metrics.isWithinMemoryLimit = totalMemory <= maxTextureMemory;

if (totalMemory > maxTextureMemory)
{
// 触发纹理内存优化
OptimizeTextureMemory();
}

UpdateMetrics();
}

private void OptimizeTextureMemory()
{
// 按内存使用量排序纹理
var sortedTextures = new List<KeyValuePair<Texture, TextureOptimizationData>>(m_TextureData);
sortedTextures.Sort((a, b) => b.Value.memoryUsage.CompareTo(a.Value.memoryUsage));

long memoryToFree = metrics.totalMemoryUsage - maxTextureMemory;
long freedMemory = 0;

foreach (var kvp in sortedTextures)
{
if (freedMemory >= memoryToFree) break;

var texture = kvp.Key;
var data = kvp.Value;

// 尝试降低纹理质量
if (data.resolution > 256) // 避免过度降低
{
// 这里可以实现纹理压缩或分辨率降低
// 实际实现需要考虑纹理类型和用途
freedMemory += data.memoryUsage / 2; // 估算释放的内存
}
}
}

private void UpdateMetrics()
{
metrics.totalTextures = m_TexturePool.Count;
metrics.optimizedTextures = 0;
metrics.totalMemoryUsage = 0;
metrics.optimizedMemoryUsage = 0;
metrics.texturesExceedingLimit = 0;

foreach (var kvp in m_TextureData)
{
var data = kvp.Value;
metrics.totalMemoryUsage += data.memoryUsage;

if (data.isOptimized)
{
metrics.optimizedTextures++;
metrics.optimizedMemoryUsage += data.memoryUsage;
}

if (data.memoryUsage > maxTextureMemory / 10) // 假设超过总内存的10%为大纹理
{
metrics.texturesExceedingLimit++;
}
}

metrics.memoryReductionPercentage = metrics.totalMemoryUsage > 0 ?
(float)(metrics.totalMemoryUsage - metrics.optimizedMemoryUsage) / metrics.totalMemoryUsage : 0f;
metrics.lastUpdate = System.DateTime.Now;
}

// 获取纹理优化数据
public TextureOptimizationData GetTextureData(Texture texture)
{
if (m_TextureData.ContainsKey(texture))
{
return m_TextureData[texture];
}
return null;
}

// 获取所有纹理数据
public Dictionary<Texture, TextureOptimizationData> GetAllTextureData()
{
return new Dictionary<Texture, TextureOptimizationData>(m_TextureData);
}

// 获取优化指标
public TextureOptimizationMetrics GetMetrics()
{
return metrics;
}

// 优化特定纹理
public void OptimizeTexture(Texture texture)
{
if (m_TextureData.ContainsKey(texture))
{
var data = m_TextureData[texture];

// 应用优化设置
data.optimizedFormat = targetFormat;
data.useMipmap = useMipmap;
data.filterMode = filterMode;

// 计算优化后的大小
data.optimizedSize = CalculateOptimizedSize(data);
data.isOptimized = true;
data.lastUpdate = System.DateTime.Now;

UpdateMetrics();
}
}

private int CalculateOptimizedSize(TextureOptimizationData data)
{
// 根据目标格式和分辨率计算优化后的大小
int width = Mathf.Min(data.resolution, maxTextureResolution);
int height = Mathf.Min(data.resolution, maxTextureResolution);

return width * height * GetFormatBytesPerPixel(targetFormat);
}

// 批量优化纹理
public void OptimizeAllTextures()
{
foreach (var texture in m_TexturePool)
{
if (texture != null)
{
OptimizeTexture(texture);
}
}
}

// 获取纹理优化建议
public string GetTextureOptimizationSuggestions()
{
var suggestions = new System.Text.StringBuilder();

if (metrics.totalMemoryUsage > maxTextureMemory)
{
suggestions.AppendLine("• 纹理内存使用超出限制,建议压缩纹理");
}

if (metrics.texturesExceedingLimit > 0)
{
suggestions.AppendLine($"• 有 {metrics.texturesExceedingLimit} 个大纹理,建议降低分辨率");
}

if (textureQualityLevel > 1)
{
suggestions.AppendLine("• 纹理质量设置过高,可考虑降低以节省内存");
}

return suggestions.ToString();
}

// 获取纹理优化报告
public string GetOptimizationReport()
{
var report = new System.Text.StringBuilder();
report.AppendLine("=== Mobile Texture Optimization Report ===");
report.AppendLine($"Total Textures: {metrics.totalTextures}");
report.AppendLine($"Optimized Textures: {metrics.optimizedTextures}");
report.AppendLine($"Total Memory: {metrics.totalMemoryUsage / 1024 / 1024:F2} MB");
report.AppendLine($"Optimized Memory: {metrics.optimizedMemoryUsage / 1024 / 1024:F2} MB");
report.AppendLine($"Memory Reduction: {metrics.memoryReductionPercentage:F2}%");
report.AppendLine($"Large Textures: {metrics.texturesExceedingLimit}");
report.AppendLine($"Within Limit: {metrics.isWithinMemoryLimit}");
report.AppendLine($"Last Update: {metrics.lastUpdate}");

return report.ToString();
}

// 重置纹理优化数据
public void ResetOptimizationData()
{
foreach (var kvp in m_TextureData)
{
kvp.Value.isOptimized = false;
kvp.Value.optimizedFormat = kvp.Value.originalFormat;
kvp.Value.optimizedSize = kvp.Value.originalSize;
}

UpdateMetrics();
}
}

22.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
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
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using System;

public class MobileLightingOptimizer : MonoBehaviour
{
[Header("Lighting Optimization Settings")]
public bool enableLightOptimization = true;
public bool preferBakedLighting = true;
public int maxRealtimeLights = 2;
public float realtimeLightDistance = 10f;
public bool enableLightCulling = true;
public float lightCullingInterval = 0.5f;

[Header("Shadow Optimization")]
public bool enableShadowOptimization = true;
public int shadowResolution = 512;
public float shadowDistance = 20f;
public float shadowBias = 0.2f;
public float shadowNormalBias = 0.5f;

[Header("LOD Settings")]
public bool enableLightLOD = true;
public float lodTransitionDistance = 30f;
public int lodLevelCount = 3;

[Header("Performance Settings")]
public float performanceCheckInterval = 1.0f;
public float targetFPS = 30f;
public int maxDrawCalls = 1000;

private float m_LastLightUpdate = 0f;
private float m_LastPerformanceCheck = 0f;
private List<Light> m_AllLights = new List<Light>();
private List<Light> m_RealtimeLights = new List<Light>();
private List<Light> m_BakedLights = new List<Light>();
private List<Light> m_DisabledLights = new List<Light>();

[System.Serializable]
public class LightingOptimizationData
{
public int totalLights;
public int realtimeLights;
public int bakedLights;
public int disabledLights;
public int maxAllowedRealtimeLights;
public float averageFPS;
public int drawCalls;
public bool isOptimal;
public System.DateTime lastUpdate;
}

[System.Serializable]
public class LightOptimizationSettings
{
public int maxRealtimeLights;
public float realtimeLightDistance;
public int shadowResolution;
public float shadowDistance;
public bool useBakedLighting;
public bool enableShadows;
public System.DateTime lastUpdate;
}

public LightingOptimizationData optimizationData = new LightingOptimizationData();
public LightOptimizationSettings optimizationSettings = new LightOptimizationSettings();

void Start()
{
if (enableLightOptimization)
{
InitializeLightOptimization();
}
}

void Update()
{
if (enableLightOptimization)
{
if (Time.time - m_LastLightUpdate >= lightCullingInterval)
{
UpdateLightCulling();
m_LastLightUpdate = Time.time;
}

if (Time.time - m_LastPerformanceCheck >= performanceCheckInterval)
{
CheckPerformanceAndAdjust();
m_LastPerformanceCheck = Time.time;
}
}
}

private void InitializeLightOptimization()
{
// 收集所有灯光
CollectAllLights();

// 应用初始优化设置
ApplyLightOptimizations();

Debug.Log("[MobileLightingOptimizer] Initialized lighting optimization system");
}

private void CollectAllLights()
{
m_AllLights.Clear();
m_RealtimeLights.Clear();
m_BakedLights.Clear();
m_DisabledLights.Clear();

var lights = FindObjectsOfType<Light>();
foreach (var light in lights)
{
if (light != null && light.enabled)
{
m_AllLights.Add(light);

if (light.lightmapBakeType == LightmapBakeType.Baked ||
light.lightmapBakeType == LightmapBakeType.Mixed)
{
m_BakedLights.Add(light);
}
else
{
m_RealtimeLights.Add(light);
}
}
}
}

private void ApplyLightOptimizations()
{
// 应用阴影设置
if (enableShadowOptimization)
{
QualitySettings.shadowResolution = (ShadowResolution)Mathf.Clamp(shadowResolution / 512, 0, 3);
QualitySettings.shadowDistance = shadowDistance;
}

// 应用实时灯光限制
LimitRealtimeLights();

// 更新优化设置
UpdateOptimizationSettings();
}

private void LimitRealtimeLights()
{
if (m_RealtimeLights.Count <= maxRealtimeLights)
{
// 灯光数量在限制内,启用所有实时灯光
foreach (var light in m_RealtimeLights)
{
if (light != null && !light.enabled)
{
light.enabled = true;
}
}
}
else
{
// 超出限制,禁用多余的灯光
for (int i = maxRealtimeLights; i < m_RealtimeLights.Count; i++)
{
if (m_RealtimeLights[i] != null && m_RealtimeLights[i].enabled)
{
m_RealtimeLights[i].enabled = false;
if (!m_DisabledLights.Contains(m_RealtimeLights[i]))
{
m_DisabledLights.Add(m_RealtimeLights[i]);
}
}
}

// 保持在限制内的灯光启用
for (int i = 0; i < maxRealtimeLights && i < m_RealtimeLights.Count; i++)
{
if (m_RealtimeLights[i] != null && !m_RealtimeLights[i].enabled)
{
m_RealtimeLights[i].enabled = true;
m_DisabledLights.Remove(m_RealtimeLights[i]);
}
}
}
}

private void UpdateLightCulling()
{
if (!enableLightCulling || Camera.main == null) return;

var cameraPos = Camera.main.transform.position;

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

// 根据距离决定是否启用灯光
if (distance > realtimeLightDistance)
{
if (light.enabled)
{
light.enabled = false;
if (!m_DisabledLights.Contains(light))
{
m_DisabledLights.Add(light);
}
}
}
else
{
if (!light.enabled && m_DisabledLights.Contains(light))
{
light.enabled = true;
m_DisabledLights.Remove(light);
}
}
}
}
}

private void CheckPerformanceAndAdjust()
{
var currentFPS = 1.0f / Time.unscaledDeltaTime;
var drawCalls = UnityEngine.Rendering.Profiling.Profiler.GetStat(UnityEngine.Rendering.Profiling.CustomSamplerId.DrawCalls).value;

// 根据性能调整设置
if (currentFPS < targetFPS * 0.8f) // 性能不足
{
ReduceLightingQuality(currentFPS);
}
else if (currentFPS > targetFPS * 1.1f) // 性能良好
{
IncreaseLightingQuality(currentFPS);
}

// 更新优化数据
UpdateOptimizationData(currentFPS, drawCalls);
}

private void ReduceLightingQuality(float currentFPS)
{
bool changed = false;

// 减少实时灯光数量
if (maxRealtimeLights > 0)
{
maxRealtimeLights = Mathf.Max(0, maxRealtimeLights - 1);
changed = true;
}

// 降低阴影距离
if (QualitySettings.shadowDistance > 10f)
{
QualitySettings.shadowDistance = Mathf.Max(10f, QualitySettings.shadowDistance * 0.8f);
changed = true;
}

// 降低阴影分辨率
if (QualitySettings.shadowResolution > 0)
{
QualitySettings.shadowResolution = (ShadowResolution)Mathf.Max(0, (int)QualitySettings.shadowResolution - 1);
changed = true;
}

if (changed)
{
LimitRealtimeLights();
UpdateOptimizationSettings();
}
}

private void IncreaseLightingQuality(float currentFPS)
{
bool changed = false;

// 增加实时灯光数量(在限制内)
if (maxRealtimeLights < 4) // 合理的上限
{
maxRealtimeLights = Mathf.Min(4, maxRealtimeLights + 1);
changed = true;
}

// 增加阴影距离(在限制内)
if (QualitySettings.shadowDistance < shadowDistance)
{
QualitySettings.shadowDistance = Mathf.Min(shadowDistance, QualitySettings.shadowDistance * 1.1f);
changed = true;
}

if (changed)
{
LimitRealtimeLights();
UpdateOptimizationSettings();
}
}

private void UpdateOptimizationData(float currentFPS, int drawCalls)
{
optimizationData.totalLights = m_AllLights.Count;
optimizationData.realtimeLights = m_RealtimeLights.Count;
optimizationData.bakedLights = m_BakedLights.Count;
optimizationData.disabledLights = m_DisabledLights.Count;
optimizationData.maxAllowedRealtimeLights = maxRealtimeLights;
optimizationData.averageFPS = currentFPS;
optimizationData.drawCalls = drawCalls;
optimizationData.isOptimal = currentFPS >= targetFPS && drawCalls <= maxDrawCalls;
optimizationData.lastUpdate = System.DateTime.Now;
}

private void UpdateOptimizationSettings()
{
optimizationSettings.maxRealtimeLights = maxRealtimeLights;
optimizationSettings.realtimeLightDistance = realtimeLightDistance;
optimizationSettings.shadowResolution = shadowResolution;
optimizationSettings.shadowDistance = shadowDistance;
optimizationSettings.useBakedLighting = preferBakedLighting;
optimizationSettings.enableShadows = QualitySettings.shadows != ShadowQuality.Disable;
optimizationSettings.lastUpdate = System.DateTime.Now;
}

// 获取当前优化数据
public LightingOptimizationData GetOptimizationData()
{
return optimizationData;
}

// 获取当前优化设置
public LightOptimizationSettings GetOptimizationSettings()
{
return optimizationSettings;
}

// 强制重新收集灯光
public void ForceRefreshLights()
{
CollectAllLights();
ApplyLightOptimizations();
}

// 设置最大实时灯光数量
public void SetMaxRealtimeLights(int count)
{
maxRealtimeLights = Mathf.Clamp(count, 0, 8);
LimitRealtimeLights();
UpdateOptimizationSettings();
}

// 设置实时灯光距离
public void SetRealtimeLightDistance(float distance)
{
realtimeLightDistance = Mathf.Max(5f, distance);
}

// 设置阴影距离
public void SetShadowDistance(float distance)
{
shadowDistance = Mathf.Clamp(distance, 10f, 100f);
QualitySettings.shadowDistance = shadowDistance;
}

// 获取灯光列表
public List<Light> GetAllLights()
{
return new List<Light>(m_AllLights);
}

// 获取实时灯光列表
public List<Light> GetRealtimeLights()
{
return new List<Light>(m_RealtimeLights);
}

// 获取烘焙灯光列表
public List<Light> GetBakedLights()
{
return new List<Light>(m_BakedLights);
}

// 获取禁用的灯光列表
public List<Light> GetDisabledLights()
{
return new List<Light>(m_DisabledLights);
}

// 启用特定灯光
public void EnableLight(Light light)
{
if (light != null && m_RealtimeLights.Contains(light))
{
// 检查是否超出实时灯光限制
int enabledRealtimeCount = 0;
foreach (var rl in m_RealtimeLights)
{
if (rl != null && rl.enabled)
{
enabledRealtimeCount++;
}
}

if (enabledRealtimeCount < maxRealtimeLights)
{
light.enabled = true;
m_DisabledLights.Remove(light);
}
}
}

// 禁用特定灯光
public void DisableLight(Light light)
{
if (light != null && m_RealtimeLights.Contains(light) && light.enabled)
{
light.enabled = false;
if (!m_DisabledLights.Contains(light))
{
m_DisabledLights.Add(light);
}
}
}

// 获取优化建议
public string GetOptimizationSuggestions()
{
var suggestions = new System.Text.StringBuilder();

if (optimizationData.averageFPS < targetFPS)
{
suggestions.AppendLine("• 帧率过低,建议减少实时灯光数量");
}

if (optimizationData.realtimeLights > maxRealtimeLights)
{
suggestions.AppendLine("• 实时光源过多,建议使用烘焙光照");
}

if (optimizationData.drawCalls > maxDrawCalls)
{
suggestions.AppendLine("• 绘制调用过多,可能与光照相关");
}

if (QualitySettings.shadowDistance > 30f)
{
suggestions.AppendLine("• 阴影距离过远,建议适当降低");
}

return suggestions.ToString();
}

// 获取性能摘要
public string GetPerformanceSummary()
{
return $"FPS: {optimizationData.averageFPS:F1}, " +
$"Lights: {optimizationData.realtimeLights}/{optimizationData.totalLights}, " +
$"Disabled: {optimizationData.disabledLights}, " +
$"Draw Calls: {optimizationData.drawCalls}";
}

// 获取光照优化报告
public string GetOptimizationReport()
{
var report = new System.Text.StringBuilder();
report.AppendLine("=== Mobile Lighting Optimization Report ===");
report.AppendLine($"Total Lights: {optimizationData.totalLights}");
report.AppendLine($"Realtime Lights: {optimizationData.realtimeLights}");
report.AppendLine($"Baked Lights: {optimizationData.bakedLights}");
report.AppendLine($"Disabled Lights: {optimizationData.disabledLights}");
report.AppendLine($"Max Realtime Allowed: {optimizationData.maxAllowedRealtimeLights}");
report.AppendLine($"Current FPS: {optimizationData.averageFPS:F1}");
report.AppendLine($"Draw Calls: {optimizationData.drawCalls}");
report.AppendLine($"Is Optimal: {optimizationData.isOptimal}");
report.AppendLine($"Last Update: {optimizationData.lastUpdate}");

return report.ToString();
}

// 重置优化设置
public void ResetOptimizations()
{
maxRealtimeLights = 2;
realtimeLightDistance = 10f;
shadowDistance = 20f;

// 重新应用设置
ApplyLightOptimizations();
}

void OnDestroy()
{
m_AllLights.Clear();
m_RealtimeLights.Clear();
m_BakedLights.Clear();
m_DisabledLights.Clear();
}
}

实践练习

22.10 练习1:移动端性能分析

目标:创建移动端性能分析工具

步骤

  1. 实现性能数据收集
  2. 创建性能监控界面
  3. 分析性能瓶颈
  4. 生成优化建议
  5. 验证优化效果

分析要点

  • FPS稳定性
  • 内存使用情况
  • 绘制调用数量
  • GPU利用率

22.11 练习2:LOD系统实现

目标:实现移动端LOD系统

步骤

  1. 创建LOD组管理器
  2. 实现距离计算逻辑
  3. 设计LOD切换机制
  4. 优化切换平滑度
  5. 测试性能提升

实现要素

  • 多级细节模型
  • 动态切换算法
  • 性能监控

22.12 练习3:纹理优化系统

目标:创建纹理优化系统

步骤

  1. 实现纹理格式检测
  2. 创建压缩优化逻辑
  3. 设计内存管理机制
  4. 实现流式传输
  5. 验证内存节省

优化方面

  • 压缩格式选择
  • 分辨率调整
  • Mipmap管理

22.13 练习4:光照优化策略

目标:实现光照优化策略

步骤

  1. 分析场景光照需求
  2. 实现烘焙光照优先
  3. 创建灯光管理器
  4. 优化阴影计算
  5. 验证视觉效果

优化策略

  • 烘焙与实时光照平衡
  • 灯光数量限制
  • 阴影质量调整

22.14 练习5:综合优化方案

目标:创建移动端综合优化方案

步骤

  1. 集成各项优化技术
  2. 实现自动调整机制
  3. 创建性能监控面板
  4. 测试多种设备
  5. 验证整体效果

方案特性

  • 自适应优化
  • 实时调整
  • 性能反馈

总结

第22章详细介绍了移动端URP优化的各个方面。移动端平台由于硬件限制和功耗考虑,需要特别的优化策略来确保良好的用户体验。

关键要点总结:

  1. 配置策略:根据移动端特性调整URP设置
  2. LOD系统:使用距离和性能动态调整细节级别
  3. 变体管理:控制Shader变体数量以节省内存
  4. 纹理优化:选择合适的压缩格式和分辨率
  5. 光照简化:平衡烘焙和实时光照
  6. 性能分析:使用工具监控和优化性能

移动端优化是一个持续的过程,需要在视觉效果和性能之间找到最佳平衡点。通过系统化的优化策略,可以显著提升移动端应用的性能表现。