浏览代码

Refactored SkyManager to be able to handle several sky rendering context at the same time (baking, visual and lighting override sky)

/main
Julien Ignace 7 年前
当前提交
dae258a5
共有 14 个文件被更改,包括 497 次插入315 次删除
  1. 15
      ScriptableRenderPipeline/HDRenderPipeline/Editor/Sky/SkySettingsEditor.cs
  2. 31
      ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
  3. 20
      ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightLoop/LightLoop.cs
  4. 7
      ScriptableRenderPipeline/HDRenderPipeline/Material/GGXConvolution/RuntimeFilterIBL.cs
  5. 2
      ScriptableRenderPipeline/HDRenderPipeline/Sky/HDRISky/HDRISkyRenderer.cs
  6. 2
      ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/ProceduralSkyRenderer.cs
  7. 344
      ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyManager.cs
  8. 2
      ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyRenderer.cs
  9. 54
      ScriptableRenderPipeline/HDRenderPipeline/Sky/SkySettings.cs
  10. 303
      ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyRenderingContext.cs
  11. 11
      ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyRenderingContext.cs.meta
  12. 10
      ScriptableRenderPipeline/HDRenderPipeline/Shadows/HDShadowSettings.cs
  13. 11
      ScriptableRenderPipeline/HDRenderPipeline/Shadows/HDShadowSettings.cs.meta

15
ScriptableRenderPipeline/HDRenderPipeline/Editor/Sky/SkySettingsEditor.cs


SerializedDataParameter m_SkyRotation;
SerializedDataParameter m_EnvUpdateMode;
SerializedDataParameter m_EnvUpdatePeriod;
SerializedDataParameter m_LightingOverride;
SerializedProperty m_UseForBaking;
public override void OnEnable()
{

m_SkyRotation = Unpack(o.Find(x => x.rotation));
m_EnvUpdateMode = Unpack(o.Find(x => x.updateMode));
m_EnvUpdatePeriod = Unpack(o.Find(x => x.updatePeriod));
m_LightingOverride = Unpack(o.Find(x => x.lightingOverride));
m_UseForBaking = o.Find(x => x.useForBaking);
}
protected void CommonSkySettingsGUI()

PropertyField(m_EnvUpdatePeriod);
EditorGUI.indentLevel--;
}
PropertyField(m_LightingOverride);
using(var scope = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.PropertyField(m_UseForBaking);
if(scope.changed)
{
(target as SkySettings).OnValidate();
}
}
}
}
}

31
ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs


// TODO: This is the wrong way to handle resize/allocation. We can have several different camera here, mean that the loop on camera will allocate and deallocate
// the below buffer which is bad. Best is to have a set of buffer for each camera that is persistent and reallocate resource if need
// For now consider we have only one camera that go to this code, the main one.
m_SkyManager.Resize(camera.nearClipPlane, camera.farClipPlane); // TODO: Also a bad naming, here we just want to realloc texture if skyparameters change (useful for lookdev)
bool resolutionChanged = camera.pixelWidth != m_CurrentWidth || camera.pixelHeight != m_CurrentHeight;
if (resolutionChanged || m_CameraDepthStencilBuffer == null)

using (new ProfilingSample(cmd, "Push Global Parameters", GetSampler(CustomSamplerId.PushGlobalParameters)))
{
hdCamera.SetupGlobalParams(cmd);
if (m_SkyManager.IsSkyValid())
{
m_SkyManager.SetGlobalSkyTexture(cmd);
cmd.SetGlobalInt(HDShaderIDs._EnvLightSkyEnabled, 1);
}
else
{
cmd.SetGlobalInt(HDShaderIDs._EnvLightSkyEnabled, 0);
}
// Broadcast SSS parameters to all shaders.
cmd.SetGlobalInt(HDShaderIDs._EnableSSSAndTransmission, m_CurrentDebugDisplaySettings.renderingDebugSettings.enableSSSAndTransmission ? 1 : 0);

InitAndClearBuffer(hdCamera, enableBakeShadowMask, cmd);
RenderDepthPrepass(m_CullResults, hdCamera, renderContext, cmd, true);
RenderDepthPrepass(m_CullResults, hdCamera, renderContext, cmd, true);
RenderVelocity(m_CullResults, hdCamera, renderContext, cmd);
RenderVelocity(m_CullResults, hdCamera, renderContext, cmd);
RenderDBuffer(hdCamera.cameraPos, renderContext, cmd);
RenderDBuffer(hdCamera.cameraPos, renderContext, cmd);
// Caution: We require sun light here as some skies use the sun light to render, it means that UpdateSkyEnvironment must be called after PrepareLightsForGPU.
// 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);
RenderPyramidDepth(camera, cmd, renderContext, FullScreenDebugMode.DepthPyramid);

CommandBufferPool.Release(cmd);
cmd = CommandBufferPool.Get("");
buildGPULightListsCompleteFence = m_LightLoop.BuildGPULightListsAsyncBegin(camera, renderContext, m_CameraDepthStencilBufferRT, m_CameraStencilBufferCopyRT, startFence);
buildGPULightListsCompleteFence = m_LightLoop.BuildGPULightListsAsyncBegin(camera, renderContext, m_CameraDepthStencilBufferRT, m_CameraStencilBufferCopyRT, startFence, m_SkyManager.IsSkyValid());
}
using (new ProfilingSample(cmd, "Render shadows", GetSampler(CustomSamplerId.RenderShadows)))

