Files
XericLibrary-WebGL-Publish/Runtime/Generation/Primitive/PrimitiveCacheRendererBase.cs
T
2026-07-20 11:08:12 +08:00

230 lines
6.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace XericLibrary.Runtime.UIGraph
{
/// <summary>
/// 图元缓存渲染器基类
/// 管理 PrimitiveCacheEntry 列表 + 脏标记范围更新
/// LateUpdate 中只重建脏标记范围内的图元
/// </summary>
[RequireComponent(typeof(CanvasRenderer))]
public abstract class PrimitiveCacheRendererBase : MaskableGraphic
{
#region 默认材质
private static Material s_DefaultMaterial;
private const string DefaultShaderPath = "XericLibrary/UIGraph/UIPattern";
/// <summary>
/// 获取图元渲染器的默认材质(基于 UIPattern.shader
/// </summary>
public override Material defaultMaterial
{
get
{
if (s_DefaultMaterial == null)
{
var shader = Shader.Find(DefaultShaderPath);
if (shader != null)
s_DefaultMaterial = new Material(shader);
else
s_DefaultMaterial = base.defaultMaterial;
}
return s_DefaultMaterial;
}
}
#endregion
#region 数据缓存
/// <summary>
/// 图元列表
/// </summary>
protected List<PrimitiveCacheEntry> m_Primitives = new List<PrimitiveCacheEntry>();
/// <summary>
/// 模型顶点缓存
/// </summary>
protected List<UIVertex> m_MeshVertexCache = new List<UIVertex>();
/// <summary>
/// 三角形索引缓存
/// </summary>
protected List<int> m_MeshIndexCache = new List<int>();
/// <summary>
/// 脏标记范围起点(图元索引),-1 表示无脏标记
/// </summary>
protected int m_DirtyStartIndex = -1;
/// <summary>
/// 脏标记范围终点(图元索引)
/// </summary>
protected int m_DirtyEndIndex = -1;
#endregion
#region API
/// <summary>
/// 添加一个图元
/// </summary>
/// <returns>图元索引</returns>
public int AddPrimitive(PrimitiveCacheEntry entry)
{
int index = m_Primitives.Count;
m_Primitives.Add(entry);
MarkDirty(index);
return index;
}
/// <summary>
/// 移除指定图元
/// </summary>
public void RemovePrimitive(int index)
{
if (index < 0 || index >= m_Primitives.Count) return;
m_Primitives.RemoveAt(index);
RebuildAll();
}
/// <summary>
/// 标记指定图元为脏
/// </summary>
public void SetPrimitiveDirty(int index)
{
MarkDirty(index);
}
/// <summary>
/// 清空所有图元
/// </summary>
public void ClearAll()
{
m_Primitives.Clear();
m_MeshVertexCache.Clear();
m_MeshIndexCache.Clear();
m_DirtyStartIndex = -1;
m_DirtyEndIndex = -1;
SetVerticesDirty();
}
#endregion
#region 脏标记
protected void MarkDirty(int index)
{
if (m_DirtyStartIndex < 0 || index < m_DirtyStartIndex)
m_DirtyStartIndex = index;
if (m_DirtyEndIndex < 0 || index > m_DirtyEndIndex)
m_DirtyEndIndex = index;
}
/// <summary>
/// 标记所有图元为脏(下次 LateUpdate 全量重绘)
/// 适用于:更新顶点坐标后,不改变元素数量的重绘
/// </summary>
public void RebuildAll()
{
m_DirtyStartIndex = 0;
m_DirtyEndIndex = m_Primitives.Count - 1;
if (m_DirtyEndIndex < 0)
m_DirtyStartIndex = -1;
}
#endregion
#region LateUpdate
protected virtual void LateUpdate()
{
if (m_DirtyStartIndex < 0) return;
// 全量重建策略:从脏范围起点开始,重绘该条目及后续所有条目
// 保证所有条目 startVertexIndex/startIndexIndex 始终正确
int start = m_DirtyStartIndex;
// 统计脏范围前的顶点/索引数(这些条目无需重建)
int preVertexCount = 0;
int preIndexCount = 0;
for (int i = 0; i < start; i++)
{
preVertexCount += m_Primitives[i].vertexCount;
preIndexCount += m_Primitives[i].triangleCount * 3;
}
// 从 start 开始重建所有条目
var tempVerts = new List<UIVertex>();
var tempIndices = new List<int>();
int vAccum = preVertexCount;
int iAccum = preIndexCount;
for (int i = start; i < m_Primitives.Count; i++)
{
var entry = m_Primitives[i];
int vertBefore = tempVerts.Count;
int idxBefore = tempIndices.Count;
PrimitiveMeshGenerator.GeneratePrimitive(entry, tempVerts, tempIndices);
var updated = entry;
updated.startVertexIndex = vAccum;
updated.vertexCount = tempVerts.Count - vertBefore;
updated.startIndexIndex = iAccum;
updated.triangleCount = (tempIndices.Count - idxBefore) / 3;
m_Primitives[i] = updated;
vAccum += updated.vertexCount;
iAccum += updated.triangleCount * 3;
}
// 合并到主缓存
int totalVertices = vAccum;
int totalIndices = iAccum;
while (m_MeshVertexCache.Count < totalVertices)
m_MeshVertexCache.Add(new UIVertex());
while (m_MeshIndexCache.Count < totalIndices)
m_MeshIndexCache.Add(0);
for (int i = 0; i < tempVerts.Count; i++)
m_MeshVertexCache[preVertexCount + i] = tempVerts[i];
for (int i = 0; i < tempIndices.Count; i++)
m_MeshIndexCache[preIndexCount + i] = tempIndices[i] + preVertexCount;
SetVerticesDirty();
m_DirtyStartIndex = -1;
m_DirtyEndIndex = -1;
}
#endregion
#region OnPopulateMesh
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
if (m_MeshVertexCache.Count == 0 || m_MeshIndexCache.Count == 0) return;
vh.AddUIVertexStream(m_MeshVertexCache, m_MeshIndexCache);
}
#endregion
#region 生命周期
protected override void OnEnable()
{
base.OnEnable();
RebuildAll();
}
protected override void OnDestroy()
{
base.OnDestroy();
}
#endregion
}
}