您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
237 行
11 KiB
237 行
11 KiB
using System;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace UnityEngine.Experimental.Rendering.HDPipeline
|
|
{
|
|
public class ReflectionProbeCache
|
|
{
|
|
internal static readonly int s_InputTexID = Shader.PropertyToID("_InputTex");
|
|
internal static readonly int s_LoDID = Shader.PropertyToID("_LoD");
|
|
internal static readonly int s_FaceIndexID = Shader.PropertyToID("_FaceIndex");
|
|
|
|
enum ProbeFilteringState
|
|
{
|
|
Convolving,
|
|
Ready
|
|
}
|
|
|
|
int m_ProbeSize;
|
|
int m_CacheSize;
|
|
IBLFilterGGX m_IBLFilterGGX;
|
|
TextureCacheCubemap m_TextureCache;
|
|
RenderTexture m_TempRenderTexture;
|
|
RenderTexture m_ConvolutionTargetTexture;
|
|
ProbeFilteringState[] m_ProbeBakingState;
|
|
Material m_ConvertTextureMaterial;
|
|
Material m_CubeToPano;
|
|
MaterialPropertyBlock m_ConvertTextureMPB;
|
|
bool m_PerformBC6HCompression;
|
|
|
|
public ReflectionProbeCache(HDRenderPipelineAsset hdAsset, IBLFilterGGX iblFilter, int cacheSize, int probeSize, TextureFormat probeFormat, bool isMipmaped)
|
|
{
|
|
m_ConvertTextureMaterial = CoreUtils.CreateEngineMaterial(hdAsset.renderPipelineResources.blitCubeTextureFace);
|
|
m_ConvertTextureMPB = new MaterialPropertyBlock();
|
|
m_CubeToPano = CoreUtils.CreateEngineMaterial(hdAsset.renderPipelineResources.cubeToPanoShader);
|
|
|
|
// BC6H requires CPP feature not yet available
|
|
probeFormat = TextureFormat.RGBAHalf;
|
|
|
|
Debug.Assert(probeFormat == TextureFormat.BC6H || probeFormat == TextureFormat.RGBAHalf, "Reflection Probe Cache format for HDRP can only be BC6H or FP16.");
|
|
|
|
m_ProbeSize = probeSize;
|
|
m_CacheSize = cacheSize;
|
|
m_TextureCache = new TextureCacheCubemap();
|
|
m_TextureCache.AllocTextureArray(cacheSize, probeSize, probeFormat, isMipmaped, m_CubeToPano);
|
|
m_IBLFilterGGX = iblFilter;
|
|
|
|
m_PerformBC6HCompression = probeFormat == TextureFormat.BC6H;
|
|
|
|
InitializeProbeBakingStates();
|
|
}
|
|
|
|
void Initialize()
|
|
{
|
|
if (m_TempRenderTexture == null)
|
|
{
|
|
// Temporary RT used for convolution and compression
|
|
m_TempRenderTexture = new RenderTexture(m_ProbeSize, m_ProbeSize, 1, RenderTextureFormat.ARGBHalf);
|
|
m_TempRenderTexture.hideFlags = HideFlags.HideAndDontSave;
|
|
m_TempRenderTexture.dimension = TextureDimension.Cube;
|
|
m_TempRenderTexture.useMipMap = true;
|
|
m_TempRenderTexture.autoGenerateMips = false;
|
|
m_TempRenderTexture.name = CoreUtils.GetRenderTargetAutoName(m_ProbeSize, m_ProbeSize, RenderTextureFormat.ARGBHalf, "PlanarReflection", mips : true);
|
|
m_TempRenderTexture.Create();
|
|
|
|
m_ConvolutionTargetTexture = new RenderTexture(m_ProbeSize, m_ProbeSize, 1, RenderTextureFormat.ARGBHalf);
|
|
m_ConvolutionTargetTexture.hideFlags = HideFlags.HideAndDontSave;
|
|
m_ConvolutionTargetTexture.dimension = TextureDimension.Cube;
|
|
m_ConvolutionTargetTexture.useMipMap = true;
|
|
m_ConvolutionTargetTexture.autoGenerateMips = false;
|
|
m_ConvolutionTargetTexture.name = CoreUtils.GetRenderTargetAutoName(m_ProbeSize, m_ProbeSize, RenderTextureFormat.ARGBHalf, "PlanarReflection", mips : true);
|
|
m_ConvolutionTargetTexture.Create();
|
|
|
|
InitializeProbeBakingStates();
|
|
}
|
|
}
|
|
|
|
void InitializeProbeBakingStates()
|
|
{
|
|
m_ProbeBakingState = new ProbeFilteringState[m_CacheSize];
|
|
for (int i = 0; i < m_CacheSize; ++i)
|
|
m_ProbeBakingState[i] = ProbeFilteringState.Convolving;
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
if (m_TextureCache != null)
|
|
{
|
|
m_TextureCache.Release();
|
|
m_TextureCache = null;
|
|
}
|
|
if (m_TempRenderTexture != null)
|
|
{
|
|
m_TempRenderTexture.Release();
|
|
m_TempRenderTexture = null;
|
|
}
|
|
if (m_ConvolutionTargetTexture != null)
|
|
{
|
|
m_ConvolutionTargetTexture.Release();
|
|
m_ConvolutionTargetTexture = null;
|
|
}
|
|
m_ProbeBakingState = null;
|
|
|
|
CoreUtils.Destroy(m_ConvertTextureMaterial);
|
|
CoreUtils.Destroy(m_CubeToPano);
|
|
}
|
|
|
|
public void NewFrame()
|
|
{
|
|
Initialize();
|
|
m_TextureCache.NewFrame();
|
|
}
|
|
|
|
// This method is used to convert inputs that are either compressed or not of the right size.
|
|
// We can't use Graphics.ConvertTexture here because it does not work with a RenderTexture as destination.
|
|
void ConvertTexture(CommandBuffer cmd, Texture input, RenderTexture target)
|
|
{
|
|
m_ConvertTextureMPB.SetTexture(s_InputTexID, input);
|
|
m_ConvertTextureMPB.SetFloat(s_LoDID, 0.0f); // We want to convert mip 0 to whatever the size of the destination cache is.
|
|
for (int f = 0 ; f < 6 ; ++f)
|
|
{
|
|
m_ConvertTextureMPB.SetFloat(s_FaceIndexID, (float)f);
|
|
CoreUtils.SetRenderTarget(cmd, target, ClearFlag.None, Color.black, 0, (CubemapFace)f);
|
|
CoreUtils.DrawFullScreen(cmd, m_ConvertTextureMaterial, m_ConvertTextureMPB);
|
|
}
|
|
}
|
|
|
|
Texture ConvolveProbeTexture(CommandBuffer cmd, Texture texture)
|
|
{
|
|
// Probes can be either Cubemaps (for baked probes) or RenderTextures (for realtime probes)
|
|
Cubemap cubeTexture = texture as Cubemap;
|
|
RenderTexture renderTexture = texture as RenderTexture;
|
|
|
|
RenderTexture convolutionSourceTexture = null;
|
|
if (cubeTexture != null)
|
|
{
|
|
// if the size if different from the cache probe size or if the input texture format is compressed, we need to convert it
|
|
// 1) to a format for which we can generate mip maps
|
|
// 2) to the proper reflection probe cache size
|
|
bool sizeMismatch = cubeTexture.width != m_ProbeSize || cubeTexture.height != m_ProbeSize;
|
|
bool formatMismatch = cubeTexture.format != TextureFormat.RGBAHalf; // Temporary RT for convolution is always FP16
|
|
if (formatMismatch || sizeMismatch)
|
|
{
|
|
if (sizeMismatch)
|
|
{
|
|
Debug.LogWarningFormat("Baked Reflection Probe {0} does not match HDRP Reflection Probe Cache size of {1}. Consider baking it at the same size for better loading performance.", texture.name, m_ProbeSize);
|
|
}
|
|
else if (cubeTexture.format == TextureFormat.BC6H)
|
|
{
|
|
Debug.LogWarningFormat("Baked Reflection Probe {0} is compressed but the HDRP Reflection Probe Cache is not. Consider removing compression from the input texture for better quality.", texture.name);
|
|
}
|
|
ConvertTexture(cmd, cubeTexture, m_TempRenderTexture);
|
|
}
|
|
else
|
|
{
|
|
for (int f = 0; f < 6; f++)
|
|
{
|
|
cmd.CopyTexture(cubeTexture, f, 0, m_TempRenderTexture, f, 0);
|
|
}
|
|
}
|
|
|
|
// Ideally if input is not compressed and has mipmaps, don't do anything here. Problem is, we can't know if mips have been already convolved offline...
|
|
cmd.GenerateMips(m_TempRenderTexture);
|
|
convolutionSourceTexture = m_TempRenderTexture;
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(renderTexture != null);
|
|
if (renderTexture.dimension != TextureDimension.Cube)
|
|
{
|
|
Debug.LogError("Realtime reflection probe should always be a Cube RenderTexture.");
|
|
return null;
|
|
}
|
|
|
|
// TODO: Do a different case for downsizing, in this case, instead of doing ConvertTexture just use the relevant mipmaps.
|
|
bool sizeMismatch = renderTexture.width != m_ProbeSize || renderTexture.height != m_ProbeSize;
|
|
if (sizeMismatch)
|
|
{
|
|
ConvertTexture(cmd, renderTexture, m_TempRenderTexture);
|
|
convolutionSourceTexture = m_TempRenderTexture;
|
|
}
|
|
else
|
|
{
|
|
convolutionSourceTexture = renderTexture;
|
|
}
|
|
// Generate unfiltered mipmaps as a base for convolution
|
|
// TODO: Make sure that we don't first convolve everything on the GPU with the legacy code path executed after rendering the probe.
|
|
cmd.GenerateMips(convolutionSourceTexture);
|
|
}
|
|
|
|
m_IBLFilterGGX.FilterCubemap(cmd, convolutionSourceTexture, m_ConvolutionTargetTexture);
|
|
|
|
return m_ConvolutionTargetTexture;
|
|
}
|
|
|
|
public int FetchSlice(CommandBuffer cmd, Texture texture)
|
|
{
|
|
bool needUpdate;
|
|
var sliceIndex = m_TextureCache.ReserveSlice(texture, out needUpdate);
|
|
if (sliceIndex != -1)
|
|
{
|
|
if(needUpdate || m_ProbeBakingState[sliceIndex] != ProbeFilteringState.Ready)
|
|
{
|
|
using (new ProfilingSample(cmd, "Convolve Reflection Probe"))
|
|
{
|
|
// For now baking is done directly but will be time sliced in the future. Just preparing the code here.
|
|
m_ProbeBakingState[sliceIndex] = ProbeFilteringState.Convolving;
|
|
|
|
Texture result = ConvolveProbeTexture(cmd, texture);
|
|
if (result == null)
|
|
return -1;
|
|
|
|
if (m_PerformBC6HCompression)
|
|
{
|
|
cmd.BC6HEncodeFastCubemap(
|
|
result, m_ProbeSize, m_TextureCache.GetTexCache(),
|
|
0, int.MaxValue, sliceIndex);
|
|
m_TextureCache.SetSliceHash(sliceIndex, m_TextureCache.GetTextureHash(texture));
|
|
}
|
|
else
|
|
{
|
|
m_TextureCache.UpdateSlice(cmd, sliceIndex, result, m_TextureCache.GetTextureHash(texture)); // Be careful to provide the update count from the input texture, not the temporary one used for convolving.
|
|
}
|
|
|
|
m_ProbeBakingState[sliceIndex] = ProbeFilteringState.Ready;
|
|
}
|
|
}
|
|
}
|
|
|
|
return sliceIndex;
|
|
}
|
|
|
|
public Texture GetTexCache()
|
|
{
|
|
return m_TextureCache.GetTexCache();
|
|
}
|
|
}
|
|
}
|