{
using (new ProfilingSample(cmd, "Build Light list", GetSampler(CustomSamplerId.BuildLightList)))
{
m_LightLoop.BuildGPULightLists(camera, cmd, m_CameraDepthStencilBufferRT, m_CameraStencilBufferCopyRT);
m_LightLoop.BuildGPULightLists(camera, cmd, m_CameraDepthStencilBufferRT, m_CameraStencilBufferCopyRT, m_SkyManager.IsSkyValid());
// 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);

20
ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightLoop/LightLoop.cs


return m_LightLoopSettings.enableAsyncCompute;
}
public void BuildGPULightListsCommon(Camera camera, CommandBuffer cmd, RenderTargetIdentifier cameraDepthBufferRT, RenderTargetIdentifier stencilTextureRT)
public void BuildGPULightListsCommon(Camera camera, CommandBuffer cmd, RenderTargetIdentifier cameraDepthBufferRT, RenderTargetIdentifier stencilTextureRT, bool skyEnabled)
{
cmd.BeginSample("Build Light List");

{
baseFeatureFlags |= (uint)LightFeatureFlags.Directional;
}
if (Shader.GetGlobalInt(HDShaderIDs._EnvLightSkyEnabled) != 0)
if (skyEnabled)
{
baseFeatureFlags |= (uint)LightFeatureFlags.Sky;
}

cmd.EndSample("Build Light List");
}
public void BuildGPULightLists(Camera camera, CommandBuffer cmd, RenderTargetIdentifier cameraDepthBufferRT, RenderTargetIdentifier stencilTextureRT)
public void BuildGPULightLists(Camera camera, CommandBuffer cmd, RenderTargetIdentifier cameraDepthBufferRT, RenderTargetIdentifier stencilTextureRT, bool skyEnabled)
BuildGPULightListsCommon(camera, cmd, cameraDepthBufferRT, stencilTextureRT);
BuildGPULightListsCommon(camera, cmd, cameraDepthBufferRT, stencilTextureRT, skyEnabled);
public GPUFence BuildGPULightListsAsyncBegin(Camera camera, ScriptableRenderContext renderContext, RenderTargetIdentifier cameraDepthBufferRT, RenderTargetIdentifier stencilTextureRT, GPUFence startFence)
public GPUFence BuildGPULightListsAsyncBegin(Camera camera, ScriptableRenderContext renderContext, RenderTargetIdentifier cameraDepthBufferRT, RenderTargetIdentifier stencilTextureRT, GPUFence startFence, bool skyEnabled)
BuildGPULightListsCommon(camera, cmd, cameraDepthBufferRT, stencilTextureRT);
BuildGPULightListsCommon(camera, cmd, cameraDepthBufferRT, stencilTextureRT, skyEnabled);
GPUFence completeFence = cmd.CreateGPUFence();
renderContext.ExecuteCommandBufferAsync(cmd, ComputeQueueType.Background);
CommandBufferPool.Release(cmd);

string singlePassName = "SinglePass - Deferred Lighting Pass";
string SinglePassMRTName = "SinglePass - Deferred Lighting Pass MRT";
// TODO: Check if we can remove this, when I test I can't
Texture skyTexture = Shader.GetGlobalTexture(HDShaderIDs._SkyTexture);
float skyTextureMipCount = Shader.GetGlobalFloat(HDShaderIDs._SkyTextureMipCount);
string sLabel = m_LightLoopSettings.enableTileAndCluster ?
(options.outputSplitLighting ? tilePassMRTName : tilePassName) :
(options.outputSplitLighting ? SinglePassMRTName : singlePassName);

// TODO: Is it possible to setup this outside the loop ? Can figure out how, get this: Property (specularLightingUAV) at kernel index (21) is not set
cmd.SetComputeTextureParam(deferredComputeShader, kernel, HDShaderIDs.specularLightingUAV, colorBuffers[0]);
cmd.SetComputeTextureParam(deferredComputeShader, kernel, HDShaderIDs.diffuseLightingUAV, colorBuffers[1]);
// TODO: Check if we can remove this, when I test I can't
cmd.SetComputeTextureParam(deferredComputeShader, kernel, HDShaderIDs._SkyTexture, skyTexture ? skyTexture : m_DefaultTextureCube);
cmd.SetComputeFloatParam(deferredComputeShader, HDShaderIDs._SkyTextureMipCount, skyTextureMipCount);
// always do deferred lighting in blocks of 16x16 (not same as tiled light size)

7
ScriptableRenderPipeline/HDRenderPipeline/Material/GGXConvolution/RuntimeFilterIBL.cs


RenderPipelineResources m_RenderPipelinesResources;
public bool supportMis
{
get { return !TextureCache.isMobileBuildTarget; }
}
public IBLFilterGGX(RenderPipelineResources renderPipelinesResources)
{
m_RenderPipelinesResources = renderPipelinesResources;

m_ComputeGgxIblSampleDataKernel = m_ComputeGgxIblSampleDataCS.FindKernel("ComputeGgxIblSampleData");
}
if (!m_BuildProbabilityTablesCS && supportMis)
if (!m_BuildProbabilityTablesCS)
{
m_BuildProbabilityTablesCS = m_RenderPipelinesResources.buildProbabilityTables;
m_ConditionalDensitiesKernel = m_BuildProbabilityTablesCS.FindKernel("ComputeConditionalDensities");

2
ScriptableRenderPipeline/HDRenderPipeline/Sky/HDRISky/HDRISkyRenderer.cs


CoreUtils.DrawFullScreen(builtinParams.commandBuffer, m_SkyHDRIMaterial, m_PropertyBlock, renderForCubemap ? 0 : 1);
}
public override bool IsSkyValid()
public override bool IsValid()
{
return m_HdriSkyParams != null && m_SkyHDRIMaterial != null;
}

2
ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/ProceduralSkyRenderer.cs


CoreUtils.DrawFullScreen(builtinParams.commandBuffer, m_SkyProceduralMaterial, m_PropertyBlock, renderForCubemap ? 0 : 1);
}
public override bool IsSkyValid()
public override bool IsValid()
{
return true;
}

