From 418c0e12827920184913682c6a323e46842dd0fd Mon Sep 17 00:00:00 2001 From: Anis Date: Thu, 30 Apr 2020 15:40:58 +0200 Subject: [PATCH 01/15] Initial implementation for the new planar reflection filtering --- .../CHANGELOG.md | 1 + .../PlanarReflectionAngleGenerator.cs | 143 ++++++++++++ .../PlanarReflectionAngleGenerator.cs.meta | 11 + .../Runtime/Lighting/LightLoop/LightLoop.cs | 37 +-- .../PlanarReflectionFiltering.compute | 180 +++++++++++++++ .../PlanarReflectionFiltering.compute.meta | 8 + .../Runtime/Lighting/Reflection/HDProbe.cs | 21 ++ .../Reflection/PlanarReflectionProbeCache.cs | 14 +- .../Material/Fabric/IBLFilterCharlie.cs | 5 + .../Material/GGXConvolution/IBLFilterGGX.cs | 168 ++++++++++++++ .../Runtime/Material/IBLFilterBSDF.cs | 13 +- .../Runtime/Material/Lit/Lit.hlsl | 15 +- .../RenderPipeline/HDRenderPipeline.cs | 20 +- .../RenderPipeline/HDStringConstants.cs | 18 ++ .../RenderPipeline/RenderPipelineResources.cs | 5 +- .../HDRenderPipelineResources.asset | 216 ++++++++++++------ .../Texture/GGXConeAngle70pc.png | 3 + .../Texture/GGXConeAngle70pc.png.meta | 106 +++++++++ .../Runtime/Utilities/HDRenderUtilities.cs | 11 + 19 files changed, 881 insertions(+), 114 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs create mode 100644 com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs.meta create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute.meta create mode 100644 com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png create mode 100644 com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png.meta diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index ac2cdd2ba4c..3c110ba9377 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -693,6 +693,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Use multi_compile API for deferred compute shader with shadow mask. - Made the StaticLightingSky class public so that users can change it by script for baking purpose. - Shadowmask and realtime reflectoin probe property are hide in Quality settings +- Changed the way planar reflections are filtered in order to be a bit more "physically based". ## [7.1.1] - 2019-09-05 diff --git a/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs b/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs new file mode 100644 index 00000000000..196fca5c8b1 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs @@ -0,0 +1,143 @@ +using System.IO; + +namespace UnityEngine.Rendering.HighDefinition +{ + internal class PlanarReflectionAngleGenerator : MonoBehaviour + { + void Start() + { + } + + public class GenerationParameters + { + public int outputWidth; + public int outputHeight; + public int angleSubdivision; + public float brdfPercentage; + } + + float SafeDiv(float numer, float denom) + { + return (numer != denom) ? numer / denom : 1; + } + + float D_GGXNoPI(float NdotH, float roughness) + { + float a2 = roughness * roughness; + float s = (NdotH * a2 - NdotH) * NdotH + 1.0f; + // If roughness is 0, returns (NdotH == 1 ? 1 : 0). + // That is, it returns 1 for perfect mirror reflection, and 0 otherwise. + return SafeDiv(a2, s * s); + } + + public void GenerateTableExample() + { + GenerationParameters generationParameters = new GenerationParameters(); + generationParameters.outputWidth = 128; + generationParameters.outputHeight = 128; + generationParameters.angleSubdivision = 128; + generationParameters.brdfPercentage = 0.7f; + GenerateTable(generationParameters); + } + + void GetLocalFrame(Vector3 localZ, Vector3 localX, out Vector3 localY) + { + localY = Vector3.Cross(localZ, localX); + } + + public void GenerateTable(GenerationParameters generationParameters) + { + // This buffer will hold the theta values on which the brdfPercentage criterion is full-filed + float[] thetaValues = new float[generationParameters.outputWidth * generationParameters.outputHeight]; + + // To make it simple the point we are processing is placed at the center of the world and the camera will be moving around + Vector3 pointPosition = new Vector3(0.0f, 0.0f, 0.0f); + // Normal is fixed for the whole process + Vector3 normalVector = new Vector3(0, 0, 1.0f); + + // This Buffer will hold the ggx values and histogram used to evaluate the theta angle when brdf percentage is full-filled + float[] ggxValues = new float[generationParameters.outputWidth]; + float[] ggxHistogram = new float[generationParameters.outputHeight]; + + // Let's go through all the roughness inputs + for (int currentRoughnessIdx = 0; currentRoughnessIdx < generationParameters.outputHeight; ++currentRoughnessIdx) + { + // Evaluate the current roughness value + float currentRoughness = currentRoughnessIdx / (float)generationParameters.outputHeight; + + // Loop through all the angle values that we need to process + for (int currentAngleIdx = 0; currentAngleIdx < generationParameters.outputWidth; ++currentAngleIdx) + { + // Evaluate the current angle value + float currentAngle = Mathf.Acos(currentAngleIdx / (float)generationParameters.outputWidth); + // Let's compute the view direction + Vector3 viewVector = new Vector3(Mathf.Sin(currentAngle), 0, Mathf.Cos(currentAngle)); + Vector3 incidentVector = -viewVector; + + // Let's compute the reflected direction + Vector3 reflected = incidentVector - 2 * normalVector * Vector3.Dot(incidentVector, normalVector); + + // Let's compute the local to world matrix + Vector3 localX = new Vector3(1.0f, 0.0f, 0.0f); + Vector3 localY = new Vector3(); + GetLocalFrame(reflected, localX, out localY); + + // We need to build a table that include the average direction BRDF to define the theta value that implies the cone we are interested in + for (int thetaIdx = 0; thetaIdx < generationParameters.angleSubdivision; ++thetaIdx) + { + // initialize the variable for the integration + ggxValues[thetaIdx] = 0.0f; + + // Compute the current theta value + float theta = Mathf.PI * 0.5f * thetaIdx / (float)generationParameters.angleSubdivision; + + for (int phiIdx = 0; phiIdx < generationParameters.angleSubdivision; ++phiIdx) + { + // Compute the current phi value + float phi = Mathf.PI * 2.0f * phiIdx / (float)generationParameters.angleSubdivision; + + // Generate the direction in local space (reflected dir space) + Vector3 localSampleDir = new Vector3(Mathf.Sin(theta) * Mathf.Cos(phi), Mathf.Sin(theta) * Mathf.Sin(phi), Mathf.Cos(theta)); + + // Move it to world space + localSampleDir = localSampleDir.x * localX + localSampleDir.y * localY + localSampleDir.z * reflected; + + // Compute the half vector + Vector3 H = Vector3.Normalize((localSampleDir + viewVector) * 0.5f); + ggxValues[thetaIdx] += D_GGXNoPI(Vector3.Dot(H, normalVector), currentRoughness) * Vector3.Dot(localSampleDir, normalVector); + } + ggxValues[thetaIdx] /= (float)generationParameters.angleSubdivision; + ggxHistogram[thetaIdx] = thetaIdx == 0 ? ggxValues[thetaIdx] : (ggxValues[thetaIdx] + ggxHistogram[thetaIdx - 1]); + } + + // Let's look index where we get brdfPercentage + for (int thetaIdx = 0; thetaIdx < generationParameters.angleSubdivision; ++thetaIdx) + { + if ((ggxHistogram[thetaIdx] / ggxHistogram[generationParameters.angleSubdivision - 1]) >= generationParameters.brdfPercentage) + { + thetaValues[currentAngleIdx + currentRoughnessIdx * generationParameters.outputWidth] = thetaIdx / (float)generationParameters.angleSubdivision; + break; + } + } + } + } + + + Texture2D ggxThresholds = new Texture2D(generationParameters.outputWidth, generationParameters.outputHeight); + Color color = new Color(); + for (int hIdx = 0; hIdx < generationParameters.outputHeight; ++hIdx) + { + for (int wIdx = 0; wIdx < generationParameters.outputWidth; ++wIdx) + { + color.r = thetaValues[wIdx + hIdx * generationParameters.outputWidth]; + color.g = thetaValues[wIdx + hIdx * generationParameters.outputWidth]; + color.b = thetaValues[wIdx + hIdx * generationParameters.outputWidth]; + color.a = 1.0f; + ggxThresholds.SetPixel(wIdx, hIdx, color); + } + } + byte[] bytes = ggxThresholds.EncodeToPNG(); + File.WriteAllBytes(Application.dataPath + "/GGXConeAngle.png", bytes); + } + } +} diff --git a/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs.meta b/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs.meta new file mode 100644 index 00000000000..adbab15e5d0 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 237275eedd6686446be8100a0c5aac9f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs index 390ab604361..90a8975c589 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs @@ -1773,8 +1773,30 @@ internal bool GetEnvLightData(CommandBuffer cmd, HDCamera hdCamera, in Processed if (probe.mode == ProbeSettings.Mode.Realtime && !hdCamera.frameSettings.IsEnabled(FrameSettingsField.PlanarProbe)) break; + var renderData = planarProbe.renderData; + var worldToCameraRHSMatrix = renderData.worldToCameraRHS; + var projectionMatrix = renderData.projectionMatrix; + + // We don't need to provide the capture position + // It is already encoded in the 'worldToCameraRHSMatrix' + capturePosition = Vector3.zero; + + // get the device dependent projection matrix + var gpuProj = GL.GetGPUProjectionMatrix(projectionMatrix, true); + var gpuView = worldToCameraRHSMatrix; + var vp = gpuProj * gpuView; - var scaleOffset = m_TextureCaches.reflectionPlanarProbeCache.FetchSlice(cmd, probe.texture, out int fetchIndex); + // We need to collect the set of parameters required for the filtering + IBLFilterBSDF.PlanarTextureFilteringParameters planarTextureFilteringParameters = new IBLFilterBSDF.PlanarTextureFilteringParameters(); + planarTextureFilteringParameters.probeNormal = probe.gameObject.transform.up; + planarTextureFilteringParameters.probePosition = probe.gameObject.transform.position; + planarTextureFilteringParameters.captureCameraDepthBuffer = planarProbe.realtimeDepthTexture; + planarTextureFilteringParameters.captureCameraScreenSize = new Vector4(probe.texture.width, probe.texture.height, 1.0f / probe.texture.width, 1.0f / probe.texture.height); + planarTextureFilteringParameters.captureCameraIVP = vp.inverse; + planarTextureFilteringParameters.captureCameraPosition = renderData.capturePosition; + planarTextureFilteringParameters.captureFOV = renderData.fieldOfView; + + var scaleOffset = m_TextureCaches.reflectionPlanarProbeCache.FetchSlice(cmd, probe.texture, ref planarTextureFilteringParameters, out int fetchIndex); // Indices start at 1, because -0 == 0, we can know from the bit sign which cache to use envIndex = scaleOffset == Vector4.zero ? int.MinValue : -(fetchIndex + 1); @@ -1787,18 +1809,7 @@ internal bool GetEnvLightData(CommandBuffer cmd, HDCamera hdCamera, in Processed atlasScaleOffset = scaleOffset; - var renderData = planarProbe.renderData; - var worldToCameraRHSMatrix = renderData.worldToCameraRHS; - var projectionMatrix = renderData.projectionMatrix; - - // We don't need to provide the capture position - // It is already encoded in the 'worldToCameraRHSMatrix' - capturePosition = Vector3.zero; - - // get the device dependent projection matrix - var gpuProj = GL.GetGPUProjectionMatrix(projectionMatrix, true); - var gpuView = worldToCameraRHSMatrix; - var vp = gpuProj * gpuView; + m_TextureCaches.env2DAtlasScaleOffset[fetchIndex] = scaleOffset; m_TextureCaches.env2DCaptureVP[fetchIndex] = vp; diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute new file mode 100644 index 00000000000..335e90d784d --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute @@ -0,0 +1,180 @@ +#pragma kernel FilterPlanarReflection +#pragma kernel DownScaleReflection + +#pragma only_renderers d3d11 +// #pragma enable_d3d11_debug_symbols + +// HDRP generic includes +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl" + +// Tile size of this compute +#define PLANAR_REFLECTION_TILE_SIZE 8 + +// This texture holds a radian value that matches the angle to grab 70% of the energy of the ggx lobe. +TEXTURE2D(_ThetaValuesTexture); +// Used to sample the theta values texture +SAMPLER(s_linear_clamp); +// Mip chain of depth and color +TEXTURE2D(_DepthTextureMipChain); +TEXTURE2D(_ReflectionColorMipChain); + +CBUFFER_START(ShaderVariablesPlanarReflectionFiltering) + // The screen size (width, height, 1.0 / width, 1.0 / height) that is produced by the capture + float4 _CaptureBaseScreenSize; + // The screen size (width, height, 1.0 / width, 1.0 / height) of the current level processed + float4 _CaptureCurrentScreenSize; + // Normal of the planar reflection plane + float3 _ReflectionPlaneNormal; + // Roughness value of the current integration + float _IntegrationRoughness; + // World space position of the planar reflection (non camera relative) + float3 _ReflectionPlanePosition; + // FOV of the capture camera + float _CaptureCameraFOV; + // World space position of the capture camera (non camera relative) + float3 _CaptureCameraPositon; + // The mip index of the source data + int _SourceMipIndex; + // Inverse view projection of the capture camera + float4x4 _CaptureCameraIVP; + float _RTScaleFactor; +CBUFFER_END + +// Output buffer of our code +RW_TEXTURE2D(float4, _FilteredPlanarReflectionBuffer); + +bool IntersectPlane(float3 ray_origin, float3 ray_dir, float3 pos, float3 normal, out float t) +{ + t = -1.0; + float denom = dot(normal, ray_dir); + if (abs(denom) > 1e-5) + { + float3 d = pos - ray_origin; + t = dot(d, normal) / denom; + return (t >= 0); + } + return false; +} + +float sqr(float value) +{ + return value * value; +} +float gaussian(float radius, float sigma) +{ + return exp(-sqr(radius / sigma)); +} + +[numthreads(PLANAR_REFLECTION_TILE_SIZE, PLANAR_REFLECTION_TILE_SIZE, 1)] +void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID) +{ + UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z); + + // Compute the pixel position to process + int2 currentCoord = (int2)(groupId * PLANAR_REFLECTION_TILE_SIZE + groupThreadId); + + // Compute the coordinates that shall be used for sampling + float2 sampleCoords = (currentCoord << (int)(_SourceMipIndex)) * _CaptureBaseScreenSize.zw * _RTScaleFactor; + + // Read the a filtered depth value of the tap coord + float centerDepthValue = SAMPLE_TEXTURE2D_LOD(_DepthTextureMipChain, s_trilinear_clamp_sampler, sampleCoords, _SourceMipIndex).x; + + // Compute the world position of the tapped pixel + PositionInputs centralPosInput = GetPositionInput(currentCoord, _CaptureCurrentScreenSize.zw, centerDepthValue, _CaptureCameraIVP, 0, 0); + + // Compute the direction to the reflection pixel + float3 rayDirection = normalize(centralPosInput.positionWS - _CaptureCameraPositon); + + // Compute the position on the plane we shall be integrating from + float t = -1.0; + if (!IntersectPlane(_CaptureCameraPositon, rayDirection, _ReflectionPlanePosition, _ReflectionPlaneNormal, t)) + { + // If there is no plane intersection, there is nothing to filter (means that is a position that cannot be reflected) + _FilteredPlanarReflectionBuffer[currentCoord] = float4(0.0, 0.0, 0.0, 1.0); + return; + } + + // Compute the integration position (position on the plane) + float3 integrationPositionRWS = _CaptureCameraPositon + rayDirection * t; + + // Evaluate the cone halfangle for the filtering (it is the cone angle to grab 70% of the energy of the ggx lobe) + float halfAngle = SAMPLE_TEXTURE2D_LOD(_ThetaValuesTexture, s_linear_clamp, float2(dot(rayDirection,_ReflectionPlaneNormal), _IntegrationRoughness), 0).r; + halfAngle = halfAngle * PI * 0.5f; + + // Compute the distances we need for our filtering + const float distanceCameraToPlane = length(integrationPositionRWS - _CaptureCameraPositon); + const float distancePlaneToObject = length(centralPosInput.positionWS - integrationPositionRWS); + + // Compute the cone footprint on the image reflection plane for this configuration + const float brdfConeRadius = tan(halfAngle) * distancePlaneToObject; + + // We need to compute the view cone radius + const float viewConeRadius = brdfConeRadius * distanceCameraToPlane / (distancePlaneToObject + distanceCameraToPlane); + + // Compute the view cone's half angle. This matches the FOV angle to see exactly the half of the cone + const float viewConeHalfAngle = atan(viewConeRadius / distanceCameraToPlane); + // Given the camera's fov and pixel resolution convert the viewConeHalfAngle to a number of pixels + const float pixelDistance = viewConeHalfAngle / _CaptureCameraFOV * _CaptureCurrentScreenSize.x; + // Convert this to a mip level shift starting from the mip 0 + const float miplevel = log2(pixelDistance / 2); + + // Read the integration color that we should take + const float3 integrationColor = SAMPLE_TEXTURE2D_LOD(_ReflectionColorMipChain, s_trilinear_clamp_sampler, sampleCoords, miplevel + _SourceMipIndex).xyz; + + // Write the output ray data + _FilteredPlanarReflectionBuffer[currentCoord] = float4(integrationColor, 1.0); +} + +// Half resolution output texture for our mip chain build. +RW_TEXTURE2D(float4, _HalfResReflectionBuffer); +RW_TEXTURE2D(float, _HalfResDepthBuffer); +// Given that the camera is using an oblique projection matrix, the inversion code doesnt work properly +// If we detect that we are on the far plane, we override the value by an other one. This value has been choosen experimentally. +#define OBLIQUE_CAMERA_DEPTH_CLAMP_VALUE 0.75 + +[numthreads(PLANAR_REFLECTION_TILE_SIZE, PLANAR_REFLECTION_TILE_SIZE, 1)] +void DownScaleReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID) +{ + UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z); + + // Compute the pixel position to process + int2 currentCoord = (int2)(groupId * PLANAR_REFLECTION_TILE_SIZE + groupThreadId); + + // Here we have to go wider than the simple 2x2 neighborhood or there is too much aliasing + float3 averageColor = 0.0; + float sumW = 0.0; + const float radius = 2; + const float sigma = radius * 0.75; + for (int y = -radius; y <= radius; ++y) + { + for (int x = -radius; x <= radius; ++x) + { + const int2 tapCoord = currentCoord * 2 + uint2(x, y); + float r = sqrt(x*x + y*y); + // If the pixel is outside the current screen size, its weight becomes zero + float weight = tapCoord.x > _CaptureCurrentScreenSize.x || tapCoord.x < 0 + || tapCoord.y > _CaptureCurrentScreenSize.y || tapCoord.y < 0 ? 0.0 : gaussian(r, sigma); + averageColor += LOAD_TEXTURE2D_LOD(_ReflectionColorMipChain, tapCoord, _SourceMipIndex) * weight; + sumW += weight; + } + } + // Normalize and output + _HalfResReflectionBuffer[currentCoord] = float4(averageColor / sumW, 1.0); + + // Read the depth values + float d0 = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2, _SourceMipIndex); + float d1 = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2 + int2(1, 1), _SourceMipIndex); + float d2 = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2 + int2(0, 1), _SourceMipIndex); + float d3 = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2 + int2(1, 0), _SourceMipIndex); + + // We we are on the far plane override the value + d0 = d0 == 0.0 ? OBLIQUE_CAMERA_DEPTH_CLAMP_VALUE : d0; + d1 = d1 == 0.0 ? OBLIQUE_CAMERA_DEPTH_CLAMP_VALUE : d1; + d2 = d2 == 0.0 ? OBLIQUE_CAMERA_DEPTH_CLAMP_VALUE : d2; + d3 = d3 == 0.0 ? OBLIQUE_CAMERA_DEPTH_CLAMP_VALUE : d3; + + // Average and output to the depth buffer + _HalfResDepthBuffer[currentCoord] = (d0 + d1 + d2 + d3) * 0.25f; +} \ No newline at end of file diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute.meta b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute.meta new file mode 100644 index 00000000000..2277cb2d810 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9f3f8a01b8caaaa4595591dc96d43dd2 +ComputeShaderImporter: + externalObjects: {} + currentAPIMask: 4 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/HDProbe.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/HDProbe.cs index d7acda444b7..61c6e45e314 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/HDProbe.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/HDProbe.cs @@ -118,6 +118,7 @@ float aspect // Runtime Data RenderTexture m_RealtimeTexture; + RenderTexture m_RealtimeDepthBuffer; RenderData m_RealtimeRenderData; bool m_WasRenderedSinceLastOnDemandRequest = true; @@ -189,6 +190,12 @@ public RenderTexture realtimeTexture set => m_RealtimeTexture = value; } + public RenderTexture realtimeDepthTexture + { + get => m_RealtimeDepthBuffer; + set => m_RealtimeDepthBuffer = value; + } + /// /// The texture used during lighting for this probe. /// @@ -231,6 +238,20 @@ public Texture SetTexture(ProbeSettings.Mode targetMode, Texture texture) } } + public Texture SetDepthTexture(ProbeSettings.Mode targetMode, Texture texture) + { + if (targetMode == ProbeSettings.Mode.Realtime && !(texture is RenderTexture)) + throw new ArgumentException("'texture' must be a RenderTexture for the Realtime mode."); + + switch (targetMode) + { + case ProbeSettings.Mode.Baked: return m_BakedTexture = texture; + case ProbeSettings.Mode.Custom: return m_CustomTexture = texture; + case ProbeSettings.Mode.Realtime: return m_RealtimeDepthBuffer = (RenderTexture)texture; + default: throw new ArgumentOutOfRangeException(); + } + } + /// /// The render data of the last bake /// diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/PlanarReflectionProbeCache.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/PlanarReflectionProbeCache.cs index c53d79a2e7c..f5028d138fa 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/PlanarReflectionProbeCache.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/PlanarReflectionProbeCache.cs @@ -100,7 +100,7 @@ void ConvertTexture(CommandBuffer cmd, Texture input, RenderTexture target) CoreUtils.DrawFullScreen(cmd, m_ConvertTextureMaterial, m_ConvertTextureMPB); } - Texture ConvolveProbeTexture(CommandBuffer cmd, Texture texture, out Vector4 sourceScaleOffset) + Texture ConvolveProbeTexture(CommandBuffer cmd, Texture texture, ref IBLFilterBSDF.PlanarTextureFilteringParameters planarTextureFilteringParameters, out Vector4 sourceScaleOffset) { // Probes can be either Cubemaps (for baked probes) or RenderTextures (for realtime probes) Texture2D texture2D = texture as Texture2D; @@ -149,12 +149,12 @@ Texture ConvolveProbeTexture(CommandBuffer cmd, Texture texture, out Vector4 sou float scaleX = (float)texture.width / m_ConvolutionTargetTexture.width; float scaleY = (float)texture.height / m_ConvolutionTargetTexture.height; sourceScaleOffset = new Vector4(scaleX, scaleY, 0, 0); - m_IBLFilterGGX.FilterPlanarTexture(cmd, convolutionSourceTexture, m_ConvolutionTargetTexture); + m_IBLFilterGGX.FilterPlanarTexture(cmd, convolutionSourceTexture, ref planarTextureFilteringParameters, m_ConvolutionTargetTexture); return m_ConvolutionTargetTexture; } - public Vector4 FetchSlice(CommandBuffer cmd, Texture texture, out int fetchIndex) + public Vector4 FetchSlice(CommandBuffer cmd, Texture texture, ref IBLFilterBSDF.PlanarTextureFilteringParameters planarTextureFilteringParameters, out int fetchIndex) { Vector4 scaleOffset = Vector4.zero; fetchIndex = m_FrameProbeIndex++; @@ -163,17 +163,17 @@ public Vector4 FetchSlice(CommandBuffer cmd, Texture texture, out int fetchIndex { // If the texture is already in the atlas, we update it only if needed if (NeedsUpdate(texture) || m_ProbeBakingState[scaleOffset] != ProbeFilteringState.Ready) - if (!UpdatePlanarTexture(cmd, texture, ref scaleOffset)) + if (!UpdatePlanarTexture(cmd, texture, ref planarTextureFilteringParameters, ref scaleOffset)) Debug.LogError("Can't convolve or update the planar reflection render target"); } else // Either we add it to the atlas - if (!UpdatePlanarTexture(cmd, texture, ref scaleOffset)) + if (!UpdatePlanarTexture(cmd, texture, ref planarTextureFilteringParameters, ref scaleOffset)) Debug.LogError("No more space in the planar reflection probe atlas. To solve this issue, increase the size of the Planar Reflection Probe Atlas in the HDRP settings."); return scaleOffset; } - bool UpdatePlanarTexture(CommandBuffer cmd, Texture texture, ref Vector4 scaleOffset) + bool UpdatePlanarTexture(CommandBuffer cmd, Texture texture, ref IBLFilterBSDF.PlanarTextureFilteringParameters planarTextureFilteringParameters, ref Vector4 scaleOffset) { bool success = false; @@ -183,7 +183,7 @@ bool UpdatePlanarTexture(CommandBuffer cmd, Texture texture, ref Vector4 scaleOf m_ProbeBakingState[scaleOffset] = ProbeFilteringState.Convolving; Vector4 sourceScaleOffset; - Texture convolvedTexture = ConvolveProbeTexture(cmd, texture, out sourceScaleOffset); + Texture convolvedTexture = ConvolveProbeTexture(cmd, texture, ref planarTextureFilteringParameters, out sourceScaleOffset); if (convolvedTexture == null) return false; diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Fabric/IBLFilterCharlie.cs b/com.unity.render-pipelines.high-definition/Runtime/Material/Fabric/IBLFilterCharlie.cs index 2c6a500e3f6..297c9743d49 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/Fabric/IBLFilterCharlie.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Fabric/IBLFilterCharlie.cs @@ -85,5 +85,10 @@ override public void FilterCubemap(CommandBuffer cmd, Texture source, RenderText public override void FilterCubemapMIS(CommandBuffer cmd, Texture source, RenderTexture target, RenderTexture conditionalCdf, RenderTexture marginalRowCdf) { } + + override public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source, ref PlanarTextureFilteringParameters planarTextureFilteringParameters, RenderTexture target) + { + m_MipGenerator.RenderColorGaussianPyramid(cmd, new Vector2Int(source.width, source.height), source, target); + } } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs index 5ef402930e4..add33d19016 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs @@ -1,3 +1,5 @@ +using UnityEngine.Experimental.Rendering; + namespace UnityEngine.Rendering.HighDefinition { class IBLFilterGGX : IBLFilterBSDF @@ -13,6 +15,18 @@ class IBLFilterGGX : IBLFilterBSDF int m_ConditionalDensitiesKernel = -1; int m_MarginalRowDensitiesKernel = -1; + // Planar reflection filtering + ComputeShader m_PlanarReflectionFilteringCS; + Texture2D m_GGXConeAngle; + int m_PlanarReflectionFilteringKernel = -1; + int m_PlanarReflectionDownScaleKernel = -1; + RTHandle m_PlanarReflectionFilterTex0; + RTHandle m_PlanarReflectionFilterTex1; + RTHandle m_PlanarReflectionFilterDepthTex0; + RTHandle m_PlanarReflectionFilterDepthTex1; + // Intermediate variables + Vector4 currentScreenSize = new Vector4(1.0f, 1.0f, 1.0f, 1.0f); + public IBLFilterGGX(RenderPipelineResources renderPipelineResources, MipGenerator mipGenerator) { m_RenderPipelineResources = renderPipelineResources; @@ -58,11 +72,24 @@ public override void Initialize(CommandBuffer cmd) InitializeGgxIblSampleData(cmd); } + if (!m_PlanarReflectionFilteringCS) + { + m_PlanarReflectionFilteringCS = m_RenderPipelineResources.shaders.planarReflectionFilteringCS; + m_PlanarReflectionFilteringKernel = m_PlanarReflectionFilteringCS.FindKernel("FilterPlanarReflection"); + m_PlanarReflectionDownScaleKernel = m_PlanarReflectionFilteringCS.FindKernel("DownScaleReflection"); + m_GGXConeAngle = m_RenderPipelineResources.textures.ggxConeAngle70pc; + } + for (int i = 0; i < 6; ++i) { var lookAt = Matrix4x4.LookAt(Vector3.zero, CoreUtils.lookAtList[i], CoreUtils.upVectorList[i]); m_faceWorldToViewMatrixMatrices[i] = 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_PlanarReflectionFilterTex0 = RTHandles.Alloc(512, 512, TextureXR.slices, colorFormat: GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite: true, useDynamicScale: true, useMipMap: true, name: "PlanarReflectionTextureIntermediate0"); + m_PlanarReflectionFilterTex1 = RTHandles.Alloc(512, 512, TextureXR.slices, colorFormat: GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite: true, useDynamicScale: true, useMipMap: false, name: "PlanarReflectionTextureIntermediate1"); + m_PlanarReflectionFilterDepthTex0 = RTHandles.Alloc(512, 512, TextureXR.slices, colorFormat: GraphicsFormat.R32_SFloat, enableRandomWrite: true, useDynamicScale: true, useMipMap: true, name: "PlanarReflectionTextureIntermediateDepth0"); + m_PlanarReflectionFilterDepthTex1 = RTHandles.Alloc(512, 512, TextureXR.slices, colorFormat: GraphicsFormat.R32_SFloat, enableRandomWrite: true, useDynamicScale: true, useMipMap: false, name: "PlanarReflectionTextureIntermediateDepth1"); } void InitializeGgxIblSampleData(CommandBuffer cmd) @@ -75,6 +102,10 @@ public override void Cleanup() { CoreUtils.Destroy(m_convolveMaterial); CoreUtils.Destroy(m_GgxIblSampleData); + RTHandles.Release(m_PlanarReflectionFilterTex0); + RTHandles.Release(m_PlanarReflectionFilterTex1); + RTHandles.Release(m_PlanarReflectionFilterDepthTex0); + RTHandles.Release(m_PlanarReflectionFilterDepthTex1); } void FilterCubemapCommon(CommandBuffer cmd, @@ -153,9 +184,146 @@ override public void FilterCubemapMIS(CommandBuffer cmd, FilterCubemapCommon(cmd, source, target, m_faceWorldToViewMatrixMatrices); } + override public void FilterCubemap(CommandBuffer cmd, Texture source, RenderTexture target) { FilterCubemapCommon(cmd, source, target, m_faceWorldToViewMatrixMatrices); } + + float RoughnessStep(int textureResolution) + { + return 1.0f / (Mathf.Log((float)textureResolution, 2.0f) - 2.0f); + } + + void CheckIntermediateTexturesSize(int texWidth, int texHeight) + { + if (m_PlanarReflectionFilterTex0.rt.width < texWidth) + { + RTHandles.Release(m_PlanarReflectionFilterTex0); + RTHandles.Release(m_PlanarReflectionFilterTex1); + RTHandles.Release(m_PlanarReflectionFilterDepthTex0); + RTHandles.Release(m_PlanarReflectionFilterDepthTex1); + m_PlanarReflectionFilterTex0 = RTHandles.Alloc(texWidth, texHeight, TextureXR.slices, colorFormat: GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite: true, useDynamicScale: false, useMipMap: true, name: "PlanarReflectionTextureIntermediate0"); + m_PlanarReflectionFilterTex1 = RTHandles.Alloc(texWidth, texHeight, TextureXR.slices, colorFormat: GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite: true, useDynamicScale: false, useMipMap: false, name: "PlanarReflectionTextureIntermediate1"); + m_PlanarReflectionFilterDepthTex0 = RTHandles.Alloc(texWidth, texHeight, TextureXR.slices, colorFormat: GraphicsFormat.R32_SFloat, enableRandomWrite: true, useDynamicScale: false, useMipMap: true, name: "PlanarReflectionTextureIntermediateDepth0"); + m_PlanarReflectionFilterDepthTex1 = RTHandles.Alloc(texWidth, texHeight, TextureXR.slices, colorFormat: GraphicsFormat.R32_SFloat, enableRandomWrite: true, useDynamicScale: false, useMipMap: false, name: "PlanarReflectionTextureIntermediateDepth1"); + } + } + + void BuildColorAndDepthMipChain(CommandBuffer cmd, RenderTexture sourceColor, RenderTexture sourceDepth) + { + // The first level can be copied straight away in the mip chain + cmd.CopyTexture(sourceColor, 0, 0, 0, 0, sourceColor.width, sourceColor.height, m_PlanarReflectionFilterTex0, 0, 0, 0, 0); + cmd.CopyTexture(sourceDepth, 0, 0, 0, 0, sourceColor.width, sourceColor.height, m_PlanarReflectionFilterDepthTex0, 0, 0, 0, 0); + + // Move to the next mip and build the chain + int tileSize = 8; + int currentMipSource = 0; + int texWidth = sourceColor.width; + int texHeight = sourceColor.height; + int texWidthHalf = sourceColor.width >> 1; + int texHeightHalf = sourceColor.height >> 1; + + // Until we have a 2x2 texture, continue + while (texWidthHalf >= 2 && texHeightHalf >= 2) + { + // Constant inputs + cmd.SetComputeIntParam(m_PlanarReflectionFilteringCS, HDShaderIDs._SourceMipIndex, currentMipSource); + + // Input textures + cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionDownScaleKernel, HDShaderIDs._ReflectionColorMipChain, m_PlanarReflectionFilterTex0); + cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionDownScaleKernel, HDShaderIDs._HalfResReflectionBuffer, m_PlanarReflectionFilterTex1); + + // Output textures + cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionDownScaleKernel, HDShaderIDs._DepthTextureMipChain, m_PlanarReflectionFilterDepthTex0); + cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionDownScaleKernel, HDShaderIDs._HalfResDepthBuffer, m_PlanarReflectionFilterDepthTex1); + currentScreenSize.Set(texWidth, texHeight, 1.0f / texWidth, 1.0f / texHeight); + cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCurrentScreenSize, currentScreenSize); + + // Compute the dispatch parameters and evaluate the new mip + int numTilesXHRHalf = (texWidthHalf + (tileSize - 1)) / tileSize; + int numTilesYHRHalf = (texHeightHalf + (tileSize - 1)) / tileSize; + cmd.DispatchCompute(m_PlanarReflectionFilteringCS, m_PlanarReflectionDownScaleKernel, numTilesXHRHalf, numTilesYHRHalf, 1); + + // Given that mip to mip in compute doesn't work, we have to do this :( + cmd.CopyTexture(m_PlanarReflectionFilterTex1, 0, 0, 0, 0, texWidthHalf, texHeightHalf, m_PlanarReflectionFilterTex0, 0, currentMipSource + 1, 0, 0); + cmd.CopyTexture(m_PlanarReflectionFilterDepthTex1, 0, 0, 0, 0, texWidthHalf, texHeightHalf, m_PlanarReflectionFilterDepthTex0, 0, currentMipSource + 1, 0, 0); + + // Update the parameters for the next mip + texWidth = texWidth >> 1; + texHeight = texHeight >> 1; + texWidthHalf = texWidthHalf >> 1; + texHeightHalf = texHeightHalf >> 1; + currentMipSource++; + } + } + + override public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source, ref PlanarTextureFilteringParameters planarTextureFilteringParameters, RenderTexture target) + { + // First we need to make sure that our intermediate textures are the big enough to do our process (these textures are squares) + CheckIntermediateTexturesSize(source.width, source.height); + + // First we need to build a mip chain (one for color, one for depth) that we will sample later on in the process + BuildColorAndDepthMipChain(cmd, source, planarTextureFilteringParameters.captureCameraDepthBuffer); + + // Init the mip descent + int texWidth = source.width; + int texHeight = source.height; + + // First we need to copy the Mip0 (that matches perfectly smooth surface) + cmd.CopyTexture(m_PlanarReflectionFilterTex0, 0, 0, 0, 0, texWidth, texHeight, target, 0, 0, 0, 0); + + // Prepare the parameters for the build + int mipIndex = 1; + int tileSize = 8; + float roughnessStep = RoughnessStep(texWidth); + float currentRoughness = roughnessStep; + float rtScaleFactor = texWidth / (float)m_PlanarReflectionFilterTex0.rt.width; + texWidth = texWidth >> 1; + texHeight = texHeight >> 1; + + // Loop until we have an 8x8 texture + while (texWidth >= 8 && texHeight >= 8) + { + // Evaluate the dispatch parameters + int numTilesXHR = (texWidth + (tileSize - 1)) / tileSize; + int numTilesYHR = (texHeight + (tileSize - 1)) / tileSize; + + // Set input textures + cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionFilteringKernel, HDShaderIDs._DepthTextureMipChain, m_PlanarReflectionFilterDepthTex0); + cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionFilteringKernel, HDShaderIDs._ReflectionColorMipChain, m_PlanarReflectionFilterTex0); + cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionFilteringKernel, HDShaderIDs._ThetaValuesTexture, m_GGXConeAngle); + + // Input constant parameters required + cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureBaseScreenSize, planarTextureFilteringParameters.captureCameraScreenSize); + currentScreenSize.Set(texWidth, texHeight, 1.0f / texWidth, 1.0f / texHeight); + cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCurrentScreenSize, currentScreenSize); + cmd.SetComputeFloatParam(m_PlanarReflectionFilteringCS, HDShaderIDs._IntegrationRoughness, currentRoughness); + cmd.SetComputeIntParam(m_PlanarReflectionFilteringCS, HDShaderIDs._SourceMipIndex, mipIndex); + cmd.SetComputeFloatParam(m_PlanarReflectionFilteringCS, HDShaderIDs._RTScaleFactor, rtScaleFactor); + cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._ReflectionPlaneNormal, planarTextureFilteringParameters.probeNormal); + cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._ReflectionPlanePosition, planarTextureFilteringParameters.probePosition); + cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraPositon, planarTextureFilteringParameters.captureCameraPosition); + cmd.SetComputeMatrixParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraIVP, planarTextureFilteringParameters.captureCameraIVP); + cmd.SetComputeFloatParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraFOV, planarTextureFilteringParameters.captureFOV * Mathf.PI / 180.0f); + + // Set output textures + cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionFilteringKernel, HDShaderIDs._FilteredPlanarReflectionBuffer, m_PlanarReflectionFilterTex1); + + // Evaluate the next convolution + cmd.DispatchCompute(m_PlanarReflectionFilteringCS, m_PlanarReflectionFilteringKernel, numTilesXHR, numTilesYHR, 1); + + // Copy the convoluted texture into the next mip and move on + cmd.CopyTexture(m_PlanarReflectionFilterTex1, 0, 0, 0, 0, texWidth, texHeight, target, 0, mipIndex, 0, 0); + + // Move to the next mip + texWidth = texWidth >> 1; + texHeight = texHeight >> 1; + mipIndex++; + + // Increase the integration roughness + currentRoughness += roughnessStep; + } + } } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/IBLFilterBSDF.cs b/com.unity.render-pipelines.high-definition/Runtime/Material/IBLFilterBSDF.cs index 990459e6eba..8ec2400ff96 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/IBLFilterBSDF.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/IBLFilterBSDF.cs @@ -19,11 +19,18 @@ abstract class IBLFilterBSDF // Filters MIP map levels (other than 0) with GGX using BRDF importance sampling. abstract public void FilterCubemap(CommandBuffer cmd, Texture source, RenderTexture target); - public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source, RenderTexture target) + internal struct PlanarTextureFilteringParameters { - m_MipGenerator.RenderColorGaussianPyramid(cmd, new Vector2Int(source.width, source.height), source, target); - } + public RenderTexture captureCameraDepthBuffer; + public Matrix4x4 captureCameraIVP; + public Vector3 captureCameraPosition; + public Vector4 captureCameraScreenSize; + public Vector3 probePosition; + public Vector3 probeNormal; + public float captureFOV; + }; + abstract public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source, ref PlanarTextureFilteringParameters planarTextureFilteringParameters, RenderTexture target); public abstract void FilterCubemapMIS(CommandBuffer cmd, Texture source, RenderTexture target, RenderTexture conditionalCdf, RenderTexture marginalRowCdf); } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl index 7ff10278bd7..4b288ed9940 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl @@ -1911,20 +1911,7 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, float3 F = preLightData.specularFGD; - float iblMipLevel; - // TODO: We need to match the PerceptualRoughnessToMipmapLevel formula for planar, so we don't do this test (which is specific to our current lightloop) - // Specific case for Texture2Ds, their convolution is a gaussian one and not a GGX one - So we use another roughness mip mapping. - if (IsEnvIndexTexture2D(lightData.envIndex)) - { - // Empirical remapping - iblMipLevel = PlanarPerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness, _ColorPyramidLodCount); - } - else - { - iblMipLevel = PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness); - } - - float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, iblMipLevel, lightData.rangeCompressionFactorCompensation); + float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness), lightData.rangeCompressionFactorCompensation); weight *= preLD.a; // Used by planar reflection to discard pixel if (GPUImageBasedLightingType == GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION) diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index ba05ca5c744..41155408f38 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -1214,6 +1214,7 @@ public struct Target public RenderTargetIdentifier id; public CubemapFace face; public RenderTexture copyToTarget; + public RenderTexture targetDepth; } public HDCamera hdCamera; public bool clearCameraSettings; @@ -1612,6 +1613,10 @@ ref List renderDatas { visibleProbe.SetTexture(ProbeSettings.Mode.Realtime, HDRenderUtilities.CreatePlanarProbeRenderTarget(desiredPlanarProbeSize)); } + if (visibleProbe.realtimeDepthTexture == null || visibleProbe.realtimeDepthTexture.width != desiredPlanarProbeSize) + { + visibleProbe.SetDepthTexture(ProbeSettings.Mode.Realtime, HDRenderUtilities.CreatePlanarProbeDepthRenderTarget(desiredPlanarProbeSize)); + } // Set the viewer's camera as the default camera anchor for (var i = 0; i < cameraSettings.Count; ++i) { @@ -1732,6 +1737,7 @@ ref _cullingResults request.target = new RenderRequest.Target { id = visibleProbe.realtimeTexture, + targetDepth = visibleProbe.realtimeDepthTexture, face = CubemapFace.Unknown }; } @@ -2546,11 +2552,15 @@ void Callback(CommandBuffer c, HDCamera cam) using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.BlitToFinalRTDevBuildOnly))) { - for (int viewIndex = 0; viewIndex < hdCamera.viewCount; ++viewIndex) - { - var finalBlitParams = PrepareFinalBlitParameters(hdCamera, viewIndex); - BlitFinalCameraTexture(finalBlitParams, m_BlitPropertyBlock, m_IntermediateAfterPostProcessBuffer, target.id, cmd); - } + for (int viewIndex = 0; viewIndex < hdCamera.viewCount; ++viewIndex) + { + var finalBlitParams = PrepareFinalBlitParameters(hdCamera, viewIndex); + BlitFinalCameraTexture(finalBlitParams, m_BlitPropertyBlock, m_IntermediateAfterPostProcessBuffer, target.id, cmd); + + // If a depth target is specified, fill it + if (target.targetDepth != null) + BlitFinalCameraTexture(finalBlitParams, m_BlitPropertyBlock, m_SharedRTManager.GetDepthTexture(), target.targetDepth, cmd); + } } aovRequest.PushCameraTexture(cmd, AOVBuffers.Output, hdCamera, m_IntermediateAfterPostProcessBuffer, aovBuffers); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index 28dc5a92ebe..e9c3e241c73 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -247,6 +247,24 @@ static class HDShaderIDs public static readonly int _CameraFilteringBuffer = Shader.PropertyToID("_CameraFilteringTexture"); public static readonly int _IrradianceSource = Shader.PropertyToID("_IrradianceSource"); + // Planar reflection filtering + public static readonly int _ReflectionColorMipChain = Shader.PropertyToID("_ReflectionColorMipChain"); + public static readonly int _DepthTextureMipChain = Shader.PropertyToID("_DepthTextureMipChain"); + public static readonly int _ReflectionPlaneNormal = Shader.PropertyToID("_ReflectionPlaneNormal"); + public static readonly int _ReflectionPlanePosition = Shader.PropertyToID("_ReflectionPlanePosition"); + public static readonly int _IntegrationRoughness = Shader.PropertyToID("_IntegrationRoughness"); + public static readonly int _FilteredPlanarReflectionBuffer = Shader.PropertyToID("_FilteredPlanarReflectionBuffer"); + public static readonly int _HalfResReflectionBuffer = Shader.PropertyToID("_HalfResReflectionBuffer"); + public static readonly int _HalfResDepthBuffer = Shader.PropertyToID("_HalfResDepthBuffer"); + public static readonly int _CaptureBaseScreenSize = Shader.PropertyToID("_CaptureBaseScreenSize"); + public static readonly int _CaptureCurrentScreenSize = Shader.PropertyToID("_CaptureCurrentScreenSize"); + public static readonly int _CaptureCameraIVP = Shader.PropertyToID("_CaptureCameraIVP"); + public static readonly int _CaptureCameraPositon = Shader.PropertyToID("_CaptureCameraPositon"); + public static readonly int _SourceMipIndex = Shader.PropertyToID("_SourceMipIndex"); + public static readonly int _ThetaValuesTexture = Shader.PropertyToID("_ThetaValuesTexture"); + public static readonly int _CaptureCameraFOV = Shader.PropertyToID("_CaptureCameraFOV"); + public static readonly int _RTScaleFactor = Shader.PropertyToID("_RTScaleFactor"); + // MSAA shader properties public static readonly int _ColorTextureMS = Shader.PropertyToID("_ColorTextureMS"); public static readonly int _DepthTextureMS = Shader.PropertyToID("_DepthTextureMS"); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs index 1adb07ae3df..92f52f0928f 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs @@ -143,7 +143,8 @@ public sealed class ShaderResources public ComputeShader inScatteredRadiancePrecomputationCS; [Reload("Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSky.shader")] public Shader physicallyBasedSkyPS; - + [Reload("Runtime/Lighting/PlanarReflectionFiltering.compute")] + public ComputeShader planarReflectionFilteringCS; // Material [Reload("Runtime/Material/PreIntegratedFGD/PreIntegratedFGD_GGXDisneyDiffuse.shader")] public Shader preIntegratedFGD_GGXDisneyDiffusePS; @@ -363,6 +364,8 @@ public sealed class TextureResources [Reload("Runtime/RenderPipelineResources/Texture/DefaultHDRISky.exr")] public Cubemap defaultHDRISky; + [Reload("Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png")] + public Texture2D ggxConeAngle70pc; } [Serializable, ReloadGroup] diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset index 57616a47365..61b7c2d6a67 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineResources.asset @@ -15,86 +15,135 @@ MonoBehaviour: m_Version: 4 shaders: defaultPS: {fileID: 4800000, guid: 6e4ae4064600d784cac1e41a9e6f2e59, type: 3} - debugDisplayLatlongPS: {fileID: 4800000, guid: c1d1d149a043a5349ba367da6c2051ba, type: 3} - debugViewMaterialGBufferPS: {fileID: 4800000, guid: 439949ea1bfa91b4ba0d04269fcde33d, type: 3} + debugDisplayLatlongPS: {fileID: 4800000, guid: c1d1d149a043a5349ba367da6c2051ba, + type: 3} + debugViewMaterialGBufferPS: {fileID: 4800000, guid: 439949ea1bfa91b4ba0d04269fcde33d, + type: 3} debugViewTilesPS: {fileID: 4800000, guid: c7c2bd17b06ceb4468e14081aaf1b96f, type: 3} debugFullScreenPS: {fileID: 4800000, guid: e874aca2df8300a488258738c31f85cf, type: 3} - debugColorPickerPS: {fileID: 4800000, guid: 8137b807709e178498f22ed710864bb0, type: 3} - debugLightVolumePS: {fileID: 4800000, guid: 8e706c0e71fcec34a8f5c9713e5e2943, type: 3} - debugLightVolumeCS: {fileID: 7200000, guid: f5d5d21faef5cf445ac2c5d8ff9c4184, type: 3} + debugColorPickerPS: {fileID: 4800000, guid: 8137b807709e178498f22ed710864bb0, + type: 3} + debugLightVolumePS: {fileID: 4800000, guid: 8e706c0e71fcec34a8f5c9713e5e2943, + type: 3} + debugLightVolumeCS: {fileID: 7200000, guid: f5d5d21faef5cf445ac2c5d8ff9c4184, + type: 3} debugBlitQuad: {fileID: 4800000, guid: cf5ca5b6ef18b3f429ed707ee9ceac9f, type: 3} deferredPS: {fileID: 4800000, guid: 00dd221e34a6ab349a1196b0f2fab693, type: 3} colorPyramidPS: {fileID: 4800000, guid: 2fcfb8d92f45e4549b3f0bad5d0654bf, type: 3} depthPyramidCS: {fileID: 7200000, guid: 64a553bb564274041906f78ffba955e4, type: 3} copyChannelCS: {fileID: 7200000, guid: a4d45eda75e8e474dbe24a31f741f3b4, type: 3} - screenSpaceReflectionsCS: {fileID: 7200000, guid: d1de9ac7d9016204da289affe9677942, type: 3} + screenSpaceReflectionsCS: {fileID: 7200000, guid: d1de9ac7d9016204da289affe9677942, + type: 3} applyDistortionPS: {fileID: 4800000, guid: 02ae56f4306413c4a96dcf005cde1971, type: 3} - clearDispatchIndirectCS: {fileID: 7200000, guid: fc1f553acb80a6446a32d33e403d0656, type: 3} + clearDispatchIndirectCS: {fileID: 7200000, guid: fc1f553acb80a6446a32d33e403d0656, + type: 3} clearLightListsCS: {fileID: 7200000, guid: 743eb3491795b9545955695d591195a1, type: 3} - buildDispatchIndirectCS: {fileID: 7200000, guid: 4eb1b418be7044c40bb5200496c50f14, type: 3} + buildDispatchIndirectCS: {fileID: 7200000, guid: 4eb1b418be7044c40bb5200496c50f14, + type: 3} buildScreenAABBCS: {fileID: 7200000, guid: 728dce960f8a9c44bbc3abb3b851d8f6, type: 3} - buildPerTileLightListCS: {fileID: 7200000, guid: 65af3444cbf4b3747a4dead7ee00cfee, type: 3} - buildPerBigTileLightListCS: {fileID: 7200000, guid: 5ee1f9d6e09abe045b2f5e0b784b9072, type: 3} - buildPerVoxelLightListCS: {fileID: 7200000, guid: 0bb1b7e0ddcd5c44baf3ddc7456eb196, type: 3} - lightListClusterClearAtomicIndexCS: {fileID: 7200000, guid: 1e3472a94b14a334a93230bbc700d7b2, type: 3} - buildMaterialFlagsCS: {fileID: 7200000, guid: fb3eda953cd6e634e877fb777be2cd08, type: 3} + buildPerTileLightListCS: {fileID: 7200000, guid: 65af3444cbf4b3747a4dead7ee00cfee, + type: 3} + buildPerBigTileLightListCS: {fileID: 7200000, guid: 5ee1f9d6e09abe045b2f5e0b784b9072, + type: 3} + buildPerVoxelLightListCS: {fileID: 7200000, guid: 0bb1b7e0ddcd5c44baf3ddc7456eb196, + type: 3} + lightListClusterClearAtomicIndexCS: {fileID: 7200000, guid: 1e3472a94b14a334a93230bbc700d7b2, + type: 3} + buildMaterialFlagsCS: {fileID: 7200000, guid: fb3eda953cd6e634e877fb777be2cd08, + type: 3} deferredCS: {fileID: 7200000, guid: 0b64f79746d2daf4198eaf6eab9af259, type: 3} contactShadowCS: {fileID: 7200000, guid: 3e6900e06dc185a4380af4dacb4db0a4, type: 3} - volumeVoxelizationCS: {fileID: 7200000, guid: c20b371db720da244b73830ec74a343a, type: 3} - volumetricLightingCS: {fileID: 7200000, guid: b4901a10df2d1e24282725e9fbc77c97, type: 3} - volumetricLightingFilteringCS: {fileID: 7200000, guid: ef9a910d0ec6ebb41ae3f5c7a69daf46, type: 3} + volumeVoxelizationCS: {fileID: 7200000, guid: c20b371db720da244b73830ec74a343a, + type: 3} + volumetricLightingCS: {fileID: 7200000, guid: b4901a10df2d1e24282725e9fbc77c97, + type: 3} + volumetricLightingFilteringCS: {fileID: 7200000, guid: ef9a910d0ec6ebb41ae3f5c7a69daf46, + type: 3} deferredTilePS: {fileID: 4800000, guid: dedaf4ea0d134ca4aad1d95a558c46e5, type: 3} - screenSpaceShadowPS: {fileID: 4800000, guid: bfa43a48695613b4ea19c58858ae1a61, type: 3} - probeVolumeAtlasBlitCS: {fileID: 7200000, guid: 07f429bf534edb44eb5a0e4b2c65b108, type: 3} - probeVolumeAtlasOctahedralDepthBlitCS: {fileID: 7200000, guid: f60c895d3a3061848844b36ccf9e44a9, type: 3} - probeVolumeAtlasOctahedralDepthConvolveCS: {fileID: 7200000, guid: 7ef71ce05401a4c4081039b475d3b9ee, type: 3} - debugDisplayProbeVolumePS: {fileID: 4800000, guid: e7c19cfee7a88394fbb53652b9644cc0, type: 3} - subsurfaceScatteringCS: {fileID: 7200000, guid: b06a7993621def248addd55d0fe931b1, type: 3} + screenSpaceShadowPS: {fileID: 4800000, guid: bfa43a48695613b4ea19c58858ae1a61, + type: 3} + probeVolumeAtlasBlitCS: {fileID: 7200000, guid: 07f429bf534edb44eb5a0e4b2c65b108, + type: 3} + probeVolumeAtlasOctahedralDepthBlitCS: {fileID: 7200000, guid: f60c895d3a3061848844b36ccf9e44a9, + type: 3} + probeVolumeAtlasOctahedralDepthConvolveCS: {fileID: 7200000, guid: 7ef71ce05401a4c4081039b475d3b9ee, + type: 3} + debugDisplayProbeVolumePS: {fileID: 4800000, guid: e7c19cfee7a88394fbb53652b9644cc0, + type: 3} + subsurfaceScatteringCS: {fileID: 7200000, guid: b06a7993621def248addd55d0fe931b1, + type: 3} combineLightingPS: {fileID: 4800000, guid: 2e37131331fbdca449b1a2bc47a639ca, type: 3} - cameraMotionVectorsPS: {fileID: 4800000, guid: 035941b63024d1943af48811c1db20d9, type: 3} - clearStencilBufferPS: {fileID: 4800000, guid: 8ea49ef16606acd489439e676ab84040, type: 3} - copyStencilBufferPS: {fileID: 4800000, guid: 3d1574f1cdfa0ce4995f9bc79ed7f8ec, type: 3} + cameraMotionVectorsPS: {fileID: 4800000, guid: 035941b63024d1943af48811c1db20d9, + type: 3} + clearStencilBufferPS: {fileID: 4800000, guid: 8ea49ef16606acd489439e676ab84040, + type: 3} + copyStencilBufferPS: {fileID: 4800000, guid: 3d1574f1cdfa0ce4995f9bc79ed7f8ec, + type: 3} copyDepthBufferPS: {fileID: 4800000, guid: 42dfcc8fe803ece4096c58630689982f, type: 3} blitPS: {fileID: 4800000, guid: 370f7a9cc4e362d488af024d371091e8, type: 3} downsampleDepthPS: {fileID: 4800000, guid: 67d6171b0acc6554aad48c845ec7e67f, type: 3} - upsampleTransparentPS: {fileID: 4800000, guid: 2ad7ce40f0dbaf64dadef1f58d8524d3, type: 3} + upsampleTransparentPS: {fileID: 4800000, guid: 2ad7ce40f0dbaf64dadef1f58d8524d3, + type: 3} resolveStencilCS: {fileID: 7200000, guid: 65b89cac5f286b043a31bf8041776ee7, type: 3} blitCubemapPS: {fileID: 4800000, guid: d05913e251bed7a4992c921c62e1b647, type: 3} - buildProbabilityTablesCS: {fileID: 7200000, guid: b9f26cf340afe9145a699753531b2a4c, type: 3} - computeGgxIblSampleDataCS: {fileID: 7200000, guid: 764a24bb47ef5ba4781d9ae82ca07445, type: 3} + buildProbabilityTablesCS: {fileID: 7200000, guid: b9f26cf340afe9145a699753531b2a4c, + type: 3} + computeGgxIblSampleDataCS: {fileID: 7200000, guid: 764a24bb47ef5ba4781d9ae82ca07445, + type: 3} GGXConvolvePS: {fileID: 4800000, guid: 123ed592ad5c2494b8aed301fd609e7b, type: 3} charlieConvolvePS: {fileID: 4800000, guid: 5685fd17e71045e4ca9fefca38a7c177, type: 3} - opaqueAtmosphericScatteringPS: {fileID: 4800000, guid: 32f724728cf19904291226f239ec16f0, type: 3} + opaqueAtmosphericScatteringPS: {fileID: 4800000, guid: 32f724728cf19904291226f239ec16f0, + type: 3} hdriSkyPS: {fileID: 4800000, guid: 9bd32a6ece529fd4f9408b8d7e00c10d, type: 3} - integrateHdriSkyPS: {fileID: 4800000, guid: 48db2705cf2856d4e893eb30a6892d1b, type: 3} + integrateHdriSkyPS: {fileID: 4800000, guid: 48db2705cf2856d4e893eb30a6892d1b, + type: 3} skyboxCubemapPS: {fileID: 103, guid: 0000000000000000f000000000000000, type: 0} gradientSkyPS: {fileID: 4800000, guid: 2b5d4f1b26f03dc4a873b093e0c4adb1, type: 3} - ambientProbeConvolutionCS: {fileID: 7200000, guid: 6d048f7b1bd45e840b4e79ec92639fa8, type: 3} - groundIrradiancePrecomputationCS: {fileID: 7200000, guid: eb6ae6f326207ee4d987a3e5adddf63a, type: 3} - inScatteredRadiancePrecomputationCS: {fileID: 7200000, guid: 70c69d514688f8545855680760d77418, type: 3} - physicallyBasedSkyPS: {fileID: 4800000, guid: a06934a4863e778498be65d8f865b7a4, type: 3} - preIntegratedFGD_GGXDisneyDiffusePS: {fileID: 4800000, guid: 123f13d52852ef547b2962de4bd9eaad, type: 3} - preIntegratedFGD_CharlieFabricLambertPS: {fileID: 4800000, guid: 3b3bf235775cf8b4baae7f3306787ab0, type: 3} - preIntegratedFGD_WardPS: {fileID: 4800000, guid: d279c46a545b0af4f9f0c4fa82cd489e, type: 3} - preIntegratedFGD_CookTorrancePS: {fileID: 4800000, guid: a6402c19b020b4a4fb7073aaa2e26aba, type: 3} + ambientProbeConvolutionCS: {fileID: 7200000, guid: 6d048f7b1bd45e840b4e79ec92639fa8, + type: 3} + groundIrradiancePrecomputationCS: {fileID: 7200000, guid: eb6ae6f326207ee4d987a3e5adddf63a, + type: 3} + inScatteredRadiancePrecomputationCS: {fileID: 7200000, guid: 70c69d514688f8545855680760d77418, + type: 3} + physicallyBasedSkyPS: {fileID: 4800000, guid: a06934a4863e778498be65d8f865b7a4, + type: 3} + planarReflectionFilteringCS: {fileID: 7200000, guid: 9f3f8a01b8caaaa4595591dc96d43dd2, + type: 3} + preIntegratedFGD_GGXDisneyDiffusePS: {fileID: 4800000, guid: 123f13d52852ef547b2962de4bd9eaad, + type: 3} + preIntegratedFGD_CharlieFabricLambertPS: {fileID: 4800000, guid: 3b3bf235775cf8b4baae7f3306787ab0, + type: 3} + preIntegratedFGD_WardPS: {fileID: 4800000, guid: d279c46a545b0af4f9f0c4fa82cd489e, + type: 3} + preIntegratedFGD_CookTorrancePS: {fileID: 4800000, guid: a6402c19b020b4a4fb7073aaa2e26aba, + type: 3} encodeBC6HCS: {fileID: 7200000, guid: aa922d239de60304f964e24488559eeb, type: 3} cubeToPanoPS: {fileID: 4800000, guid: 595434cc3b6405246b6cd3086d0b6f7d, type: 3} - blitCubeTextureFacePS: {fileID: 4800000, guid: d850d0a2481878d4bbf17e5126b04163, type: 3} - filterAreaLightCookiesPS: {fileID: 4800000, guid: c243aac96dda5fa40bed693ed5ba02c4, type: 3} - clearUIntTextureCS: {fileID: 7200000, guid: d067ad4b88af51c498875426894aef76, type: 3} + blitCubeTextureFacePS: {fileID: 4800000, guid: d850d0a2481878d4bbf17e5126b04163, + type: 3} + filterAreaLightCookiesPS: {fileID: 4800000, guid: c243aac96dda5fa40bed693ed5ba02c4, + type: 3} + clearUIntTextureCS: {fileID: 7200000, guid: d067ad4b88af51c498875426894aef76, + type: 3} xrMirrorViewPS: {fileID: 4800000, guid: e6255f98cf405eb45ab6f9006cf11e1f, type: 3} xrOcclusionMeshPS: {fileID: 4800000, guid: 46a45b32bb110604fb36216b63bcdb81, type: 3} shadowClearPS: {fileID: 4800000, guid: e3cab24f27741f44d8af1e94d006267c, type: 3} evsmBlurCS: {fileID: 7200000, guid: fb36979473602464fa32deacb9630c08, type: 3} - debugHDShadowMapPS: {fileID: 4800000, guid: 93d40cc9a6e13994f86f576a624efa18, type: 3} + debugHDShadowMapPS: {fileID: 4800000, guid: 93d40cc9a6e13994f86f576a624efa18, + type: 3} momentShadowsCS: {fileID: 7200000, guid: 4dea53e2ff15ed0448817c2aa4246e53, type: 3} - decalNormalBufferPS: {fileID: 4800000, guid: fd532bf1795188c4daaa66ea798b8b0a, type: 3} - decalClearPropertyMaskBufferCS: {fileID: 7200000, guid: 1076a08965d4a91479b72599724f7fd6, type: 3} + decalNormalBufferPS: {fileID: 4800000, guid: fd532bf1795188c4daaa66ea798b8b0a, + type: 3} + decalClearPropertyMaskBufferCS: {fileID: 7200000, guid: 1076a08965d4a91479b72599724f7fd6, + type: 3} GTAOCS: {fileID: 7200000, guid: 6710b06492bd58c4bb8aec0fdc1fced3, type: 3} - GTAOSpatialDenoiseCS: {fileID: 7200000, guid: 2cb33c21587d12b4388d7866ab6c65f6, type: 3} - GTAOTemporalDenoiseCS: {fileID: 7200000, guid: 31e0ca4c210f97c468037d11a5b832bb, type: 3} + GTAOSpatialDenoiseCS: {fileID: 7200000, guid: 2cb33c21587d12b4388d7866ab6c65f6, + type: 3} + GTAOTemporalDenoiseCS: {fileID: 7200000, guid: 31e0ca4c210f97c468037d11a5b832bb, + type: 3} GTAOCopyHistoryCS: {fileID: 7200000, guid: 7f43be57ffd12ff469d4fc175c00c4b4, type: 3} - GTAOBlurAndUpsample: {fileID: 7200000, guid: 9eb1abde882538a4ea46fa23e49ab9fa, type: 3} + GTAOBlurAndUpsample: {fileID: 7200000, guid: 9eb1abde882538a4ea46fa23e49ab9fa, + type: 3} depthValuesPS: {fileID: 4800000, guid: 6e6a4a3dbb788234594aa74f2d6aeb6f, type: 3} colorResolvePS: {fileID: 4800000, guid: dd7047092f3c82b40b3a07868f9c4de2, type: 3} copyAlphaCS: {fileID: 7200000, guid: c2c7eb6611725264187721ef9df0354b, type: 3} @@ -103,23 +152,38 @@ MonoBehaviour: applyExposureCS: {fileID: 7200000, guid: 1a6fea1dc099b984d8f2b27d504dc096, type: 3} uberPostCS: {fileID: 7200000, guid: f1bf52f7c71bffd4f91e6cd90d12a4f7, type: 3} lutBuilder3DCS: {fileID: 7200000, guid: 37f2b1b0ecd6f1c439e4c1b4f2fdb524, type: 3} - depthOfFieldKernelCS: {fileID: 7200000, guid: 7869415cc3e4eaa4d82ac21a752a2780, type: 3} + depthOfFieldKernelCS: {fileID: 7200000, guid: 7869415cc3e4eaa4d82ac21a752a2780, + type: 3} depthOfFieldCoCCS: {fileID: 7200000, guid: 048b235b54fbfaa4d80ec85ea847d4f8, type: 3} - depthOfFieldCoCReprojectCS: {fileID: 7200000, guid: 4980decaa3878d6448569489f5fc7931, type: 3} - depthOfFieldDilateCS: {fileID: 7200000, guid: 1c93af4338c0c1b42b92464992eebc10, type: 3} + depthOfFieldCoCReprojectCS: {fileID: 7200000, guid: 4980decaa3878d6448569489f5fc7931, + type: 3} + depthOfFieldDilateCS: {fileID: 7200000, guid: 1c93af4338c0c1b42b92464992eebc10, + type: 3} depthOfFieldMipCS: {fileID: 7200000, guid: d3ef53de069ded64e8377cba6eb951fa, type: 3} - depthOfFieldMipSafeCS: {fileID: 7200000, guid: 2d24ee7b2c804d947a5c371c12ed46bd, type: 3} - depthOfFieldPrefilterCS: {fileID: 7200000, guid: f2b89d19910854346b792fe7177ce634, type: 3} - depthOfFieldTileMaxCS: {fileID: 7200000, guid: 84f84585ea8a7a849bea4a581adb93a7, type: 3} - depthOfFieldGatherCS: {fileID: 7200000, guid: 486be52dddc4e054fb10a7b9b78788c2, type: 3} - depthOfFieldCombineCS: {fileID: 7200000, guid: c8049ca85c4c7d047ba28f34d800c663, type: 3} - depthOfFieldPreCombineFarCS: {fileID: 7200000, guid: 3b4a2acd03d1ce2438d93c325d588735, type: 3} - depthOfFieldClearIndirectArgsCS: {fileID: 7200000, guid: 69905045e1d0a65458b205d6ab55502b, type: 3} - paniniProjectionCS: {fileID: 7200000, guid: 0ddbf72c8fbb6e44b983f470c8384ef6, type: 3} - motionBlurMotionVecPrepCS: {fileID: 7200000, guid: ed9438fa777911d48933402087203b15, type: 3} - motionBlurGenTileCS: {fileID: 7200000, guid: 336e1fdbb3a1b8647b06208415f87804, type: 3} - motionBlurMergeTileCS: {fileID: 7200000, guid: cd14ddf849edeed43b0e3ccf66023038, type: 3} - motionBlurNeighborhoodTileCS: {fileID: 7200000, guid: 5ea9865df3e53b448856785b88f8e7b9, type: 3} + depthOfFieldMipSafeCS: {fileID: 7200000, guid: 2d24ee7b2c804d947a5c371c12ed46bd, + type: 3} + depthOfFieldPrefilterCS: {fileID: 7200000, guid: f2b89d19910854346b792fe7177ce634, + type: 3} + depthOfFieldTileMaxCS: {fileID: 7200000, guid: 84f84585ea8a7a849bea4a581adb93a7, + type: 3} + depthOfFieldGatherCS: {fileID: 7200000, guid: 486be52dddc4e054fb10a7b9b78788c2, + type: 3} + depthOfFieldCombineCS: {fileID: 7200000, guid: c8049ca85c4c7d047ba28f34d800c663, + type: 3} + depthOfFieldPreCombineFarCS: {fileID: 7200000, guid: 3b4a2acd03d1ce2438d93c325d588735, + type: 3} + depthOfFieldClearIndirectArgsCS: {fileID: 7200000, guid: 69905045e1d0a65458b205d6ab55502b, + type: 3} + paniniProjectionCS: {fileID: 7200000, guid: 0ddbf72c8fbb6e44b983f470c8384ef6, + type: 3} + motionBlurMotionVecPrepCS: {fileID: 7200000, guid: ed9438fa777911d48933402087203b15, + type: 3} + motionBlurGenTileCS: {fileID: 7200000, guid: 336e1fdbb3a1b8647b06208415f87804, + type: 3} + motionBlurMergeTileCS: {fileID: 7200000, guid: cd14ddf849edeed43b0e3ccf66023038, + type: 3} + motionBlurNeighborhoodTileCS: {fileID: 7200000, guid: 5ea9865df3e53b448856785b88f8e7b9, + type: 3} motionBlurCS: {fileID: 7200000, guid: 2af5c49c7865edb4b823826970ec176a, type: 3} bloomPrefilterCS: {fileID: 7200000, guid: 243b24008041aaa4a91800690f63c684, type: 3} bloomBlurCS: {fileID: 7200000, guid: 133a68380d324de4ea8d3ff8657b02d8, type: 3} @@ -128,8 +192,10 @@ MonoBehaviour: finalPassPS: {fileID: 4800000, guid: 5ac9ef0c50282754b93c7692488e7ee7, type: 3} clearBlackPS: {fileID: 4800000, guid: 3330c1503ea8c6d4d9408df3f64227eb, type: 3} SMAAPS: {fileID: 4800000, guid: 9655f4aa89a469c49aceaceabf9bc77b, type: 3} - temporalAntialiasingPS: {fileID: 4800000, guid: 3dd9fd928fdb83743b1f27d15df22179, type: 3} - contrastAdaptiveSharpenCS: {fileID: 7200000, guid: 560896aec2f412c48995be35551a4ac6, type: 3} + temporalAntialiasingPS: {fileID: 4800000, guid: 3dd9fd928fdb83743b1f27d15df22179, + type: 3} + contrastAdaptiveSharpenCS: {fileID: 7200000, guid: 560896aec2f412c48995be35551a4ac6, + type: 3} accumulationCS: {fileID: 7200000, guid: ed80add7a217efa468d137d6f7c668f3, type: 3} alphaInjectionPS: {fileID: 4800000, guid: 4edd96259a5e8b44c90479928f0cd11e, type: 3} chromaKeyingPS: {fileID: 4800000, guid: 49feb6b111e82ec4eb6d3d08e4b6903e, type: 3} @@ -204,15 +270,20 @@ MonoBehaviour: - {fileID: 2800000, guid: 7641a2b116fafd64d9c3d6459fdfe801, type: 3} - {fileID: 2800000, guid: c6a5e40e6746fef4fa486e8f620ee8d4, type: 3} - {fileID: 2800000, guid: fd4189357c6dfb94fa2d36afbce72086, type: 3} - owenScrambledRGBATex: {fileID: 2800000, guid: b0fe077c1ee7d80428f3d8dfa28a027d, type: 3} - owenScrambled256Tex: {fileID: 2800000, guid: 2a205358e67aa9e4a94a128ac9362f4e, type: 3} + owenScrambledRGBATex: {fileID: 2800000, guid: b0fe077c1ee7d80428f3d8dfa28a027d, + type: 3} + owenScrambled256Tex: {fileID: 2800000, guid: 2a205358e67aa9e4a94a128ac9362f4e, + type: 3} scramblingTex: {fileID: 2800000, guid: bf25cd6288e2c8d43854a61a8496a830, type: 3} rankingTile1SPP: {fileID: 2800000, guid: f2fe0251f704c4c478a8063775cffedb, type: 3} - scramblingTile1SPP: {fileID: 2800000, guid: 6185473f62ad3e74da4acac5d482917a, type: 3} + scramblingTile1SPP: {fileID: 2800000, guid: 6185473f62ad3e74da4acac5d482917a, + type: 3} rankingTile8SPP: {fileID: 2800000, guid: af4bd638a4b3eb14781e6441adcdfbb9, type: 3} - scramblingTile8SPP: {fileID: 2800000, guid: 152f8b933250a7b448fc2d4d301b9944, type: 3} + scramblingTile8SPP: {fileID: 2800000, guid: 152f8b933250a7b448fc2d4d301b9944, + type: 3} rankingTile256SPP: {fileID: 2800000, guid: 1e604a266c415cd46b36d97cd9220aa8, type: 3} - scramblingTile256SPP: {fileID: 2800000, guid: 882fb55d7b3e7c94598a318df9376e32, type: 3} + scramblingTile256SPP: {fileID: 2800000, guid: 882fb55d7b3e7c94598a318df9376e32, + type: 3} filmGrainTex: - {fileID: 2800000, guid: 284a1ac236869fa4eacf377d73c7dff8, type: 3} - {fileID: 2800000, guid: bd74961b009b93145a998ae93a5fc186, type: 3} @@ -227,7 +298,10 @@ MonoBehaviour: SMAASearchTex: {fileID: 2800000, guid: dc95d70472e232b438d0fd38651e7ec2, type: 3} SMAAAreaTex: {fileID: 2800000, guid: 92e0d85ab4eca874098e7fcf6f8f674e, type: 3} defaultHDRISky: {fileID: 8900000, guid: 8253d41e6e8b11a4cbe77a4f8f82934d, type: 3} + ggxConeAngle70pc: {fileID: 2800000, guid: 794081635e7e0fe46b6c3fa0afa70d87, type: 3} assets: - defaultDiffusionProfile: {fileID: 11400000, guid: 2b7005ba3a4d8474b8cdc34141ad766e, type: 2} - emissiveCylinderMesh: {fileID: 2534964839176971238, guid: accb6d90f0d50fe4ca0f68159b4323de, type: 3} + defaultDiffusionProfile: {fileID: 11400000, guid: 2b7005ba3a4d8474b8cdc34141ad766e, + type: 2} + emissiveCylinderMesh: {fileID: 2534964839176971238, guid: accb6d90f0d50fe4ca0f68159b4323de, + type: 3} emissiveQuadMesh: {fileID: 4300000, guid: 1d5a8595286f94f4bb54171d49f473c3, type: 3} diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png new file mode 100644 index 00000000000..19d576549dd --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0da2da1052140ef0777aa9f787f2a66b162167b5b0a1e94c6c2661cb69873052 +size 5512 diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png.meta b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png.meta new file mode 100644 index 00000000000..6b4bcdae5e0 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png.meta @@ -0,0 +1,106 @@ +fileFormatVersion: 2 +guid: 794081635e7e0fe46b6c3fa0afa70d87 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: -1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Utilities/HDRenderUtilities.cs b/com.unity.render-pipelines.high-definition/Runtime/Utilities/HDRenderUtilities.cs index 1cfa26a673e..c6c19aaaa1e 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Utilities/HDRenderUtilities.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Utilities/HDRenderUtilities.cs @@ -365,6 +365,17 @@ public static RenderTexture CreatePlanarProbeRenderTarget(int planarSize) }; } + public static RenderTexture CreatePlanarProbeDepthRenderTarget(int planarSize) + { + return new RenderTexture(planarSize, planarSize, 1, GraphicsFormat.R32_SFloat) + { + dimension = TextureDimension.Tex2D, + enableRandomWrite = true, + useMipMap = true, + autoGenerateMips = false + }; + } + /// /// Create the texture target for a baked reflection probe. /// From 6983a4cc20feea9d72c68ad1e150363ba852d385 Mon Sep 17 00:00:00 2001 From: Anis Date: Mon, 4 May 2020 16:38:13 +0200 Subject: [PATCH 02/15] Small improvement and "proper" support of oblique projection --- .../PlanarReflectionFiltering.compute | 85 +++++++------- .../Material/GGXConvolution/IBLFilterGGX.cs | 3 - .../RenderPipeline/RenderPipelineResources.cs | 2 - .../Texture/GGXConeAngle70pc.png | 3 - .../Texture/GGXConeAngle70pc.png.meta | 106 ------------------ 5 files changed, 38 insertions(+), 161 deletions(-) delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png.meta diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute index 335e90d784d..543f623051b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute @@ -12,10 +12,6 @@ // Tile size of this compute #define PLANAR_REFLECTION_TILE_SIZE 8 -// This texture holds a radian value that matches the angle to grab 70% of the energy of the ggx lobe. -TEXTURE2D(_ThetaValuesTexture); -// Used to sample the theta values texture -SAMPLER(s_linear_clamp); // Mip chain of depth and color TEXTURE2D(_DepthTextureMipChain); TEXTURE2D(_ReflectionColorMipChain); @@ -39,33 +35,30 @@ CBUFFER_START(ShaderVariablesPlanarReflectionFiltering) int _SourceMipIndex; // Inverse view projection of the capture camera float4x4 _CaptureCameraIVP; + // Given that sometimes our writing texture can be bigger than the current target, we need to apply a scale factor before using the sampling intrinsic float _RTScaleFactor; CBUFFER_END -// Output buffer of our code +// Output buffer of our filtering code RW_TEXTURE2D(float4, _FilteredPlanarReflectionBuffer); -bool IntersectPlane(float3 ray_origin, float3 ray_dir, float3 pos, float3 normal, out float t) +// This function could be placed in a shared file. +bool IntersectPlane(float3 rayOrigin, float3 rayDirection, float3 planePosition, float3 planeNormal, out float t) { t = -1.0; - float denom = dot(normal, ray_dir); + float denom = dot(planeNormal, rayDirection); if (abs(denom) > 1e-5) { - float3 d = pos - ray_origin; - t = dot(d, normal) / denom; + float3 d = planePosition - rayOrigin; + t = dot(d, planeNormal) / denom; return (t >= 0); } return false; } -float sqr(float value) -{ - return value * value; -} -float gaussian(float radius, float sigma) -{ - return exp(-sqr(radius / sigma)); -} +// These angles have been experimentally computed to match the result of reflection probes. Initially this was a table dependent on angle and roughness, but given that every planar has a +// finite number of LODs and those LODS have fixed roughness and the angle changes the result, but not that much. I changed it to a per LOD LUT +static const float reflectionProbeEquivalentAngles[8] = {0.0, 0.04, 0.12, 0.4, 0.9, 1.2, 1.2, 1.2}; [numthreads(PLANAR_REFLECTION_TILE_SIZE, PLANAR_REFLECTION_TILE_SIZE, 1)] void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID) @@ -75,17 +68,20 @@ void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 // Compute the pixel position to process int2 currentCoord = (int2)(groupId * PLANAR_REFLECTION_TILE_SIZE + groupThreadId); + // Fetch the depth value for the current pixel. It would be great to use sample instead, but oblique matrices prevent us from doing it. + float centerDepthValue = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord, _SourceMipIndex).x; + // Compute the coordinates that shall be used for sampling float2 sampleCoords = (currentCoord << (int)(_SourceMipIndex)) * _CaptureBaseScreenSize.zw * _RTScaleFactor; - // Read the a filtered depth value of the tap coord - float centerDepthValue = SAMPLE_TEXTURE2D_LOD(_DepthTextureMipChain, s_trilinear_clamp_sampler, sampleCoords, _SourceMipIndex).x; - // Compute the world position of the tapped pixel PositionInputs centralPosInput = GetPositionInput(currentCoord, _CaptureCurrentScreenSize.zw, centerDepthValue, _CaptureCameraIVP, 0, 0); // Compute the direction to the reflection pixel float3 rayDirection = normalize(centralPosInput.positionWS - _CaptureCameraPositon); + // For obliques matrices, when the depth is equal to zero (aka far plane), the position generated ends-up behind the camera. Frankly, I am not sure + // why but by inverting it we get the "correct result" + rayDirection = centerDepthValue == 0.0 ? -rayDirection : rayDirection; // Compute the position on the plane we shall be integrating from float t = -1.0; @@ -97,11 +93,10 @@ void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 } // Compute the integration position (position on the plane) - float3 integrationPositionRWS = _CaptureCameraPositon + rayDirection * t; + const float3 integrationPositionRWS = _CaptureCameraPositon + rayDirection * t; - // Evaluate the cone halfangle for the filtering (it is the cone angle to grab 70% of the energy of the ggx lobe) - float halfAngle = SAMPLE_TEXTURE2D_LOD(_ThetaValuesTexture, s_linear_clamp, float2(dot(rayDirection,_ReflectionPlaneNormal), _IntegrationRoughness), 0).r; - halfAngle = halfAngle * PI * 0.5f; + // Evaluate the cone halfangle for the filtering + const float halfAngle = reflectionProbeEquivalentAngles[_SourceMipIndex]; // Compute the distances we need for our filtering const float distanceCameraToPlane = length(integrationPositionRWS - _CaptureCameraPositon); @@ -113,15 +108,19 @@ void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 // We need to compute the view cone radius const float viewConeRadius = brdfConeRadius * distanceCameraToPlane / (distancePlaneToObject + distanceCameraToPlane); - // Compute the view cone's half angle. This matches the FOV angle to see exactly the half of the cone + // Compute the view cone's half angle. This matches the FOV angle to see exactly the half of the cone (The tangent could be precomputed in the table) const float viewConeHalfAngle = atan(viewConeRadius / distanceCameraToPlane); // Given the camera's fov and pixel resolution convert the viewConeHalfAngle to a number of pixels const float pixelDistance = viewConeHalfAngle / _CaptureCameraFOV * _CaptureCurrentScreenSize.x; + // Convert this to a mip level shift starting from the mip 0 const float miplevel = log2(pixelDistance / 2); + // Because of the high level of aliasing that this algorithm causes, especially on the higher mips, we apply a mip bias during the sampling to try to hide it + const float mipBias = _SourceMipIndex > 3 ? lerp(2.0, 5.0, (7.0 - _SourceMipIndex) / 5.0) : 0.0; + // Read the integration color that we should take - const float3 integrationColor = SAMPLE_TEXTURE2D_LOD(_ReflectionColorMipChain, s_trilinear_clamp_sampler, sampleCoords, miplevel + _SourceMipIndex).xyz; + const float3 integrationColor = SAMPLE_TEXTURE2D_LOD(_ReflectionColorMipChain, s_trilinear_clamp_sampler, sampleCoords, clamp(miplevel + _SourceMipIndex + mipBias, 0, 6)).xyz; // Write the output ray data _FilteredPlanarReflectionBuffer[currentCoord] = float4(integrationColor, 1.0); @@ -130,9 +129,13 @@ void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 // Half resolution output texture for our mip chain build. RW_TEXTURE2D(float4, _HalfResReflectionBuffer); RW_TEXTURE2D(float, _HalfResDepthBuffer); -// Given that the camera is using an oblique projection matrix, the inversion code doesnt work properly -// If we detect that we are on the far plane, we override the value by an other one. This value has been choosen experimentally. -#define OBLIQUE_CAMERA_DEPTH_CLAMP_VALUE 0.75 + +// Use to compute the gauassian weight for our blur +float gaussianWeight(float radius, float sigma) +{ + float k = radius / sigma; + return exp(-(k * k)); +} [numthreads(PLANAR_REFLECTION_TILE_SIZE, PLANAR_REFLECTION_TILE_SIZE, 1)] void DownScaleReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID) @@ -142,7 +145,7 @@ void DownScaleReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 gro // Compute the pixel position to process int2 currentCoord = (int2)(groupId * PLANAR_REFLECTION_TILE_SIZE + groupThreadId); - // Here we have to go wider than the simple 2x2 neighborhood or there is too much aliasing + // Unfortunately, we have to go wider than the simple 2x2 neighborhood or there is too much aliasing float3 averageColor = 0.0; float sumW = 0.0; const float radius = 2; @@ -152,29 +155,17 @@ void DownScaleReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 gro for (int x = -radius; x <= radius; ++x) { const int2 tapCoord = currentCoord * 2 + uint2(x, y); - float r = sqrt(x*x + y*y); + float r = sqrt(x * x + y * y); // If the pixel is outside the current screen size, its weight becomes zero float weight = tapCoord.x > _CaptureCurrentScreenSize.x || tapCoord.x < 0 - || tapCoord.y > _CaptureCurrentScreenSize.y || tapCoord.y < 0 ? 0.0 : gaussian(r, sigma); - averageColor += LOAD_TEXTURE2D_LOD(_ReflectionColorMipChain, tapCoord, _SourceMipIndex) * weight; + || tapCoord.y > _CaptureCurrentScreenSize.y || tapCoord.y < 0 ? 0.0 : gaussianWeight(r, sigma); + averageColor += LOAD_TEXTURE2D_LOD(_ReflectionColorMipChain, tapCoord, _SourceMipIndex).xyz * weight; sumW += weight; } } // Normalize and output _HalfResReflectionBuffer[currentCoord] = float4(averageColor / sumW, 1.0); - // Read the depth values - float d0 = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2, _SourceMipIndex); - float d1 = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2 + int2(1, 1), _SourceMipIndex); - float d2 = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2 + int2(0, 1), _SourceMipIndex); - float d3 = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2 + int2(1, 0), _SourceMipIndex); - - // We we are on the far plane override the value - d0 = d0 == 0.0 ? OBLIQUE_CAMERA_DEPTH_CLAMP_VALUE : d0; - d1 = d1 == 0.0 ? OBLIQUE_CAMERA_DEPTH_CLAMP_VALUE : d1; - d2 = d2 == 0.0 ? OBLIQUE_CAMERA_DEPTH_CLAMP_VALUE : d2; - d3 = d3 == 0.0 ? OBLIQUE_CAMERA_DEPTH_CLAMP_VALUE : d3; - - // Average and output to the depth buffer - _HalfResDepthBuffer[currentCoord] = (d0 + d1 + d2 + d3) * 0.25f; + // Experimentally, picking d0 instead of the average (when possible, not always due to oblique matrix projection) doesn't introduce major artifacts + _HalfResDepthBuffer[currentCoord] = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2, _SourceMipIndex).x; } \ No newline at end of file diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs index add33d19016..9dd5451334a 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs @@ -17,7 +17,6 @@ class IBLFilterGGX : IBLFilterBSDF // Planar reflection filtering ComputeShader m_PlanarReflectionFilteringCS; - Texture2D m_GGXConeAngle; int m_PlanarReflectionFilteringKernel = -1; int m_PlanarReflectionDownScaleKernel = -1; RTHandle m_PlanarReflectionFilterTex0; @@ -77,7 +76,6 @@ public override void Initialize(CommandBuffer cmd) m_PlanarReflectionFilteringCS = m_RenderPipelineResources.shaders.planarReflectionFilteringCS; m_PlanarReflectionFilteringKernel = m_PlanarReflectionFilteringCS.FindKernel("FilterPlanarReflection"); m_PlanarReflectionDownScaleKernel = m_PlanarReflectionFilteringCS.FindKernel("DownScaleReflection"); - m_GGXConeAngle = m_RenderPipelineResources.textures.ggxConeAngle70pc; } for (int i = 0; i < 6; ++i) @@ -292,7 +290,6 @@ override public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source // Set input textures cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionFilteringKernel, HDShaderIDs._DepthTextureMipChain, m_PlanarReflectionFilterDepthTex0); cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionFilteringKernel, HDShaderIDs._ReflectionColorMipChain, m_PlanarReflectionFilterTex0); - cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionFilteringKernel, HDShaderIDs._ThetaValuesTexture, m_GGXConeAngle); // Input constant parameters required cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureBaseScreenSize, planarTextureFilteringParameters.captureCameraScreenSize); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs index 92f52f0928f..6e1fc43b2e4 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs @@ -364,8 +364,6 @@ public sealed class TextureResources [Reload("Runtime/RenderPipelineResources/Texture/DefaultHDRISky.exr")] public Cubemap defaultHDRISky; - [Reload("Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png")] - public Texture2D ggxConeAngle70pc; } [Serializable, ReloadGroup] diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png deleted file mode 100644 index 19d576549dd..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0da2da1052140ef0777aa9f787f2a66b162167b5b0a1e94c6c2661cb69873052 -size 5512 diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png.meta b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png.meta deleted file mode 100644 index 6b4bcdae5e0..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Texture/GGXConeAngle70pc.png.meta +++ /dev/null @@ -1,106 +0,0 @@ -fileFormatVersion: 2 -guid: 794081635e7e0fe46b6c3fa0afa70d87 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: -1 - mipBias: -100 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 0 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: From 2e10eee9ce7f379b086e38ede966d45c1d08bff3 Mon Sep 17 00:00:00 2001 From: Anis Date: Fri, 15 May 2020 15:15:11 +0200 Subject: [PATCH 03/15] quality improvement to the filtering. --- .../Runtime/Lighting/LightLoop/LightLoop.cs | 30 ++++++-- .../PlanarReflectionFiltering.compute | 75 +++++++++++++------ .../Material/GGXConvolution/IBLFilterGGX.cs | 67 +++++++++++------ .../Runtime/Material/IBLFilterBSDF.cs | 15 ++++ .../RenderPipeline/HDStringConstants.cs | 5 ++ 5 files changed, 139 insertions(+), 53 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs index 90a8975c589..083d1463f28 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs @@ -1773,18 +1773,23 @@ internal bool GetEnvLightData(CommandBuffer cmd, HDCamera hdCamera, in Processed if (probe.mode == ProbeSettings.Mode.Realtime && !hdCamera.frameSettings.IsEnabled(FrameSettingsField.PlanarProbe)) break; + + // Grab the render data that was used to render the probe var renderData = planarProbe.renderData; + // Grab the world to camera matrix of the capture camera var worldToCameraRHSMatrix = renderData.worldToCameraRHS; + // Grab the projection matrix that was used to render var projectionMatrix = renderData.projectionMatrix; + // Build an alternative matrix for projection that is not oblique + var projectionMatrixNonOblique = Matrix4x4.Perspective(renderData.fieldOfView, probe.texture.width / probe.texture.height, probe.settings.cameraSettings.frustum.nearClipPlaneRaw, probe.settings.cameraSettings.frustum.farClipPlane); - // We don't need to provide the capture position - // It is already encoded in the 'worldToCameraRHSMatrix' - capturePosition = Vector3.zero; - - // get the device dependent projection matrix + // Convert the projection matrices to their GPU version var gpuProj = GL.GetGPUProjectionMatrix(projectionMatrix, true); - var gpuView = worldToCameraRHSMatrix; - var vp = gpuProj * gpuView; + var gpuProjNonOblique = GL.GetGPUProjectionMatrix(projectionMatrixNonOblique, true); + + // Build the oblique and non oblique view projection matrices + var vp = gpuProj * worldToCameraRHSMatrix; + var vpNonOblique = gpuProjNonOblique * worldToCameraRHSMatrix; // We need to collect the set of parameters required for the filtering IBLFilterBSDF.PlanarTextureFilteringParameters planarTextureFilteringParameters = new IBLFilterBSDF.PlanarTextureFilteringParameters(); @@ -1793,10 +1798,20 @@ internal bool GetEnvLightData(CommandBuffer cmd, HDCamera hdCamera, in Processed planarTextureFilteringParameters.captureCameraDepthBuffer = planarProbe.realtimeDepthTexture; planarTextureFilteringParameters.captureCameraScreenSize = new Vector4(probe.texture.width, probe.texture.height, 1.0f / probe.texture.width, 1.0f / probe.texture.height); planarTextureFilteringParameters.captureCameraIVP = vp.inverse; + planarTextureFilteringParameters.captureCameraIVP_NonOblique = vpNonOblique.inverse; + planarTextureFilteringParameters.captureCameraVP_NonOblique = vpNonOblique; planarTextureFilteringParameters.captureCameraPosition = renderData.capturePosition; planarTextureFilteringParameters.captureFOV = renderData.fieldOfView; + planarTextureFilteringParameters.captureNearPlane = probe.settings.cameraSettings.frustum.nearClipPlaneRaw; + planarTextureFilteringParameters.captureFarPlane = probe.settings.cameraSettings.frustum.farClipPlane; + // Fetch the slice and do the filtering var scaleOffset = m_TextureCaches.reflectionPlanarProbeCache.FetchSlice(cmd, probe.texture, ref planarTextureFilteringParameters, out int fetchIndex); + + // We don't need to provide the capture position + // It is already encoded in the 'worldToCameraRHSMatrix' + capturePosition = Vector3.zero; + // Indices start at 1, because -0 == 0, we can know from the bit sign which cache to use envIndex = scaleOffset == Vector4.zero ? int.MinValue : -(fetchIndex + 1); @@ -1808,7 +1823,6 @@ internal bool GetEnvLightData(CommandBuffer cmd, HDCamera hdCamera, in Processed } atlasScaleOffset = scaleOffset; - m_TextureCaches.env2DAtlasScaleOffset[fetchIndex] = scaleOffset; m_TextureCaches.env2DCaptureVP[fetchIndex] = vp; diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute index 543f623051b..e25da5cb51f 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute @@ -1,5 +1,6 @@ #pragma kernel FilterPlanarReflection -#pragma kernel DownScaleReflection +#pragma kernel DownScale +#pragma kernel DepthConversion #pragma only_renderers d3d11 // #pragma enable_d3d11_debug_symbols @@ -33,10 +34,16 @@ CBUFFER_START(ShaderVariablesPlanarReflectionFiltering) float3 _CaptureCameraPositon; // The mip index of the source data int _SourceMipIndex; - // Inverse view projection of the capture camera + // Inverse view projection of the capture camera (oblique) float4x4 _CaptureCameraIVP; + // Inverse view projection of the capture camera (non oblique) + float4x4 _CaptureCameraIVP_NO; + // View projection of the capture camera (non oblique) + float4x4 _CaptureCameraVP_NO; // Given that sometimes our writing texture can be bigger than the current target, we need to apply a scale factor before using the sampling intrinsic float _RTScaleFactor; + // Far plane of the capture camera + float _CaptureCameraFarPlane; CBUFFER_END // Output buffer of our filtering code @@ -68,20 +75,17 @@ void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 // Compute the pixel position to process int2 currentCoord = (int2)(groupId * PLANAR_REFLECTION_TILE_SIZE + groupThreadId); - // Fetch the depth value for the current pixel. It would be great to use sample instead, but oblique matrices prevent us from doing it. - float centerDepthValue = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord, _SourceMipIndex).x; - // Compute the coordinates that shall be used for sampling float2 sampleCoords = (currentCoord << (int)(_SourceMipIndex)) * _CaptureBaseScreenSize.zw * _RTScaleFactor; + // Fetch the depth value for the current pixel. + float centerDepthValue = SAMPLE_TEXTURE2D_LOD(_DepthTextureMipChain, s_trilinear_clamp_sampler, sampleCoords, _SourceMipIndex).x; + // Compute the world position of the tapped pixel - PositionInputs centralPosInput = GetPositionInput(currentCoord, _CaptureCurrentScreenSize.zw, centerDepthValue, _CaptureCameraIVP, 0, 0); - + PositionInputs centralPosInput = GetPositionInput(currentCoord, _CaptureCurrentScreenSize.zw, centerDepthValue, _CaptureCameraIVP_NO, 0, 0); + // Compute the direction to the reflection pixel - float3 rayDirection = normalize(centralPosInput.positionWS - _CaptureCameraPositon); - // For obliques matrices, when the depth is equal to zero (aka far plane), the position generated ends-up behind the camera. Frankly, I am not sure - // why but by inverting it we get the "correct result" - rayDirection = centerDepthValue == 0.0 ? -rayDirection : rayDirection; + const float3 rayDirection = normalize(centralPosInput.positionWS - _CaptureCameraPositon); // Compute the position on the plane we shall be integrating from float t = -1.0; @@ -130,15 +134,8 @@ void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 RW_TEXTURE2D(float4, _HalfResReflectionBuffer); RW_TEXTURE2D(float, _HalfResDepthBuffer); -// Use to compute the gauassian weight for our blur -float gaussianWeight(float radius, float sigma) -{ - float k = radius / sigma; - return exp(-(k * k)); -} - [numthreads(PLANAR_REFLECTION_TILE_SIZE, PLANAR_REFLECTION_TILE_SIZE, 1)] -void DownScaleReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID) +void DownScale(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID) { UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z); @@ -149,7 +146,6 @@ void DownScaleReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 gro float3 averageColor = 0.0; float sumW = 0.0; const float radius = 2; - const float sigma = radius * 0.75; for (int y = -radius; y <= radius; ++y) { for (int x = -radius; x <= radius; ++x) @@ -158,7 +154,7 @@ void DownScaleReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 gro float r = sqrt(x * x + y * y); // If the pixel is outside the current screen size, its weight becomes zero float weight = tapCoord.x > _CaptureCurrentScreenSize.x || tapCoord.x < 0 - || tapCoord.y > _CaptureCurrentScreenSize.y || tapCoord.y < 0 ? 0.0 : gaussianWeight(r, sigma); + || tapCoord.y > _CaptureCurrentScreenSize.y || tapCoord.y < 0 ? 0.0 : 1.0; averageColor += LOAD_TEXTURE2D_LOD(_ReflectionColorMipChain, tapCoord, _SourceMipIndex).xyz * weight; sumW += weight; } @@ -166,6 +162,39 @@ void DownScaleReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 gro // Normalize and output _HalfResReflectionBuffer[currentCoord] = float4(averageColor / sumW, 1.0); - // Experimentally, picking d0 instead of the average (when possible, not always due to oblique matrix projection) doesn't introduce major artifacts - _HalfResDepthBuffer[currentCoord] = LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2, _SourceMipIndex).x; + // We average the 4 depths and move on + _HalfResDepthBuffer[currentCoord] = (LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2, _SourceMipIndex).x + + LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2 + uint2(0,1), _SourceMipIndex).x + + LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2 + uint2(1,0), _SourceMipIndex).x + + LOAD_TEXTURE2D_LOD(_DepthTextureMipChain, currentCoord * 2 + uint2(1,1), _SourceMipIndex).x) * 0.25; +} + +// Initial depth buffer (oblique) +TEXTURE2D(_DepthTextureOblique); +// Converted depth values (non oblique) +RW_TEXTURE2D(float, _DepthTextureNonOblique); + +[numthreads(PLANAR_REFLECTION_TILE_SIZE, PLANAR_REFLECTION_TILE_SIZE, 1)] +void DepthConversion(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID) +{ + UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z); + + // Compute the pixel position to process + int2 currentCoord = (int2)(groupId * PLANAR_REFLECTION_TILE_SIZE + groupThreadId); + + // Fetch the depth value for the current pixel. It would be great to use sample instead, but oblique matrices prevent us from doing it. + float centerDepthValue = LOAD_TEXTURE2D_LOD(_DepthTextureOblique, currentCoord, 0).x; + + // Compute the world position of the tapped pixel + PositionInputs centralPosInput = GetPositionInput(currentCoord, _CaptureCurrentScreenSize.zw, centerDepthValue, _CaptureCameraIVP, 0, 0); + + // For some reason, with oblique matrices, when the point is on the background the reconstructed position ends up behind the camera and at the worng position + float3 rayDirection = normalize(_CaptureCameraPositon - centralPosInput.positionWS); + rayDirection = centerDepthValue == 0.0 ? -rayDirection : rayDirection; + // Adjust the position + centralPosInput.positionWS = centerDepthValue == 0.0 ? _CaptureCameraPositon + rayDirection * _CaptureCameraFarPlane : centralPosInput.positionWS; + + // Re-do the projeciton, but this time without the oblique part and export it + float4 hClip = mul(_CaptureCameraVP_NO, float4(centralPosInput.positionWS, 1.0)); + _DepthTextureNonOblique[currentCoord] = saturate(hClip.z / hClip.w); } \ No newline at end of file diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs index 9dd5451334a..40e41855ea6 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs @@ -17,12 +17,14 @@ class IBLFilterGGX : IBLFilterBSDF // Planar reflection filtering ComputeShader m_PlanarReflectionFilteringCS; - int m_PlanarReflectionFilteringKernel = -1; + int m_PlanarReflectionDepthConversionKernel = -1; int m_PlanarReflectionDownScaleKernel = -1; + int m_PlanarReflectionFilteringKernel = -1; RTHandle m_PlanarReflectionFilterTex0; RTHandle m_PlanarReflectionFilterTex1; RTHandle m_PlanarReflectionFilterDepthTex0; RTHandle m_PlanarReflectionFilterDepthTex1; + const int k_DefaultPlanarResolution = 512; // Intermediate variables Vector4 currentScreenSize = new Vector4(1.0f, 1.0f, 1.0f, 1.0f); @@ -74,8 +76,9 @@ public override void Initialize(CommandBuffer cmd) if (!m_PlanarReflectionFilteringCS) { m_PlanarReflectionFilteringCS = m_RenderPipelineResources.shaders.planarReflectionFilteringCS; + m_PlanarReflectionDepthConversionKernel = m_PlanarReflectionFilteringCS.FindKernel("DepthConversion"); + m_PlanarReflectionDownScaleKernel = m_PlanarReflectionFilteringCS.FindKernel("DownScale"); m_PlanarReflectionFilteringKernel = m_PlanarReflectionFilteringCS.FindKernel("FilterPlanarReflection"); - m_PlanarReflectionDownScaleKernel = m_PlanarReflectionFilteringCS.FindKernel("DownScaleReflection"); } for (int i = 0; i < 6; ++i) @@ -83,11 +86,6 @@ public override void Initialize(CommandBuffer cmd) var lookAt = Matrix4x4.LookAt(Vector3.zero, CoreUtils.lookAtList[i], CoreUtils.upVectorList[i]); m_faceWorldToViewMatrixMatrices[i] = 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_PlanarReflectionFilterTex0 = RTHandles.Alloc(512, 512, TextureXR.slices, colorFormat: GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite: true, useDynamicScale: true, useMipMap: true, name: "PlanarReflectionTextureIntermediate0"); - m_PlanarReflectionFilterTex1 = RTHandles.Alloc(512, 512, TextureXR.slices, colorFormat: GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite: true, useDynamicScale: true, useMipMap: false, name: "PlanarReflectionTextureIntermediate1"); - m_PlanarReflectionFilterDepthTex0 = RTHandles.Alloc(512, 512, TextureXR.slices, colorFormat: GraphicsFormat.R32_SFloat, enableRandomWrite: true, useDynamicScale: true, useMipMap: true, name: "PlanarReflectionTextureIntermediateDepth0"); - m_PlanarReflectionFilterDepthTex1 = RTHandles.Alloc(512, 512, TextureXR.slices, colorFormat: GraphicsFormat.R32_SFloat, enableRandomWrite: true, useDynamicScale: true, useMipMap: false, name: "PlanarReflectionTextureIntermediateDepth1"); } void InitializeGgxIblSampleData(CommandBuffer cmd) @@ -101,9 +99,13 @@ public override void Cleanup() CoreUtils.Destroy(m_convolveMaterial); CoreUtils.Destroy(m_GgxIblSampleData); RTHandles.Release(m_PlanarReflectionFilterTex0); + m_PlanarReflectionFilterTex0 = null; RTHandles.Release(m_PlanarReflectionFilterTex1); + m_PlanarReflectionFilterTex1 = null; RTHandles.Release(m_PlanarReflectionFilterDepthTex0); + m_PlanarReflectionFilterDepthTex0 = null; RTHandles.Release(m_PlanarReflectionFilterDepthTex1); + m_PlanarReflectionFilterDepthTex1 = null; } void FilterCubemapCommon(CommandBuffer cmd, @@ -195,8 +197,10 @@ float RoughnessStep(int textureResolution) void CheckIntermediateTexturesSize(int texWidth, int texHeight) { - if (m_PlanarReflectionFilterTex0.rt.width < texWidth) + // If the first texture is not the right size + if (m_PlanarReflectionFilterTex0 == null || m_PlanarReflectionFilterTex0.rt.width < texWidth) { + // We re-allocate them all RTHandles.Release(m_PlanarReflectionFilterTex0); RTHandles.Release(m_PlanarReflectionFilterTex1); RTHandles.Release(m_PlanarReflectionFilterDepthTex0); @@ -208,17 +212,36 @@ void CheckIntermediateTexturesSize(int texWidth, int texHeight) } } - void BuildColorAndDepthMipChain(CommandBuffer cmd, RenderTexture sourceColor, RenderTexture sourceDepth) + void BuildColorAndDepthMipChain(CommandBuffer cmd, RenderTexture sourceColor, RenderTexture sourceDepth, ref PlanarTextureFilteringParameters planarTextureFilteringParameters) { - // The first level can be copied straight away in the mip chain + int currentTexWidth = sourceColor.width; + int currentTexHeight = sourceColor.height; + + // The first color level can be copied straight away in the mip chain, nothing special to be done cmd.CopyTexture(sourceColor, 0, 0, 0, 0, sourceColor.width, sourceColor.height, m_PlanarReflectionFilterTex0, 0, 0, 0, 0); - cmd.CopyTexture(sourceDepth, 0, 0, 0, 0, sourceColor.width, sourceColor.height, m_PlanarReflectionFilterDepthTex0, 0, 0, 0, 0); - // Move to the next mip and build the chain + // For depth it is a bit trickier, we want to convert the depth from oblique space to non-oblique space due to the poor interpolation properties of the oblique matrix + cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraPositon, planarTextureFilteringParameters.captureCameraPosition); + cmd.SetComputeMatrixParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraVP_NO, planarTextureFilteringParameters.captureCameraVP_NonOblique); + cmd.SetComputeMatrixParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraIVP, planarTextureFilteringParameters.captureCameraIVP); + currentScreenSize.Set(currentTexWidth, currentTexHeight, 1.0f / currentTexWidth, 1.0f / currentTexHeight); + cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCurrentScreenSize, currentScreenSize); + cmd.SetComputeFloatParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraFarPlane, planarTextureFilteringParameters.captureFarPlane); + + // Input textures + cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionDepthConversionKernel, HDShaderIDs._DepthTextureOblique, sourceDepth); + + // Output textures + cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionDepthConversionKernel, HDShaderIDs._DepthTextureNonOblique, m_PlanarReflectionFilterDepthTex0); + + // Compute the dispatch parameters and evaluate the new mip int tileSize = 8; + int numTilesXHR = (currentTexWidth + (tileSize - 1)) / tileSize; + int numTilesYHR = (currentTexHeight + (tileSize - 1)) / tileSize; + cmd.DispatchCompute(m_PlanarReflectionFilteringCS, m_PlanarReflectionDepthConversionKernel, numTilesXHR, numTilesYHR, 1); + + // Move to the next mip and build the chain int currentMipSource = 0; - int texWidth = sourceColor.width; - int texHeight = sourceColor.height; int texWidthHalf = sourceColor.width >> 1; int texHeightHalf = sourceColor.height >> 1; @@ -235,7 +258,7 @@ void BuildColorAndDepthMipChain(CommandBuffer cmd, RenderTexture sourceColor, Re // Output textures cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionDownScaleKernel, HDShaderIDs._DepthTextureMipChain, m_PlanarReflectionFilterDepthTex0); cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionDownScaleKernel, HDShaderIDs._HalfResDepthBuffer, m_PlanarReflectionFilterDepthTex1); - currentScreenSize.Set(texWidth, texHeight, 1.0f / texWidth, 1.0f / texHeight); + currentScreenSize.Set(currentTexWidth, currentTexHeight, 1.0f / currentTexWidth, 1.0f / currentTexHeight); cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCurrentScreenSize, currentScreenSize); // Compute the dispatch parameters and evaluate the new mip @@ -248,8 +271,8 @@ void BuildColorAndDepthMipChain(CommandBuffer cmd, RenderTexture sourceColor, Re cmd.CopyTexture(m_PlanarReflectionFilterDepthTex1, 0, 0, 0, 0, texWidthHalf, texHeightHalf, m_PlanarReflectionFilterDepthTex0, 0, currentMipSource + 1, 0, 0); // Update the parameters for the next mip - texWidth = texWidth >> 1; - texHeight = texHeight >> 1; + currentTexWidth = currentTexWidth >> 1; + currentTexHeight = currentTexHeight >> 1; texWidthHalf = texWidthHalf >> 1; texHeightHalf = texHeightHalf >> 1; currentMipSource++; @@ -261,17 +284,17 @@ override public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source // First we need to make sure that our intermediate textures are the big enough to do our process (these textures are squares) CheckIntermediateTexturesSize(source.width, source.height); - // First we need to build a mip chain (one for color, one for depth) that we will sample later on in the process - BuildColorAndDepthMipChain(cmd, source, planarTextureFilteringParameters.captureCameraDepthBuffer); + // Then we need to build a mip chain (one for color, one for depth) that we will sample later on in the process + BuildColorAndDepthMipChain(cmd, source, planarTextureFilteringParameters.captureCameraDepthBuffer, ref planarTextureFilteringParameters); // Init the mip descent int texWidth = source.width; int texHeight = source.height; - // First we need to copy the Mip0 (that matches perfectly smooth surface) + // First we need to copy the Mip0 (that matches perfectly smooth surface), no processing to be done on it cmd.CopyTexture(m_PlanarReflectionFilterTex0, 0, 0, 0, 0, texWidth, texHeight, target, 0, 0, 0, 0); - // Prepare the parameters for the build + // Initialize the parameters for the descent int mipIndex = 1; int tileSize = 8; float roughnessStep = RoughnessStep(texWidth); @@ -301,7 +324,7 @@ override public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._ReflectionPlaneNormal, planarTextureFilteringParameters.probeNormal); cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._ReflectionPlanePosition, planarTextureFilteringParameters.probePosition); cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraPositon, planarTextureFilteringParameters.captureCameraPosition); - cmd.SetComputeMatrixParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraIVP, planarTextureFilteringParameters.captureCameraIVP); + cmd.SetComputeMatrixParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraIVP_NO, planarTextureFilteringParameters.captureCameraIVP_NonOblique); cmd.SetComputeFloatParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraFOV, planarTextureFilteringParameters.captureFOV * Mathf.PI / 180.0f); // Set output textures diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/IBLFilterBSDF.cs b/com.unity.render-pipelines.high-definition/Runtime/Material/IBLFilterBSDF.cs index 8ec2400ff96..7198cb15810 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/IBLFilterBSDF.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/IBLFilterBSDF.cs @@ -21,13 +21,28 @@ abstract class IBLFilterBSDF internal struct PlanarTextureFilteringParameters { + // Depth buffer (oblique) that was produced public RenderTexture captureCameraDepthBuffer; + // Inverse view projection matrix (oblique) public Matrix4x4 captureCameraIVP; + // View projection matrix (non oblique) + public Matrix4x4 captureCameraVP_NonOblique; + // Inverse view projection matrix (non oblique) + public Matrix4x4 captureCameraIVP_NonOblique; + // Position of the capture camera public Vector3 captureCameraPosition; + // Resolution of the capture camera public Vector4 captureCameraScreenSize; + // Position of the probe public Vector3 probePosition; + // Normal of the reflection probe public Vector3 probeNormal; + // FOV of the capture camera public float captureFOV; + // Near clipping plane of the capture camera + public float captureNearPlane; + // Far clipping plane of the capture camera + public float captureFarPlane; }; abstract public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source, ref PlanarTextureFilteringParameters planarTextureFilteringParameters, RenderTexture target); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index e9c3e241c73..ac01fba1bff 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -264,6 +264,11 @@ static class HDShaderIDs public static readonly int _ThetaValuesTexture = Shader.PropertyToID("_ThetaValuesTexture"); public static readonly int _CaptureCameraFOV = Shader.PropertyToID("_CaptureCameraFOV"); public static readonly int _RTScaleFactor = Shader.PropertyToID("_RTScaleFactor"); + public static readonly int _CaptureCameraVP_NO = Shader.PropertyToID("_CaptureCameraVP_NO"); + public static readonly int _CaptureCameraFarPlane = Shader.PropertyToID("_CaptureCameraFarPlane"); + public static readonly int _DepthTextureOblique = Shader.PropertyToID("_DepthTextureOblique"); + public static readonly int _DepthTextureNonOblique = Shader.PropertyToID("_DepthTextureNonOblique"); + public static readonly int _CaptureCameraIVP_NO = Shader.PropertyToID("_CaptureCameraIVP_NO"); // MSAA shader properties public static readonly int _ColorTextureMS = Shader.PropertyToID("_ColorTextureMS"); From ef0dcf1b975d51c50dc97004294539d6ec573211 Mon Sep 17 00:00:00 2001 From: anisunity <42026998+anisunity@users.noreply.github.com> Date: Wed, 27 May 2020 10:55:49 +0200 Subject: [PATCH 04/15] Update PlanarReflectionFiltering.compute --- .../Runtime/Lighting/PlanarReflectionFiltering.compute | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute index e25da5cb51f..347021fa22e 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute @@ -2,7 +2,7 @@ #pragma kernel DownScale #pragma kernel DepthConversion -#pragma only_renderers d3d11 +#pragma only_renderers d3d11 playstation xboxone vulkan metal switch // #pragma enable_d3d11_debug_symbols // HDRP generic includes @@ -197,4 +197,4 @@ void DepthConversion(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupTh // Re-do the projeciton, but this time without the oblique part and export it float4 hClip = mul(_CaptureCameraVP_NO, float4(centralPosInput.positionWS, 1.0)); _DepthTextureNonOblique[currentCoord] = saturate(hClip.z / hClip.w); -} \ No newline at end of file +} From d586534746a1ff0c94b7366dd7705d2fc5e02978 Mon Sep 17 00:00:00 2001 From: Anis Date: Fri, 5 Jun 2020 11:53:56 +0200 Subject: [PATCH 05/15] review corrections --- .../ShaderLibrary/GeometricTools.hlsl | 15 ++ .../PlanarReflectionAngleGenerator.cs | 143 ------------------ .../PlanarReflectionAngleGenerator.cs.meta | 11 -- .../PlanarReflectionFiltering.compute | 35 ++--- .../Material/GGXConvolution/IBLFilterGGX.cs | 8 +- .../RenderPipeline/HDStringConstants.cs | 1 + 6 files changed, 37 insertions(+), 176 deletions(-) delete mode 100644 com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs delete mode 100644 com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs.meta diff --git a/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl index 5868d98babd..8500108f36d 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl @@ -132,6 +132,21 @@ float3 IntersectRayPlane(float3 rayOrigin, float3 rayDirection, float3 planeOrig return rayOrigin + rayDirection * dist; } + +// This function could be placed in a shared file. +bool IntersectRayPlane(float3 rayOrigin, float3 rayDirection, float3 planePosition, float3 planeNormal, out float t) +{ + t = -1.0; + float denom = dot(planeNormal, rayDirection); + if (abs(denom) > 1e-5) + { + float3 d = planePosition - rayOrigin; + t = dot(d, planeNormal) / denom; + return (t >= 0); + } + return false; +} + // Can support cones with an elliptic base: pre-scale 'coneAxisX' and 'coneAxisY' by (h/r_x) and (h/r_y). // Returns parametric distances 'tEntr' and 'tExit' along the ray, // subject to constraints 'tMin' and 'tMax'. diff --git a/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs b/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs deleted file mode 100644 index 196fca5c8b1..00000000000 --- a/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System.IO; - -namespace UnityEngine.Rendering.HighDefinition -{ - internal class PlanarReflectionAngleGenerator : MonoBehaviour - { - void Start() - { - } - - public class GenerationParameters - { - public int outputWidth; - public int outputHeight; - public int angleSubdivision; - public float brdfPercentage; - } - - float SafeDiv(float numer, float denom) - { - return (numer != denom) ? numer / denom : 1; - } - - float D_GGXNoPI(float NdotH, float roughness) - { - float a2 = roughness * roughness; - float s = (NdotH * a2 - NdotH) * NdotH + 1.0f; - // If roughness is 0, returns (NdotH == 1 ? 1 : 0). - // That is, it returns 1 for perfect mirror reflection, and 0 otherwise. - return SafeDiv(a2, s * s); - } - - public void GenerateTableExample() - { - GenerationParameters generationParameters = new GenerationParameters(); - generationParameters.outputWidth = 128; - generationParameters.outputHeight = 128; - generationParameters.angleSubdivision = 128; - generationParameters.brdfPercentage = 0.7f; - GenerateTable(generationParameters); - } - - void GetLocalFrame(Vector3 localZ, Vector3 localX, out Vector3 localY) - { - localY = Vector3.Cross(localZ, localX); - } - - public void GenerateTable(GenerationParameters generationParameters) - { - // This buffer will hold the theta values on which the brdfPercentage criterion is full-filed - float[] thetaValues = new float[generationParameters.outputWidth * generationParameters.outputHeight]; - - // To make it simple the point we are processing is placed at the center of the world and the camera will be moving around - Vector3 pointPosition = new Vector3(0.0f, 0.0f, 0.0f); - // Normal is fixed for the whole process - Vector3 normalVector = new Vector3(0, 0, 1.0f); - - // This Buffer will hold the ggx values and histogram used to evaluate the theta angle when brdf percentage is full-filled - float[] ggxValues = new float[generationParameters.outputWidth]; - float[] ggxHistogram = new float[generationParameters.outputHeight]; - - // Let's go through all the roughness inputs - for (int currentRoughnessIdx = 0; currentRoughnessIdx < generationParameters.outputHeight; ++currentRoughnessIdx) - { - // Evaluate the current roughness value - float currentRoughness = currentRoughnessIdx / (float)generationParameters.outputHeight; - - // Loop through all the angle values that we need to process - for (int currentAngleIdx = 0; currentAngleIdx < generationParameters.outputWidth; ++currentAngleIdx) - { - // Evaluate the current angle value - float currentAngle = Mathf.Acos(currentAngleIdx / (float)generationParameters.outputWidth); - // Let's compute the view direction - Vector3 viewVector = new Vector3(Mathf.Sin(currentAngle), 0, Mathf.Cos(currentAngle)); - Vector3 incidentVector = -viewVector; - - // Let's compute the reflected direction - Vector3 reflected = incidentVector - 2 * normalVector * Vector3.Dot(incidentVector, normalVector); - - // Let's compute the local to world matrix - Vector3 localX = new Vector3(1.0f, 0.0f, 0.0f); - Vector3 localY = new Vector3(); - GetLocalFrame(reflected, localX, out localY); - - // We need to build a table that include the average direction BRDF to define the theta value that implies the cone we are interested in - for (int thetaIdx = 0; thetaIdx < generationParameters.angleSubdivision; ++thetaIdx) - { - // initialize the variable for the integration - ggxValues[thetaIdx] = 0.0f; - - // Compute the current theta value - float theta = Mathf.PI * 0.5f * thetaIdx / (float)generationParameters.angleSubdivision; - - for (int phiIdx = 0; phiIdx < generationParameters.angleSubdivision; ++phiIdx) - { - // Compute the current phi value - float phi = Mathf.PI * 2.0f * phiIdx / (float)generationParameters.angleSubdivision; - - // Generate the direction in local space (reflected dir space) - Vector3 localSampleDir = new Vector3(Mathf.Sin(theta) * Mathf.Cos(phi), Mathf.Sin(theta) * Mathf.Sin(phi), Mathf.Cos(theta)); - - // Move it to world space - localSampleDir = localSampleDir.x * localX + localSampleDir.y * localY + localSampleDir.z * reflected; - - // Compute the half vector - Vector3 H = Vector3.Normalize((localSampleDir + viewVector) * 0.5f); - ggxValues[thetaIdx] += D_GGXNoPI(Vector3.Dot(H, normalVector), currentRoughness) * Vector3.Dot(localSampleDir, normalVector); - } - ggxValues[thetaIdx] /= (float)generationParameters.angleSubdivision; - ggxHistogram[thetaIdx] = thetaIdx == 0 ? ggxValues[thetaIdx] : (ggxValues[thetaIdx] + ggxHistogram[thetaIdx - 1]); - } - - // Let's look index where we get brdfPercentage - for (int thetaIdx = 0; thetaIdx < generationParameters.angleSubdivision; ++thetaIdx) - { - if ((ggxHistogram[thetaIdx] / ggxHistogram[generationParameters.angleSubdivision - 1]) >= generationParameters.brdfPercentage) - { - thetaValues[currentAngleIdx + currentRoughnessIdx * generationParameters.outputWidth] = thetaIdx / (float)generationParameters.angleSubdivision; - break; - } - } - } - } - - - Texture2D ggxThresholds = new Texture2D(generationParameters.outputWidth, generationParameters.outputHeight); - Color color = new Color(); - for (int hIdx = 0; hIdx < generationParameters.outputHeight; ++hIdx) - { - for (int wIdx = 0; wIdx < generationParameters.outputWidth; ++wIdx) - { - color.r = thetaValues[wIdx + hIdx * generationParameters.outputWidth]; - color.g = thetaValues[wIdx + hIdx * generationParameters.outputWidth]; - color.b = thetaValues[wIdx + hIdx * generationParameters.outputWidth]; - color.a = 1.0f; - ggxThresholds.SetPixel(wIdx, hIdx, color); - } - } - byte[] bytes = ggxThresholds.EncodeToPNG(); - File.WriteAllBytes(Application.dataPath + "/GGXConeAngle.png", bytes); - } - } -} diff --git a/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs.meta b/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs.meta deleted file mode 100644 index adbab15e5d0..00000000000 --- a/com.unity.render-pipelines.high-definition/Editor/RayTracing/PlanarReflectionAngleGenerator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 237275eedd6686446be8100a0c5aac9f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute index 347021fa22e..cb4318600cb 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute @@ -5,8 +5,16 @@ #pragma only_renderers d3d11 playstation xboxone vulkan metal switch // #pragma enable_d3d11_debug_symbols +// The process is done in 3 steps. We start by converting the depth from oblique to regular frustum depth. +// Then we build a mip chain of both the depth and the color. The depth is averaged in 2x2 and the color +// is filtered in a wider neighborhood (otherwise we get too much artifacts) when doing the actual filtering. +// The filtering estimates the pixel footprint of the blur based on the distance to the occluder, the roughness +// of the current mip and the distance to the pixel. we then select the input from the right mip (the idea) +// Is to avoid a 128x128 blur for the rougher values. + // HDRP generic includes #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl" @@ -44,25 +52,13 @@ CBUFFER_START(ShaderVariablesPlanarReflectionFiltering) float _RTScaleFactor; // Far plane of the capture camera float _CaptureCameraFarPlane; + // The number of valid mips in the mip chain + int _MaxMipLevels; CBUFFER_END // Output buffer of our filtering code RW_TEXTURE2D(float4, _FilteredPlanarReflectionBuffer); -// This function could be placed in a shared file. -bool IntersectPlane(float3 rayOrigin, float3 rayDirection, float3 planePosition, float3 planeNormal, out float t) -{ - t = -1.0; - float denom = dot(planeNormal, rayDirection); - if (abs(denom) > 1e-5) - { - float3 d = planePosition - rayOrigin; - t = dot(d, planeNormal) / denom; - return (t >= 0); - } - return false; -} - // These angles have been experimentally computed to match the result of reflection probes. Initially this was a table dependent on angle and roughness, but given that every planar has a // finite number of LODs and those LODS have fixed roughness and the angle changes the result, but not that much. I changed it to a per LOD LUT static const float reflectionProbeEquivalentAngles[8] = {0.0, 0.04, 0.12, 0.4, 0.9, 1.2, 1.2, 1.2}; @@ -89,7 +85,7 @@ void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 // Compute the position on the plane we shall be integrating from float t = -1.0; - if (!IntersectPlane(_CaptureCameraPositon, rayDirection, _ReflectionPlanePosition, _ReflectionPlaneNormal, t)) + if (!IntersectRayPlane(_CaptureCameraPositon, rayDirection, _ReflectionPlanePosition, _ReflectionPlaneNormal, t)) { // If there is no plane intersection, there is nothing to filter (means that is a position that cannot be reflected) _FilteredPlanarReflectionBuffer[currentCoord] = float4(0.0, 0.0, 0.0, 1.0); @@ -121,10 +117,10 @@ void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 const float miplevel = log2(pixelDistance / 2); // Because of the high level of aliasing that this algorithm causes, especially on the higher mips, we apply a mip bias during the sampling to try to hide it - const float mipBias = _SourceMipIndex > 3 ? lerp(2.0, 5.0, (7.0 - _SourceMipIndex) / 5.0) : 0.0; + const float mipBias = _SourceMipIndex > 3 ? lerp(0.0, 2.0, (_MaxMipLevels - _SourceMipIndex) / _MaxMipLevels) : 0.0; // Read the integration color that we should take - const float3 integrationColor = SAMPLE_TEXTURE2D_LOD(_ReflectionColorMipChain, s_trilinear_clamp_sampler, sampleCoords, clamp(miplevel + _SourceMipIndex + mipBias, 0, 6)).xyz; + const float3 integrationColor = SAMPLE_TEXTURE2D_LOD(_ReflectionColorMipChain, s_trilinear_clamp_sampler, sampleCoords, clamp(miplevel + _SourceMipIndex + mipBias, 0, _MaxMipLevels)).xyz; // Write the output ray data _FilteredPlanarReflectionBuffer[currentCoord] = float4(integrationColor, 1.0); @@ -151,7 +147,6 @@ void DownScale(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId for (int x = -radius; x <= radius; ++x) { const int2 tapCoord = currentCoord * 2 + uint2(x, y); - float r = sqrt(x * x + y * y); // If the pixel is outside the current screen size, its weight becomes zero float weight = tapCoord.x > _CaptureCurrentScreenSize.x || tapCoord.x < 0 || tapCoord.y > _CaptureCurrentScreenSize.y || tapCoord.y < 0 ? 0.0 : 1.0; @@ -188,13 +183,13 @@ void DepthConversion(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupTh // Compute the world position of the tapped pixel PositionInputs centralPosInput = GetPositionInput(currentCoord, _CaptureCurrentScreenSize.zw, centerDepthValue, _CaptureCameraIVP, 0, 0); - // For some reason, with oblique matrices, when the point is on the background the reconstructed position ends up behind the camera and at the worng position + // For some reason, with oblique matrices, when the point is on the background the reconstructed position ends up behind the camera and at the wrong position float3 rayDirection = normalize(_CaptureCameraPositon - centralPosInput.positionWS); rayDirection = centerDepthValue == 0.0 ? -rayDirection : rayDirection; // Adjust the position centralPosInput.positionWS = centerDepthValue == 0.0 ? _CaptureCameraPositon + rayDirection * _CaptureCameraFarPlane : centralPosInput.positionWS; - // Re-do the projeciton, but this time without the oblique part and export it + // Re-do the projection, but this time without the oblique part and export it float4 hClip = mul(_CaptureCameraVP_NO, float4(centralPosInput.positionWS, 1.0)); _DepthTextureNonOblique[currentCoord] = saturate(hClip.z / hClip.w); } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs index 40e41855ea6..fd98e14fd99 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs @@ -297,7 +297,10 @@ override public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source // Initialize the parameters for the descent int mipIndex = 1; int tileSize = 8; - float roughnessStep = RoughnessStep(texWidth); + // The number of mips that are used at the the end is fixed + const float roughnessStep = 1.0f / k_GgxIblMipCountMinusOne; + // Based on the initial texture resolution, the number of available mips for us to read from is variable and is based on the maximal texture width + int numMipsChain = (int)(Mathf.Log((float)texWidth, 2.0f) - 1.0f); float currentRoughness = roughnessStep; float rtScaleFactor = texWidth / (float)m_PlanarReflectionFilterTex0.rt.width; texWidth = texWidth >> 1; @@ -320,13 +323,14 @@ override public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCurrentScreenSize, currentScreenSize); cmd.SetComputeFloatParam(m_PlanarReflectionFilteringCS, HDShaderIDs._IntegrationRoughness, currentRoughness); cmd.SetComputeIntParam(m_PlanarReflectionFilteringCS, HDShaderIDs._SourceMipIndex, mipIndex); + cmd.SetComputeIntParam(m_PlanarReflectionFilteringCS, HDShaderIDs._MaxMipLevels, numMipsChain); cmd.SetComputeFloatParam(m_PlanarReflectionFilteringCS, HDShaderIDs._RTScaleFactor, rtScaleFactor); cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._ReflectionPlaneNormal, planarTextureFilteringParameters.probeNormal); cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._ReflectionPlanePosition, planarTextureFilteringParameters.probePosition); cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraPositon, planarTextureFilteringParameters.captureCameraPosition); cmd.SetComputeMatrixParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraIVP_NO, planarTextureFilteringParameters.captureCameraIVP_NonOblique); cmd.SetComputeFloatParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCameraFOV, planarTextureFilteringParameters.captureFOV * Mathf.PI / 180.0f); - + // Set output textures cmd.SetComputeTextureParam(m_PlanarReflectionFilteringCS, m_PlanarReflectionFilteringKernel, HDShaderIDs._FilteredPlanarReflectionBuffer, m_PlanarReflectionFilterTex1); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index 9ce6fce2ac1..5e79a78c0a8 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -266,6 +266,7 @@ static class HDShaderIDs public static readonly int _CaptureCameraIVP = Shader.PropertyToID("_CaptureCameraIVP"); public static readonly int _CaptureCameraPositon = Shader.PropertyToID("_CaptureCameraPositon"); public static readonly int _SourceMipIndex = Shader.PropertyToID("_SourceMipIndex"); + public static readonly int _MaxMipLevels = Shader.PropertyToID("_MaxMipLevels"); public static readonly int _ThetaValuesTexture = Shader.PropertyToID("_ThetaValuesTexture"); public static readonly int _CaptureCameraFOV = Shader.PropertyToID("_CaptureCameraFOV"); public static readonly int _RTScaleFactor = Shader.PropertyToID("_RTScaleFactor"); From ba941a4f7c63cdabb48f6a0b2bbe92978e4cd2e0 Mon Sep 17 00:00:00 2001 From: Sebastien Lagarde Date: Sat, 6 Jun 2020 16:25:17 +0200 Subject: [PATCH 06/15] Update planar filter for all material (was not replaced) + update screenshots --- .../Direct3D11/None/2203_PlanarProbes.png | 4 +-- .../Direct3D12/None/2203_PlanarProbes.png | 4 +-- .../ShaderLibrary/ImageBasedLighting.hlsl | 6 ----- .../Runtime/Material/AxF/AxF.hlsl | 27 ++----------------- .../Runtime/Material/Eye/Eye.hlsl | 15 +---------- .../Runtime/Material/Fabric/Fabric.hlsl | 15 +---------- .../Runtime/Material/Hair/Hair.hlsl | 15 +---------- .../Runtime/Material/Lit/SimpleLit.hlsl | 15 +---------- .../Runtime/Material/StackLit/StackLit.hlsl | 14 +--------- 9 files changed, 11 insertions(+), 104 deletions(-) diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2203_PlanarProbes.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2203_PlanarProbes.png index 165ef79ea3c..9641030f7c3 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2203_PlanarProbes.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2203_PlanarProbes.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60c1060c81f32c243029cdbec19c825ae19b8316d8973d3035b249109f29fcdc -size 256035 +oid sha256:7ed4ce60d3a30820a71a4d31f325ced889ef492c1b19ee98c0470590ca2853f0 +size 249360 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2203_PlanarProbes.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2203_PlanarProbes.png index 9381fcaa296..9641030f7c3 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2203_PlanarProbes.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2203_PlanarProbes.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e6e6ea9401358eda14f0242daabfdd89e75005034437fa20435322ecf169b20 -size 287739 +oid sha256:7ed4ce60d3a30820a71a4d31f325ced889ef492c1b19ee98c0470590ca2853f0 +size 249360 diff --git a/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl index 4f19e17fa7e..8f0eaabe5d0 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl @@ -32,12 +32,6 @@ real PerceptualRoughnessToMipmapLevel(real perceptualRoughness) return PerceptualRoughnessToMipmapLevel(perceptualRoughness, UNITY_SPECCUBE_LOD_STEPS); } -// Mapping for convolved Texture2D, this is an empirical remapping to match GGX version of cubemap convolution -real PlanarPerceptualRoughnessToMipmapLevel(real perceptualRoughness, uint mipMapcount) -{ - return PositivePow(perceptualRoughness, 0.8) * uint(max(mipMapcount - 1, 0)); -} - // The *accurate* version of the non-linear remapping. It works by // approximating the cone of the specular lobe, and then computing the MIP map level // which (approximately) covers the footprint of the lobe with a single texel. diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.hlsl index 1a42ba904eb..a2725d95010 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.hlsl @@ -2374,23 +2374,6 @@ IndirectLighting EvaluateBSDF_ScreenspaceRefraction( LightLoopContext lightLo //----------------------------------------------------------------------------- // EvaluateBSDF_Env // ---------------------------------------------------------------------------- -float GetEnvMipLevel(EnvLightData lightData, float iblPerceptualRoughness) -{ - float iblMipLevel; - - // TODO: We need to match the PerceptualRoughnessToMipmapLevel formula for planar, so we don't do this test (which is specific to our current lightloop) - // Specific case for Texture2Ds, their convolution is a gaussian one and not a GGX one - So we use another roughness mip mapping. - if (IsEnvIndexTexture2D(lightData.envIndex)) - { - // Empirical remapping - iblMipLevel = PlanarPerceptualRoughnessToMipmapLevel(iblPerceptualRoughness, _ColorPyramidLodCount); - } - else - { - iblMipLevel = PerceptualRoughnessToMipmapLevel(iblPerceptualRoughness); - } - return iblMipLevel; -} float3 GetModifiedEnvSamplingDir(EnvLightData lightData, float3 N, float3 iblR, float iblPerceptualRoughness, float clampedNdotV) { @@ -2468,11 +2451,8 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, // bottom reflection is full. Lit doesn't have this problem too much in practice since only GetModifiedEnvSamplingDir // changes the direction vs the coat.) - float IBLMipLevel; - IBLMipLevel = GetEnvMipLevel(lightData, preLightData.iblPerceptualRoughness); - // Sample the pre-integrated environment lighting - float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, envSamplingDirForBottomLayer, IBLMipLevel, lightData.rangeCompressionFactorCompensation); + float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, envSamplingDirForBottomLayer, PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness), lightData.rangeCompressionFactorCompensation); weight *= preLD.w; // Used by planar reflection to discard pixel envLighting = GetSpecularIndirectDimmer() * preLightData.specularFGD * preLD.xyz; @@ -2526,11 +2506,8 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, // Single lobe approach // We computed an average mip level stored in preLightData.iblPerceptualRoughness that we use for all CT lobes - float IBLMipLevel; - IBLMipLevel = GetEnvMipLevel(lightData, preLightData.iblPerceptualRoughness); - // Sample the actual environment lighting - float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, envSamplingDirForBottomLayer, IBLMipLevel, lightData.rangeCompressionFactorCompensation); + float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, envSamplingDirForBottomLayer, PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness), lightData.rangeCompressionFactorCompensation); float3 envLighting; envLighting = preLightData.specularCTFGDSingleLobe * GetSpecularIndirectDimmer(); diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Eye/Eye.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/Eye/Eye.hlsl index a34ad165590..d9996850b21 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/Eye/Eye.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Eye/Eye.hlsl @@ -787,20 +787,7 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, float3 F = preLightData.specularFGD; - float iblMipLevel; - // TODO: We need to match the PerceptualRoughnessToMipmapLevel formula for planar, so we don't do this test (which is specific to our current lightloop) - // Specific case for Texture2Ds, their convolution is a gaussian one and not a GGX one - So we use another roughness mip mapping. - if (IsEnvIndexTexture2D(lightData.envIndex)) - { - // Empirical remapping - iblMipLevel = PlanarPerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness, _ColorPyramidLodCount); - } - else - { - iblMipLevel = PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness); - } - - float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, iblMipLevel, lightData.rangeCompressionFactorCompensation); + float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness), lightData.rangeCompressionFactorCompensation); weight *= preLD.a; // Used by planar reflection to discard pixel envLighting = F * preLD.rgb; diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Fabric/Fabric.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/Fabric/Fabric.hlsl index 010c1a2f3db..3d3513ec381 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/Fabric/Fabric.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Fabric/Fabric.hlsl @@ -611,19 +611,6 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, // Note: using influenceShapeType and projectionShapeType instead of (lightData|proxyData).shapeType allow to make compiler optimization in case the type is know (like for sky) EvaluateLight_EnvIntersection(positionWS, bsdfData.normalWS, lightData, influenceShapeType, R, weight); - float iblMipLevel; - // TODO: We need to match the PerceptualRoughnessToMipmapLevel formula for planar, so we don't do this test (which is specific to our current lightloop) - // Specific case for Texture2Ds, their convolution is a gaussian one and not a GGX one - So we use another roughness mip mapping. - if (IsEnvIndexTexture2D(lightData.envIndex)) - { - // Empirical remapping - iblMipLevel = PositivePow(preLightData.iblPerceptualRoughness, 0.8) * uint(max(_ColorPyramidLodCount - 1, 0)); - } - else - { - iblMipLevel = PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness); - } - // If it is a silk, we need to use the GGX convolution (slice0), otherwise the charlie convolution (slice1) int sliceIndex = 0; if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_FABRIC_COTTON_WOOL)) @@ -631,7 +618,7 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, sliceIndex = _EnvSliceSize - 1; } - float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, iblMipLevel, lightData.rangeCompressionFactorCompensation, sliceIndex); + float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness), lightData.rangeCompressionFactorCompensation, sliceIndex); weight *= preLD.a; // Used by planar reflection to discard pixel envLighting = preLightData.specularFGD * preLD.rgb; diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Hair/Hair.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/Hair/Hair.hlsl index ec96e98ab8c..3f076852c55 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/Hair/Hair.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Hair/Hair.hlsl @@ -555,20 +555,7 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, // Note: using influenceShapeType and projectionShapeType instead of (lightData|proxyData).shapeType allow to make compiler optimization in case the type is know (like for sky) EvaluateLight_EnvIntersection(positionWS, bsdfData.normalWS, lightData, influenceShapeType, R, weight); - float iblMipLevel; - // TODO: We need to match the PerceptualRoughnessToMipmapLevel formula for planar, so we don't do this test (which is specific to our current lightloop) - // Specific case for Texture2Ds, their convolution is a gaussian one and not a GGX one - So we use another roughness mip mapping. - if (IsEnvIndexTexture2D(lightData.envIndex)) - { - // Empirical remapping - iblMipLevel = PositivePow(preLightData.iblPerceptualRoughness, 0.8) * uint(max(_ColorPyramidLodCount - 1, 0)); - } - else - { - iblMipLevel = PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness); - } - - float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, iblMipLevel, lightData.rangeCompressionFactorCompensation); + float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness), lightData.rangeCompressionFactorCompensation); weight *= preLD.a; // Used by planar reflection to discard pixel envLighting = preLightData.specularFGD * preLD.rgb; diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/SimpleLit.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/SimpleLit.hlsl index 93ee8bb6450..f4a46c44d29 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/SimpleLit.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/SimpleLit.hlsl @@ -417,20 +417,7 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, EvaluateLight_EnvIntersection(posInput.positionWS, bsdfData.normalWS, lightData, influenceShapeType, R, weight); - float iblMipLevel; - // TODO: We need to match the PerceptualRoughnessToMipmapLevel formula for planar, so we don't do this test (which is specific to our current lightloop) - // Specific case for Texture2Ds, their convolution is a gaussian one and not a GGX one - So we use another roughness mip mapping. - if (IsEnvIndexTexture2D(lightData.envIndex)) - { - // Empirical remapping - iblMipLevel = PlanarPerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness, _ColorPyramidLodCount); - } - else - { - iblMipLevel = PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness); - } - - float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, iblMipLevel, lightData.rangeCompressionFactorCompensation); + float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness), lightData.rangeCompressionFactorCompensation); weight *= preLD.a; // Used by planar reflection to discard pixel envLighting = F_Schlick(bsdfData.fresnel0, dot(bsdfData.normalWS, V)) * preLD.rgb; diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/StackLit/StackLit.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/StackLit/StackLit.hlsl index e588302833e..d18d3d0c107 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/StackLit/StackLit.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/StackLit/StackLit.hlsl @@ -4377,20 +4377,8 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, EvaluateLight_EnvIntersection(positionWS, normal, lightData, influenceShapeType, R[i], tempWeight[i]); - float iblMipLevel; - // TODO: We need to match the PerceptualRoughnessToMipmapLevel formula for planar, so we don't do this test (which is specific to our current lightloop) - // Specific case for Texture2Ds, their convolution is a gaussian one and not a GGX one - So we use another roughness mip mapping. - if (IsEnvIndexTexture2D(lightData.envIndex)) - { - // Empirical remapping - iblMipLevel = PlanarPerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness[i], _ColorPyramidLodCount); - } - else - { - iblMipLevel = PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness[i]); - } + float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R[i], PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness[i]), lightData.rangeCompressionFactorCompensation); - float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R[i], iblMipLevel, lightData.rangeCompressionFactorCompensation); // Used by planar reflection to discard pixel: tempWeight[i] *= preLD.a; From 36b3f92fa81e0716e53aa6e48c5c67f3e9ecc162 Mon Sep 17 00:00:00 2001 From: Sebastien Lagarde Date: Sat, 6 Jun 2020 16:44:51 +0200 Subject: [PATCH 07/15] Update IBLFilterGGX.cs --- .../Runtime/Material/GGXConvolution/IBLFilterGGX.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs index fd98e14fd99..fc345229d1b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs @@ -190,11 +190,6 @@ override public void FilterCubemap(CommandBuffer cmd, Texture source, RenderText FilterCubemapCommon(cmd, source, target, m_faceWorldToViewMatrixMatrices); } - float RoughnessStep(int textureResolution) - { - return 1.0f / (Mathf.Log((float)textureResolution, 2.0f) - 2.0f); - } - void CheckIntermediateTexturesSize(int texWidth, int texHeight) { // If the first texture is not the right size From 0fe28455e368cd5725f4e658b6419fb03a4ce33b Mon Sep 17 00:00:00 2001 From: Sebastien Lagarde Date: Sat, 6 Jun 2020 18:43:05 +0200 Subject: [PATCH 08/15] fix shader warning on vulkan --- .../ShaderLibrary/GeometricTools.hlsl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl index 8500108f36d..a84aeda1098 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl @@ -132,19 +132,21 @@ float3 IntersectRayPlane(float3 rayOrigin, float3 rayDirection, float3 planeOrig return rayOrigin + rayDirection * dist; } - -// This function could be placed in a shared file. +// Same as above but return intersection distance and true / false if the ray hit/miss bool IntersectRayPlane(float3 rayOrigin, float3 rayDirection, float3 planePosition, float3 planeNormal, out float t) { + bool res = false; t = -1.0; + float denom = dot(planeNormal, rayDirection); if (abs(denom) > 1e-5) { float3 d = planePosition - rayOrigin; t = dot(d, planeNormal) / denom; - return (t >= 0); + res = (t >= 0); } - return false; + + return res; } // Can support cones with an elliptic base: pre-scale 'coneAxisX' and 'coneAxisY' by (h/r_x) and (h/r_y). From b69db0331e8f7221c066886621608778f0ecb958 Mon Sep 17 00:00:00 2001 From: Sebastien Lagarde Date: Sun, 7 Jun 2020 02:18:50 +0200 Subject: [PATCH 09/15] update references screenshots --- .../Linear/LinuxEditor/Vulkan/None/2203_PlanarProbes.png | 4 ++-- .../Linear/OSXEditor/Metal/None/2203_PlanarProbes.png | 4 ++-- .../Linear/WindowsEditor/Vulkan/None/2203_PlanarProbes.png | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2203_PlanarProbes.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2203_PlanarProbes.png index fdb71657a76..dca88adeecd 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2203_PlanarProbes.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2203_PlanarProbes.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b9468ad4eaf403e3d7ece2949564efe9b7bc4b9151cbf75e645abb12b711eb4 -size 287818 +oid sha256:68de75d3ec406dcb07f9da2d10a8adc05315a26fd55918e3dc9d3e37ff386675 +size 249589 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2203_PlanarProbes.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2203_PlanarProbes.png index 9f3de7e29d3..9d3392e8eb7 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2203_PlanarProbes.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2203_PlanarProbes.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b6dc89292419a8e6fa1b16df9d87786737834c5f8205d7e88d028f66f1ba215 -size 249122 +oid sha256:1fa30284b8cfd475c55be0d839fc7d68f58b1222f2297050563d50d500a27988 +size 253523 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2203_PlanarProbes.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2203_PlanarProbes.png index 6548a948b05..0025800a6a8 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2203_PlanarProbes.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2203_PlanarProbes.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:977995200e0b81238a2c98040f6e2f467dc34a5aa8aa24a5ba929fc370ac3fac -size 256309 +oid sha256:2bbca94d46ece9ae108580b877128f7f192586f70f382aa60db05d8b5e1c1247 +size 249589 From 45c7ba5620ec7d0ac3c8cdb1db4815fcbb98d5bc Mon Sep 17 00:00:00 2001 From: Anis Date: Mon, 8 Jun 2020 12:33:33 +0200 Subject: [PATCH 10/15] Fixes for the plane normal and number of mips to be computed --- .../Runtime/Lighting/LightLoop/LightLoop.cs | 2 +- .../Runtime/Material/GGXConvolution/IBLFilterGGX.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs index a73c098552e..65725217fc3 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs @@ -1807,7 +1807,7 @@ internal bool GetEnvLightData(CommandBuffer cmd, HDCamera hdCamera, in Processed // We need to collect the set of parameters required for the filtering IBLFilterBSDF.PlanarTextureFilteringParameters planarTextureFilteringParameters = new IBLFilterBSDF.PlanarTextureFilteringParameters(); - planarTextureFilteringParameters.probeNormal = probe.gameObject.transform.up; + planarTextureFilteringParameters.probeNormal = Vector3.Normalize(hdCamera.camera.transform.position - renderData.capturePosition); planarTextureFilteringParameters.probePosition = probe.gameObject.transform.position; planarTextureFilteringParameters.captureCameraDepthBuffer = planarProbe.realtimeDepthTexture; planarTextureFilteringParameters.captureCameraScreenSize = new Vector4(probe.texture.width, probe.texture.height, 1.0f / probe.texture.width, 1.0f / probe.texture.height); diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs index fc345229d1b..52804a28710 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs @@ -301,8 +301,8 @@ override public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source texWidth = texWidth >> 1; texHeight = texHeight >> 1; - // Loop until we have an 8x8 texture - while (texWidth >= 8 && texHeight >= 8) + // Loop until we have the right amount of mips + while (mipIndex < (int)EnvConstants.ConvolutionMipCount) { // Evaluate the dispatch parameters int numTilesXHR = (texWidth + (tileSize - 1)) / tileSize; From 004ec940617549ce26de6f4c412a74a909de49d2 Mon Sep 17 00:00:00 2001 From: Anis Date: Mon, 8 Jun 2020 14:49:17 +0200 Subject: [PATCH 11/15] Fix shift that was to the right in the blurred version --- .../Runtime/Lighting/PlanarReflectionFiltering.compute | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute index cb4318600cb..c1ae448994a 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute @@ -141,10 +141,10 @@ void DownScale(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId // Unfortunately, we have to go wider than the simple 2x2 neighborhood or there is too much aliasing float3 averageColor = 0.0; float sumW = 0.0; - const float radius = 2; - for (int y = -radius; y <= radius; ++y) + // In order to avoid a one pixel shift to the right, we need to center our down sample. + for (int y = -1; y <= 2; ++y) { - for (int x = -radius; x <= radius; ++x) + for (int x = -1; x <= 2; ++x) { const int2 tapCoord = currentCoord * 2 + uint2(x, y); // If the pixel is outside the current screen size, its weight becomes zero From 4ba8c6930d8119272b54756956a61825f0fb1f05 Mon Sep 17 00:00:00 2001 From: Sebastien Lagarde Date: Mon, 8 Jun 2020 21:08:43 +0200 Subject: [PATCH 12/15] update references screenshots --- .../Linear/LinuxEditor/Vulkan/None/2203_PlanarProbes.png | 4 ++-- .../WindowsEditor/Direct3D11/None/2203_PlanarProbes.png | 4 ++-- .../Linear/WindowsEditor/Direct3D11/None/2501_LightLayers.png | 4 ++-- .../WindowsEditor/Direct3D12/None/2203_PlanarProbes.png | 4 ++-- .../Linear/WindowsEditor/Vulkan/None/2203_PlanarProbes.png | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2203_PlanarProbes.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2203_PlanarProbes.png index dca88adeecd..468a8bccd4f 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2203_PlanarProbes.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2203_PlanarProbes.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68de75d3ec406dcb07f9da2d10a8adc05315a26fd55918e3dc9d3e37ff386675 -size 249589 +oid sha256:fbb807957524dba90475ee0fd8dadc4482a99bb171fdc141395a4f7a6554c59f +size 250643 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2203_PlanarProbes.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2203_PlanarProbes.png index 9641030f7c3..b6fdb8c4797 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2203_PlanarProbes.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2203_PlanarProbes.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ed4ce60d3a30820a71a4d31f325ced889ef492c1b19ee98c0470590ca2853f0 -size 249360 +oid sha256:05fa4c6ce0cd88b7554d0a3b57fe4301d832b8bcb19caeb1e0bfd8eab9ab18da +size 250503 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2501_LightLayers.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2501_LightLayers.png index c4c6d4d2f1d..47463655def 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2501_LightLayers.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2501_LightLayers.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8908b4238dc180c24f4ccdb465034610ca4801a048997ce060fb9690977498a9 -size 120500 +oid sha256:45d38b91f49dfec90d7c2672cc67ccc7ea51baeb146c9122876909ac047e7aeb +size 120529 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2203_PlanarProbes.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2203_PlanarProbes.png index 9641030f7c3..b6fdb8c4797 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2203_PlanarProbes.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2203_PlanarProbes.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ed4ce60d3a30820a71a4d31f325ced889ef492c1b19ee98c0470590ca2853f0 -size 249360 +oid sha256:05fa4c6ce0cd88b7554d0a3b57fe4301d832b8bcb19caeb1e0bfd8eab9ab18da +size 250503 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2203_PlanarProbes.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2203_PlanarProbes.png index 0025800a6a8..43ef90b0a39 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2203_PlanarProbes.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2203_PlanarProbes.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2bbca94d46ece9ae108580b877128f7f192586f70f382aa60db05d8b5e1c1247 -size 249589 +oid sha256:4321afcd6d2dbdc4b35f1efb6ad1a9fd80bbac1a8c2f7d7cd1c8811703d15cb8 +size 250643 From ac2b0df8e075c592fb97539a7540998d2bd66c0b Mon Sep 17 00:00:00 2001 From: Sebastien Lagarde Date: Mon, 8 Jun 2020 22:09:37 +0200 Subject: [PATCH 13/15] fix shader warning --- .../Runtime/Lighting/PlanarReflectionFiltering.compute | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute index c1ae448994a..941088411ee 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute @@ -41,7 +41,7 @@ CBUFFER_START(ShaderVariablesPlanarReflectionFiltering) // World space position of the capture camera (non camera relative) float3 _CaptureCameraPositon; // The mip index of the source data - int _SourceMipIndex; + uint _SourceMipIndex; // Inverse view projection of the capture camera (oblique) float4x4 _CaptureCameraIVP; // Inverse view projection of the capture camera (non oblique) @@ -53,7 +53,7 @@ CBUFFER_START(ShaderVariablesPlanarReflectionFiltering) // Far plane of the capture camera float _CaptureCameraFarPlane; // The number of valid mips in the mip chain - int _MaxMipLevels; + uint _MaxMipLevels; CBUFFER_END // Output buffer of our filtering code @@ -69,7 +69,7 @@ void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z); // Compute the pixel position to process - int2 currentCoord = (int2)(groupId * PLANAR_REFLECTION_TILE_SIZE + groupThreadId); + uint2 currentCoord = (uint2)(groupId * PLANAR_REFLECTION_TILE_SIZE + groupThreadId); // Compute the coordinates that shall be used for sampling float2 sampleCoords = (currentCoord << (int)(_SourceMipIndex)) * _CaptureBaseScreenSize.zw * _RTScaleFactor; From 9b234597df21905b941269c4a3a4e7054944ef46 Mon Sep 17 00:00:00 2001 From: Sebastien Lagarde Date: Tue, 9 Jun 2020 00:01:29 +0200 Subject: [PATCH 14/15] Some cleanup --- .../Runtime/Lighting/PlanarReflectionFiltering.compute | 5 ++--- .../Runtime/Material/GGXConvolution/IBLFilterGGX.cs | 7 ------- .../Runtime/RenderPipeline/HDStringConstants.cs | 1 - 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute index 941088411ee..a66e3964ba2 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute @@ -15,6 +15,7 @@ // HDRP generic includes #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl" @@ -32,8 +33,6 @@ CBUFFER_START(ShaderVariablesPlanarReflectionFiltering) float4 _CaptureCurrentScreenSize; // Normal of the planar reflection plane float3 _ReflectionPlaneNormal; - // Roughness value of the current integration - float _IntegrationRoughness; // World space position of the planar reflection (non camera relative) float3 _ReflectionPlanePosition; // FOV of the capture camera @@ -61,7 +60,7 @@ RW_TEXTURE2D(float4, _FilteredPlanarReflectionBuffer); // These angles have been experimentally computed to match the result of reflection probes. Initially this was a table dependent on angle and roughness, but given that every planar has a // finite number of LODs and those LODS have fixed roughness and the angle changes the result, but not that much. I changed it to a per LOD LUT -static const float reflectionProbeEquivalentAngles[8] = {0.0, 0.04, 0.12, 0.4, 0.9, 1.2, 1.2, 1.2}; +static const float reflectionProbeEquivalentAngles[UNITY_SPECCUBE_LOD_STEPS + 1] = {0.0, 0.04, 0.12, 0.4, 0.9, 1.2, 1.2}; [numthreads(PLANAR_REFLECTION_TILE_SIZE, PLANAR_REFLECTION_TILE_SIZE, 1)] void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs index 52804a28710..54dbc40af2b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/GGXConvolution/IBLFilterGGX.cs @@ -292,11 +292,8 @@ override public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source // Initialize the parameters for the descent int mipIndex = 1; int tileSize = 8; - // The number of mips that are used at the the end is fixed - const float roughnessStep = 1.0f / k_GgxIblMipCountMinusOne; // Based on the initial texture resolution, the number of available mips for us to read from is variable and is based on the maximal texture width int numMipsChain = (int)(Mathf.Log((float)texWidth, 2.0f) - 1.0f); - float currentRoughness = roughnessStep; float rtScaleFactor = texWidth / (float)m_PlanarReflectionFilterTex0.rt.width; texWidth = texWidth >> 1; texHeight = texHeight >> 1; @@ -316,7 +313,6 @@ override public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureBaseScreenSize, planarTextureFilteringParameters.captureCameraScreenSize); currentScreenSize.Set(texWidth, texHeight, 1.0f / texWidth, 1.0f / texHeight); cmd.SetComputeVectorParam(m_PlanarReflectionFilteringCS, HDShaderIDs._CaptureCurrentScreenSize, currentScreenSize); - cmd.SetComputeFloatParam(m_PlanarReflectionFilteringCS, HDShaderIDs._IntegrationRoughness, currentRoughness); cmd.SetComputeIntParam(m_PlanarReflectionFilteringCS, HDShaderIDs._SourceMipIndex, mipIndex); cmd.SetComputeIntParam(m_PlanarReflectionFilteringCS, HDShaderIDs._MaxMipLevels, numMipsChain); cmd.SetComputeFloatParam(m_PlanarReflectionFilteringCS, HDShaderIDs._RTScaleFactor, rtScaleFactor); @@ -339,9 +335,6 @@ override public void FilterPlanarTexture(CommandBuffer cmd, RenderTexture source texWidth = texWidth >> 1; texHeight = texHeight >> 1; mipIndex++; - - // Increase the integration roughness - currentRoughness += roughnessStep; } } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index 65fe72ac8f5..cab5ed02e01 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -257,7 +257,6 @@ static class HDShaderIDs public static readonly int _DepthTextureMipChain = Shader.PropertyToID("_DepthTextureMipChain"); public static readonly int _ReflectionPlaneNormal = Shader.PropertyToID("_ReflectionPlaneNormal"); public static readonly int _ReflectionPlanePosition = Shader.PropertyToID("_ReflectionPlanePosition"); - public static readonly int _IntegrationRoughness = Shader.PropertyToID("_IntegrationRoughness"); public static readonly int _FilteredPlanarReflectionBuffer = Shader.PropertyToID("_FilteredPlanarReflectionBuffer"); public static readonly int _HalfResReflectionBuffer = Shader.PropertyToID("_HalfResReflectionBuffer"); public static readonly int _HalfResDepthBuffer = Shader.PropertyToID("_HalfResDepthBuffer"); From 3182935f23718ce801cbaaa9291b63109a43a696 Mon Sep 17 00:00:00 2001 From: Sebastien Lagarde Date: Tue, 9 Jun 2020 03:12:12 +0200 Subject: [PATCH 15/15] change to fast Atan --- .../Runtime/Lighting/PlanarReflectionFiltering.compute | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute index a66e3964ba2..426c8273d03 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/PlanarReflectionFiltering.compute @@ -108,7 +108,7 @@ void FilterPlanarReflection(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 const float viewConeRadius = brdfConeRadius * distanceCameraToPlane / (distancePlaneToObject + distanceCameraToPlane); // Compute the view cone's half angle. This matches the FOV angle to see exactly the half of the cone (The tangent could be precomputed in the table) - const float viewConeHalfAngle = atan(viewConeRadius / distanceCameraToPlane); + const float viewConeHalfAngle = FastATanPos(viewConeRadius / distanceCameraToPlane); // Given the camera's fov and pixel resolution convert the viewConeHalfAngle to a number of pixels const float pixelDistance = viewConeHalfAngle / _CaptureCameraFOV * _CaptureCurrentScreenSize.x;