添加了覆盖屏幕空间的纹理检查。
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
# Unity 屏幕空间后处理阶段检查器-模型数据提取器
|
# Unity 屏幕空间后处理阶段检查器-模型数据提取器
|
||||||
|
|
||||||
|
依赖 [MaterialFunctionLibrary](https://gitea.xeric.cc/LiRuochen_WorkFlow/MaterialFunctionLibrary) 插件。
|
||||||
@@ -88,7 +88,7 @@ namespace XericLibrary.PostProcess
|
|||||||
#region 数据访问 API
|
#region 数据访问 API
|
||||||
|
|
||||||
private PickedGeoData[] m_DecodedDataArray;
|
private PickedGeoData[] m_DecodedDataArray;
|
||||||
private int m_ValidDataCount = 0;
|
private int m_ValidDataCount = 0;
|
||||||
|
|
||||||
public IReadOnlyList<PickedGeoData> GetDecodedData() => m_DecodedDataArray;
|
public IReadOnlyList<PickedGeoData> GetDecodedData() => m_DecodedDataArray;
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ namespace XericLibrary.PostProcess
|
|||||||
|
|
||||||
int index = pixelY * pickRTSize.x + pixelX;
|
int index = pixelY * pickRTSize.x + pixelX;
|
||||||
if (index < 0 || index >= m_DecodedDataArray.Length) return false;
|
if (index < 0 || index >= m_DecodedDataArray.Length) return false;
|
||||||
|
|
||||||
data = m_DecodedDataArray[index];
|
data = m_DecodedDataArray[index];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -136,38 +136,44 @@ namespace XericLibrary.PostProcess
|
|||||||
|
|
||||||
#region Inspector 配置参数
|
#region Inspector 配置参数
|
||||||
|
|
||||||
[Header("拾取材质与尺寸")]
|
[Header("拾取材质与尺寸")] public Material pickMaterial;
|
||||||
public Material pickMaterial;
|
|
||||||
public Vector2Int pickRTSize = new Vector2Int(64, 64);
|
public Vector2Int pickRTSize = new Vector2Int(64, 64);
|
||||||
|
|
||||||
[Header("采样区域设置")]
|
[Header("采样区域设置")] public Rect sampleRect = new Rect(0f, 0f, 1f, 1f);
|
||||||
public Rect sampleRect = new Rect(0f, 0f, 1f, 1f);
|
|
||||||
|
|
||||||
[Header("读取频率控制")]
|
[Header("读取频率控制")] [Range(0.01f, 1.0f)]
|
||||||
[Range(0.01f, 1.0f)]
|
|
||||||
public float readbackInterval = 0.1f;
|
public float readbackInterval = 0.1f;
|
||||||
|
|
||||||
[Header("调试设置")]
|
[Header("调试设置")] public bool enableDebugLog = false;
|
||||||
public bool enableDebugLog = false;
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// 核心修改:全面使用 RTHandle 替代 RenderTexture
|
// 核心修改:全面使用 RTHandle 替代 RenderTexture
|
||||||
private RTHandle m_PickRTHandle;
|
private RTHandle m_PickRTHandle;
|
||||||
private RTHandle m_ReadbackBufferHandle;
|
private RTHandle m_ReadbackBufferHandle;
|
||||||
|
|
||||||
private float m_TimeSinceLastReadback = 0f;
|
private float m_TimeSinceLastReadback = 0f;
|
||||||
private bool m_IsReadbackInProgress = false;
|
private bool m_IsReadbackInProgress = false;
|
||||||
private int m_ReadbackFrameCounter = 0;
|
private int m_ReadbackFrameCounter = 0;
|
||||||
|
|
||||||
|
// 调试覆盖图相关
|
||||||
|
private Material m_DebugOverlayMaterial;
|
||||||
|
private static readonly int DebugRectProp = Shader.PropertyToID("_DebugRect");
|
||||||
|
private static readonly int DebugMainTex = Shader.PropertyToID("_MainTex");
|
||||||
|
|
||||||
class CustomRenderPass : ScriptableRenderPass
|
class CustomRenderPass : ScriptableRenderPass
|
||||||
{
|
{
|
||||||
public Material passMaterial;
|
public Material passMaterial;
|
||||||
public RTHandle passRTHandle;
|
public RTHandle passRTHandle;
|
||||||
public RTHandle passReadbackBuffer;
|
public RTHandle passReadbackBuffer;
|
||||||
public List<SubMeshDrawData> passDrawList;
|
public List<SubMeshDrawData> passDrawList;
|
||||||
public Rect passSampleRect;
|
public Rect passSampleRect;
|
||||||
public bool requestReadback;
|
public bool requestReadback;
|
||||||
|
|
||||||
|
// 屏幕调试
|
||||||
|
public bool drawDebugOverlay;
|
||||||
|
public Material debugOverlayMaterial;
|
||||||
|
public RTHandle cameraColorTarget; // 用于获取屏幕渲染目标
|
||||||
|
|
||||||
private int m_MatIDProperty = Shader.PropertyToID("_MatID");
|
private int m_MatIDProperty = Shader.PropertyToID("_MatID");
|
||||||
|
|
||||||
@@ -223,12 +229,52 @@ namespace XericLibrary.PostProcess
|
|||||||
context.ExecuteCommandBuffer(cmd);
|
context.ExecuteCommandBuffer(cmd);
|
||||||
CommandBufferPool.Release(cmd);
|
CommandBufferPool.Release(cmd);
|
||||||
|
|
||||||
// 在 CommandBuffer 执行后,发起回读请求(读取隔离缓冲区)
|
|
||||||
if (requestReadback && passReadbackBuffer != null)
|
if (requestReadback && passReadbackBuffer != null)
|
||||||
{
|
{
|
||||||
AsyncGPUReadback.Request(passReadbackBuffer.rt, 0, TextureFormat.RGBAFloat,
|
AsyncGPUReadback.Request(passReadbackBuffer.rt, 0, TextureFormat.RGBAFloat,
|
||||||
GeoLayerPickerRenderPassFeature.Instance.OnReadbackComplete);
|
GeoLayerPickerRenderPassFeature.Instance.OnReadbackComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 绘制全屏调试图 ---
|
||||||
|
if (drawDebugOverlay && debugOverlayMaterial != null && passRTHandle != null)
|
||||||
|
{
|
||||||
|
var feature = GeoLayerPickerRenderPassFeature.Instance;
|
||||||
|
if (feature == null) return;
|
||||||
|
|
||||||
|
RTHandle currentColorTarget = renderingData.cameraData.renderer.cameraColorTargetHandle;
|
||||||
|
CommandBuffer debugCmd = CommandBufferPool.Get("GeoPickerDebugOverlay");
|
||||||
|
|
||||||
|
// 【核心 1】:使用 MaterialPropertyBlock 隔离参数
|
||||||
|
MaterialPropertyBlock mpb = new MaterialPropertyBlock();
|
||||||
|
|
||||||
|
// 【修正 1】:直接使用字符串名称和 RTHandle 对象本身(RTHandle 隐式转为 Texture)
|
||||||
|
// 彻底避开 nameID (RenderTargetIdentifier) 的类型转换坑!
|
||||||
|
mpb.SetTexture(DebugMainTex, passRTHandle);
|
||||||
|
|
||||||
|
mpb.SetVector(DebugRectProp, new Vector4(
|
||||||
|
feature.sampleRect.x,
|
||||||
|
feature.sampleRect.y,
|
||||||
|
feature.sampleRect.width,
|
||||||
|
feature.sampleRect.height
|
||||||
|
));
|
||||||
|
|
||||||
|
// 设置渲染目标为当前屏幕
|
||||||
|
CoreUtils.SetRenderTarget(debugCmd, currentColorTarget);
|
||||||
|
|
||||||
|
// 【修正 2】:DrawProcedural 必须显式传入 instanceCount (1) 作为第 6 个参数!
|
||||||
|
debugCmd.DrawProcedural(
|
||||||
|
Matrix4x4.identity, // 1. matrix
|
||||||
|
debugOverlayMaterial, // 2. material
|
||||||
|
0, // 3. shaderPass
|
||||||
|
MeshTopology.Triangles, // 4. topology
|
||||||
|
3, // 5. vertexCount (全屏三角形)
|
||||||
|
1, // 6. instanceCount (必须显式写 1!)
|
||||||
|
mpb // 7. MaterialPropertyBlock
|
||||||
|
);
|
||||||
|
|
||||||
|
context.ExecuteCommandBuffer(debugCmd);
|
||||||
|
CommandBufferPool.Release(debugCmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,19 +291,28 @@ namespace XericLibrary.PostProcess
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 释放旧的 RTHandle
|
// 释放旧的 RTHandle
|
||||||
if (m_PickRTHandle != null) { m_PickRTHandle.Release(); m_PickRTHandle = null; }
|
if (m_PickRTHandle != null)
|
||||||
if (m_ReadbackBufferHandle != null) { m_ReadbackBufferHandle.Release(); m_ReadbackBufferHandle = null; }
|
{
|
||||||
|
m_PickRTHandle.Release();
|
||||||
|
m_PickRTHandle = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ReadbackBufferHandle != null)
|
||||||
|
{
|
||||||
|
m_ReadbackBufferHandle.Release();
|
||||||
|
m_ReadbackBufferHandle = null;
|
||||||
|
}
|
||||||
|
|
||||||
// 分配新的 RTHandle
|
// 分配新的 RTHandle
|
||||||
m_PickRTHandle = RTHandles.Alloc(
|
m_PickRTHandle = RTHandles.Alloc(
|
||||||
pickRTSize.x, pickRTSize.y,
|
pickRTSize.x, pickRTSize.y,
|
||||||
colorFormat: GraphicsFormat.R32G32B32A32_SFloat,
|
colorFormat: GraphicsFormat.R32G32B32A32_SFloat,
|
||||||
filterMode: FilterMode.Point,
|
filterMode: FilterMode.Point,
|
||||||
name: "GeoLayerPickRT"
|
name: "GeoLayerPickRT"
|
||||||
);
|
);
|
||||||
|
|
||||||
m_ReadbackBufferHandle = RTHandles.Alloc(
|
m_ReadbackBufferHandle = RTHandles.Alloc(
|
||||||
pickRTSize.x, pickRTSize.y,
|
pickRTSize.x, pickRTSize.y,
|
||||||
colorFormat: GraphicsFormat.R32G32B32A32_SFloat,
|
colorFormat: GraphicsFormat.R32G32B32A32_SFloat,
|
||||||
filterMode: FilterMode.Point,
|
filterMode: FilterMode.Point,
|
||||||
name: "GeoLayerReadbackBuffer"
|
name: "GeoLayerReadbackBuffer"
|
||||||
@@ -267,7 +322,21 @@ namespace XericLibrary.PostProcess
|
|||||||
if (m_DecodedDataArray == null || m_DecodedDataArray.Length != requiredLength)
|
if (m_DecodedDataArray == null || m_DecodedDataArray.Length != requiredLength)
|
||||||
{
|
{
|
||||||
m_DecodedDataArray = new PickedGeoData[requiredLength];
|
m_DecodedDataArray = new PickedGeoData[requiredLength];
|
||||||
if(enableDebugLog) Debug.Log($"[GeoLayerPicker] 数组重新初始化,长度: {requiredLength}");
|
if (enableDebugLog) Debug.Log($"[GeoLayerPicker] 数组重新初始化,长度: {requiredLength}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化调试材质
|
||||||
|
if (m_DebugOverlayMaterial == null)
|
||||||
|
{
|
||||||
|
Shader overlayShader = Shader.Find("Hidden/XericLibrary/ScreenOverrideRect");
|
||||||
|
if (overlayShader != null)
|
||||||
|
{
|
||||||
|
m_DebugOverlayMaterial = CoreUtils.CreateEngineMaterial(overlayShader);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError("[GeoLayerPicker] 找不到调试 Shader: Hidden/XericLibrary/Debug/GeoPickerOverlay");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,14 +348,14 @@ namespace XericLibrary.PostProcess
|
|||||||
{
|
{
|
||||||
RebuildDrawList();
|
RebuildDrawList();
|
||||||
m_IsDirty = false;
|
m_IsDirty = false;
|
||||||
if(enableDebugLog) Debug.Log($"[GeoLayerPicker] DrawList 重建完成,包含 {m_DrawList.Count} 个 SubMesh。");
|
if (enableDebugLog) Debug.Log($"[GeoLayerPicker] DrawList 重建完成,包含 {m_DrawList.Count} 个 SubMesh。");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ReadbackFrameCounter++;
|
m_ReadbackFrameCounter++;
|
||||||
if (m_IsReadbackInProgress && m_ReadbackFrameCounter > 60)
|
if (m_IsReadbackInProgress && m_ReadbackFrameCounter > 60)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[GeoLayerPicker] AsyncGPUReadback 疑似卡死,强制重置并清理队列。");
|
Debug.LogWarning("[GeoLayerPicker] AsyncGPUReadback 疑似卡死,强制重置并清理队列。");
|
||||||
AsyncGPUReadback.WaitAllRequests();
|
AsyncGPUReadback.WaitAllRequests();
|
||||||
m_IsReadbackInProgress = false;
|
m_IsReadbackInProgress = false;
|
||||||
m_ReadbackFrameCounter = 0;
|
m_ReadbackFrameCounter = 0;
|
||||||
}
|
}
|
||||||
@@ -298,17 +367,23 @@ namespace XericLibrary.PostProcess
|
|||||||
{
|
{
|
||||||
m_TimeSinceLastReadback = 0f;
|
m_TimeSinceLastReadback = 0f;
|
||||||
m_IsReadbackInProgress = true;
|
m_IsReadbackInProgress = true;
|
||||||
m_ReadbackFrameCounter = 0;
|
m_ReadbackFrameCounter = 0;
|
||||||
shouldRead = true;
|
shouldRead = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 后处理参数
|
||||||
m_ScriptablePass.passMaterial = pickMaterial;
|
m_ScriptablePass.passMaterial = pickMaterial;
|
||||||
m_ScriptablePass.passRTHandle = m_PickRTHandle;
|
m_ScriptablePass.passRTHandle = m_PickRTHandle;
|
||||||
m_ScriptablePass.passReadbackBuffer = m_ReadbackBufferHandle;
|
m_ScriptablePass.passReadbackBuffer = m_ReadbackBufferHandle;
|
||||||
m_ScriptablePass.passDrawList = m_DrawList;
|
m_ScriptablePass.passDrawList = m_DrawList;
|
||||||
m_ScriptablePass.passSampleRect = sampleRect;
|
m_ScriptablePass.passSampleRect = sampleRect;
|
||||||
m_ScriptablePass.requestReadback = shouldRead;
|
m_ScriptablePass.requestReadback = shouldRead;
|
||||||
|
|
||||||
|
// 配置调试覆盖图参数
|
||||||
|
m_ScriptablePass.drawDebugOverlay = enableDebugLog; // 由 Inspector 开关控制
|
||||||
|
m_ScriptablePass.debugOverlayMaterial = m_DebugOverlayMaterial;
|
||||||
|
// m_ScriptablePass.cameraColorTarget = renderer.cameraColorTargetHandle; // 获取当前屏幕目标
|
||||||
|
|
||||||
renderer.EnqueuePass(m_ScriptablePass);
|
renderer.EnqueuePass(m_ScriptablePass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +391,7 @@ namespace XericLibrary.PostProcess
|
|||||||
{
|
{
|
||||||
m_IsReadbackInProgress = false;
|
m_IsReadbackInProgress = false;
|
||||||
|
|
||||||
if (request.hasError || m_DecodedDataArray == null)
|
if (request.hasError || m_DecodedDataArray == null)
|
||||||
{
|
{
|
||||||
Debug.LogError("[GeoLayerPicker] Readback 发生错误或数组为空!");
|
Debug.LogError("[GeoLayerPicker] Readback 发生错误或数组为空!");
|
||||||
return;
|
return;
|
||||||
@@ -324,14 +399,14 @@ namespace XericLibrary.PostProcess
|
|||||||
|
|
||||||
var rawData = request.GetData<Color>();
|
var rawData = request.GetData<Color>();
|
||||||
if (rawData.Length == 0) return;
|
if (rawData.Length == 0) return;
|
||||||
|
|
||||||
// 修复:使用 m_ReadbackBufferHandle.rt 获取宽高
|
// 修复:使用 m_ReadbackBufferHandle.rt 获取宽高
|
||||||
int width = m_ReadbackBufferHandle.rt.width;
|
int width = m_ReadbackBufferHandle.rt.width;
|
||||||
int height = m_ReadbackBufferHandle.rt.height;
|
int height = m_ReadbackBufferHandle.rt.height;
|
||||||
int count = m_DecodedDataArray.Length;
|
int count = m_DecodedDataArray.Length;
|
||||||
|
|
||||||
bool flipY = SystemInfo.graphicsUVStartsAtTop;
|
bool flipY = SystemInfo.graphicsUVStartsAtTop;
|
||||||
m_ValidDataCount = 0;
|
m_ValidDataCount = 0;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
@@ -341,15 +416,15 @@ namespace XericLibrary.PostProcess
|
|||||||
int sourceY = flipY ? (height - 1 - y) : y;
|
int sourceY = flipY ? (height - 1 - y) : y;
|
||||||
int sourceIndex = sourceY * width + x;
|
int sourceIndex = sourceY * width + x;
|
||||||
|
|
||||||
if (sourceIndex < 0 || sourceIndex >= rawData.Length)
|
if (sourceIndex < 0 || sourceIndex >= rawData.Length)
|
||||||
{
|
{
|
||||||
m_DecodedDataArray[i] = new PickedGeoData { isValid = false };
|
m_DecodedDataArray[i] = new PickedGeoData { isValid = false };
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color pixel = rawData[sourceIndex];
|
Color pixel = rawData[sourceIndex];
|
||||||
|
|
||||||
if (pixel.a > 0.5f)
|
if (pixel.a > 0.5f)
|
||||||
{
|
{
|
||||||
m_DecodedDataArray[i] = new PickedGeoData
|
m_DecodedDataArray[i] = new PickedGeoData
|
||||||
{
|
{
|
||||||
@@ -364,7 +439,7 @@ namespace XericLibrary.PostProcess
|
|||||||
m_DecodedDataArray[i] = new PickedGeoData { isValid = false, matID = 0 };
|
m_DecodedDataArray[i] = new PickedGeoData { isValid = false, matID = 0 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enableDebugLog)
|
if (enableDebugLog)
|
||||||
{
|
{
|
||||||
Debug.Log($"[GeoLayerPicker] 回读完成!总像素: {count}, 有效拾取像素: {m_ValidDataCount}");
|
Debug.Log($"[GeoLayerPicker] 回读完成!总像素: {count}, 有效拾取像素: {m_ValidDataCount}");
|
||||||
@@ -395,16 +470,25 @@ namespace XericLibrary.PostProcess
|
|||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
// 修复:正确释放 RTHandle 并置空
|
// 修复:正确释放 RTHandle 并置空
|
||||||
if (m_PickRTHandle != null)
|
if (m_PickRTHandle != null)
|
||||||
{
|
{
|
||||||
m_PickRTHandle.Release();
|
m_PickRTHandle.Release();
|
||||||
m_PickRTHandle = null;
|
m_PickRTHandle = null;
|
||||||
}
|
}
|
||||||
if (m_ReadbackBufferHandle != null)
|
|
||||||
{
|
if (m_ReadbackBufferHandle != null)
|
||||||
m_ReadbackBufferHandle.Release();
|
{
|
||||||
m_ReadbackBufferHandle = null;
|
m_ReadbackBufferHandle.Release();
|
||||||
|
m_ReadbackBufferHandle = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 释放调试材质
|
||||||
|
if (m_DebugOverlayMaterial != null)
|
||||||
|
{
|
||||||
|
CoreUtils.Destroy(m_DebugOverlayMaterial);
|
||||||
|
m_DebugOverlayMaterial = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (Instance == this) Instance = null;
|
if (Instance == this) Instance = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user