344
ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyManager.cs


public class SkyManager
{
RenderTexture m_SkyboxCubemapRT;
RenderTexture m_SkyboxGGXCubemapRT;
RenderTexture m_SkyboxMarginalRowCdfRT;
RenderTexture m_SkyboxConditionalCdfRT;
IBLFilterGGX m_iblFilterGgx;
Vector4 m_CubemapScreenSize;
Matrix4x4[] m_facePixelCoordToViewDirMatrices = new Matrix4x4[6];
Matrix4x4[] m_faceCameraInvViewProjectionMatrix = new Matrix4x4[6];
BuiltinSkyParameters m_BuiltinParameters = new BuiltinSkyParameters();
SkyRenderer m_Renderer;
int m_SkyParametersHash = -1;
bool m_NeedLowLevelUpdateEnvironment;
int m_UpdatedFramesRequired = 2; // The first frame after the scene load is currently not rendered correctly
float m_CurrentUpdateTime;
bool m_UpdateRequired =false;
bool m_NeedUpdateSkyMaterialFromBaking = false;
bool m_NeedUpdateRealtimeEnv = false;
bool m_useMIS = false;
// This is the sky used for rendering in the main view. It will also be used for lighting if no lighting override sky is setup.
// Ambient Probe: Only for real time GI (otherwise we use the baked one)
// Reflection Probe : Always used and updated depending on the OnChanged/Realtime flags.
SkyRenderingContext m_VisualSky;
// This is optional and is used only to compute ambient probe and sky reflection for
// Ambient Probe: Only for real time GI (otherwise we use the baked one)
// Reflection Probe : Always used and updated depending on the OnChanged/Realtime flags.
SkyRenderingContext m_LightingOverrideSky;
// This is mandatory when using baked GI. This sky is used to setup the global Skybox material used by the GI system to bake sky GI.
SkyRenderingContext m_BakingSky;
SkySettings m_SkySettings;
public Texture skyReflection { get { return m_SkyboxGGXCubemapRT; } }
public Texture skyReflection
{
get
{
if (m_LightingOverrideSky.skySettings != null)
return m_LightingOverrideSky.reflectionTexture;
else
return m_VisualSky.reflectionTexture;
}
}
void UpdateCurrentSkySettings()
{

}
}
if (m_SkySettings == newSkySettings)
return;
if (m_Renderer != null)
{
m_Renderer.Cleanup();
m_Renderer = null;
}
m_SkyParametersHash = -1;
m_SkySettings = newSkySettings;
m_UpdatedFramesRequired = 2;
if (newSkySettings != null)
{
m_Renderer = newSkySettings.GetRenderer();
m_Renderer.Build();
}
}
void RebuildTextures(SkySettings skySettings)
{
int resolution = 256;
// Parameters not set yet. We need them for the resolution.
if (skySettings != null)
resolution = (int)skySettings.resolution.value;
if ((m_SkyboxCubemapRT != null) && (m_SkyboxCubemapRT.width != resolution))
{
CoreUtils.Destroy(m_SkyboxCubemapRT);
CoreUtils.Destroy(m_SkyboxGGXCubemapRT);
CoreUtils.Destroy(m_SkyboxMarginalRowCdfRT);
CoreUtils.Destroy(m_SkyboxConditionalCdfRT);
m_SkyboxCubemapRT = null;
m_SkyboxGGXCubemapRT = null;
m_SkyboxMarginalRowCdfRT = null;
m_SkyboxConditionalCdfRT = null;
}
if (m_SkyboxCubemapRT == null)
{
m_SkyboxCubemapRT = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear)
{
dimension = TextureDimension.Cube,
useMipMap = true,
autoGenerateMips = false, // We will generate regular mipmap for filtered importance sampling manually
filterMode = FilterMode.Trilinear
};
m_SkyboxCubemapRT.Create();
m_SkyboxGGXCubemapRT = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear)
{
dimension = TextureDimension.Cube,
useMipMap = true,
autoGenerateMips = false,
filterMode = FilterMode.Trilinear
};
m_SkyboxGGXCubemapRT.Create();
if (m_useMIS)
{
int width = (int)LightSamplingParameters.TextureWidth;
int height = (int)LightSamplingParameters.TextureHeight;
// + 1 because we store the value of the integral of the cubemap at the end of the texture.
m_SkyboxMarginalRowCdfRT = new RenderTexture(height + 1, 1, 0, RenderTextureFormat.RFloat, RenderTextureReadWrite.Linear)
{
useMipMap = false,
autoGenerateMips = false,
enableRandomWrite = true,
filterMode = FilterMode.Point
};
m_SkyboxMarginalRowCdfRT.Create();
// TODO: switch the format to R16 (once it's available) to save some bandwidth.
m_SkyboxConditionalCdfRT = new RenderTexture(width, height, 0, RenderTextureFormat.RFloat, RenderTextureReadWrite.Linear)
{
useMipMap = false,
autoGenerateMips = false,
enableRandomWrite = true,
filterMode = FilterMode.Point
};
m_SkyboxConditionalCdfRT.Create();
}
m_VisualSky.skySettings = newSkySettings;
m_BakingSky.skySettings = SkySettings.GetBakingSkySettings();
m_LightingOverrideSky.skySettings = null;
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);
}
void RebuildSkyMatrices(float nearPlane, float farPlane)
{
if (!m_SkySettings) return;
var cubeProj = Matrix4x4.Perspective(90.0f, 1.0f, nearPlane, farPlane);
for (int i = 0; i < 6; ++i)
{
var lookAt = Matrix4x4.LookAt(Vector3.zero, CoreUtils.lookAtList[i], CoreUtils.upVectorList[i]);
var worldToView = lookAt * Matrix4x4.Scale(new Vector3(1.0f, 1.0f, -1.0f)); // Need to scale -1.0 on Z to match what is being done in the camera.wolrdToCameraMatrix API. ...
var screenSize = new Vector4((int)m_SkySettings.resolution.value, (int)m_SkySettings.resolution.value, 1.0f / (int)m_SkySettings.resolution.value, 1.0f / (int)m_SkySettings.resolution.value);
m_facePixelCoordToViewDirMatrices[i] = HDUtils.ComputePixelCoordToWorldSpaceViewDirectionMatrix(0.5f * Mathf.PI, screenSize, worldToView, true);
m_faceCameraInvViewProjectionMatrix[i] = HDUtils.GetViewProjectionMatrix(lookAt, cubeProj).inverse;
}
UpdateRenderData();
}
// Sets the global MIP-mapped cubemap '_SkyTexture' in the shader.

