优化调试过程,避免刷屏。

更好的调试效果。
This commit is contained in:
2026-06-09 19:33:37 +08:00
parent 95677e9536
commit bed44a6d82
2 changed files with 180 additions and 153 deletions
@@ -40,6 +40,7 @@ namespace XericLibrary.PostProcess
{ {
return GeoLayerPickerRenderPassFeature.Instance.GetMaterialByID(matID); return GeoLayerPickerRenderPassFeature.Instance.GetMaterialByID(matID);
} }
return null; return null;
} }
@@ -73,7 +74,7 @@ namespace XericLibrary.PostProcess
public int totalPixelCount; public int totalPixelCount;
public Vector2 centerPixelPos; public Vector2 centerPixelPos;
public Vector3 centerWorldPos; public Vector3 centerWorldPos;
public Vector3 minWorldPos; public Vector3 minWorldPos;
public Vector3 maxWorldPos; public Vector3 maxWorldPos;
public bool isValid => matID > 0 && segments.Count > 0; public bool isValid => matID > 0 && segments.Count > 0;
@@ -84,6 +85,7 @@ namespace XericLibrary.PostProcess
{ {
return GeoLayerPickerRenderPassFeature.Instance.GetMaterialByID(matID); return GeoLayerPickerRenderPassFeature.Instance.GetMaterialByID(matID);
} }
return null; return null;
} }
@@ -114,7 +116,7 @@ namespace XericLibrary.PostProcess
public Vector2 GetCenterRectLocation(RectTransform rectTransform) public Vector2 GetCenterRectLocation(RectTransform rectTransform)
{ {
var screenPos = GetCenterRectLocation(); var screenPos = GetCenterRectLocation();
Vector2 rectSize = rectTransform.rect.size; Vector2 rectSize = rectTransform.rect.size;
float x = rectTransform.rect.x + screenPos.x * rectSize.x; float x = rectTransform.rect.x + screenPos.x * rectSize.x;
float y = rectTransform.rect.y + screenPos.y * rectSize.y; float y = rectTransform.rect.y + screenPos.y * rectSize.y;
@@ -146,6 +148,7 @@ namespace XericLibrary.PostProcess
{ {
camera = Camera.main; camera = Camera.main;
} }
if (camera == null) if (camera == null)
return Vector2.zero; return Vector2.zero;
@@ -158,6 +161,7 @@ namespace XericLibrary.PostProcess
{ {
camera = Camera.main; camera = Camera.main;
} }
if (camera == null) if (camera == null)
return Vector2.zero; return Vector2.zero;
@@ -212,6 +216,7 @@ namespace XericLibrary.PostProcess
{ {
return material; return material;
} }
return null; return null;
} }
@@ -221,6 +226,7 @@ namespace XericLibrary.PostProcess
{ {
return id; return id;
} }
return -1; return -1;
} }
@@ -356,10 +362,12 @@ namespace XericLibrary.PostProcess
if (enableDebugLog) if (enableDebugLog)
{ {
Debug.Log($"[GeoLayerPicker] 材质孤岛统计完成,共 {m_MaterialIslands.Count} 个孤岛"); using (MacroMath.GetStringBuilder(out var sb))
foreach (var island in m_MaterialIslands)
{ {
Debug.Log($" MatID {island.matID} ({island.GetMaterialName()}): {island.totalPixelCount} 像素, 中心: {island.centerWorldPos}"); foreach (var island in m_MaterialIslands)
sb.Append(
$" MatID {island.matID} ({island.GetMaterialName()}): {island.totalPixelCount} 像素, 中心: {island.centerWorldPos}");
Debug.Log($"[GeoLayerPicker] 材质孤岛统计完成,共 {m_MaterialIslands.Count} 个孤岛\n{sb.ToString()}");
} }
} }
} }
@@ -367,7 +375,7 @@ namespace XericLibrary.PostProcess
private void FindMaterialIslands() private void FindMaterialIslands()
{ {
m_MaterialIslands.Clear(); m_MaterialIslands.Clear();
int width = pickRTSize.x; int width = pickRTSize.x;
int height = pickRTSize.y; int height = pickRTSize.y;
@@ -403,7 +411,7 @@ namespace XericLibrary.PostProcess
if (index >= m_DecodedDataArray.Length) break; if (index >= m_DecodedDataArray.Length) break;
PickedGeoData pixel = m_DecodedDataArray[index]; PickedGeoData pixel = m_DecodedDataArray[index];
if (!pixel.isValid || pixel.matID <= 0) if (!pixel.isValid || pixel.matID <= 0)
{ {
col++; col++;
@@ -417,12 +425,13 @@ namespace XericLibrary.PostProcess
{ {
int checkIndex = rowIndex * width + col; int checkIndex = rowIndex * width + col;
if (checkIndex >= m_DecodedDataArray.Length) break; if (checkIndex >= m_DecodedDataArray.Length) break;
PickedGeoData checkPixel = m_DecodedDataArray[checkIndex]; PickedGeoData checkPixel = m_DecodedDataArray[checkIndex];
if (!checkPixel.isValid || checkPixel.matID != matID) if (!checkPixel.isValid || checkPixel.matID != matID)
{ {
break; break;
} }
col++; col++;
} }
@@ -438,7 +447,8 @@ namespace XericLibrary.PostProcess
return segments; return segments;
} }
private List<MaterialIsland> BuildIslandsForMaterial(int targetMatID, List<List<MaterialSegment>> rowSegments, int width, int height) private List<MaterialIsland> BuildIslandsForMaterial(int targetMatID, List<List<MaterialSegment>> rowSegments,
int width, int height)
{ {
List<MaterialIsland> islands = new List<MaterialIsland>(); List<MaterialIsland> islands = new List<MaterialIsland>();
@@ -493,6 +503,7 @@ namespace XericLibrary.PostProcess
mergedIsland.segments.AddRange(islandToMerge.segments); mergedIsland.segments.AddRange(islandToMerge.segments);
islands.Remove(islandToMerge); islands.Remove(islandToMerge);
} }
mergedIsland.segments.Add(currentSegment); mergedIsland.segments.Add(currentSegment);
islands.Add(mergedIsland); islands.Add(mergedIsland);
} }
@@ -540,6 +551,7 @@ namespace XericLibrary.PostProcess
{ {
rowPixelCounts[seg.rowIndex] = 0; rowPixelCounts[seg.rowIndex] = 0;
} }
rowPixelCounts[seg.rowIndex] += seg.length; rowPixelCounts[seg.rowIndex] += seg.length;
} }
@@ -613,159 +625,172 @@ namespace XericLibrary.PostProcess
private static readonly int DebugMainTex = Shader.PropertyToID("_MainTex"); private static readonly int DebugMainTex = Shader.PropertyToID("_MainTex");
class PickRenderPass : ScriptableRenderPass class PickRenderPass : ScriptableRenderPass
{
public Material passMaterial;
public RTHandle passRTHandle;
public RTHandle passReadbackBuffer;
public List<SubMeshDrawData> passDrawList;
public Rect passSampleRect;
public bool requestReadback;
private int m_MatIDProperty = Shader.PropertyToID("_MatID");
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{ {
public Material passMaterial; if (passMaterial == null || passRTHandle == null || passDrawList == null || passDrawList.Count == 0)
public RTHandle passRTHandle; return;
public RTHandle passReadbackBuffer;
public List<SubMeshDrawData> passDrawList;
public Rect passSampleRect;
public bool requestReadback;
private int m_MatIDProperty = Shader.PropertyToID("_MatID"); CommandBuffer cmd = CommandBufferPool.Get("GeoLayerPickBuffer");
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) cmd.SetRenderTarget(passRTHandle);
cmd.ClearRenderTarget(true, true, new Color(0, 0, 0, 0));
Camera cam = renderingData.cameraData.camera;
Matrix4x4 viewMatrix = cam.worldToCameraMatrix;
Matrix4x4 projMatrix = cam.projectionMatrix;
float ndcXMin = passSampleRect.x * 2f - 1f;
float ndcXMax = (passSampleRect.x + passSampleRect.width) * 2f - 1f;
float ndcYMin = passSampleRect.y * 2f - 1f;
float ndcYMax = (passSampleRect.y + passSampleRect.height) * 2f - 1f;
// 将 NDC 子区域 [ndcMin, ndcMax] 映射到 [-1, 1]
// 投影矩阵变换: ndc = -m00 * viewX/viewZ - m02
// 修改后: ndc_new = scale * ndc_original - offset
// ndcMin → -1: scale * ndcMin - offset = -1 → offset = scale * ndcMin + 1
// ndcMax → +1: scale * ndcMax - offset = +1 → scale = 2/(ndcMax - ndcMin)
float scaleX = 2f / (ndcXMax - ndcXMin);
float scaleY = 2f / (ndcYMax - ndcYMin);
float offsetX = 1f + ndcXMin * scaleX;
float offsetY = 1f + ndcYMin * scaleY;
projMatrix.m00 *= scaleX;
projMatrix.m11 *= scaleY;
projMatrix.m02 += offsetX;
projMatrix.m12 += offsetY;
projMatrix = GL.GetGPUProjectionMatrix(projMatrix, true);
cmd.SetViewProjectionMatrices(viewMatrix, projMatrix);
cmd.SetViewport(new Rect(0, 0, passRTHandle.rt.width, passRTHandle.rt.height));
MaterialPropertyBlock drawMpb = new MaterialPropertyBlock();
for (int i = 0; i < passDrawList.Count; i++)
{ {
if (passMaterial == null || passRTHandle == null || passDrawList == null || passDrawList.Count == 0) var data = passDrawList[i];
return;
CommandBuffer cmd = CommandBufferPool.Get("GeoLayerPickBuffer"); drawMpb.SetInt(m_MatIDProperty, data.uniqueMatID);
cmd.DrawMesh(data.mesh, data.matrix, passMaterial, data.subMeshIndex, 0, drawMpb);
}
cmd.SetRenderTarget(passRTHandle); cmd.SetViewProjectionMatrices(viewMatrix, renderingData.cameraData.GetProjectionMatrix());
cmd.ClearRenderTarget(true, true, new Color(0, 0, 0, 0));
Camera cam = renderingData.cameraData.camera; if (requestReadback && passReadbackBuffer != null)
Matrix4x4 viewMatrix = cam.worldToCameraMatrix; {
Matrix4x4 projMatrix = cam.projectionMatrix; cmd.Blit(passRTHandle, passReadbackBuffer);
}
float ndcXMin = passSampleRect.x * 2f - 1f; context.ExecuteCommandBuffer(cmd);
float ndcXMax = (passSampleRect.x + passSampleRect.width) * 2f - 1f; CommandBufferPool.Release(cmd);
float ndcYMin = passSampleRect.y * 2f - 1f;
float ndcYMax = (passSampleRect.y + passSampleRect.height) * 2f - 1f;
float scaleX = 2f / (ndcXMax - ndcXMin); if (requestReadback && passReadbackBuffer != null)
float scaleY = 2f / (ndcYMax - ndcYMin); {
float offsetX = -1f - ndcXMin * scaleX; AsyncGPUReadback.Request(passReadbackBuffer.rt, 0, TextureFormat.RGBAFloat,
float offsetY = -1f - ndcYMin * scaleY; GeoLayerPickerRenderPassFeature.Instance.OnReadbackComplete);
projMatrix.m00 *= scaleX;
projMatrix.m11 *= scaleY;
projMatrix.m02 += offsetX;
projMatrix.m12 += offsetY;
projMatrix = GL.GetGPUProjectionMatrix(projMatrix, true);
cmd.SetViewProjectionMatrices(viewMatrix, projMatrix);
cmd.SetViewport(new Rect(0, 0, passRTHandle.rt.width, passRTHandle.rt.height));
MaterialPropertyBlock drawMpb = new MaterialPropertyBlock();
for (int i = 0; i < passDrawList.Count; i++)
{
var data = passDrawList[i];
drawMpb.SetInt(m_MatIDProperty, data.uniqueMatID);
cmd.DrawMesh(data.mesh, data.matrix, passMaterial, data.subMeshIndex, 0, drawMpb);
}
cmd.SetViewProjectionMatrices(viewMatrix, renderingData.cameraData.GetProjectionMatrix());
if (requestReadback && passReadbackBuffer != null)
{
cmd.Blit(passRTHandle, passReadbackBuffer);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
if (requestReadback && passReadbackBuffer != null)
{
AsyncGPUReadback.Request(passReadbackBuffer.rt, 0, TextureFormat.RGBAFloat,
GeoLayerPickerRenderPassFeature.Instance.OnReadbackComplete);
}
} }
} }
}
class DebugOverlayRenderPass : ScriptableRenderPass class DebugOverlayRenderPass : ScriptableRenderPass
{
public RTHandle sourceRTHandle;
public Material overlayMaterial;
public Rect sampleRect;
private static readonly int DebugRectProp = Shader.PropertyToID("_DebugRect");
private static readonly int DebugMainTex = Shader.PropertyToID("_MainTex");
private static bool s_HasLogged = false;
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{ {
public RTHandle sourceRTHandle; if (!s_HasLogged && GeoLayerPickerRenderPassFeature.Instance != null &&
public Material overlayMaterial; GeoLayerPickerRenderPassFeature.Instance.enableDebugLog)
public Rect sampleRect;
private static readonly int DebugRectProp = Shader.PropertyToID("_DebugRect");
private static readonly int DebugMainTex = Shader.PropertyToID("_MainTex");
private static bool s_HasLogged = false;
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{ {
if (!s_HasLogged && GeoLayerPickerRenderPassFeature.Instance != null && GeoLayerPickerRenderPassFeature.Instance.enableDebugLog) Debug.Log($"[GeoLayerPicker] DebugOverlayRenderPass.Execute called" +
{ $" overlayMaterial: {(overlayMaterial != null ? "OK" : "null")}" +
Debug.Log($"[GeoLayerPicker] DebugOverlayRenderPass.Execute called"); $" sourceRTHandle: {(sourceRTHandle != null ? "OK" : "null")}" +
Debug.Log($" overlayMaterial: {(overlayMaterial != null ? "OK" : "null")}"); $" sampleRect: {sampleRect}");
Debug.Log($" sourceRTHandle: {(sourceRTHandle != null ? "OK" : "null")}"); s_HasLogged = true;
Debug.Log($" sampleRect: {sampleRect}");
s_HasLogged = true;
}
if (overlayMaterial == null)
{
if (GeoLayerPickerRenderPassFeature.Instance != null && GeoLayerPickerRenderPassFeature.Instance.enableDebugLog)
{
Debug.LogWarning("[GeoLayerPicker] DebugOverlayRenderPass: overlayMaterial is null");
}
return;
}
if (sourceRTHandle == null)
{
if (GeoLayerPickerRenderPassFeature.Instance != null && GeoLayerPickerRenderPassFeature.Instance.enableDebugLog)
{
Debug.LogWarning("[GeoLayerPicker] DebugOverlayRenderPass: sourceRTHandle is null");
}
return;
}
RTHandle currentColorTarget = renderingData.cameraData.renderer.cameraColorTargetHandle;
if (currentColorTarget == null)
{
if (GeoLayerPickerRenderPassFeature.Instance != null && GeoLayerPickerRenderPassFeature.Instance.enableDebugLog)
{
Debug.LogWarning("[GeoLayerPicker] DebugOverlayRenderPass: currentColorTarget is null");
}
return;
}
CommandBuffer debugCmd = CommandBufferPool.Get("GeoPickerDebugOverlay");
debugCmd.Clear();
MaterialPropertyBlock debugMpb = new MaterialPropertyBlock();
debugMpb.SetTexture(DebugMainTex, sourceRTHandle);
debugMpb.SetVector(DebugRectProp, new Vector4(
sampleRect.x,
sampleRect.y,
sampleRect.width,
sampleRect.height
));
CoreUtils.SetRenderTarget(debugCmd, currentColorTarget);
debugCmd.SetViewport(new Rect(0, 0, renderingData.cameraData.camera.pixelWidth, renderingData.cameraData.camera.pixelHeight));
debugCmd.DrawProcedural(
Matrix4x4.identity,
overlayMaterial,
0,
MeshTopology.Triangles,
3,
1,
debugMpb
);
context.ExecuteCommandBuffer(debugCmd);
CommandBufferPool.Release(debugCmd);
} }
}
private PickRenderPass m_PickPass; if (overlayMaterial == null)
private DebugOverlayRenderPass m_DebugOverlayPass; {
if (GeoLayerPickerRenderPassFeature.Instance != null &&
GeoLayerPickerRenderPassFeature.Instance.enableDebugLog)
{
Debug.LogWarning("[GeoLayerPicker] DebugOverlayRenderPass: overlayMaterial is null");
}
return;
}
if (sourceRTHandle == null)
{
if (GeoLayerPickerRenderPassFeature.Instance != null &&
GeoLayerPickerRenderPassFeature.Instance.enableDebugLog)
{
Debug.LogWarning("[GeoLayerPicker] DebugOverlayRenderPass: sourceRTHandle is null");
}
return;
}
RTHandle currentColorTarget = renderingData.cameraData.renderer.cameraColorTargetHandle;
if (currentColorTarget == null)
{
if (GeoLayerPickerRenderPassFeature.Instance != null &&
GeoLayerPickerRenderPassFeature.Instance.enableDebugLog)
{
Debug.LogWarning("[GeoLayerPicker] DebugOverlayRenderPass: currentColorTarget is null");
}
return;
}
CommandBuffer debugCmd = CommandBufferPool.Get("GeoPickerDebugOverlay");
debugCmd.Clear();
MaterialPropertyBlock debugMpb = new MaterialPropertyBlock();
debugMpb.SetTexture(DebugMainTex, sourceRTHandle);
debugMpb.SetVector(DebugRectProp, new Vector4(
sampleRect.x,
sampleRect.y,
sampleRect.width,
sampleRect.height
));
CoreUtils.SetRenderTarget(debugCmd, currentColorTarget);
debugCmd.SetViewport(new Rect(0, 0, renderingData.cameraData.camera.pixelWidth,
renderingData.cameraData.camera.pixelHeight));
debugCmd.DrawProcedural(
Matrix4x4.identity,
overlayMaterial,
0,
MeshTopology.Triangles,
3,
1,
debugMpb
);
context.ExecuteCommandBuffer(debugCmd);
CommandBufferPool.Release(debugCmd);
}
}
private PickRenderPass m_PickPass;
private DebugOverlayRenderPass m_DebugOverlayPass;
public override void Create() public override void Create()
{ {
@@ -827,7 +852,8 @@ namespace XericLibrary.PostProcess
} }
else else
{ {
Debug.LogError("[GeoLayerPicker] 找不到调试 Shader: Hidden/XericLibrary/GeoLayerPicker/ScreenOverrideRect"); Debug.LogError(
"[GeoLayerPicker] 找不到调试 Shader: Hidden/XericLibrary/GeoLayerPicker/ScreenOverrideRect");
} }
} }
} }
@@ -950,7 +976,7 @@ namespace XericLibrary.PostProcess
foreach (var mf in m_GeoMeshes) foreach (var mf in m_GeoMeshes)
{ {
if (mf == null || mf.sharedMesh == null) continue; if (mf == null || mf.sharedMesh == null) continue;
var renderer = mf.GetComponent<MeshRenderer>(); var renderer = mf.GetComponent<MeshRenderer>();
Material[] materials = renderer != null ? renderer.sharedMaterials : null; Material[] materials = renderer != null ? renderer.sharedMaterials : null;
@@ -988,10 +1014,11 @@ namespace XericLibrary.PostProcess
if (enableDebugLog) if (enableDebugLog)
{ {
Debug.Log($"[GeoLayerPicker] 材质映射重建完成,共 {m_MaterialToID.Count} 个材质"); using (MacroMath.GetStringBuilder(out var sb))
foreach (var kvp in m_MaterialToID)
{ {
Debug.Log($" ID {kvp.Value}: {kvp.Key.name}"); foreach (var kvp in m_MaterialToID)
sb.Append($" ID {kvp.Value}: {kvp.Key.name}");
Debug.Log($"[GeoLayerPicker] 材质映射重建完成,共 {m_MaterialToID.Count} 个材质 \n{sb.ToString()}");
} }
} }
} }
@@ -75,8 +75,8 @@ Shader "Hidden/XericLibrary/GeoLayerPicker/ScreenOverrideRect"
} }
// 将世界坐标映射为可见颜色 // 将世界坐标映射为可见颜色
float3 debugColor = abs(sin(col.rgb * float3(0.03, 0.1, 0.05))) * 0.5; float3 debugColor = sin(col.rgb * float3(0.03, 0.1, 0.05)) * 0.5 + 0.5;
float3 debugColor2 = abs(cos(col.rgb * float3(0.05, 0.09, 0.07))) * 0.5 + 0.5; float3 debugColor2 = cos(col.rgb * float3(0.05, 0.09, 0.07)) * 0.5 + 0.5;
float matIDColor = frac(col.a * 0.07); float matIDColor = frac(col.a * 0.07);
debugColor = lerp(debugColor, debugColor2, matIDColor); debugColor = lerp(debugColor, debugColor2, matIDColor);
return float4(debugColor, 0.9); return float4(debugColor, 0.9);