调试shader
This commit is contained in:
@@ -2,6 +2,7 @@ using UnityEngine;
|
|||||||
using UnityEngine.Rendering;
|
using UnityEngine.Rendering;
|
||||||
using UnityEngine.Rendering.Universal;
|
using UnityEngine.Rendering.Universal;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Unity.Collections;
|
using Unity.Collections;
|
||||||
using UnityEngine.Experimental.Rendering;
|
using UnityEngine.Experimental.Rendering;
|
||||||
using XericLibrary.Runtime.MacroLibrary;
|
using XericLibrary.Runtime.MacroLibrary;
|
||||||
@@ -19,6 +20,7 @@ namespace XericLibrary.PostProcess
|
|||||||
public Matrix4x4 matrix;
|
public Matrix4x4 matrix;
|
||||||
public int subMeshIndex;
|
public int subMeshIndex;
|
||||||
public int uniqueMatID;
|
public int uniqueMatID;
|
||||||
|
public Material material;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -30,6 +32,48 @@ namespace XericLibrary.PostProcess
|
|||||||
public int matID;
|
public int matID;
|
||||||
public Vector3 worldPos;
|
public Vector3 worldPos;
|
||||||
public bool isValid;
|
public bool isValid;
|
||||||
|
|
||||||
|
public Material GetMaterial()
|
||||||
|
{
|
||||||
|
if (GeoLayerPickerRenderPassFeature.Instance != null)
|
||||||
|
{
|
||||||
|
return GeoLayerPickerRenderPassFeature.Instance.GetMaterialByID(matID);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetMaterialName()
|
||||||
|
{
|
||||||
|
var mat = GetMaterial();
|
||||||
|
return mat != null ? mat.name : "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 材质统计结果
|
||||||
|
/// </summary>
|
||||||
|
[System.Serializable]
|
||||||
|
public struct MaterialStatResult
|
||||||
|
{
|
||||||
|
public int matID;
|
||||||
|
public float location;
|
||||||
|
public float percentage;
|
||||||
|
public int pixelCount;
|
||||||
|
|
||||||
|
public Material GetMaterial()
|
||||||
|
{
|
||||||
|
if (GeoLayerPickerRenderPassFeature.Instance != null)
|
||||||
|
{
|
||||||
|
return GeoLayerPickerRenderPassFeature.Instance.GetMaterialByID(matID);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetMaterialName()
|
||||||
|
{
|
||||||
|
var mat = GetMaterial();
|
||||||
|
return mat != null ? mat.name : "Unknown";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -43,8 +87,31 @@ namespace XericLibrary.PostProcess
|
|||||||
|
|
||||||
private readonly List<MeshFilter> m_GeoMeshes = new List<MeshFilter>();
|
private readonly List<MeshFilter> m_GeoMeshes = new List<MeshFilter>();
|
||||||
private readonly List<SubMeshDrawData> m_DrawList = new List<SubMeshDrawData>();
|
private readonly List<SubMeshDrawData> m_DrawList = new List<SubMeshDrawData>();
|
||||||
|
private readonly Dictionary<Material, int> m_MaterialToID = new Dictionary<Material, int>();
|
||||||
|
private readonly Dictionary<int, Material> m_IDToMaterial = new Dictionary<int, Material>();
|
||||||
private bool m_IsDirty = true;
|
private bool m_IsDirty = true;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<Material, int> MaterialToID => m_MaterialToID;
|
||||||
|
public IReadOnlyDictionary<int, Material> IDToMaterial => m_IDToMaterial;
|
||||||
|
|
||||||
|
public Material GetMaterialByID(int matID)
|
||||||
|
{
|
||||||
|
if (m_IDToMaterial.TryGetValue(matID, out var material))
|
||||||
|
{
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetIDByMaterial(Material material)
|
||||||
|
{
|
||||||
|
if (material != null && m_MaterialToID.TryGetValue(material, out var id))
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddGeoMesh(MeshFilter meshFilter)
|
public void AddGeoMesh(MeshFilter meshFilter)
|
||||||
{
|
{
|
||||||
if (meshFilter != null && !m_GeoMeshes.Contains(meshFilter))
|
if (meshFilter != null && !m_GeoMeshes.Contains(meshFilter))
|
||||||
@@ -132,6 +199,270 @@ namespace XericLibrary.PostProcess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 材质统计 API
|
||||||
|
|
||||||
|
public void GetVerticalMaterialStats(List<MaterialStatResult> results, float startPos = 0f, float endPos = 1f)
|
||||||
|
{
|
||||||
|
results.Clear();
|
||||||
|
if (m_DecodedDataArray == null || m_DecodedDataArray.Length == 0) return;
|
||||||
|
|
||||||
|
startPos = Mathf.Clamp01(startPos);
|
||||||
|
endPos = Mathf.Clamp01(endPos);
|
||||||
|
if (startPos > endPos)
|
||||||
|
{
|
||||||
|
float temp = startPos;
|
||||||
|
startPos = endPos;
|
||||||
|
endPos = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int startPixelY = Mathf.FloorToInt(startPos * (pickRTSize.y - 1));
|
||||||
|
int endPixelY = Mathf.FloorToInt(endPos * (pickRTSize.y - 1));
|
||||||
|
|
||||||
|
Dictionary<int, List<float>> matIDToPositions = new Dictionary<int, List<float>>();
|
||||||
|
Dictionary<int, int> matIDToCount = new Dictionary<int, int>();
|
||||||
|
int totalValidPixels = 0;
|
||||||
|
|
||||||
|
for (int y = startPixelY; y <= endPixelY; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < pickRTSize.x; x++)
|
||||||
|
{
|
||||||
|
int index = y * pickRTSize.x + x;
|
||||||
|
if (index < 0 || index >= m_DecodedDataArray.Length) continue;
|
||||||
|
|
||||||
|
var data = m_DecodedDataArray[index];
|
||||||
|
if (!data.isValid) continue;
|
||||||
|
|
||||||
|
float normalizedY = (float)y / (pickRTSize.y - 1);
|
||||||
|
|
||||||
|
if (!matIDToPositions.ContainsKey(data.matID))
|
||||||
|
{
|
||||||
|
matIDToPositions[data.matID] = new List<float>();
|
||||||
|
matIDToCount[data.matID] = 0;
|
||||||
|
}
|
||||||
|
matIDToPositions[data.matID].Add(normalizedY);
|
||||||
|
matIDToCount[data.matID]++;
|
||||||
|
totalValidPixels++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var kvp in matIDToPositions)
|
||||||
|
{
|
||||||
|
int matID = kvp.Key;
|
||||||
|
var positions = kvp.Value;
|
||||||
|
float avgLocation = positions.Average();
|
||||||
|
float percentage = totalValidPixels > 0 ? (float)matIDToCount[matID] / totalValidPixels * 100f : 0f;
|
||||||
|
|
||||||
|
results.Add(new MaterialStatResult
|
||||||
|
{
|
||||||
|
matID = matID,
|
||||||
|
location = avgLocation,
|
||||||
|
percentage = percentage,
|
||||||
|
pixelCount = matIDToCount[matID]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
results.Sort((a, b) => a.location.CompareTo(b.location));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetHorizontalMaterialStats(List<MaterialStatResult> results, float startPos = 0f, float endPos = 1f)
|
||||||
|
{
|
||||||
|
results.Clear();
|
||||||
|
if (m_DecodedDataArray == null || m_DecodedDataArray.Length == 0) return;
|
||||||
|
|
||||||
|
startPos = Mathf.Clamp01(startPos);
|
||||||
|
endPos = Mathf.Clamp01(endPos);
|
||||||
|
if (startPos > endPos)
|
||||||
|
{
|
||||||
|
float temp = startPos;
|
||||||
|
startPos = endPos;
|
||||||
|
endPos = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int startPixelX = Mathf.FloorToInt(startPos * (pickRTSize.x - 1));
|
||||||
|
int endPixelX = Mathf.FloorToInt(endPos * (pickRTSize.x - 1));
|
||||||
|
|
||||||
|
Dictionary<int, List<float>> matIDToPositions = new Dictionary<int, List<float>>();
|
||||||
|
Dictionary<int, int> matIDToCount = new Dictionary<int, int>();
|
||||||
|
int totalValidPixels = 0;
|
||||||
|
|
||||||
|
for (int x = startPixelX; x <= endPixelX; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < pickRTSize.y; y++)
|
||||||
|
{
|
||||||
|
int index = y * pickRTSize.x + x;
|
||||||
|
if (index < 0 || index >= m_DecodedDataArray.Length) continue;
|
||||||
|
|
||||||
|
var data = m_DecodedDataArray[index];
|
||||||
|
if (!data.isValid) continue;
|
||||||
|
|
||||||
|
float normalizedX = (float)x / (pickRTSize.x - 1);
|
||||||
|
|
||||||
|
if (!matIDToPositions.ContainsKey(data.matID))
|
||||||
|
{
|
||||||
|
matIDToPositions[data.matID] = new List<float>();
|
||||||
|
matIDToCount[data.matID] = 0;
|
||||||
|
}
|
||||||
|
matIDToPositions[data.matID].Add(normalizedX);
|
||||||
|
matIDToCount[data.matID]++;
|
||||||
|
totalValidPixels++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var kvp in matIDToPositions)
|
||||||
|
{
|
||||||
|
int matID = kvp.Key;
|
||||||
|
var positions = kvp.Value;
|
||||||
|
float avgLocation = positions.Average();
|
||||||
|
float percentage = totalValidPixels > 0 ? (float)matIDToCount[matID] / totalValidPixels * 100f : 0f;
|
||||||
|
|
||||||
|
results.Add(new MaterialStatResult
|
||||||
|
{
|
||||||
|
matID = matID,
|
||||||
|
location = avgLocation,
|
||||||
|
percentage = percentage,
|
||||||
|
pixelCount = matIDToCount[matID]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
results.Sort((a, b) => a.location.CompareTo(b.location));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetDominantMaterialByVerticalSlice(List<MaterialStatResult> results, int sliceCount = 10, float startPos = 0f, float endPos = 1f)
|
||||||
|
{
|
||||||
|
results.Clear();
|
||||||
|
if (m_DecodedDataArray == null || m_DecodedDataArray.Length == 0) return;
|
||||||
|
|
||||||
|
sliceCount = Mathf.Max(1, sliceCount);
|
||||||
|
startPos = Mathf.Clamp01(startPos);
|
||||||
|
endPos = Mathf.Clamp01(endPos);
|
||||||
|
if (startPos > endPos)
|
||||||
|
{
|
||||||
|
float temp = startPos;
|
||||||
|
startPos = endPos;
|
||||||
|
endPos = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int startPixelY = Mathf.FloorToInt(startPos * (pickRTSize.y - 1));
|
||||||
|
int endPixelY = Mathf.FloorToInt(endPos * (pickRTSize.y - 1));
|
||||||
|
int totalHeight = endPixelY - startPixelY + 1;
|
||||||
|
if (totalHeight <= 0) return;
|
||||||
|
|
||||||
|
float sliceHeight = (float)totalHeight / sliceCount;
|
||||||
|
|
||||||
|
for (int sliceIdx = 0; sliceIdx < sliceCount; sliceIdx++)
|
||||||
|
{
|
||||||
|
int sliceStartY = startPixelY + Mathf.FloorToInt(sliceIdx * sliceHeight);
|
||||||
|
int sliceEndY = startPixelY + Mathf.FloorToInt((sliceIdx + 1) * sliceHeight) - 1;
|
||||||
|
sliceEndY = Mathf.Min(sliceEndY, endPixelY);
|
||||||
|
|
||||||
|
Dictionary<int, int> matIDCount = new Dictionary<int, int>();
|
||||||
|
int sliceTotal = 0;
|
||||||
|
|
||||||
|
for (int y = sliceStartY; y <= sliceEndY; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < pickRTSize.x; x++)
|
||||||
|
{
|
||||||
|
int index = y * pickRTSize.x + x;
|
||||||
|
if (index < 0 || index >= m_DecodedDataArray.Length) continue;
|
||||||
|
|
||||||
|
var data = m_DecodedDataArray[index];
|
||||||
|
if (!data.isValid) continue;
|
||||||
|
|
||||||
|
if (!matIDCount.ContainsKey(data.matID))
|
||||||
|
{
|
||||||
|
matIDCount[data.matID] = 0;
|
||||||
|
}
|
||||||
|
matIDCount[data.matID]++;
|
||||||
|
sliceTotal++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sliceTotal > 0)
|
||||||
|
{
|
||||||
|
int dominantMatID = matIDCount.Aggregate((l, r) => l.Value > r.Value ? l : r).Key;
|
||||||
|
float sliceCenterY = (sliceStartY + sliceEndY) / 2f / (pickRTSize.y - 1);
|
||||||
|
float percentage = (float)matIDCount[dominantMatID] / sliceTotal * 100f;
|
||||||
|
|
||||||
|
results.Add(new MaterialStatResult
|
||||||
|
{
|
||||||
|
matID = dominantMatID,
|
||||||
|
location = sliceCenterY,
|
||||||
|
percentage = percentage,
|
||||||
|
pixelCount = matIDCount[dominantMatID]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetDominantMaterialByHorizontalSlice(List<MaterialStatResult> results, int sliceCount = 10, float startPos = 0f, float endPos = 1f)
|
||||||
|
{
|
||||||
|
results.Clear();
|
||||||
|
if (m_DecodedDataArray == null || m_DecodedDataArray.Length == 0) return;
|
||||||
|
|
||||||
|
sliceCount = Mathf.Max(1, sliceCount);
|
||||||
|
startPos = Mathf.Clamp01(startPos);
|
||||||
|
endPos = Mathf.Clamp01(endPos);
|
||||||
|
if (startPos > endPos)
|
||||||
|
{
|
||||||
|
float temp = startPos;
|
||||||
|
startPos = endPos;
|
||||||
|
endPos = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int startPixelX = Mathf.FloorToInt(startPos * (pickRTSize.x - 1));
|
||||||
|
int endPixelX = Mathf.FloorToInt(endPos * (pickRTSize.x - 1));
|
||||||
|
int totalWidth = endPixelX - startPixelX + 1;
|
||||||
|
if (totalWidth <= 0) return;
|
||||||
|
|
||||||
|
float sliceWidth = (float)totalWidth / sliceCount;
|
||||||
|
|
||||||
|
for (int sliceIdx = 0; sliceIdx < sliceCount; sliceIdx++)
|
||||||
|
{
|
||||||
|
int sliceStartX = startPixelX + Mathf.FloorToInt(sliceIdx * sliceWidth);
|
||||||
|
int sliceEndX = startPixelX + Mathf.FloorToInt((sliceIdx + 1) * sliceWidth) - 1;
|
||||||
|
sliceEndX = Mathf.Min(sliceEndX, endPixelX);
|
||||||
|
|
||||||
|
Dictionary<int, int> matIDCount = new Dictionary<int, int>();
|
||||||
|
int sliceTotal = 0;
|
||||||
|
|
||||||
|
for (int x = sliceStartX; x <= sliceEndX; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < pickRTSize.y; y++)
|
||||||
|
{
|
||||||
|
int index = y * pickRTSize.x + x;
|
||||||
|
if (index < 0 || index >= m_DecodedDataArray.Length) continue;
|
||||||
|
|
||||||
|
var data = m_DecodedDataArray[index];
|
||||||
|
if (!data.isValid) continue;
|
||||||
|
|
||||||
|
if (!matIDCount.ContainsKey(data.matID))
|
||||||
|
{
|
||||||
|
matIDCount[data.matID] = 0;
|
||||||
|
}
|
||||||
|
matIDCount[data.matID]++;
|
||||||
|
sliceTotal++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sliceTotal > 0)
|
||||||
|
{
|
||||||
|
int dominantMatID = matIDCount.Aggregate((l, r) => l.Value > r.Value ? l : r).Key;
|
||||||
|
float sliceCenterX = (sliceStartX + sliceEndX) / 2f / (pickRTSize.x - 1);
|
||||||
|
float percentage = (float)matIDCount[dominantMatID] / sliceTotal * 100f;
|
||||||
|
|
||||||
|
results.Add(new MaterialStatResult
|
||||||
|
{
|
||||||
|
matID = dominantMatID,
|
||||||
|
location = sliceCenterX,
|
||||||
|
percentage = percentage,
|
||||||
|
pixelCount = matIDCount[dominantMatID]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Inspector 配置参数
|
#region Inspector 配置参数
|
||||||
@@ -328,14 +659,14 @@ namespace XericLibrary.PostProcess
|
|||||||
// 初始化调试材质
|
// 初始化调试材质
|
||||||
if (m_DebugOverlayMaterial == null)
|
if (m_DebugOverlayMaterial == null)
|
||||||
{
|
{
|
||||||
Shader overlayShader = Shader.Find("Hidden/XericLibrary/ScreenOverrideRect");
|
Shader overlayShader = Shader.Find("Hidden/XericLibrary/GeoLayerPicker/ScreenOverrideRect");
|
||||||
if (overlayShader != null)
|
if (overlayShader != null)
|
||||||
{
|
{
|
||||||
m_DebugOverlayMaterial = CoreUtils.CreateEngineMaterial(overlayShader);
|
m_DebugOverlayMaterial = CoreUtils.CreateEngineMaterial(overlayShader);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogError("[GeoLayerPicker] 找不到调试 Shader: Hidden/XericLibrary/Debug/GeoPickerOverlay");
|
Debug.LogError("[GeoLayerPicker] 找不到调试 Shader: Hidden/XericLibrary/GeoLayerPicker/ScreenOverrideRect");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -382,7 +713,7 @@ namespace XericLibrary.PostProcess
|
|||||||
// 配置调试覆盖图参数
|
// 配置调试覆盖图参数
|
||||||
m_ScriptablePass.drawDebugOverlay = enableDebugLog; // 由 Inspector 开关控制
|
m_ScriptablePass.drawDebugOverlay = enableDebugLog; // 由 Inspector 开关控制
|
||||||
m_ScriptablePass.debugOverlayMaterial = m_DebugOverlayMaterial;
|
m_ScriptablePass.debugOverlayMaterial = m_DebugOverlayMaterial;
|
||||||
// m_ScriptablePass.cameraColorTarget = renderer.cameraColorTargetHandle; // 获取当前屏幕目标
|
// m_ScriptablePass.cameraColorTarget = renderer.cameraColorTargetHandle; // 当前是注册阶段无法获取目标
|
||||||
|
|
||||||
renderer.EnqueuePass(m_ScriptablePass);
|
renderer.EnqueuePass(m_ScriptablePass);
|
||||||
}
|
}
|
||||||
@@ -449,22 +780,59 @@ namespace XericLibrary.PostProcess
|
|||||||
private void RebuildDrawList()
|
private void RebuildDrawList()
|
||||||
{
|
{
|
||||||
m_DrawList.Clear();
|
m_DrawList.Clear();
|
||||||
|
m_MaterialToID.Clear();
|
||||||
|
m_IDToMaterial.Clear();
|
||||||
int globalIDCounter = 1;
|
int globalIDCounter = 1;
|
||||||
|
|
||||||
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>();
|
||||||
|
Material[] materials = renderer != null ? renderer.sharedMaterials : null;
|
||||||
|
|
||||||
for (int sub = 0; sub < mf.sharedMesh.subMeshCount; sub++)
|
for (int sub = 0; sub < mf.sharedMesh.subMeshCount; sub++)
|
||||||
{
|
{
|
||||||
|
Material material = null;
|
||||||
|
if (materials != null && sub < materials.Length)
|
||||||
|
{
|
||||||
|
material = materials[sub];
|
||||||
|
}
|
||||||
|
|
||||||
|
int matID;
|
||||||
|
if (material != null)
|
||||||
|
{
|
||||||
|
if (!m_MaterialToID.TryGetValue(material, out matID))
|
||||||
|
{
|
||||||
|
matID = globalIDCounter++;
|
||||||
|
m_MaterialToID[material] = matID;
|
||||||
|
m_IDToMaterial[matID] = material;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
matID = globalIDCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
m_DrawList.Add(new SubMeshDrawData
|
m_DrawList.Add(new SubMeshDrawData
|
||||||
{
|
{
|
||||||
mesh = mf.sharedMesh,
|
mesh = mf.sharedMesh,
|
||||||
matrix = mf.transform.localToWorldMatrix,
|
matrix = mf.transform.localToWorldMatrix,
|
||||||
subMeshIndex = sub,
|
subMeshIndex = sub,
|
||||||
uniqueMatID = globalIDCounter++
|
uniqueMatID = matID,
|
||||||
|
material = material
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (enableDebugLog)
|
||||||
|
{
|
||||||
|
Debug.Log($"[GeoLayerPicker] 材质映射重建完成,共 {m_MaterialToID.Count} 个材质");
|
||||||
|
foreach (var kvp in m_MaterialToID)
|
||||||
|
{
|
||||||
|
Debug.Log($" ID {kvp.Value}: {kvp.Key.name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
Shader "Hidden/XericLibrary/GeoLayerPicker/ScreenOverrideRect"
|
||||||
|
{
|
||||||
|
SubShader
|
||||||
|
{
|
||||||
|
Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline" }
|
||||||
|
LOD 100
|
||||||
|
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "GeoPickerDebugOverlay"
|
||||||
|
ZWrite Off
|
||||||
|
ZTest Always
|
||||||
|
Cull Off
|
||||||
|
Blend SrcAlpha OneMinusSrcAlpha
|
||||||
|
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma vertex vert
|
||||||
|
#pragma fragment frag
|
||||||
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||||||
|
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" // 引入 Blitter 的标准顶点结构
|
||||||
|
|
||||||
|
// 在 HLSL 中声明变量(不需要在 Properties 中声明)
|
||||||
|
TEXTURE2D_X(_MainTex); // 使用 URP 标准的跨平台纹理宏
|
||||||
|
SAMPLER(sampler_MainTex);
|
||||||
|
float4 _DebugRect;
|
||||||
|
|
||||||
|
// 使用 Blitter 的标准片元输入结构 (包含完美的屏幕 UV)
|
||||||
|
struct v2f
|
||||||
|
{
|
||||||
|
float4 positionCS : SV_POSITION;
|
||||||
|
float2 texcoord : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 【核心】:使用 Blitter 的标准顶点着色器,它会自动生成完美的全屏三角形和 UV
|
||||||
|
v2f vert(Attributes input)
|
||||||
|
{
|
||||||
|
v2f output;
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
||||||
|
|
||||||
|
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
|
||||||
|
output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 frag (v2f i) : SV_Target
|
||||||
|
{
|
||||||
|
float2 rectMin = _DebugRect.xy;
|
||||||
|
float2 rectMax = rectMin + _DebugRect.zw;
|
||||||
|
|
||||||
|
// 1. 裁剪区域判断 (使用 Blitter 提供的完美屏幕 UV)
|
||||||
|
if (i.texcoord.x < rectMin.x || i.texcoord.x > rectMax.x ||
|
||||||
|
i.texcoord.y < rectMin.y || i.texcoord.y > rectMax.y)
|
||||||
|
{
|
||||||
|
return float4(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. UV 映射
|
||||||
|
float2 localUV = (i.texcoord - rectMin) / _DebugRect.zw;
|
||||||
|
|
||||||
|
// 处理 Y 轴翻转 (Blitter 的 UV 原点在左下角,而 RT 渲染原点在左上角)
|
||||||
|
#if UNITY_UV_STARTS_AT_TOP
|
||||||
|
localUV.y = 1.0 - localUV.y;
|
||||||
|
#else
|
||||||
|
// 如果平台原点在左上,不需要翻转
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 3. 采样 HDR 纹理 (使用 URP 标准采样宏)
|
||||||
|
float4 col = SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, localUV);
|
||||||
|
|
||||||
|
// 4. 数据可视化
|
||||||
|
if (col.a < 0.5)
|
||||||
|
{
|
||||||
|
return float4(0.0, 0.0, 0.0, 0.3); // 未拾取区域半透黑
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将世界坐标映射为可见颜色
|
||||||
|
float3 debugColor = frac(col.rgb * 0.1) ^ col.a;
|
||||||
|
return float4(debugColor, 0.9);
|
||||||
|
}
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bb4d6709ee2e40e4a9d9ec614a6491d9
|
||||||
|
timeCreated: 1780885782
|
||||||
Reference in New Issue
Block a user