cmd.SetGlobalTexture(HDShaderIDs._SkyTexture, m_SkyboxGGXCubemapRT);
float mipCount = Mathf.Clamp(Mathf.Log((float)m_SkyboxGGXCubemapRT.width, 2.0f) + 1, 0.0f, 6.0f);
cmd.SetGlobalTexture(HDShaderIDs._SkyTexture, skyReflection);
float mipCount = Mathf.Clamp(Mathf.Log((float)skyReflection.width, 2.0f) + 1, 0.0f, 6.0f);
public void Resize(float nearPlane, float farPlane)
public void UpdateRenderData()
// When loading RenderDoc, RenderTextures will go null
RebuildTextures(m_SkySettings);
RebuildSkyMatrices(nearPlane, farPlane);
m_BakingSky.RebuildTextures();
m_VisualSky.RebuildTextures();
m_LightingOverrideSky.RebuildTextures();
m_LastFrameUpdated = -1;
m_iblFilterGgx = iblFilterGGX;
// For now, both these rendering context will allocate render textures
// In theory, when we have a lighting override we don't need any cubemaps from the visual sky so we could avoid allocating them
m_VisualSky = new SkyRenderingContext(true, iblFilterGGX);
m_LightingOverrideSky = new SkyRenderingContext(true, iblFilterGGX);
// Here we don't need convolution supports because this sky will never need to generate it (only sky cubemap for GI system)
m_BakingSky = new SkyRenderingContext(false, iblFilterGGX);
// TODO: We need to have an API to send our sky information to Enlighten. For now use a workaround through skybox/cubemap material...
m_CurrentUpdateTime = 0.0f;
CoreUtils.Destroy(m_SkyboxCubemapRT);
CoreUtils.Destroy(m_SkyboxGGXCubemapRT);
CoreUtils.Destroy(m_SkyboxMarginalRowCdfRT);
CoreUtils.Destroy(m_SkyboxConditionalCdfRT);
if (m_Renderer != null)
m_Renderer.Cleanup();
m_BakingSky.Cleanup();
m_VisualSky.Cleanup();
m_LightingOverrideSky.Cleanup();
return m_Renderer != null && m_Renderer.IsSkyValid();
return m_VisualSky.IsValid();
void RenderSkyToCubemap(BuiltinSkyParameters builtinParams, SkySettings skySettings, RenderTexture target)
{
for (int i = 0; i < 6; ++i)
{
builtinParams.pixelCoordToViewDirMatrix = m_facePixelCoordToViewDirMatrices[i];
builtinParams.invViewProjMatrix = m_faceCameraInvViewProjectionMatrix[i];
builtinParams.colorBuffer = target;
builtinParams.depthBuffer = BuiltinSkyParameters.nullRT;
CoreUtils.SetRenderTarget(builtinParams.commandBuffer, target, ClearFlag.None, 0, (CubemapFace)i);
m_Renderer.RenderSky(builtinParams, true);
}
// Generate mipmap for our cubemap
Debug.Assert(target.autoGenerateMips == false);
builtinParams.commandBuffer.GenerateMips(target);
}
void BlitCubemap(CommandBuffer cmd, Cubemap source, RenderTexture dest)
{

cmd.GenerateMips(dest);
}
void RenderCubemapGGXConvolution(CommandBuffer cmd, Texture input, RenderTexture target)
{
using (new ProfilingSample(cmd, "Update Env: GGX Convolution"))
{
if (m_useMIS && m_iblFilterGgx.supportMis)
m_iblFilterGgx.FilterCubemapMIS(cmd, input, target, m_SkyboxConditionalCdfRT, m_SkyboxMarginalRowCdfRT);
else
m_iblFilterGgx.FilterCubemap(cmd, input, target);
}
}
m_UpdatedFramesRequired = Math.Max(m_UpdatedFramesRequired, 1);
m_UpdateRequired = true;
public void UpdateEnvironment(HDCamera camera, Light sunLight, CommandBuffer cmd)
{

UpdateCurrentSkySettings();
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)
// Both m_NeedUpdateSkyMaterialFromBaking and m_NeedUpdateRealtimeEnv are done here because we need to wait for one frame that the command buffer is executed before using the resulting textures.
if(m_NeedUpdateSkyMaterialFromBaking)
// TODO: Properly send the cubemap to Enlighten. Currently workaround is to set the cubemap in a Skybox/cubemap material
float intensity = IsSkyValid() ? 1.0f : 0.0f; // Eliminate all diffuse if we don't have a skybox (meaning for now the background is black in HDRP)
m_StandardSkyboxMaterial.SetTexture("_Tex", m_SkyboxCubemapRT);
// Here we update the global SkyMaterial so that it uses our baking sky cubemap. This way, next time the GI is baked, the right sky will be present.
float intensity = m_BakingSky.IsValid() ? 1.0f : 0.0f; // Eliminate all diffuse if we don't have a skybox (meaning for now the background is black in HDRP)
m_StandardSkyboxMaterial.SetTexture("_Tex", m_BakingSky.cubemapRT);
RenderSettings.skybox = m_StandardSkyboxMaterial; // Setup this material as the default to be use in RenderSettings
RenderSettings.ambientIntensity = intensity;
RenderSettings.ambientMode = AmbientMode.Skybox; // Force skybox for our HDRI

