浏览代码

- ConvertTexture is now properly called from the CommandBuffer and not Graphics in the Texture Cache

- Fixed probe convolution to not happen when rendering realtime probes.
- Fixed Sky Environment update to happen at the beginning of the frame (so during reflection probe updates if any) to avoid visual lag in reflections.
/Add-support-for-light-specular-color-tint
Julien Ignace 7 年前
当前提交
faa9bda2
共有 5 个文件被更改,包括 116 次插入108 次删除
  1. 20
      ScriptableRenderPipeline/Core/TextureCache.cs
  2. 12
      ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
  3. 142
      ScriptableRenderPipeline/HDRenderPipeline/Lighting/ReflectionProbeCache.cs
  4. 36
      ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs
  5. 14
      ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyManager.cs

20
ScriptableRenderPipeline/Core/TextureCache.cs


if (mismatch)
{
if (!Graphics.ConvertTexture(texture, 0, m_Cache, sliceIndex))
{
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})",
texture.name, m_Cache.width, m_Cache.height, m_Cache.format);
}
cmd.ConvertTexture(texture, 0, m_Cache, sliceIndex);
}
else
{

if (mismatch)
{
bool failed = false;
if (!Graphics.ConvertTexture(texture, f, m_Cache, 6 * sliceIndex + f))
{
failed = true;
break;
}
}
if (failed)
{
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})",
texture.name, m_Cache.width, m_Cache.height, m_Cache.format);
cmd.ConvertTexture(texture, f, m_Cache, 6 * sliceIndex + f);
}
}
else

12
ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs


m_LightLoop.BuildGPULightLists(camera, cmd, m_CameraDepthStencilBufferRT, GetStencilTexture());
}
// Don't update the sky environment if we are rendering a cubemap (it should be update already)
if (camera.cameraType != CameraType.Reflection)
{
// Caution: We require sun light here as some sky use the sun light to render, mean UpdateSkyEnvironment
// must be call after BuildGPULightLists.
// TODO: Try to arrange code so we can trigger this call earlier and use async compute here to run sky convolution during other passes (once we move convolution shader to compute).
UpdateSkyEnvironment(hdCamera, cmd);
}
// Caution: We require sun light here as some sky use the sun light to render, mean UpdateSkyEnvironment
// must be call after BuildGPULightLists.
// TODO: Try to arrange code so we can trigger this call earlier and use async compute here to run sky convolution during other passes (once we move convolution shader to compute).
UpdateSkyEnvironment(hdCamera, cmd);
RenderDeferredLighting(hdCamera, cmd);

142
ScriptableRenderPipeline/HDRenderPipeline/Lighting/ReflectionProbeCache.cs


{
enum ProbeFilteringState
{
Baking,
Convolving,
TextureFormat m_CacheFormat;
IBLFilterGGX m_IBLFilterGGX;
TextureCacheCubemap m_TextureCache;
RenderTexture m_TempRenderTexture;

{
Debug.Assert(probeFormat == TextureFormat.BC6H || probeFormat == TextureFormat.RGBAHalf, "Reflection Probe Cache format for HDRP can only be BC6H or FP16.");
m_CacheFormat = probeFormat;
m_ProbeSize = probeSize;
m_CacheSize = cacheSize;
m_TextureCache = new TextureCacheCubemap();

{
m_ProbeBakingState = new ProbeFilteringState[m_CacheSize];
for (int i = 0; i < m_CacheSize; ++i)
m_ProbeBakingState[i] = ProbeFilteringState.Baking;
m_ProbeBakingState[i] = ProbeFilteringState.Convolving;
}
public void Release()

}
}
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;

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.Baking;
m_ProbeBakingState[sliceIndex] = ProbeFilteringState.Convolving;
// Probes can be either Cubemaps (for baked probes) or RenderTextures (for realtime probes)
Cubemap cubeTexture = texture as Cubemap;
RenderTexture renderTexture = texture as RenderTexture;
Texture result = ConvolveProbeTexture(cmd, texture);
if (result == null)
return -1;
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 -1;
}
// 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);
m_TextureCache.UpdateSlice(cmd, sliceIndex, m_ConvolutionTargetTexture, m_TextureCache.GetTextureUpdateCount(texture)); // Be careful to provide the update count from the input texture, not the temporary one used for baking.
m_TextureCache.UpdateSlice(cmd, sliceIndex, m_ConvolutionTargetTexture, m_TextureCache.GetTextureUpdateCount(texture)); // Be careful to provide the update count from the input texture, not the temporary one used for convolving.
m_ProbeBakingState[sliceIndex] = ProbeFilteringState.Ready;
}

36
ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs


