|
|
|
|
|
|
[Serializable] |
|
|
|
public struct DensityVolumeParameters |
|
|
|
{ |
|
|
|
public Color albedo; // Single scattering albedo [0, 1]. Alpha is ignored
|
|
|
|
public float meanFreePath; // In meters [1, inf]. Should be chromatic - this is an optimization!
|
|
|
|
public float asymmetry; // Only used if (isLocal == false)
|
|
|
|
public Color albedo; // Single scattering albedo: [0, 1]. Alpha is ignored
|
|
|
|
public float meanFreePath; // In meters: [1, 1000000]. Should be chromatic - this is an optimization!
|
|
|
|
public float asymmetry; // Controls the phase function: [-1, 1]
|
|
|
|
|
|
|
|
public void Constrain() |
|
|
|
{ |
|
|
|
|
|
|
Normal, |
|
|
|
Ultra, |
|
|
|
Count |
|
|
|
} |
|
|
|
class VBuffer |
|
|
|
} // enum VolumetricLightingPreset
|
|
|
|
|
|
|
|
[Serializable] |
|
|
|
public struct ControllerParameters |
|
|
|
public float vBufferNearPlane; // Distance in meters
|
|
|
|
public float vBufferFarPlane; // Distance in meters
|
|
|
|
public float depthSliceDistributionUniformity; // Controls the exponential depth distribution: [0, 1]
|
|
|
|
} // struct ControllerParameters
|
|
|
|
|
|
|
|
public class VBuffer |
|
|
|
{ |
|
|
|
public struct Parameters |
|
|
|
{ |
|
|
|
public Vector4 resolution; |
|
|
|
public Vector2 sliceCount; |
|
|
|
public Vector4 depthEncodingParams; |
|
|
|
public Vector4 depthDecodingParams; |
|
|
|
|
|
|
|
public Parameters(int w, int h, int d, ControllerParameters controlParams) |
|
|
|
{ |
|
|
|
resolution = new Vector4(w, h, 1.0f / w, 1.0f / h); |
|
|
|
sliceCount = new Vector2(d, 1.0f / d); |
|
|
|
depthEncodingParams = Vector4.zero; // C# doesn't allow function calls before all members have been init
|
|
|
|
depthDecodingParams = Vector4.zero; // C# doesn't allow function calls before all members have been init
|
|
|
|
|
|
|
|
Update(controlParams); |
|
|
|
} |
|
|
|
|
|
|
|
public void Update(ControllerParameters controlParams) |
|
|
|
{ |
|
|
|
float n = controlParams.vBufferNearPlane; |
|
|
|
float f = controlParams.vBufferFarPlane; |
|
|
|
float c = 2 - 2 * controlParams.depthSliceDistributionUniformity; // remap [0, 1] -> [2, 0]
|
|
|
|
|
|
|
|
depthEncodingParams = ComputeLogarithmicDepthEncodingParams(n, f, c); |
|
|
|
depthDecodingParams = ComputeLogarithmicDepthDecodingParams(n, f, c); |
|
|
|
} |
|
|
|
|
|
|
|
} // struct Parameters
|
|
|
|
|
|
|
|
const int k_NumFrames = 2; // Double-buffer history and feedback
|
|
|
|
const int k_NumBuffers = 4; // See the list below
|
|
|
|
|
|
|
|
long m_ViewID = -1; // -1 is invalid; positive for Game Views, 0 otherwise
|
|
|
|
RenderTexture[] m_Textures = null; |
|
|
|
RenderTargetIdentifier[] m_Identifiers = null; |
|
|
|
long m_ViewID = -1; // (m_ViewID > 0) if valid
|
|
|
|
RenderTexture[] m_Textures = null; |
|
|
|
RenderTargetIdentifier[] m_Identifiers = null; |
|
|
|
Parameters[] m_Params = null; // For the current and the previous frame
|
|
|
|
|
|
|
|
public long GetViewID() |
|
|
|
{ |
|
|
|
return m_ViewID; |
|
|
|
} |
|
|
|
|
|
|
|
public bool IsValid() |
|
|
|
{ |
|
|
|
return m_ViewID > 0 && m_Textures != null && m_Textures[0] != null; |
|
|
|
} |
|
|
|
|
|
|
|
public Parameters GetParameters(uint frameIndex) |
|
|
|
{ |
|
|
|
return m_Params[frameIndex & 1]; |
|
|
|
} |
|
|
|
|
|
|
|
public void SetParameters(Parameters parameters, uint frameIndex) |
|
|
|
{ |
|
|
|
m_Params[frameIndex & 1] = parameters; |
|
|
|
} |
|
|
|
Debug.Assert(m_ViewID >= 0); |
|
|
|
Debug.Assert(IsValid()); |
|
|
|
Debug.Assert(m_ViewID >= 0); |
|
|
|
Debug.Assert(IsValid()); |
|
|
|
public RenderTargetIdentifier GetLightingHistoryBuffer() // From the previous frame
|
|
|
|
public RenderTargetIdentifier GetLightingHistoryBuffer(uint frameIndex) // From the previous frame
|
|
|
|
Debug.Assert(m_ViewID > 0); // Game View only
|
|
|
|
return m_Identifiers[k_IndexHistory + (Time.renderedFrameCount & 1)]; |
|
|
|
Debug.Assert(IsValid()); |
|
|
|
return m_Identifiers[k_IndexHistory + (frameIndex & 1)]; |
|
|
|
public RenderTargetIdentifier GetLightingFeedbackBuffer() // For the next frame
|
|
|
|
public RenderTargetIdentifier GetLightingFeedbackBuffer(uint frameIndex) // For the next frame
|
|
|
|
Debug.Assert(m_ViewID > 0); // Game View only
|
|
|
|
return m_Identifiers[k_IndexFeedback - (Time.renderedFrameCount & 1)]; |
|
|
|
Debug.Assert(IsValid()); |
|
|
|
return m_Identifiers[k_IndexFeedback - (frameIndex & 1)]; |
|
|
|
public void Create(long viewID, int w, int h, int d) |
|
|
|
public void Create(long viewID, int w, int h, int d, ControllerParameters controlParams) |
|
|
|
Debug.Assert(viewID >= 0); |
|
|
|
Debug.Assert(viewID > 0); |
|
|
|
// Only Game Views need history and feedback buffers.
|
|
|
|
bool isGameView = viewID > 0; |
|
|
|
int n = isGameView ? 4 : 2; |
|
|
|
|
|
|
|
m_Textures = new RenderTexture[n]; |
|
|
|
m_Identifiers = new RenderTargetIdentifier[n]; |
|
|
|
m_Textures = new RenderTexture[k_NumBuffers]; |
|
|
|
m_Identifiers = new RenderTargetIdentifier[k_NumBuffers]; |
|
|
|
m_Params = new Parameters[k_NumFrames]; |
|
|
|
for (int i = 0; i < n; i++) |
|
|
|
for (int i = 0; i < k_NumBuffers; i++) |
|
|
|
m_Textures[i] = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); |
|
|
|
m_Textures[i] = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); |
|
|
|
m_Textures[i].hideFlags = HideFlags.HideAndDontSave; |
|
|
|
m_Textures[i].filterMode = FilterMode.Trilinear; // Custom
|
|
|
|
m_Textures[i].dimension = TextureDimension.Tex3D; // TODO: request the thick 3D tiling layout
|
|
|
|
|
|
|
|
|
|
|
m_Identifiers[i] = new RenderTargetIdentifier(m_Textures[i]); |
|
|
|
} |
|
|
|
|
|
|
|
// Start with the same parameters for both frames. Then incrementally update them.
|
|
|
|
Parameters parameters = new Parameters(w, h, d, controlParams); |
|
|
|
m_Params[0] = parameters; |
|
|
|
m_Params[1] = parameters; |
|
|
|
} |
|
|
|
|
|
|
|
public void Destroy() |
|
|
|
|
|
|
for (int i = 0, n = m_Textures.Length; i < n; i++) |
|
|
|
for (int i = 0; i < k_NumBuffers; i++) |
|
|
|
{ |
|
|
|
if (m_Textures[i] != null) |
|
|
|
{ |
|
|
|
|
|
|
m_ViewID = -1; |
|
|
|
m_Textures = null; |
|
|
|
m_Identifiers = null; |
|
|
|
} |
|
|
|
public void GetResolution(ref int w, ref int h, ref int d) |
|
|
|
{ |
|
|
|
Debug.Assert(m_Textures != null); |
|
|
|
Debug.Assert(m_Textures[0] != null); |
|
|
|
Debug.Assert(m_Identifiers != null); |
|
|
|
|
|
|
|
w = m_Textures[0].width; |
|
|
|
h = m_Textures[0].height; |
|
|
|
d = m_Textures[0].volumeDepth; |
|
|
|
m_Params = null; |
|
|
|
|
|
|
|
public long GetViewID() |
|
|
|
{ |
|
|
|
return m_ViewID; |
|
|
|
} |
|
|
|
|
|
|
|
public bool IsValid() |
|
|
|
{ |
|
|
|
return m_ViewID >= 0 && m_Textures != null && m_Textures[0] != null; |
|
|
|
} |
|
|
|
|
|
|
|
ComputeShader m_VolumeVoxelizationCS = null; |
|
|
|
ComputeShader m_VolumetricLightingCS = null; |
|
|
|
static ComputeShader m_VolumeVoxelizationCS = null; |
|
|
|
static ComputeShader m_VolumetricLightingCS = null; |
|
|
|
List<VBuffer> m_VBuffers = null; |
|
|
|
List<OrientedBBox> m_VisibleVolumeBounds = null; |
|
|
|
List<DensityVolumeData> m_VisibleVolumeData = null; |
|
|
|
public const int k_MaxVisibleVolumeCount = 512; |
|
|
|
List<VBuffer> m_VBuffers = null; |
|
|
|
List<OrientedBBox> m_VisibleVolumeBounds = null; |
|
|
|
List<DensityVolumeData> m_VisibleVolumeData = null; |
|
|
|
public const int k_MaxVisibleVolumeCount = 512; |
|
|
|
static ComputeBuffer s_VisibleVolumeBoundsBuffer = null; |
|
|
|
static ComputeBuffer s_VisibleVolumeDataBuffer = null; |
|
|
|
|
|
|
|
float m_VBufferNearPlane = 0.5f; // Distance in meters; dynamic modifications not handled by reprojection
|
|
|
|
float m_VBufferFarPlane = 64.0f; // Distance in meters; dynamic modifications not handled by reprojection
|
|
|
|
const float k_LogScale = 0.5f; // Tweak constant, controls the logarithmic depth distribution
|
|
|
|
static ComputeBuffer s_VisibleVolumeBoundsBuffer = null; |
|
|
|
static ComputeBuffer s_VisibleVolumeDataBuffer = null; |
|
|
|
|
|
|
|
public void Build(HDRenderPipelineAsset asset) |
|
|
|
{ |
|
|
|
|
|
|
CoreUtils.SafeRelease(s_VisibleVolumeDataBuffer); |
|
|
|
} |
|
|
|
|
|
|
|
public void ResizeVBuffer(HDCamera camera, int screenWidth, int screenHeight) |
|
|
|
public void ResizeVBufferAndUpdateProperties(HDCamera camera, uint frameIndex) |
|
|
|
long viewID = camera.GetViewID(); |
|
|
|
var controller = camera.camera.GetComponent<VolumetricLightingController>(); |
|
|
|
Debug.Assert(viewID >= 0); |
|
|
|
if (camera.camera.cameraType == CameraType.SceneView) |
|
|
|
{ |
|
|
|
// HACK: since it's not possible to add a component to a scene camera,
|
|
|
|
// we take one from the "main" camera (if present).
|
|
|
|
Camera mainCamera = Camera.main; |
|
|
|
|
|
|
|
if (mainCamera != null) |
|
|
|
{ |
|
|
|
controller = mainCamera.GetComponent<VolumetricLightingController>(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (controller == null) return; |
|
|
|
|
|
|
|
int screenWidth = (int)camera.screenSize.x; |
|
|
|
int screenHeight = (int)camera.screenSize.y; |
|
|
|
long viewID = camera.GetViewID(); |
|
|
|
|
|
|
|
Debug.Assert(viewID > 0); |
|
|
|
|
|
|
|
int w = 0, h = 0, d = 0; |
|
|
|
ComputeVBufferResolutionAndScale(preset, screenWidth, screenHeight, ref w, ref h, ref d); |
|
|
|
|
|
|
if (vBuffer != null) |
|
|
|
{ |
|
|
|
int width = 0, height = 0, depth = 0; |
|
|
|
vBuffer.GetResolution(ref width, ref height, ref depth); |
|
|
|
VBuffer.Parameters frameParams = vBuffer.GetParameters(frameIndex); |
|
|
|
if (w == width && h == height && d == depth) |
|
|
|
if (w == frameParams.resolution.x && |
|
|
|
h == frameParams.resolution.y && |
|
|
|
d == frameParams.sliceCount.x) |
|
|
|
// Everything matches, nothing to do here.
|
|
|
|
// The resolution matches.
|
|
|
|
// Depth parameters may have changed, so update those.
|
|
|
|
frameParams.Update(controller.parameters); |
|
|
|
vBuffer.SetParameters(frameParams, frameIndex); |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
m_VBuffers.Add(vBuffer); |
|
|
|
} |
|
|
|
|
|
|
|
vBuffer.Create(viewID, w, h, d); |
|
|
|
vBuffer.Create(viewID, w, h, d, controller.parameters); |
|
|
|
Debug.Assert(viewID >= 0); |
|
|
|
Debug.Assert(viewID > 0); |
|
|
|
|
|
|
|
VBuffer vBuffer = null; |
|
|
|
|
|
|
|
|
|
|
// Since a single voxel corresponds to a tile (e.g. 8x8) of pixels,
|
|
|
|
// the VBuffer can potentially extend past the boundaries of the viewport.
|
|
|
|
// The function returns the fraction of the {width, height} of the VBuffer visible on screen.
|
|
|
|
// Note: for performance reasons, scale is unused (implicitly 1). The error is typically under 1%.
|
|
|
|
// Note: for performance reasons, the scale is unused (implicitly 1). The error is typically under 1%.
|
|
|
|
static Vector2 ComputeVBufferResolutionAndScale(VolumetricLightingPreset preset, |
|
|
|
int screenWidth, int screenHeight, |
|
|
|
ref int w, ref int h, ref int d) |
|
|
|
|
|
|
float n = nearPlane; |
|
|
|
float f = farPlane; |
|
|
|
|
|
|
|
depthParams.x = Mathf.Log(c, 2) * (1.0f / Mathf.Log(c * (f - n) + 1, 2)); |
|
|
|
c = Mathf.Max(c, 0.001f); // Avoid NaNs
|
|
|
|
|
|
|
|
depthParams.x = Mathf.Log(c, 2) * depthParams.y; |
|
|
|
depthParams.z = n - 1.0f / c; // Same
|
|
|
|
depthParams.w = 0.0f; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float n = nearPlane; |
|
|
|
float f = farPlane; |
|
|
|
|
|
|
|
c = Mathf.Max(c, 0.001f); // Avoid NaNs
|
|
|
|
depthParams.y = c * (f - n) + 1; |
|
|
|
depthParams.y = Mathf.Log(c * (f - n) + 1, 2); |
|
|
|
depthParams.z = n - 1.0f / c; // Same
|
|
|
|
depthParams.w = 0.0f; |
|
|
|
|
|
|
|
|
|
|
return (1.0f / (4.0f * Mathf.PI)) * 1.5f * (1.0f - g * g) / (2.0f + g * g); |
|
|
|
} |
|
|
|
|
|
|
|
public void PushGlobalParams(HDCamera camera, CommandBuffer cmd) |
|
|
|
public void PushGlobalParams(HDCamera camera, CommandBuffer cmd, uint frameIndex) |
|
|
|
|
|
|
|
if (visualEnvironment == null || visualEnvironment.fogType != FogType.Volumetric) return; |
|
|
|
if (visualEnvironment.fogType != FogType.Volumetric) return; |
|
|
|
// Modify the near plane.
|
|
|
|
// Warning: it can screw up the reprojection. However, we have to do it in order for clustered lighting to work correctly.
|
|
|
|
m_VBufferNearPlane = camera.camera.nearClipPlane; |
|
|
|
// VisualEnvironment sets global fog parameters: _GlobalAsymmetry, _GlobalScattering, _GlobalExtinction.
|
|
|
|
Debug.Assert(vBuffer != null); |
|
|
|
|
|
|
|
int w = 0, h = 0, d = 0; |
|
|
|
vBuffer.GetResolution(ref w, ref h, ref d); |
|
|
|
if (vBuffer == null) |
|
|
|
{ |
|
|
|
// Set the neutral black texture.
|
|
|
|
cmd.SetGlobalTexture(HDShaderIDs._VBufferLighting, CoreUtils.blackVolumeTexture); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Get the interpolated asymmetry value.
|
|
|
|
var fog = VolumeManager.instance.stack.GetComponent<VolumetricFog>(); |
|
|
|
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferResolution, new Vector4(w, h, 1.0f / w, 1.0f / h)); |
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferSliceCount, new Vector4(d, 1.0f / d)); |
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferDepthEncodingParams, ComputeLogarithmicDepthEncodingParams(m_VBufferNearPlane, m_VBufferFarPlane, k_LogScale)); |
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferDepthDecodingParams, ComputeLogarithmicDepthDecodingParams(m_VBufferNearPlane, m_VBufferFarPlane, k_LogScale)); |
|
|
|
cmd.SetGlobalTexture(HDShaderIDs._VBufferLighting, vBuffer.GetLightingIntegralBuffer()); |
|
|
|
var currFrameParams = vBuffer.GetParameters(frameIndex); |
|
|
|
var prevFrameParams = vBuffer.GetParameters(frameIndex - 1); |
|
|
|
|
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferResolution, currFrameParams.resolution); |
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferSliceCount, currFrameParams.sliceCount); |
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferDepthEncodingParams, currFrameParams.depthEncodingParams); |
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferDepthDecodingParams, currFrameParams.depthDecodingParams); |
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferPrevResolution, prevFrameParams.resolution); |
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferPrevSliceCount, prevFrameParams.sliceCount); |
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferPrevDepthEncodingParams, prevFrameParams.depthEncodingParams); |
|
|
|
cmd.SetGlobalVector( HDShaderIDs._VBufferPrevDepthDecodingParams, prevFrameParams.depthDecodingParams); |
|
|
|
cmd.SetGlobalTexture(HDShaderIDs._VBufferLighting, vBuffer.GetLightingIntegralBuffer()); |
|
|
|
} |
|
|
|
|
|
|
|
public DensityVolumeList PrepareVisibleDensityVolumeList(HDCamera camera, CommandBuffer cmd) |
|
|
|
|
|
|
if (preset == VolumetricLightingPreset.Off) return densityVolumes; |
|
|
|
|
|
|
|
if (visualEnvironment == null || visualEnvironment.fogType != FogType.Volumetric) return densityVolumes; |
|
|
|
if (visualEnvironment.fogType != FogType.Volumetric) return densityVolumes; |
|
|
|
|
|
|
|
VBuffer vBuffer = FindVBuffer(camera.GetViewID()); |
|
|
|
if (vBuffer == null) return densityVolumes; |
|
|
|
|
|
|
|
using (new ProfilingSample(cmd, "Prepare Visible Density Volume List")) |
|
|
|
{ |
|
|
|
|
|
|
m_VisibleVolumeData.Clear(); |
|
|
|
|
|
|
|
// Collect all visible finite volume data, and upload it to the GPU.
|
|
|
|
HomogeneousDensityVolume[] volumes = Object.FindObjectsOfType(typeof(HomogeneousDensityVolume)) as HomogeneousDensityVolume[]; |
|
|
|
HomogeneousDensityVolume[] volumes = DensityVolumeManager.manager.GetAllVolumes(); |
|
|
|
// Only test active finite volumes.
|
|
|
|
if (volume.enabled) |
|
|
|
{ |
|
|
|
// TODO: cache these?
|
|
|
|
var obb = OrientedBBox.Create(volume.transform); |
|
|
|
// TODO: cache these?
|
|
|
|
var obb = OrientedBBox.Create(volume.transform); |
|
|
|
// Handle camera-relative rendering.
|
|
|
|
obb.center -= camOffset; |
|
|
|
// Handle camera-relative rendering.
|
|
|
|
obb.center -= camOffset; |
|
|
|
// Frustum cull on the CPU for now. TODO: do it on the GPU.
|
|
|
|
if (GeometryUtils.Overlap(obb, camera.frustum, 6, 8)) |
|
|
|
{ |
|
|
|
// TODO: cache these?
|
|
|
|
var data = volume.parameters.GetData(); |
|
|
|
// Frustum cull on the CPU for now. TODO: do it on the GPU.
|
|
|
|
if (GeometryUtils.Overlap(obb, camera.frustum, 6, 8)) |
|
|
|
{ |
|
|
|
// TODO: cache these?
|
|
|
|
var data = volume.parameters.GetData(); |
|
|
|
m_VisibleVolumeBounds.Add(obb); |
|
|
|
m_VisibleVolumeData.Add(data); |
|
|
|
} |
|
|
|
m_VisibleVolumeBounds.Add(obb); |
|
|
|
m_VisibleVolumeData.Add(data); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
// Fill the struct with pointers in order to share the data with the light loop.
|
|
|
|
densityVolumes.bounds = m_VisibleVolumeBounds; |
|
|
|
densityVolumes.bounds = m_VisibleVolumeBounds; |
|
|
|
densityVolumes.density = m_VisibleVolumeData; |
|
|
|
|
|
|
|
return densityVolumes; |
|
|
|
|
|
|
public void VolumeVoxelizationPass(DensityVolumeList densityVolumes, HDCamera camera, CommandBuffer cmd, FrameSettings settings) |
|
|
|
public void VolumeVoxelizationPass(DensityVolumeList densityVolumes, HDCamera camera, CommandBuffer cmd, FrameSettings settings, uint frameIndex) |
|
|
|
|
|
|
|
if (visualEnvironment == null || visualEnvironment.fogType != FogType.Volumetric) return; |
|
|
|
if (visualEnvironment.fogType != FogType.Volumetric) return; |
|
|
|
|
|
|
|
VBuffer vBuffer = FindVBuffer(camera.GetViewID()); |
|
|
|
if (vBuffer == null) return; |
|
|
|
|
|
|
|
using (new ProfilingSample(cmd, "Volume Voxelization")) |
|
|
|
{ |
|
|
|
|
|
|
// Use the workaround by running the full shader with 0 density
|
|
|
|
} |
|
|
|
|
|
|
|
VBuffer vBuffer = FindVBuffer(camera.GetViewID()); |
|
|
|
Debug.Assert(vBuffer != null); |
|
|
|
|
|
|
|
int w = 0, h = 0, d = 0; |
|
|
|
vBuffer.GetResolution(ref w, ref h, ref d); |
|
|
|
|
|
|
|
float vFoV = camera.camera.fieldOfView * Mathf.Deg2Rad; |
|
|
|
Vector4 resolution = new Vector4(w, h, 1.0f / w, 1.0f / h); |
|
|
|
Matrix4x4 transform = HDUtils.ComputePixelCoordToWorldSpaceViewDirectionMatrix(vFoV, resolution, camera.viewMatrix, false); |
|
|
|
var frameParams = vBuffer.GetParameters(frameIndex); |
|
|
|
Vector4 resolution = frameParams.resolution; |
|
|
|
float vFoV = camera.camera.fieldOfView * Mathf.Deg2Rad; |
|
|
|
|
|
|
|
// Compose the matrix which allows us to compute the world space view direction.
|
|
|
|
Matrix4x4 transform = HDUtils.ComputePixelCoordToWorldSpaceViewDirectionMatrix(vFoV, resolution, camera.viewMatrix, false); |
|
|
|
|
|
|
|
cmd.SetComputeTextureParam(m_VolumeVoxelizationCS, kernel, HDShaderIDs._VBufferDensity, vBuffer.GetDensityBuffer()); |
|
|
|
cmd.SetComputeBufferParam( m_VolumeVoxelizationCS, kernel, HDShaderIDs._VolumeBounds, s_VisibleVolumeBoundsBuffer); |
|
|
|
|
|
|
cmd.SetComputeMatrixParam( m_VolumeVoxelizationCS, HDShaderIDs._VBufferCoordToViewDirWS, transform); |
|
|
|
cmd.SetComputeIntParam( m_VolumeVoxelizationCS, HDShaderIDs._NumVisibleDensityVolumes, numVisibleVolumes); |
|
|
|
|
|
|
|
int w = (int)resolution.x; |
|
|
|
int h = (int)resolution.y; |
|
|
|
|
|
|
|
// The shader defines GROUP_SIZE_1D = 8.
|
|
|
|
cmd.DispatchCompute(m_VolumeVoxelizationCS, kernel, (w + 7) / 8, (h + 7) / 8, 1); |
|
|
|
|
|
|
return coords; |
|
|
|
} |
|
|
|
|
|
|
|
public void VolumetricLightingPass(HDCamera camera, CommandBuffer cmd, FrameSettings settings) |
|
|
|
public void VolumetricLightingPass(HDCamera camera, CommandBuffer cmd, FrameSettings settings, uint frameIndex) |
|
|
|
|
|
|
|
if (visualEnvironment == null || visualEnvironment.fogType != FogType.Volumetric) return; |
|
|
|
if (visualEnvironment.fogType != FogType.Volumetric) return; |
|
|
|
|
|
|
|
VBuffer vBuffer = FindVBuffer(camera.GetViewID()); |
|
|
|
if (vBuffer == null) return; |
|
|
|
VBuffer vBuffer = FindVBuffer(camera.GetViewID()); |
|
|
|
Debug.Assert(vBuffer != null); |
|
|
|
|
|
|
|
// Only available in the Play Mode because all the frame counters in the Edit Mode are broken.
|
|
|
|
bool enableClustered = settings.lightLoopSettings.enableTileAndCluster; |
|
|
|
bool enableReprojection = Application.isPlaying && camera.camera.cameraType == CameraType.Game; |
|
|
|
|
|
|
: "VolumetricLightingBruteforce"); |
|
|
|
} |
|
|
|
|
|
|
|
int w = 0, h = 0, d = 0; |
|
|
|
vBuffer.GetResolution(ref w, ref h, ref d); |
|
|
|
|
|
|
|
var frameParams = vBuffer.GetParameters(frameIndex); |
|
|
|
Vector4 resolution = frameParams.resolution; |
|
|
|
float vFoV = camera.camera.fieldOfView * Mathf.Deg2Rad; |
|
|
|
float vFoV = camera.camera.fieldOfView * Mathf.Deg2Rad; |
|
|
|
Vector4 resolution = new Vector4(w, h, 1.0f / w, 1.0f / h); |
|
|
|
Matrix4x4 transform = HDUtils.ComputePixelCoordToWorldSpaceViewDirectionMatrix(vFoV, resolution, camera.viewMatrix, false); |
|
|
|
Matrix4x4 transform = HDUtils.ComputePixelCoordToWorldSpaceViewDirectionMatrix(vFoV, resolution, camera.viewMatrix, false); |
|
|
|
|
|
|
|
Vector2[] xySeq = GetHexagonalClosePackedSpheres7(); |
|
|
|
|
|
|
|
|
|
|
// | x | x | x | x | x | x | x |
|
|
|
|
float[] zSeq = {7.0f/14.0f, 3.0f/14.0f, 11.0f/14.0f, 5.0f/14.0f, 9.0f/14.0f, 1.0f/14.0f, 13.0f/14.0f}; |
|
|
|
|
|
|
|
int rfc = Time.renderedFrameCount; |
|
|
|
int sampleIndex = rfc % 7; |
|
|
|
int sampleIndex = (int)frameIndex % 7; |
|
|
|
Vector4 offset = new Vector4(xySeq[sampleIndex].x, xySeq[sampleIndex].y, zSeq[sampleIndex], rfc); |
|
|
|
Vector4 offset = new Vector4(xySeq[sampleIndex].x, xySeq[sampleIndex].y, zSeq[sampleIndex], frameIndex); |
|
|
|
|
|
|
|
// Get the interpolated asymmetry value.
|
|
|
|
var fog = VolumeManager.instance.stack.GetComponent<VolumetricFog>(); |
|
|
|
|
|
|
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingIntegral, vBuffer.GetLightingIntegralBuffer()); // Write
|
|
|
|
if (enableReprojection) |
|
|
|
{ |
|
|
|
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingFeedback, vBuffer.GetLightingFeedbackBuffer()); // Write
|
|
|
|
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingHistory, vBuffer.GetLightingHistoryBuffer()); // Read
|
|
|
|
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingFeedback, vBuffer.GetLightingFeedbackBuffer(frameIndex)); // Write
|
|
|
|
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingHistory, vBuffer.GetLightingHistoryBuffer(frameIndex)); // Read
|
|
|
|
|
|
|
|
int w = (int)resolution.x; |
|
|
|
int h = (int)resolution.y; |
|
|
|
|
|
|
|
// The shader defines GROUP_SIZE_1D = 8.
|
|
|
|
cmd.DispatchCompute(m_VolumetricLightingCS, kernel, (w + 7) / 8, (h + 7) / 8, 1); |
|
|
|