m_NeedLowLevelUpdateEnvironment = false;
m_NeedUpdateSkyMaterialFromBaking = false;
if (IsSkyValid())
if(m_NeedUpdateRealtimeEnv)
m_CurrentUpdateTime += Time.deltaTime;
// TODO: Here we need to do that in case we are using real time GI. Unfortunately we don't have a way to check that atm.
//DynamicGI.SetEnvironmentData();
m_NeedUpdateRealtimeEnv = false;
}
m_BuiltinParameters.commandBuffer = cmd;
m_BuiltinParameters.sunLight = sunLight;
m_BuiltinParameters.screenSize = m_CubemapScreenSize;
m_BuiltinParameters.cameraPosWS = camera.camera.transform.position;
UpdateCurrentSkySettings();
int sunHash = 0;
if(sunLight != null)
sunHash = (sunLight.GetHashCode() * 23 + sunLight.transform.position.GetHashCode()) * 23 + sunLight.transform.rotation.GetHashCode();
int skyHash = sunHash * 23 + m_SkySettings.GetHashCode();
m_NeedUpdateSkyMaterialFromBaking = m_BakingSky.UpdateEnvironment(camera, sunLight, m_UpdateRequired, cmd);
if(m_LightingOverrideSky.IsValid())
{
m_NeedUpdateRealtimeEnv = m_LightingOverrideSky.UpdateEnvironment(camera, sunLight, m_UpdateRequired, cmd);
}
else
{
m_NeedUpdateRealtimeEnv = m_VisualSky.UpdateEnvironment(camera, sunLight, m_UpdateRequired, cmd);
}
if (m_UpdatedFramesRequired > 0 ||
(m_SkySettings.updateMode == EnvironementUpdateMode.OnChanged && skyHash != m_SkyParametersHash) ||
(m_SkySettings.updateMode == EnvironementUpdateMode.Realtime && m_CurrentUpdateTime > m_SkySettings.updatePeriod))
{
using (new ProfilingSample(cmd, "Sky Environment Pass"))
{
using (new ProfilingSample(cmd, "Update Env: Generate Lighting Cubemap"))
{
// Render sky into a cubemap - doesn't happen every frame, can be controlled
// Note that m_SkyboxCubemapRT is created with auto-generate mipmap, it mean that here we have also our mipmap correctly box filtered for importance sampling.
if(m_SkySettings.lightingOverride.value == null)
RenderSkyToCubemap(m_BuiltinParameters, m_SkySettings, m_SkyboxCubemapRT);
// In case the user overrides the lighting, we already have a cubemap ready but we need to blit it anyway for potential resize and so that we can generate proper mipmaps for enlighten.
else
BlitCubemap(cmd, m_SkySettings.lightingOverride, m_SkyboxCubemapRT);
}
m_UpdateRequired = false;
// Convolve downsampled cubemap
RenderCubemapGGXConvolution(cmd, m_SkyboxCubemapRT, m_SkyboxGGXCubemapRT);
m_LastFrameUpdated = Time.frameCount;
m_NeedLowLevelUpdateEnvironment = true;
m_UpdatedFramesRequired--;
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.
// Changing the hash of the rendertarget allow to say that GI is dirty
m_SkyboxCubemapRT.imageContentsHash = new Hash128((uint)m_SkySettings.GetHashCode(), 0, 0, 0);
#endif
}
}
SetGlobalSkyTexture(cmd);
if (IsSkyValid())
{
cmd.SetGlobalInt(HDShaderIDs._EnvLightSkyEnabled, 1);
if (m_SkyParametersHash != 0)
{
using (new ProfilingSample(cmd, "Reset Sky Environment"))
{
CoreUtils.ClearCubemap(cmd, m_SkyboxGGXCubemapRT, Color.black, true);
m_SkyParametersHash = 0;
m_NeedLowLevelUpdateEnvironment = true;
}
}
cmd.SetGlobalInt(HDShaderIDs._EnvLightSkyEnabled, 0);
using (new ProfilingSample(cmd, "Sky Pass"))
{
if (IsSkyValid())
{
m_BuiltinParameters.commandBuffer = cmd;
m_BuiltinParameters.sunLight = sunLight;
m_BuiltinParameters.pixelCoordToViewDirMatrix = HDUtils.ComputePixelCoordToWorldSpaceViewDirectionMatrix(camera.camera.fieldOfView * Mathf.Deg2Rad, camera.screenSize, camera.viewMatrix, false);
m_BuiltinParameters.invViewProjMatrix = camera.viewProjMatrix.inverse;
m_BuiltinParameters.screenSize = camera.screenSize;
m_BuiltinParameters.cameraPosWS = camera.camera.transform.position;
m_BuiltinParameters.colorBuffer = colorBuffer;
m_BuiltinParameters.depthBuffer = depthBuffer;
m_Renderer.SetRenderTargets(m_BuiltinParameters);
m_Renderer.RenderSky(m_BuiltinParameters, false);
}
}
m_VisualSky.RenderSky(camera, sunLight, colorBuffer, depthBuffer, cmd);
}
public void RenderOpaqueAtmosphericScattering(CommandBuffer cmd)