m_lightList.lightVolumes.Add(lightVolumeData);
}
public bool GetEnvLightData(CommandBuffer cmd, VisibleReflectionProbe probe)
public bool GetEnvLightData(CommandBuffer cmd, Camera camera, VisibleReflectionProbe probe)
// For now we won't display real time probe when rendering one.
// TODO: We may want to display last frame result but in this case we need to be careful not to update the atlas before all realtime probes are rendered (for frame coherency).
// Unfortunately we don't have this information at the moment.
if (probe.probe.mode == ReflectionProbeMode.Realtime && camera.cameraType == CameraType.Reflection)
return false;
int envIndex = m_ReflectionProbeCache.FetchSlice(cmd, probe.texture);
// -1 means that the texture is not ready yet (ie not convolved/compressed yet)
if (envIndex == -1)

// Return true if BakedShadowMask are enabled
public bool PrepareLightsForGPU(CommandBuffer cmd, ShadowSettings shadowSettings, CullResults cullResults, Camera camera)
{
using (new ProfilingSample(cmd, "Prepare Lights For GPU"))
{
// If any light require it, we need to enabled bake shadow mask feature
m_enableBakeShadowMask = false;

VisibleReflectionProbe probe = cullResults.visibleReflectionProbes[probeIndex];
if(GetEnvLightData(cmd, probe))
if (GetEnvLightData(cmd, camera, probe))
GetEnvLightVolumeDataAndBound(probe, lightVolumeType, worldToView);
GetEnvLightVolumeDataAndBound(probe, lightVolumeType, worldToView);
// We make the light position camera-relative as late as possible in order
// to allow the preceding code to work with the absolute world space coordinates.
if (ShaderConfig.s_CameraRelativeRendering != 0)
{
// Caution: 'EnvLightData.positionWS' is camera-relative after this point.
int n = m_lightList.envLights.Count;
EnvLightData envLightData = m_lightList.envLights[n - 1];
envLightData.positionWS -= camPosWS;
m_lightList.envLights[n - 1] = envLightData;
// We make the light position camera-relative as late as possible in order
// to allow the preceding code to work with the absolute world space coordinates.
if (ShaderConfig.s_CameraRelativeRendering != 0)
{
// Caution: 'EnvLightData.positionWS' is camera-relative after this point.
int n = m_lightList.envLights.Count;
EnvLightData envLightData = m_lightList.envLights[n - 1];
envLightData.positionWS -= camPosWS;
m_lightList.envLights[n - 1] = envLightData;
}
}
}

m_maxShadowDistance = shadowSettings.maxShadowDistance;
return m_enableBakeShadowMask;
}
}
void VoxelLightListGeneration(CommandBuffer cmd, Camera camera, Matrix4x4 projscr, Matrix4x4 invProjscr, RenderTargetIdentifier cameraDepthBufferRT)

14
ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyManager.cs


bool m_NeedLowLevelUpdateEnvironment;
int m_UpdatedFramesRequired = 2; // The first frame after the scene load is currently not rendered correctly
float m_CurrentUpdateTime;
int m_LastFrameUpdated = -1;
bool m_useMIS = false;

}
m_UpdatedFramesRequired = 2; // Special case. Even if update mode is set to OnDemand, we need to regenerate the environment after destroying the texture.
m_LastFrameUpdated = -1;
}
m_CubemapScreenSize = new Vector4((float)resolution, (float)resolution, 1.0f / (float)resolution, 1.0f / (float)resolution);

public void UpdateEnvironment(HDCamera camera, Light sunLight, CommandBuffer cmd)
{
if (m_LastFrameUpdated == Time.frameCount)
return;
m_LastFrameUpdated = Time.frameCount;
// We need one frame delay for this update to work since DynamicGI.UpdateEnvironment is executed directly but the renderloop is not (so we need to wait for the sky texture to be rendered first)
if (m_NeedLowLevelUpdateEnvironment)
{

m_BuiltinParameters.screenSize = m_CubemapScreenSize;
m_BuiltinParameters.cameraPosWS = camera.camera.transform.position;
int sunHash = (sunLight.GetHashCode() * 23 + sunLight.transform.position.GetHashCode()) * 23 + sunLight.transform.rotation.GetHashCode();
int skyHash = sunHash * 23 + skySettings.GetHashCode();
(skySettings.updateMode == EnvironementUpdateMode.OnChanged && skySettings.GetHashCode() != m_SkyParametersHash) ||
(skySettings.updateMode == EnvironementUpdateMode.OnChanged && skyHash != m_SkyParametersHash) ||
(skySettings.updateMode == EnvironementUpdateMode.Realtime && m_CurrentUpdateTime > skySettings.updatePeriod))
{
using (new ProfilingSample(cmd, "Sky Environment Pass"))

m_NeedLowLevelUpdateEnvironment = true;
m_UpdatedFramesRequired--;
m_SkyParametersHash = skySettings.GetHashCode();
m_SkyParametersHash = skyHash;
m_CurrentUpdateTime = 0.0f;
#if UNITY_EDITOR
// In the editor when we change the sky we want to make the GI dirty so when baking again the new sky is taken into account.

正在加载...
取消
保存