添加从纹理到屏幕空间的换算。

This commit is contained in:
2026-06-08 17:10:59 +08:00
parent c3b9eef683
commit efc9ce0456
@@ -1,3 +1,4 @@
using System;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering; using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal; using UnityEngine.Rendering.Universal;
@@ -88,6 +89,45 @@ namespace XericLibrary.PostProcess
var mat = GetMaterial(); var mat = GetMaterial();
return mat != null ? mat.name : "Unknown"; return mat != null ? mat.name : "Unknown";
} }
public Vector2 GetCenterRectLocation()
{
var feature = GeoLayerPickerRenderPassFeature.Instance;
if (feature == null)
return Vector2.zero;
float texWidth = feature.pickRTSize.x;
float texHeight = feature.pickRTSize.y;
float normalizedX = centerPixelPos.x / texWidth;
float normalizedY = centerPixelPos.y / texHeight;
return new Vector2(normalizedX, normalizedY);
}
public Vector2 GetCenterRectLocation(RectTransform rectTransform)
{
var normalized = GetCenterRectLocation();
Vector2 rectSize = rectTransform.rect.size;
float x = rectTransform.rect.x + normalized.x * rectSize.x;
float y = rectTransform.rect.y + normalized.y * rectSize.y;
return new Vector2(x, y);
}
public Vector2 GetCenterRectAnchoredPosition(RectTransform rectTransform)
{
var normalized = GetCenterRectLocation();
Vector2 pivot = rectTransform.pivot;
Vector2 rectSize = rectTransform.rect.size;
float anchoredX = (normalized.x - pivot.x) * rectSize.x;
float anchoredY = (normalized.y - pivot.y) * rectSize.y;
return new Vector2(anchoredX, anchoredY);
}
} }
/// <summary> /// <summary>
@@ -495,79 +535,63 @@ namespace XericLibrary.PostProcess
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{ {
if (passMaterial == null || passRTHandle == null || passDrawList == null || passDrawList.Count == 0) if (passMaterial != null && passRTHandle != null && passDrawList != null && passDrawList.Count > 0)
return;
CommandBuffer cmd = CommandBufferPool.Get("GeoLayerPickBuffer");
// 手动设置渲染目标并清理,避免 URP 隐式状态干扰
cmd.SetRenderTarget(passRTHandle);
cmd.ClearRenderTarget(true, true, new Color(0, 0, 0, 0));
if (drawDebugOverlay)
{ {
Debug.Log($"[GeoLayerPicker] 开始绘制 {passDrawList.Count} 个SubMesh"); CommandBuffer cmd = CommandBufferPool.Get("GeoLayerPickBuffer");
Debug.Log($"[GeoLayerPicker] 渲染目标: {passRTHandle.rt.name}, 尺寸: {passRTHandle.rt.width}x{passRTHandle.rt.height}");
}
Camera cam = renderingData.cameraData.camera; cmd.SetRenderTarget(passRTHandle);
Matrix4x4 viewMatrix = cam.worldToCameraMatrix; cmd.ClearRenderTarget(true, true, new Color(0, 0, 0, 0));
Matrix4x4 projMatrix = cam.projectionMatrix;
float ndcXMin = passSampleRect.x * 2f - 1f; Camera cam = renderingData.cameraData.camera;
float ndcXMax = (passSampleRect.x + passSampleRect.width) * 2f - 1f; Matrix4x4 viewMatrix = cam.worldToCameraMatrix;
float ndcYMin = passSampleRect.y * 2f - 1f; Matrix4x4 projMatrix = cam.projectionMatrix;
float ndcYMax = (passSampleRect.y + passSampleRect.height) * 2f - 1f;
float scaleX = 2f / (ndcXMax - ndcXMin); float ndcXMin = passSampleRect.x * 2f - 1f;
float scaleY = 2f / (ndcYMax - ndcYMin); float ndcXMax = (passSampleRect.x + passSampleRect.width) * 2f - 1f;
float offsetX = -1f - ndcXMin * scaleX; float ndcYMin = passSampleRect.y * 2f - 1f;
float offsetY = -1f - ndcYMin * scaleY; float ndcYMax = (passSampleRect.y + passSampleRect.height) * 2f - 1f;
projMatrix.m00 *= scaleX; float scaleX = 2f / (ndcXMax - ndcXMin);
projMatrix.m11 *= scaleY; float scaleY = 2f / (ndcYMax - ndcYMin);
projMatrix.m02 += offsetX; float offsetX = -1f - ndcXMin * scaleX;
projMatrix.m12 += offsetY; float offsetY = -1f - ndcYMin * scaleY;
projMatrix = GL.GetGPUProjectionMatrix(projMatrix, true); projMatrix.m00 *= scaleX;
cmd.SetViewProjectionMatrices(viewMatrix, projMatrix); projMatrix.m11 *= scaleY;
cmd.SetViewport(new Rect(0, 0, passRTHandle.rt.width, passRTHandle.rt.height)); projMatrix.m02 += offsetX;
projMatrix.m12 += offsetY;
MaterialPropertyBlock drawMpb = new MaterialPropertyBlock(); projMatrix = GL.GetGPUProjectionMatrix(projMatrix, true);
cmd.SetViewProjectionMatrices(viewMatrix, projMatrix);
for (int i = 0; i < passDrawList.Count; i++) cmd.SetViewport(new Rect(0, 0, passRTHandle.rt.width, passRTHandle.rt.height));
{
var data = passDrawList[i]; MaterialPropertyBlock drawMpb = new MaterialPropertyBlock();
drawMpb.SetInt(m_MatIDProperty, data.uniqueMatID); for (int i = 0; i < passDrawList.Count; i++)
cmd.DrawMesh(data.mesh, data.matrix, passMaterial, data.subMeshIndex, 0, drawMpb);
if (GeoLayerPickerRenderPassFeature.Instance != null &&
GeoLayerPickerRenderPassFeature.Instance.enableDebugLog &&
(i == 0 || i == passDrawList.Count - 1))
{ {
Debug.Log($"[GeoLayerPicker] 绘制第{i}个SubMesh, MatID={data.uniqueMatID}, 材质={data.material?.name ?? "null"}"); 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);
} }
} }
cmd.SetViewProjectionMatrices(viewMatrix, renderingData.cameraData.GetProjectionMatrix());
// 如果本帧需要回读,将数据安全地 Blit 到隔离缓冲区
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);
}
// --- 绘制全屏调试图 ---
if (drawDebugOverlay && debugOverlayMaterial != null && passRTHandle != null) if (drawDebugOverlay && debugOverlayMaterial != null && passRTHandle != null)
{ {
var feature = GeoLayerPickerRenderPassFeature.Instance; var feature = GeoLayerPickerRenderPassFeature.Instance;
@@ -576,11 +600,7 @@ namespace XericLibrary.PostProcess
RTHandle currentColorTarget = renderingData.cameraData.renderer.cameraColorTargetHandle; RTHandle currentColorTarget = renderingData.cameraData.renderer.cameraColorTargetHandle;
CommandBuffer debugCmd = CommandBufferPool.Get("GeoPickerDebugOverlay"); CommandBuffer debugCmd = CommandBufferPool.Get("GeoPickerDebugOverlay");
// 【核心 1】:使用 MaterialPropertyBlock 隔离参数
MaterialPropertyBlock debugMpb = new MaterialPropertyBlock(); MaterialPropertyBlock debugMpb = new MaterialPropertyBlock();
// 【修正 1】:直接使用字符串名称和 RTHandle 对象本身(RTHandle 隐式转为 Texture)
// 彻底避开 nameID (RenderTargetIdentifier) 的类型转换坑!
debugMpb.SetTexture(DebugMainTex, passRTHandle); debugMpb.SetTexture(DebugMainTex, passRTHandle);
debugMpb.SetVector(DebugRectProp, new Vector4( debugMpb.SetVector(DebugRectProp, new Vector4(
@@ -590,18 +610,16 @@ namespace XericLibrary.PostProcess
feature.sampleRect.height feature.sampleRect.height
)); ));
// 设置渲染目标为当前屏幕
CoreUtils.SetRenderTarget(debugCmd, currentColorTarget); CoreUtils.SetRenderTarget(debugCmd, currentColorTarget);
// 【修正 2】:DrawProcedural 必须显式传入 instanceCount (1) 作为第 6 个参数!
debugCmd.DrawProcedural( debugCmd.DrawProcedural(
Matrix4x4.identity, // 1. matrix Matrix4x4.identity,
debugOverlayMaterial, // 2. material debugOverlayMaterial,
0, // 3. shaderPass 0,
MeshTopology.Triangles, // 4. topology MeshTopology.Triangles,
3, // 5. vertexCount (全屏三角形) 3,
1, // 6. instanceCount (必须显式写 1!) 1,
debugMpb // 7. MaterialPropertyBlock debugMpb
); );
context.ExecuteCommandBuffer(debugCmd); context.ExecuteCommandBuffer(debugCmd);
@@ -758,17 +776,10 @@ namespace XericLibrary.PostProcess
if (pixel.a > 0.5f) if (pixel.a > 0.5f)
{ {
int decodedMatID = Mathf.RoundToInt(pixel.a);
if (enableDebugLog && i == 0)
{
Debug.Log($"[GeoLayerPicker] 像素({x},{y}), alpha={pixel.a:F4}, 解码MatID={decodedMatID}");
}
m_DecodedDataArray[i] = new PickedGeoData m_DecodedDataArray[i] = new PickedGeoData
{ {
isValid = true, isValid = true,
matID = decodedMatID, matID = Mathf.RoundToInt(pixel.a),
worldPos = new Vector3(pixel.r, pixel.g, pixel.b) worldPos = new Vector3(pixel.r, pixel.g, pixel.b)
}; };
m_ValidDataCount++; m_ValidDataCount++;
@@ -779,31 +790,6 @@ namespace XericLibrary.PostProcess
} }
} }
if (enableDebugLog)
{
Debug.Log($"[GeoLayerPicker] 回读完成!总像素: {count}, 有效拾取像素: {m_ValidDataCount}");
Dictionary<int, int> matIDCounts = new Dictionary<int, int>();
foreach (var data in m_DecodedDataArray)
{
if (data.isValid)
{
if (!matIDCounts.ContainsKey(data.matID))
{
matIDCounts[data.matID] = 0;
}
matIDCounts[data.matID]++;
}
}
Debug.Log("[GeoLayerPicker] 材质ID分布:");
foreach (var kvp in matIDCounts)
{
var mat = GetMaterialByID(kvp.Key);
Debug.Log($" MatID={kvp.Key} ({mat?.name ?? "未知"}): {kvp.Value} 像素");
}
}
MarkIslandsDirty(); MarkIslandsDirty();
} }