public Texture2D ExportSkyToTexture()
{
if(m_Renderer == null)
if(!m_VisualSky.IsValid())
Debug.LogError("Cannot export sky to a texture, no SkyRenderer is setup.");
Debug.LogError("Cannot export sky to a texture, no Sky is setup.");
if(m_SkySettings == null)
{
Debug.LogError("Cannot export sky to a texture, no Sky settings are setup.");
return null;
}
int resolution = (int)m_SkySettings.resolution.value;
int resolution = (int)m_VisualSky.skySettings.resolution.value;
var tempRT = new RenderTexture(resolution * 6, resolution, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear)
{

int offset = 0;
for (int i = 0; i < 6; ++i)
{
UnityEngine.Graphics.SetRenderTarget(m_SkyboxCubemapRT, 0, (CubemapFace)i);
UnityEngine.Graphics.SetRenderTarget(m_VisualSky.cubemapRT, 0, (CubemapFace)i);
temp.ReadPixels(new Rect(0, 0, resolution, resolution), offset, 0);
temp.Apply();
offset += resolution;

// Temporarily disabled until proper API reaches trunk
UnityEngine.Graphics.Blit(temp, tempRT, new Vector2(1.0f, -1.0f), new Vector2(0.0f, 0.0f));
result.ReadPixels(new Rect(0, 0, resolution * 6, resolution), 0, 0);

2
ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyRenderer.cs


public abstract void SetRenderTargets(BuiltinSkyParameters builtinParams);
// renderForCubemap: When rendering into a cube map, no depth buffer is available so user has to make sure not to use depth testing or the depth texture.
public abstract void RenderSky(BuiltinSkyParameters builtinParams, bool renderForCubemap);
public abstract bool IsSkyValid();
public abstract bool IsValid();
}
}

54
ScriptableRenderPipeline/HDRenderPipeline/Sky/SkySettings.cs


using System;
using System.Collections.Generic;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{

public EnvUpdateParameter updateMode = new EnvUpdateParameter(EnvironementUpdateMode.OnChanged);
[Tooltip("If environment update is set to realtime, period in seconds at which it is updated (0.0 means every frame).")]
public MinFloatParameter updatePeriod = new MinFloatParameter(0.0f, 0.0f);
[Tooltip("If a lighting override cubemap is provided, this cubemap will be used to compute lighting instead of the result from the visible sky.")]
public CubemapParameter lightingOverride = new CubemapParameter(null);
[Tooltip("If enabled, this sky setting will be the one used for baking the GI. Only one should be enabled at any given time.")]
public bool useForBaking = false;
// Unused for now. In the future we might want to expose this option for very high range skies.
private bool m_useMIS = false;
public bool useMIS { get { return m_useMIS; } }
// This list will hold the sky settings that should be used for baking.
// In practice we will always use the last one registered but we use a list to be able to roll back to the previous one once the user deletes the superfluous instances.
private static List<SkySettings> m_BakingSkySettings = new List<SkySettings>();
public override int GetHashCode()
{

//<<<
hash = hash * 23 + updatePeriod.GetHashCode();
hash = lightingOverride != null ? hash * 23 + rotation.GetHashCode() : hash;
static public SkySettings GetBakingSkySettings()
{
if (m_BakingSkySettings.Count == 0)
return null;
else
return m_BakingSkySettings[m_BakingSkySettings.Count - 1];
}
protected override void OnEnable()
{
base.OnEnable();
OnValidate();
}
protected override void OnDisable()
{
base.OnDisable();
OnValidate();
}
public void OnValidate()
{
if(useForBaking && !m_BakingSkySettings.Contains(this))
{
if(m_BakingSkySettings.Count != 0)
{
Debug.LogWarning("One sky component was already set for baking, only the latest one will be used.");
}
m_BakingSkySettings.Add(this);
}
if (!useForBaking)
{
m_BakingSkySettings.Remove(this);
}
}
public abstract SkyRenderer GetRenderer();
}

303
ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyRenderingContext.cs


using UnityEngine.Rendering;
using System;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
internal class SkyRenderingContext
{
IBLFilterGGX m_IBLFilterGGX;
SkySettings m_SkySettings;
SkyRenderer m_Renderer;
RenderTexture m_SkyboxCubemapRT;
RenderTexture m_SkyboxGGXCubemapRT;
RenderTexture m_SkyboxMarginalRowCdfRT;
RenderTexture m_SkyboxConditionalCdfRT;
Vector4 m_CubemapScreenSize;
Matrix4x4[] m_facePixelCoordToViewDirMatrices = new Matrix4x4[6];
Matrix4x4[] m_faceCameraInvViewProjectionMatrix = new Matrix4x4[6];
BuiltinSkyParameters m_BuiltinParameters = new BuiltinSkyParameters();
int m_SkyParametersHash = -1;
float m_CurrentUpdateTime = 0.0f;
int m_UpdatedFramesRequired = 1; // The first frame after the scene load is currently not rendered correctly
bool m_SupportsConvolution = false;
public RenderTexture cubemapRT { get { return m_SkyboxCubemapRT; } }
public Texture reflectionTexture { get { return m_SkyboxGGXCubemapRT; } }
public SkySettings skySettings
{
get { return m_SkySettings; }
set
{
if (m_SkySettings == value)
return;
if (m_Renderer != null)
{
m_Renderer.Cleanup();
m_Renderer = null;
}
m_SkyParametersHash = -1;
m_SkySettings = value;
m_UpdatedFramesRequired = 1;
if (value != null)
{
m_Renderer = value.GetRenderer();
m_Renderer.Build();
}
}
}
public SkyRenderer renderer { get { return m_Renderer; } }
public SkyRenderingContext(bool supportsConvolution, IBLFilterGGX filterGGX)
{
m_SupportsConvolution = supportsConvolution;
m_IBLFilterGGX = filterGGX;
}
public void RebuildTextures()
{
int resolution = 256;
bool useMIS = false;
// Parameters not set yet. We need them for the resolution.
if (skySettings != null)
{
resolution = (int)skySettings.resolution.value;
useMIS = skySettings.useMIS;
}
bool updateNeeded = m_SkyboxCubemapRT == null || (m_SkyboxCubemapRT.width != resolution);
// Cleanup first if needed
if(updateNeeded)
{
CoreUtils.Destroy(m_SkyboxCubemapRT);
CoreUtils.Destroy(m_SkyboxGGXCubemapRT);
m_SkyboxCubemapRT = null;
m_SkyboxGGXCubemapRT = null;
}
if (!useMIS && (m_SkyboxConditionalCdfRT != null))
{
CoreUtils.Destroy(m_SkyboxConditionalCdfRT);
CoreUtils.Destroy(m_SkyboxMarginalRowCdfRT);
m_SkyboxConditionalCdfRT = null;
m_SkyboxMarginalRowCdfRT = null;
}
// Reallocate everything
if (m_SkyboxCubemapRT == null)
{
m_SkyboxCubemapRT = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear)
{
dimension = TextureDimension.Cube,
useMipMap = true,
autoGenerateMips = false, // We will generate regular mipmap for filtered importance sampling manually
filterMode = FilterMode.Trilinear
};
m_SkyboxCubemapRT.Create();
}
if (m_SkyboxGGXCubemapRT == null && m_SupportsConvolution)
{
m_SkyboxGGXCubemapRT = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear)
{
dimension = TextureDimension.Cube,
useMipMap = true,
autoGenerateMips = false,
filterMode = FilterMode.Trilinear
};
m_SkyboxGGXCubemapRT.Create();
}
if (useMIS && (m_SkyboxConditionalCdfRT == null))
{
// Temporary, it should be dependent on the sky resolution
int width = (int)LightSamplingParameters.TextureWidth;
int height = (int)LightSamplingParameters.TextureHeight;
// + 1 because we store the value of the integral of the cubemap at the end of the texture.
m_SkyboxMarginalRowCdfRT = new RenderTexture(height + 1, 1, 0, RenderTextureFormat.RFloat, RenderTextureReadWrite.Linear)
{
useMipMap = false,
autoGenerateMips = false,
enableRandomWrite = true,
filterMode = FilterMode.Point
};
m_SkyboxMarginalRowCdfRT.Create();
// TODO: switch the format to R16 (once it's available) to save some bandwidth.
m_SkyboxConditionalCdfRT = new RenderTexture(width, height, 0, RenderTextureFormat.RFloat, RenderTextureReadWrite.Linear)
{
useMipMap = false,
autoGenerateMips = false,
enableRandomWrite = true,
filterMode = FilterMode.Point
};
m_SkyboxConditionalCdfRT.Create();
}
m_CubemapScreenSize = new Vector4((float)resolution, (float)resolution, 1.0f / (float)resolution, 1.0f / (float)resolution);
if(updateNeeded)
{
m_UpdatedFramesRequired = 1; // Special case. Even if update mode is set to OnDemand, we need to regenerate the environment after destroying the texture.
RebuildSkyMatrices(resolution);
}
}
public void RebuildSkyMatrices(int resolution)
{
var cubeProj = Matrix4x4.Perspective(90.0f, 1.0f, 0.01f, 1.0f);
for (int i = 0; i < 6; ++i)
{
var lookAt = Matrix4x4.LookAt(Vector3.zero, CoreUtils.lookAtList[i], CoreUtils.upVectorList[i]);
var worldToView = lookAt * Matrix4x4.Scale(new Vector3(1.0f, 1.0f, -1.0f)); // Need to scale -1.0 on Z to match what is being done in the camera.wolrdToCameraMatrix API. ...
m_facePixelCoordToViewDirMatrices[i] = HDUtils.ComputePixelCoordToWorldSpaceViewDirectionMatrix(0.5f * Mathf.PI, m_CubemapScreenSize, worldToView, true);
m_faceCameraInvViewProjectionMatrix[i] = HDUtils.GetViewProjectionMatrix(lookAt, cubeProj).inverse;
}
}
public bool IsValid()
{
return m_Renderer != null && m_Renderer.IsValid();
}
public void Cleanup()
{
CoreUtils.Destroy(m_SkyboxCubemapRT);
CoreUtils.Destroy(m_SkyboxGGXCubemapRT);
CoreUtils.Destroy(m_SkyboxMarginalRowCdfRT);
CoreUtils.Destroy(m_SkyboxConditionalCdfRT);
if (m_Renderer != null)
m_Renderer.Cleanup();
}
void RenderSkyToCubemap()
{
for (int i = 0; i < 6; ++i)
{
m_BuiltinParameters.pixelCoordToViewDirMatrix = m_facePixelCoordToViewDirMatrices[i];
m_BuiltinParameters.invViewProjMatrix = m_faceCameraInvViewProjectionMatrix[i];
m_BuiltinParameters.colorBuffer = m_SkyboxCubemapRT;
m_BuiltinParameters.depthBuffer = BuiltinSkyParameters.nullRT;
CoreUtils.SetRenderTarget(m_BuiltinParameters.commandBuffer, m_SkyboxCubemapRT, ClearFlag.None, 0, (CubemapFace)i);
m_Renderer.RenderSky(m_BuiltinParameters, true);
}
// Generate mipmap for our cubemap
Debug.Assert(m_SkyboxCubemapRT.autoGenerateMips == false);
m_BuiltinParameters.commandBuffer.GenerateMips(m_SkyboxCubemapRT);
}
void RenderCubemapGGXConvolution()
{
using (new ProfilingSample(m_BuiltinParameters.commandBuffer, "Update Env: GGX Convolution"))
{
if (skySettings.useMIS)
m_IBLFilterGGX.FilterCubemapMIS(m_BuiltinParameters.commandBuffer, m_SkyboxCubemapRT, m_SkyboxGGXCubemapRT, m_SkyboxConditionalCdfRT, m_SkyboxMarginalRowCdfRT);
else
m_IBLFilterGGX.FilterCubemap(m_BuiltinParameters.commandBuffer, m_SkyboxCubemapRT, m_SkyboxGGXCubemapRT);
}
}
public bool UpdateEnvironment(HDCamera camera, Light sunLight, bool updateRequired, CommandBuffer cmd)
{
bool result = false;
if (IsValid())
{
m_CurrentUpdateTime += Time.deltaTime;
m_BuiltinParameters.commandBuffer = cmd;
m_BuiltinParameters.sunLight = sunLight;
m_BuiltinParameters.screenSize = m_CubemapScreenSize;
m_BuiltinParameters.cameraPosWS = camera.camera.transform.position;
int sunHash = 0;
if (sunLight != null)
sunHash = (sunLight.GetHashCode() * 23 + sunLight.transform.position.GetHashCode()) * 23 + sunLight.transform.rotation.GetHashCode();
int skyHash = sunHash * 23 + m_SkySettings.GetHashCode();
bool forceUpdate = (updateRequired || m_UpdatedFramesRequired > 0);
if (forceUpdate ||
(m_SkySettings.updateMode == EnvironementUpdateMode.OnChanged && skyHash != m_SkyParametersHash) ||
(m_SkySettings.updateMode == EnvironementUpdateMode.Realtime && m_CurrentUpdateTime > m_SkySettings.updatePeriod))
{
using (new ProfilingSample(cmd, "Sky Environment Pass"))
{
using (new ProfilingSample(cmd, "Update Env: Generate Lighting Cubemap"))
{
RenderSkyToCubemap();
}
if(m_SupportsConvolution)
{
using (new ProfilingSample(cmd, "Update Env: Convolve Lighting Cubemap"))
{
RenderCubemapGGXConvolution();
}
}
result = true;
m_SkyParametersHash = skyHash;
m_CurrentUpdateTime = 0.0f;
m_UpdatedFramesRequired--;
#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.
// Changing the hash of the rendertarget allow to say that GI is dirty
m_SkyboxCubemapRT.imageContentsHash = new Hash128((uint)m_SkySettings.GetHashCode(), 0, 0, 0);
#endif
}
}
}
else
{
if (m_SkyParametersHash != 0 && m_SupportsConvolution)
{
using (new ProfilingSample(cmd, "Reset Sky Environment"))
{
CoreUtils.ClearCubemap(cmd, m_SkyboxGGXCubemapRT, Color.black, true);
m_SkyParametersHash = 0;
result = true;
}
}
}
return result;
}
public void RenderSky(HDCamera camera, Light sunLight, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, CommandBuffer cmd)
{
if (IsValid())
{
using (new ProfilingSample(cmd, "Sky Pass"))
{
m_BuiltinParameters.commandBuffer = cmd;
m_BuiltinParameters.sunLight = sunLight;
m_BuiltinParameters.pixelCoordToViewDirMatrix = HDUtils.ComputePixelCoordToWorldSpaceViewDirectionMatrix(camera.camera.fieldOfView * Mathf.Deg2Rad, camera.screenSize, camera.viewMatrix, false);
m_BuiltinParameters.invViewProjMatrix = camera.viewProjMatrix.inverse;
m_BuiltinParameters.screenSize = camera.screenSize;
m_BuiltinParameters.cameraPosWS = camera.camera.transform.position;
m_BuiltinParameters.colorBuffer = colorBuffer;
m_BuiltinParameters.depthBuffer = depthBuffer;
m_Renderer.SetRenderTargets(m_BuiltinParameters);
m_Renderer.RenderSky(m_BuiltinParameters, false);
}
}
}
}
}

11
ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyRenderingContext.cs.meta


fileFormatVersion: 2
guid: c4ab0092e7db6c5428185f7d8efb35c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

10
ScriptableRenderPipeline/HDRenderPipeline/Shadows/HDShadowSettings.cs


using System;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
[Serializable]
public class HDShadowSettings : VolumeComponent
{
public NoInterpMinFloatParameter maxShadowDistance = new NoInterpMinFloatParameter(500.0f, 0.0f);
}
}

11
ScriptableRenderPipeline/HDRenderPipeline/Shadows/HDShadowSettings.cs.meta


fileFormatVersion: 2
guid: 7ddcec8a8eb2d684d833ac8f5d26aebd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存