add hi-z occlusion culling. depth pyramid

This commit is contained in:
StarBeats 2025-06-18 19:13:30 +08:00
parent ab7cd8606e
commit 7a6c54e876
19 changed files with 833 additions and 3 deletions

View File

@ -28,7 +28,7 @@ MonoBehaviour:
m_SupportsHDR: 1 m_SupportsHDR: 1
m_HDRColorBufferPrecision: 0 m_HDRColorBufferPrecision: 0
m_MSAA: 1 m_MSAA: 1
m_RenderScale: 1 m_RenderScale: 0.6667969
m_UpscalingFilter: 1 m_UpscalingFilter: 1
m_FsrOverrideSharpness: 1 m_FsrOverrideSharpness: 1
m_FsrSharpness: 1 m_FsrSharpness: 1
@ -114,5 +114,5 @@ MonoBehaviour:
m_PrefilterNativeRenderPass: 1 m_PrefilterNativeRenderPass: 1
m_ShaderVariantLogLevel: 0 m_ShaderVariantLogLevel: 0
m_ShadowCascades: 0 m_ShadowCascades: 0
superResolution: 3 superResolution: 16
vrsRate: 0 vrsRate: 0

View File

@ -187,6 +187,25 @@ MonoBehaviour:
- {fileID: 2800000, guid: 3302065f671a8450b82c9ddf07426f3a, type: 3} - {fileID: 2800000, guid: 3302065f671a8450b82c9ddf07426f3a, type: 3}
- {fileID: 2800000, guid: 56a77a3e8d64f47b6afe9e3c95cb57d5, type: 3} - {fileID: 2800000, guid: 56a77a3e8d64f47b6afe9e3c95cb57d5, type: 3}
m_Shader: {fileID: 4800000, guid: 0849e84e3d62649e8882e9d6f056a017, type: 3} m_Shader: {fileID: 4800000, guid: 0849e84e3d62649e8882e9d6f056a017, type: 3}
--- !u!114 &-1629415145513658388
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9f7bf3c01c632d044877a67f9e9abb21, type: 3}
m_Name: HierarchicalZFeature
m_EditorClassIdentifier:
m_Active: 1
settings:
PyramidFunc: 0
SkipThreeMip: 0
ComputeShader: {fileID: 0}
Spd: {fileID: 0}
CopyDepth: {fileID: 0}
--- !u!114 &-1133205096357012623 --- !u!114 &-1133205096357012623
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -251,7 +270,8 @@ MonoBehaviour:
- {fileID: -8043853166483734676} - {fileID: -8043853166483734676}
- {fileID: 4071882023117421450} - {fileID: 4071882023117421450}
- {fileID: -7284859345190182597} - {fileID: -7284859345190182597}
m_RendererFeatureMap: bc3f630842f2e70dd6a559c442a94bfd4529d15534f2d3de228858dca8d12222716523fbf3439fdb7a327b7bff4bdd446ac59dfa966ffa88ca6373cd5da9013d6cff55ca297e5e908a7b3653203b82383b2141bb05fbe69a - {fileID: -1629415145513658388}
m_RendererFeatureMap: bc3f630842f2e70dd6a559c442a94bfd4529d15534f2d3de228858dca8d12222716523fbf3439fdb7a327b7bff4bdd446ac59dfa966ffa88ca6373cd5da9013d6cff55ca297e5e908a7b3653203b82383b2141bb05fbe69aec5704e48e2763e9
m_UseNativeRenderPass: 0 m_UseNativeRenderPass: 0
postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2}
shaders: shaders:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 254de63035289b541b164255ef99689e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,22 @@
using System;
using UnityEngine.Rendering.Universal;
namespace X.Rendering.Feature
{
public class CheckerboardRenderFeature : ScriptableRendererFeature
{
[Serializable]
public class Settings
{
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
}
public override void Create()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3d151bb2c5d317147aadf868d86c644b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 966cb1ff9ec849a49b72b81985f4b1a7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,352 @@
using Codice.Client.GameUI.Update;
using System;
using Unity.Burst.CompilerServices;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace X.Rendering.Feature
{
public class HierarchicalZFeature : ScriptableRendererFeature
{
public enum EDepthPyramidFunc
{
CopyDepth,
Compute,
SPD
}
[Serializable]
public class Settings
{
public EDepthPyramidFunc PyramidFunc = EDepthPyramidFunc.CopyDepth;
public bool SkipThreeMip;
public bool UseThreeFrameReadback;
public ComputeShader ComputeShader;
public ComputeShader Spd;
public Material CopyDepth;
}
[SerializeField]
private Settings settings;
private HizPass hizPass;
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (renderingData.cameraData.cameraType == UnityEngine.CameraType.Game)
{
renderer.EnqueuePass(hizPass);
}
}
public override void Create()
{
hizPass = new(settings);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if(hizPass != null)
{
hizPass.Dispose();
}
}
internal class HizPass : ScriptableRenderPass, IDisposable
{
private static readonly int depthTextureId = Shader.PropertyToID("_CameraDepthTexture");
private static readonly int depthInputId = Shader.PropertyToID("_InputDepth");
private static readonly int depthPyramidTexId = Shader.PropertyToID("_DepthPyramidTexture");
private static readonly int inputScaleAndMaxIndexId = Shader.PropertyToID("_InputScaleAndMaxIndex");
private readonly Settings settings;
private ProfilingSampler profiler;
private Vector2Int cachedHardwareTextureSize;
private bool cachedSkipThreeMip;
private Vector2Int mip0SizeNOP;
private Vector2Int depthPyramidTextureSize;
private int mipLevelCount;
private Vector2Int[] mipLevelOffsets;
private Vector2Int[] mipLevelSizes;
private Vector4[] mipOffsetAndSizes = new Vector4[32];
private RTHandle[] depthPyramidTexs = new RTHandle[3];
private static string[] depthPyramidNames = new string[3] { "_DepthPyramidTextureA", "_DepthPyramidTextureB", "_DepthPyramidTextureC" };
public HizPass(Settings settings)
{
renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
profiler = new("DepthPyramid");
this.settings = settings;
mipLevelOffsets = new Vector2Int[32];
mipLevelSizes = new Vector2Int[32];
}
public static int HizIndex { get; private set; }
private int GetHizIndex()
{
if(settings.UseThreeFrameReadback)
{
HizIndex = Time.frameCount % 3;
}
else
{
HizIndex = 0;
}
return HizIndex;
}
public void ComputePackedMipChainInfo(Vector2Int viewportSize)
{
if (cachedHardwareTextureSize == viewportSize && cachedSkipThreeMip == settings.SkipThreeMip)
{
return;
}
cachedHardwareTextureSize = viewportSize;
cachedSkipThreeMip = settings.SkipThreeMip;
mip0SizeNOP = viewportSize;
int resizeX = Mathf.IsPowerOfTwo(viewportSize.x) ? viewportSize.x : Mathf.NextPowerOfTwo(viewportSize.x);
int resizeY = Mathf.IsPowerOfTwo(viewportSize.y) ? viewportSize.y : Mathf.NextPowerOfTwo(viewportSize.y);
Vector2Int hardwareTextureSize = new Vector2Int(resizeX, resizeY);
mipLevelOffsets[0] = Vector2Int.zero;
mipLevelSizes[0] = Vector2Int.zero;
int mipLevel = 0;
Vector2Int mipSize = hardwareTextureSize;
Vector2Int texSize = Vector2Int.zero;
do
{
mipLevel++;
// Round up.
mipSize.x = System.Math.Max(1, (mipSize.x + 1) >> 1);
mipSize.y = System.Math.Max(1, (mipSize.y + 1) >> 1);
mipLevelSizes[mipLevel] = mipSize;
Vector2Int prevMipBegin = mipLevelOffsets[mipLevel - 1];
Vector2Int prevMipEnd = prevMipBegin + mipLevelSizes[mipLevel - 1];
Vector2Int mipBegin = new Vector2Int();
if ((mipLevel & 1) != 0)
{
mipBegin.x = prevMipBegin.x;
mipBegin.y = prevMipEnd.y;
}
else
{
mipBegin.x = prevMipEnd.x;
mipBegin.y = prevMipBegin.y;
}
if (settings.SkipThreeMip && mipLevel == 4) //跳过前面3级的Mip,从第四级开始算
{
mipBegin = Vector2Int.zero;
texSize = Vector2Int.zero;
}
mipLevelOffsets[mipLevel] = mipBegin;
texSize.x = System.Math.Max(texSize.x, mipBegin.x + mipSize.x);
texSize.y = System.Math.Max(texSize.y, mipBegin.y + mipSize.y);
}
while ((mipSize.x > 1) || (mipSize.y > 1));
mipLevelSizes[0] = hardwareTextureSize;
//RT实际大小
depthPyramidTextureSize = new Vector2Int((int)Mathf.Ceil((float)texSize.x), (int)Mathf.Ceil((float)texSize.y));
mipLevelCount = mipLevel + 1;
}
private static int[] depthMipId = null;
private void DoCopyDepth(CommandBuffer cmd, Texture depthTex)
{
if (depthMipId == null)
{
depthMipId = new int[32];
for (int i = 0; i < depthMipId.Length; i++)
{
depthMipId[i] = Shader.PropertyToID("_DepthMip" + i);
}
}
var sampleName = "DepthDownSample";
cmd.BeginSample(sampleName);
cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
cmd.SetGlobalTexture(depthInputId, depthTex);
for (int i = 1; i < mipLevelCount; i++)
{
var mipSize = mipLevelSizes[i];
var inputMipSize = i == 1 ? mip0SizeNOP : mipLevelSizes[i - 1];
var texId = depthMipId[i];
cmd.SetGlobalVector(inputScaleAndMaxIndexId, new Vector4(inputMipSize.x / (float)mipSize.x, inputMipSize.y / (float)mipSize.y, inputMipSize.x - 1, inputMipSize.y - 1));
cmd.GetTemporaryRT(texId, mipSize.x, mipSize.y, 0, FilterMode.Point, RenderTextureFormat.RFloat);
cmd.SetRenderTarget(texId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, settings.CopyDepth, 0, 0);
cmd.SetGlobalTexture(depthInputId, texId);
}
cmd.EndSample(sampleName);
sampleName = "DepthCombine";
cmd.BeginSample(sampleName);
var hizIndex = GetHizIndex();
RTHandle hizRt = depthPyramidTexs[hizIndex];
RenderingUtils.ReAllocateIfNeeded(ref hizRt, new RenderTextureDescriptor()
{
width = depthPyramidTextureSize.x,
height = depthPyramidTextureSize.y,
dimension = TextureDimension.Tex2D,
colorFormat = RenderTextureFormat.RFloat,
msaaSamples = 1,
}, filterMode : FilterMode.Point, name: depthPyramidNames[hizIndex]);
depthPyramidTexs[hizIndex] = hizRt;
cmd.SetRenderTarget(hizRt, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
for (int i = 1; i < mipLevelCount; i++)
{
var texId = depthMipId[i];
cmd.SetGlobalTexture(depthInputId, texId);
var mipSize = mipLevelSizes[i];
var mipOffset = mipLevelOffsets[i];
mipOffsetAndSizes[i] = new (mipOffset.x, mipOffset.y, mipSize.x, mipSize.y);
cmd.SetViewport(new Rect(mipOffset.x, mipOffset.y, mipSize.x, mipSize.y));
cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, settings.CopyDepth, 0, 1);
}
cmd.SetGlobalTexture(depthPyramidTexId, hizRt);
cmd.EndSample(sampleName);
for (int i = 0; i < depthMipId.Length; i++)
{
var texId = depthMipId[i];
cmd.ReleaseTemporaryRT(texId);
}
}
private void DoComputeDepth(CommandBuffer cmd, Texture depthTex)
{
var hizIndex = GetHizIndex();
RTHandle hizBuffer = depthPyramidTexs[hizIndex];
RenderingUtils.ReAllocateIfNeeded(ref hizBuffer, new RenderTextureDescriptor()
{
width = depthPyramidTextureSize.x,
height = depthPyramidTextureSize.y,
dimension = TextureDimension.Tex2D,
colorFormat = RenderTextureFormat.RFloat,
msaaSamples = 1,
enableRandomWrite = true,
}, filterMode: FilterMode.Point, name: depthPyramidNames[hizIndex]);
depthPyramidTexs[hizIndex] = hizBuffer;
int outputMipCnt = mipLevelCount - 1;
int dispatchCnt = Mathf.CeilToInt(outputMipCnt / 4f);
int mipCnt = outputMipCnt;
Matrix4x4 matrix4X4 = new Matrix4x4();
for (int i = 0; i <= dispatchCnt; i++)
{
int startMip = i * 4;
int mip1 = startMip + 1;
int mip2 = startMip + 2;
int mip3 = startMip + 3;
int mip4 = startMip + 4;
var outputMipSize = mipLevelSizes[mip1];
if(outputMipSize.x == 0 || outputMipSize.y == 0)
{
break;
}
int kernelId = 0;
if (i == 0)
{
kernelId = 1;
if (settings.SkipThreeMip)
{
kernelId = 2;
}
}
cmd.SetComputeTextureParam(settings.ComputeShader, kernelId, depthInputId, i == 0 ? depthTex : hizBuffer);
cmd.SetComputeTextureParam(settings.ComputeShader, kernelId, "_DepthMipChain", hizBuffer);
int inputMipIndex = startMip;
var inputMipOffset = mipLevelOffsets[inputMipIndex];
var inputMipSize = inputMipIndex == 0 ? mip0SizeNOP : mipLevelSizes[inputMipIndex];
cmd.SetComputeVectorParam(settings.ComputeShader, "_InputMipOffsetAndSize", new Vector4(inputMipOffset.x, inputMipOffset.y, inputMipSize.x, inputMipSize.y));
cmd.SetComputeIntParam(settings.ComputeShader, "_MipCount", Mathf.Min(mipCnt, 4));
ref var mipOffset = ref mipLevelOffsets[mip1];
ref var mipSize = ref mipLevelSizes[mip1];
matrix4X4.SetRow(0, new Vector4(mipOffset.x, mipOffset.y, mipSize.x, mipSize.y));
mipOffset = ref mipLevelOffsets[mip2];
mipSize = ref mipLevelSizes[mip2];
matrix4X4.SetRow(1, new Vector4(mipOffset.x, mipOffset.y, mipSize.x, mipSize.y));
mipOffset = ref mipLevelOffsets[mip3];
mipSize = ref mipLevelSizes[mip3];
matrix4X4.SetRow(2, new Vector4(mipOffset.x, mipOffset.y, mipSize.x, mipSize.y));
mipOffset = ref mipLevelOffsets[mip4];
mipSize = ref mipLevelSizes[mip4];
matrix4X4.SetRow(3, new Vector4(mipOffset.x, mipOffset.y, mipSize.x, mipSize.y));
cmd.SetComputeMatrixParam(settings.ComputeShader, "_MipOffsetAndSizeArray", matrix4X4);
// XXX: 可以测试是否有正面作用
// cmd.SetExecutionFlags(CommandBufferExecutionFlags.AsyncCompute);
cmd.DispatchCompute(settings.ComputeShader, kernelId, Mathf.CeilToInt(outputMipSize.x / 8f), Mathf.CeilToInt(outputMipSize.y / 8f), 1);
mipCnt = mipCnt - 4;
}
cmd.SetGlobalTexture(depthPyramidTexId, hizBuffer);
}
private void DoSpdDepth(CommandBuffer cmd, Texture depthTex)
{
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var cmd = renderingData.commandBuffer;
using var soc = new ProfilingScope(cmd, profiler);
Texture depthTex = Shader.GetGlobalTexture(depthTextureId);
if(depthTex == null)
{
return;
}
ComputePackedMipChainInfo(new Vector2Int(depthTex.width, depthTex.height));
switch (settings.PyramidFunc)
{
case EDepthPyramidFunc.CopyDepth:
DoCopyDepth(cmd, depthTex);
break;
case EDepthPyramidFunc.Compute:
DoComputeDepth(cmd, depthTex);
break;
case EDepthPyramidFunc.SPD:
DoSpdDepth(cmd, depthTex);
break;
default:
break;
}
}
public void Dispose()
{
for (int i = 0; i < depthPyramidTexs.Length; i++)
{
var rt = depthPyramidTexs[i];
rt?.Release();
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f7bf3c01c632d044877a67f9e9abb21
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,54 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace X.Rendering.Feature
{
public class HziCullingFeature : ScriptableRendererFeature
{
[Serializable]
public class Settings
{
//TODO: 通过使用上一帧的摄像机位置包括矩阵和上一帧的深度图做剔除储存已经被剔除的物体和未被剔除的物体然后绘制未被剔除的物体到GBuffer包含深度图
//再二次生成HiZ DepthTexture并对已经被剔除的物体使用一遍新的深度和当前摄像机的位置做一次剔除判断
public bool UseTowCullPass;
}
[SerializeField]
private Settings settings;
private CullPass cullPass;
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (renderingData.cameraData.cameraType == CameraType.Game)
{
renderer.EnqueuePass(cullPass);
}
}
public override void Create()
{
cullPass = new(settings);
}
internal class CullPass : ScriptableRenderPass
{
private Settings settings;
private ProfilingSampler profiler;
public CullPass(Settings settings)
{
profiler = new("Hi-Z Culling");
this.settings = settings;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var cmd = renderingData.commandBuffer;
using var soc = new ProfilingScope(cmd, profiler);
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a0b8751ae563c82438124306d98fffd5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d52a54cc0a95d6c4c83efcba0b275bba
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,106 @@
Shader "Hidden/CopyDepth"
{
SubShader
{
Pass
{
HLSLPROGRAM
#pragma vertex Vertex
#pragma fragment DownsampleDepthFrag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 texcoord : TEXCOORD0;
};
struct Varyings
{
float2 uv : TEXCOORD0;
float4 positionCS : SV_POSITION;
};
Varyings Vertex(Attributes input)
{
Varyings output = (Varyings)0;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = input.texcoord;
return output;
}
#if UNITY_REVERSED_Z
# define MIN_DEPTH(l, r) min(l, r)
#else
# define MIN_DEPTH(l, r) max(l, r)
#endif
TEXTURE2D_FLOAT(_InputDepth);
SAMPLER(sampler_InputDepth);
float4 _InputScaleAndMaxIndex;//xy: inputeTexsize/outputTextureSize , zw:textureSize - 1
half4 DownsampleDepthFrag(Varyings input) : SV_Target
{
int2 texCrood = int2(input.positionCS.xy) * _InputScaleAndMaxIndex.xy;
uint2 maxIndex = _InputScaleAndMaxIndex.zw;
int2 texCrood00 = min(texCrood + uint2(0, 0), maxIndex);
int2 texCrood10 = min(texCrood + uint2(1, 0), maxIndex);
int2 texCrood01 = min(texCrood + uint2(0, 1), maxIndex);
int2 texCrood11 = min(texCrood + uint2(1, 1), maxIndex);
float p00 = LOAD_TEXTURE2D_LOD(_InputDepth,texCrood00,0);
float p01 = LOAD_TEXTURE2D_LOD(_InputDepth,texCrood10,0);
float p10 = LOAD_TEXTURE2D_LOD(_InputDepth,texCrood01,0);
float p11 = LOAD_TEXTURE2D_LOD(_InputDepth,texCrood11,0);
return MIN_DEPTH(MIN_DEPTH(p00 ,p01), MIN_DEPTH(p10, p11));
}
ENDHLSL
}
Pass
{
HLSLPROGRAM
#pragma vertex Vertex
#pragma fragment CopyDepthFrag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 texcoord : TEXCOORD0;
};
struct Varyings
{
float2 uv : TEXCOORD0;
float4 positionCS : SV_POSITION;
};
Varyings Vertex(Attributes input)
{
Varyings output = (Varyings)0;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = input.texcoord;
return output;
}
#if UNITY_REVERSED_Z
# define MIN_DEPTH(l, r) min(l, r)
#else
# define MIN_DEPTH(l, r) max(l, r)
#endif
TEXTURE2D_FLOAT(_InputDepth);
SAMPLER(sampler_InputDepth);
half4 CopyDepthFrag(Varyings input) : SV_Target
{
return SAMPLE_TEXTURE2D(_InputDepth, sampler_InputDepth, input.uv);
}
ENDHLSL
}
}
}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 7f9d51c52061c72418245bdd5c8e83be
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,145 @@
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMainMipmapGroup0
#pragma kernel CSMainMipmapGroup0 _INPUTE_DEPTH_TEXTURE
#pragma kernel CSMainMipmapGroup0 _INPUTE_DEPTH_TEXTURE _SKIP_3_MIP
Texture2D<float> _InputDepth;
RWTexture2D<float> _DepthMipChain;
#if UNITY_REVERSED_Z
#define MIN_DEPTH(l, r) min(l, r)
#else
#define MIN_DEPTH(l, r) max(l, r)
#endif
#define GROUP_TILE_SIZE 8
float4x4 _MipOffsetAndSizeArray;
float4 _InputMipOffsetAndSize;
float _MipCount;
groupshared float _LDSDepths[GROUP_TILE_SIZE * GROUP_TILE_SIZE];
[numthreads(GROUP_TILE_SIZE, GROUP_TILE_SIZE, 1)]
void CSMainMipmapGroup0(uint3 dispatchThreadId : SV_DispatchThreadID, uint groupThreadIndex : SV_GroupIndex, uint2 groupId : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID)
{
uint2 curMipSize = _MipOffsetAndSizeArray[0].zw;
//Mip0从InputeTexture贴图下采样
float2 uv = dispatchThreadId.xy / float2(curMipSize);
uv = clamp(uv, 0, 1);
int2 texCrood = _InputMipOffsetAndSize.xy + uv * (_InputMipOffsetAndSize.zw);
uint2 maxIndex = _InputMipOffsetAndSize.xy + _InputMipOffsetAndSize.zw - 1;
#ifdef _INPUTE_DEPTH_TEXTURE //第一次Dispath使用Depth Texture
float p00 = _InputDepth[min(texCrood + uint2(0, 0), maxIndex)];
float p01 = _InputDepth[min(texCrood + uint2(1, 0), maxIndex)];
float p10 = _InputDepth[min(texCrood + uint2(0, 1), maxIndex)];
float p11 = _InputDepth[min(texCrood + uint2(1, 1), maxIndex)];
#else
float p00 = _DepthMipChain[min(texCrood + uint2(0, 0), maxIndex)];
float p01 = _DepthMipChain[min(texCrood + uint2(1, 0), maxIndex)];
float p10 = _DepthMipChain[min(texCrood + uint2(0, 1), maxIndex)];
float p11 = _DepthMipChain[min(texCrood + uint2(1, 1), maxIndex)];
#endif
float4 depths = float4(p00, p10, p01, p11);
float minDepth = MIN_DEPTH(MIN_DEPTH(depths.x, depths.y), MIN_DEPTH(depths.z, depths.w));
if (all(dispatchThreadId.xy < curMipSize.xy))
{
#ifndef _SKIP_3_MIP //跳过前3级,不输出到RT
_DepthMipChain[_MipOffsetAndSizeArray[0].xy + dispatchThreadId.xy] = minDepth;
#endif
_LDSDepths[groupThreadIndex] = minDepth;
}
GroupMemoryBarrierWithGroupSync();
//Mip1
curMipSize = curMipSize >> 1;
uint preMipTileSize = GROUP_TILE_SIZE;
uint TileSize = GROUP_TILE_SIZE / 2; //线程数减半
float4 parentFurthestDeviceZ;
uint2 xy = min(groupThreadID.xy, TileSize - 1);
uint2 xy2 = xy * 2; //间隔索引:[0,2,4,6]
uint index0 = xy2.x + xy2.y * preMipTileSize;
uint index1 = (xy2.x + 1) + xy2.y * preMipTileSize;
uint index2 = xy2.x + (xy2.y + 1) * preMipTileSize;
uint index3 = (xy2.x + 1) + (xy2.y + 1) * preMipTileSize;
parentFurthestDeviceZ.x = _LDSDepths[index0];
parentFurthestDeviceZ.y = _LDSDepths[index1];
parentFurthestDeviceZ.z = _LDSDepths[index2];
parentFurthestDeviceZ.w = _LDSDepths[index3];
float furthestDeviceZ = MIN_DEPTH(MIN_DEPTH(parentFurthestDeviceZ.x, parentFurthestDeviceZ.y), MIN_DEPTH(parentFurthestDeviceZ.z, parentFurthestDeviceZ.w));
uint2 localIndex = dispatchThreadId.xy - (groupId.xy * (GROUP_TILE_SIZE - TileSize)); //因为过滤了3/4的线程组,所以线程索引需要往前补上
if (all(localIndex < curMipSize.xy) //索引在贴图范围内的
&& all(groupThreadID.xy < TileSize) //每次每个线程组保留1/4的线程
)
{
#ifndef _SKIP_3_MIP //跳过前3级,不输出到RT
_DepthMipChain[_MipOffsetAndSizeArray[1].xy + localIndex] = furthestDeviceZ;
#endif
int threadIndex = xy.x + xy.y * TileSize;
_LDSDepths[threadIndex] = furthestDeviceZ;
}
//Mip2
GroupMemoryBarrierWithGroupSync();
curMipSize = curMipSize >> 1;
preMipTileSize = TileSize;
TileSize = TileSize / 2; //线程数减半
xy = min(groupThreadID.xy, TileSize - 1);
xy2 = xy * 2; //间隔索引:[0,2,4,6]
index0 = xy2.x + xy2.y * preMipTileSize;
index1 = (xy2.x + 1) + xy2.y * preMipTileSize;
index2 = xy2.x + (xy2.y + 1) * preMipTileSize;
index3 = (xy2.x + 1) + (xy2.y + 1) * preMipTileSize;
parentFurthestDeviceZ.x = _LDSDepths[index0];
parentFurthestDeviceZ.y = _LDSDepths[index1];
parentFurthestDeviceZ.z = _LDSDepths[index2];
parentFurthestDeviceZ.w = _LDSDepths[index3];
GroupMemoryBarrierWithGroupSync();
furthestDeviceZ = MIN_DEPTH(MIN_DEPTH(parentFurthestDeviceZ.x, parentFurthestDeviceZ.y), MIN_DEPTH(parentFurthestDeviceZ.z, parentFurthestDeviceZ.w));
localIndex = dispatchThreadId.xy - (groupId.xy * (GROUP_TILE_SIZE - TileSize)); //因为过滤了3/4的线程组,所以线程索引需要往前补上
if (all(localIndex < curMipSize.xy) //索引在贴图范围内的
&& all(groupThreadID.xy < TileSize) //每次每个线程组保留1/4的线程
)
{
#ifndef _SKIP_3_MIP //跳过前3级,不输出到RT
_DepthMipChain[_MipOffsetAndSizeArray[2].xy + localIndex] = furthestDeviceZ;
#endif
int threadIndex = xy.x + xy.y * TileSize;
_LDSDepths[threadIndex] = furthestDeviceZ;
}
//Mip3
GroupMemoryBarrierWithGroupSync();
curMipSize = curMipSize >> 1;
preMipTileSize = TileSize;
TileSize = TileSize / 2; //线程数减半
xy = min(groupThreadID.xy, TileSize - 1);
xy2 = xy * 2; //间隔索引:[0,2,4,6]
index0 = xy2.x + xy2.y * preMipTileSize;
index1 = (xy2.x + 1) + xy2.y * preMipTileSize;
index2 = xy2.x + (xy2.y + 1) * preMipTileSize;
index3 = (xy2.x + 1) + (xy2.y + 1) * preMipTileSize;
parentFurthestDeviceZ.x = _LDSDepths[index0];
parentFurthestDeviceZ.y = _LDSDepths[index1];
parentFurthestDeviceZ.z = _LDSDepths[index2];
parentFurthestDeviceZ.w = _LDSDepths[index3];
GroupMemoryBarrierWithGroupSync();
furthestDeviceZ = MIN_DEPTH(MIN_DEPTH(parentFurthestDeviceZ.x, parentFurthestDeviceZ.y), MIN_DEPTH(parentFurthestDeviceZ.z, parentFurthestDeviceZ.w));
localIndex = dispatchThreadId.xy - (groupId.xy * (GROUP_TILE_SIZE - TileSize)); //因为过滤了3/4的线程组,所以线程索引需要往前补上
if (all(localIndex < curMipSize.xy) //索引在贴图范围内的
&& all(groupThreadID.xy < TileSize) //每次每个线程组保留1/4的线程
)
{
_DepthMipChain[_MipOffsetAndSizeArray[3].xy + localIndex] = furthestDeviceZ;
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b10c09f63c5a5864ca12e07b1b361d56
ComputeShaderImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,29 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Hidden_CopyDepth
m_Shader: {fileID: 4800000, guid: 7f9d51c52061c72418245bdd5c8e83be, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs: []
m_Ints: []
m_Floats: []
m_Colors: []
m_BuildTextureStacks: []

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5f8ec7ea87b60a1448091fade6a0e68f
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,14 @@
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> Result;
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
// TODO: insert actual code here!
Result[id.xy] = float4(id.x & id.y, (id.x & 15)/15.0, (id.y & 15)/15.0, 0.0);
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2c0519b45f80f5c47b4ee3edb2e7931b
ComputeShaderImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: