您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
136 行
6.3 KiB
136 行
6.3 KiB
using UnityEngine.Rendering;
|
|
|
|
namespace UnityEngine.Experimental.Rendering.HDPipeline
|
|
{
|
|
using RTHandle = RTHandleSystem.RTHandle;
|
|
|
|
public class MipGenerator
|
|
{
|
|
RTHandle m_TempColorTarget;
|
|
|
|
ComputeShader m_DepthPyramidCS;
|
|
ComputeShader m_ColorPyramidCS;
|
|
|
|
int m_DepthDownsampleKernel;
|
|
int m_ColorDownsampleKernel;
|
|
int m_ColorDownsampleKernelCopyMip0;
|
|
int m_ColorGaussianKernel;
|
|
|
|
public MipGenerator(HDRenderPipelineAsset asset)
|
|
{
|
|
m_DepthPyramidCS = asset.renderPipelineResources.depthPyramidCS;
|
|
m_ColorPyramidCS = asset.renderPipelineResources.colorPyramidCS;
|
|
|
|
m_DepthDownsampleKernel = m_DepthPyramidCS.FindKernel("KDepthDownsample8DualUav");
|
|
m_ColorDownsampleKernel = m_ColorPyramidCS.FindKernel("KColorDownsample");
|
|
m_ColorDownsampleKernelCopyMip0 = m_ColorPyramidCS.FindKernel("KColorDownsampleCopyMip0");
|
|
m_ColorGaussianKernel = m_ColorPyramidCS.FindKernel("KColorGaussian");
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
RTHandles.Release(m_TempColorTarget);
|
|
m_TempColorTarget = null;
|
|
}
|
|
|
|
// Generates an in-place depth pyramid
|
|
// Returns the number of generated mips
|
|
// TODO: Mip-mapping depth is problematic for precision at lower mips, generate a packed atlas instead
|
|
public int RenderMinDepthPyramid(CommandBuffer cmd, Vector2Int size, RenderTexture texture)
|
|
{
|
|
var cs = m_DepthPyramidCS;
|
|
int kernel = m_DepthDownsampleKernel;
|
|
int srcMipLevel = 0;
|
|
int srcMipWidth = size.x;
|
|
int srcMipHeight = size.y;
|
|
|
|
// TODO: Do it 1x MIP at a time for now. In the future, do 4x MIPs per pass, or even use a single pass.
|
|
// Note: Gather() doesn't take a LOD parameter and we cannot bind an SRV of a MIP level,
|
|
// and we don't support Min samplers either. So we are forced to perform 4x loads.
|
|
while (srcMipWidth >= 2 || srcMipHeight >= 2)
|
|
{
|
|
int dstMipWidth = Mathf.Max(1, srcMipWidth >> 1);
|
|
int dstMipHeight = Mathf.Max(1, srcMipHeight >> 1);
|
|
|
|
cmd.SetComputeVectorParam(cs, HDShaderIDs._Size, new Vector4(srcMipWidth, srcMipHeight, 0f, 0f));
|
|
cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._Source, texture, srcMipLevel);
|
|
cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._Destination, texture, srcMipLevel + 1);
|
|
cmd.DispatchCompute(cs, kernel, (dstMipWidth + 7) / 8, (dstMipHeight + 7) / 8, 1);
|
|
|
|
srcMipLevel++;
|
|
srcMipWidth = srcMipWidth >> 1;
|
|
srcMipHeight = srcMipHeight >> 1;
|
|
}
|
|
|
|
return srcMipLevel - 1;
|
|
}
|
|
|
|
// Generates the gaussian pyramid of source into destination
|
|
// We can't do it in place as the color pyramid has to be read while writing to the color
|
|
// buffer in some cases (e.g. refraction, distortion)
|
|
// Returns the number of mips
|
|
public int RenderColorGaussianPyramid(CommandBuffer cmd, Vector2Int size, Texture source, RenderTexture destination)
|
|
{
|
|
// Only create the temporary target on-demand in case the game doesn't actually need it
|
|
if (m_TempColorTarget == null)
|
|
{
|
|
m_TempColorTarget = RTHandles.Alloc(
|
|
Vector2.one * 0.5f,
|
|
filterMode: FilterMode.Bilinear,
|
|
colorFormat: RenderTextureFormat.ARGBHalf,
|
|
sRGB: false,
|
|
enableRandomWrite: true,
|
|
useMipMap: false,
|
|
enableMSAA: false,
|
|
name: "Temp Gaussian Pyramid Target"
|
|
);
|
|
}
|
|
|
|
var cs = m_ColorPyramidCS;
|
|
int downsampleKernel = m_ColorDownsampleKernel;
|
|
int downsampleKernelMip0 = m_ColorDownsampleKernelCopyMip0;
|
|
int gaussianKernel = m_ColorGaussianKernel;
|
|
int srcMipLevel = 0;
|
|
int srcMipWidth = size.x;
|
|
int srcMipHeight = size.y;
|
|
|
|
|
|
// Note: smaller mips are excluded as we don't need them and the gaussian compute works
|
|
// on 8x8 blocks
|
|
// TODO: Could be further optimized by merging the smaller mips to reduce the amount of dispatches
|
|
while (srcMipWidth >= 8 || srcMipHeight >= 8)
|
|
{
|
|
int dstMipWidth = Mathf.Max(1, srcMipWidth >> 1);
|
|
int dstMipHeight = Mathf.Max(1, srcMipHeight >> 1);
|
|
|
|
cmd.SetComputeVectorParam(cs, HDShaderIDs._Size, new Vector4(srcMipWidth, srcMipHeight, 0f, 0f));
|
|
|
|
// First dispatch also copies src to dst mip0
|
|
if (srcMipLevel == 0)
|
|
{
|
|
cmd.SetComputeTextureParam(cs, downsampleKernelMip0, HDShaderIDs._Source, source, 0);
|
|
cmd.SetComputeTextureParam(cs, downsampleKernelMip0, HDShaderIDs._Mip0, destination, 0);
|
|
cmd.SetComputeTextureParam(cs, downsampleKernelMip0, HDShaderIDs._Destination, m_TempColorTarget);
|
|
cmd.DispatchCompute(cs, downsampleKernelMip0, (dstMipWidth + 7) / 8, (dstMipHeight + 7) / 8, 1);
|
|
}
|
|
else
|
|
{
|
|
cmd.SetComputeTextureParam(cs, downsampleKernel, HDShaderIDs._Source, destination, srcMipLevel);
|
|
cmd.SetComputeTextureParam(cs, downsampleKernel, HDShaderIDs._Destination, m_TempColorTarget);
|
|
cmd.DispatchCompute(cs, downsampleKernel, (dstMipWidth + 7) / 8, (dstMipHeight + 7) / 8, 1);
|
|
}
|
|
|
|
cmd.SetComputeVectorParam(cs, HDShaderIDs._Size, new Vector4(dstMipWidth, dstMipHeight, 0f, 0f));
|
|
cmd.SetComputeTextureParam(cs, gaussianKernel, HDShaderIDs._Source, m_TempColorTarget);
|
|
cmd.SetComputeTextureParam(cs, gaussianKernel, HDShaderIDs._Destination, destination, srcMipLevel + 1);
|
|
cmd.DispatchCompute(cs, gaussianKernel, (dstMipWidth + 7) / 8, (dstMipHeight + 7) / 8, 1);
|
|
|
|
srcMipLevel++;
|
|
srcMipWidth = srcMipWidth >> 1;
|
|
srcMipHeight = srcMipHeight >> 1;
|
|
}
|
|
|
|
return srcMipLevel - 1;
|
|
}
|
|
}
|
|
}
|