249 lines
15 KiB
C#
249 lines
15 KiB
C#
using UnityEngine.Experimental.Rendering;
|
|
|
|
namespace UnityEngine.Rendering.HighDefinition
|
|
{
|
|
class DebugLightVolumes
|
|
{
|
|
// Material used to blit the output texture into the camera render target
|
|
Material m_Blit;
|
|
// Material used to render the light volumes
|
|
Material m_DebugLightVolumeMaterial;
|
|
// Material to resolve the light volume textures
|
|
ComputeShader m_DebugLightVolumeCompute;
|
|
int m_DebugLightVolumeGradientKernel;
|
|
int m_DebugLightVolumeColorsKernel;
|
|
|
|
// Texture used to display the gradient
|
|
Texture2D m_ColorGradientTexture = null;
|
|
|
|
// Shader property ids
|
|
public static readonly int _ColorShaderID = Shader.PropertyToID("_Color");
|
|
public static readonly int _OffsetShaderID = Shader.PropertyToID("_Offset");
|
|
public static readonly int _RangeShaderID = Shader.PropertyToID("_Range");
|
|
public static readonly int _DebugLightCountBufferShaderID = Shader.PropertyToID("_DebugLightCountBuffer");
|
|
public static readonly int _DebugColorAccumulationBufferShaderID = Shader.PropertyToID("_DebugColorAccumulationBuffer");
|
|
public static readonly int _DebugLightVolumesTextureShaderID = Shader.PropertyToID("_DebugLightVolumesTexture");
|
|
public static readonly int _ColorGradientTextureShaderID = Shader.PropertyToID("_ColorGradientTexture");
|
|
public static readonly int _MaxDebugLightCountShaderID = Shader.PropertyToID("_MaxDebugLightCount");
|
|
public static readonly int _BorderRadiusShaderID = Shader.PropertyToID("_BorderRadius");
|
|
|
|
MaterialPropertyBlock m_MaterialProperty = new MaterialPropertyBlock();
|
|
|
|
public DebugLightVolumes()
|
|
{
|
|
}
|
|
|
|
public void InitData(RenderPipelineResources renderPipelineResources)
|
|
{
|
|
m_DebugLightVolumeMaterial = CoreUtils.CreateEngineMaterial(renderPipelineResources.shaders.debugLightVolumePS);
|
|
m_DebugLightVolumeCompute = renderPipelineResources.shaders.debugLightVolumeCS;
|
|
m_DebugLightVolumeGradientKernel = m_DebugLightVolumeCompute.FindKernel("LightVolumeGradient");
|
|
m_DebugLightVolumeColorsKernel = m_DebugLightVolumeCompute.FindKernel("LightVolumeColors");
|
|
m_ColorGradientTexture = renderPipelineResources.textures.colorGradient;
|
|
|
|
m_Blit = CoreUtils.CreateEngineMaterial(renderPipelineResources.shaders.blitPS);
|
|
}
|
|
|
|
public void ReleaseData()
|
|
{
|
|
CoreUtils.Destroy(m_Blit);
|
|
CoreUtils.Destroy(m_DebugLightVolumeMaterial);
|
|
}
|
|
|
|
public struct RenderLightVolumesParameters
|
|
{
|
|
public HDCamera hdCamera;
|
|
public CullingResults cullResults;
|
|
public Material debugLightVolumeMaterial;
|
|
public ComputeShader debugLightVolumeCS;
|
|
public int debugLightVolumeKernel;
|
|
public int maxDebugLightCount;
|
|
public float borderRadius;
|
|
public Texture2D colorGradientTexture;
|
|
public bool lightOverlapEnabled;
|
|
}
|
|
|
|
public RenderLightVolumesParameters PrepareLightVolumeParameters(HDCamera hdCamera, LightingDebugSettings lightDebugSettings, CullingResults cullResults)
|
|
{
|
|
var parameters = new RenderLightVolumesParameters();
|
|
bool lightOverlapEnabled = CoreUtils.IsLightOverlapDebugEnabled(hdCamera.camera);
|
|
bool useColorAndEdge = lightDebugSettings.lightVolumeDebugByCategory == LightVolumeDebug.ColorAndEdge || lightOverlapEnabled;
|
|
|
|
parameters.hdCamera = hdCamera;
|
|
parameters.cullResults = cullResults;
|
|
parameters.debugLightVolumeMaterial = m_DebugLightVolumeMaterial;
|
|
parameters.debugLightVolumeCS = m_DebugLightVolumeCompute;
|
|
parameters.debugLightVolumeKernel = useColorAndEdge ? m_DebugLightVolumeColorsKernel : m_DebugLightVolumeGradientKernel;
|
|
parameters.maxDebugLightCount = (int)lightDebugSettings.maxDebugLightCount;
|
|
parameters.borderRadius = lightOverlapEnabled ? 0.5f : 1f;
|
|
parameters.colorGradientTexture = m_ColorGradientTexture;
|
|
parameters.lightOverlapEnabled = lightOverlapEnabled;
|
|
|
|
return parameters;
|
|
}
|
|
|
|
public static void RenderLightVolumes(CommandBuffer cmd,
|
|
in RenderLightVolumesParameters parameters,
|
|
RenderTargetIdentifier[] accumulationMRT, // [0] = m_LightCountBuffer, [1] m_ColorAccumulationBuffer
|
|
RTHandle lightCountBuffer,
|
|
RTHandle colorAccumulationBuffer,
|
|
RTHandle debugLightVolumesTexture,
|
|
RTHandle depthBuffer,
|
|
RTHandle destination,
|
|
MaterialPropertyBlock mpb)
|
|
{
|
|
if (parameters.lightOverlapEnabled)
|
|
{
|
|
// We only need the accumulation buffer, not the color (we only disply the outline of the light shape in this mode).
|
|
CoreUtils.SetRenderTarget(cmd, accumulationMRT[0], depthBuffer);
|
|
|
|
// The cullresult doesn't contains overlapping lights so we use a custom list
|
|
foreach (var overlappingHDLight in HDAdditionalLightData.s_overlappingHDLights)
|
|
{
|
|
RenderLightVolume(cmd, parameters, overlappingHDLight, overlappingHDLight.legacyLight, mpb);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Set the render target array
|
|
CoreUtils.SetRenderTarget(cmd, accumulationMRT, depthBuffer);
|
|
|
|
// First of all let's do the regions for the light sources (we only support Punctual and Area)
|
|
int numLights = parameters.cullResults.visibleLights.Length;
|
|
for (int lightIdx = 0; lightIdx < numLights; ++lightIdx)
|
|
{
|
|
// Let's build the light's bounding sphere matrix
|
|
Light currentLegacyLight = parameters.cullResults.visibleLights[lightIdx].light;
|
|
if (currentLegacyLight == null) continue;
|
|
HDAdditionalLightData currentHDRLight = currentLegacyLight.GetComponent<HDAdditionalLightData>();
|
|
if (currentHDRLight == null) continue;
|
|
|
|
RenderLightVolume(cmd, parameters, currentHDRLight, currentLegacyLight, mpb);
|
|
}
|
|
|
|
// When we enable the light overlap mode we hide probes as they can't be baked in shadow masks
|
|
if (!parameters.lightOverlapEnabled)
|
|
{
|
|
// Now let's do the same but for reflection probes
|
|
int numProbes = parameters.cullResults.visibleReflectionProbes.Length;
|
|
for (int probeIdx = 0; probeIdx < numProbes; ++probeIdx)
|
|
{
|
|
// Let's build the light's bounding sphere matrix
|
|
ReflectionProbe currentLegacyProbe = parameters.cullResults.visibleReflectionProbes[probeIdx].reflectionProbe;
|
|
HDAdditionalReflectionData currentHDProbe = currentLegacyProbe.GetComponent<HDAdditionalReflectionData>();
|
|
|
|
if (!currentHDProbe)
|
|
continue;
|
|
|
|
MaterialPropertyBlock m_MaterialProperty = new MaterialPropertyBlock();
|
|
Mesh targetMesh = null;
|
|
if (currentHDProbe.influenceVolume.shape == InfluenceShape.Sphere)
|
|
{
|
|
m_MaterialProperty.SetVector(_RangeShaderID, new Vector3(currentHDProbe.influenceVolume.sphereRadius, currentHDProbe.influenceVolume.sphereRadius, currentHDProbe.influenceVolume.sphereRadius));
|
|
targetMesh = DebugShapes.instance.RequestSphereMesh();
|
|
}
|
|
else
|
|
{
|
|
m_MaterialProperty.SetVector(_RangeShaderID, new Vector3(currentHDProbe.influenceVolume.boxSize.x, currentHDProbe.influenceVolume.boxSize.y, currentHDProbe.influenceVolume.boxSize.z));
|
|
targetMesh = DebugShapes.instance.RequestBoxMesh();
|
|
}
|
|
|
|
m_MaterialProperty.SetColor(_ColorShaderID, new Color(1.0f, 1.0f, 0.0f, 1.0f));
|
|
m_MaterialProperty.SetVector(_OffsetShaderID, new Vector3(0, 0, 0));
|
|
Matrix4x4 positionMat = Matrix4x4.Translate(currentLegacyProbe.transform.position);
|
|
cmd.DrawMesh(targetMesh, positionMat, parameters.debugLightVolumeMaterial, 0, 0, m_MaterialProperty);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the input params for the compute
|
|
cmd.SetComputeTextureParam(parameters.debugLightVolumeCS, parameters.debugLightVolumeKernel, _DebugLightCountBufferShaderID, lightCountBuffer);
|
|
cmd.SetComputeTextureParam(parameters.debugLightVolumeCS, parameters.debugLightVolumeKernel, _DebugColorAccumulationBufferShaderID, colorAccumulationBuffer);
|
|
cmd.SetComputeTextureParam(parameters.debugLightVolumeCS, parameters.debugLightVolumeKernel, _DebugLightVolumesTextureShaderID, debugLightVolumesTexture);
|
|
cmd.SetComputeTextureParam(parameters.debugLightVolumeCS, parameters.debugLightVolumeKernel, _ColorGradientTextureShaderID, parameters.colorGradientTexture);
|
|
cmd.SetComputeIntParam(parameters.debugLightVolumeCS, _MaxDebugLightCountShaderID, parameters.maxDebugLightCount);
|
|
cmd.SetComputeFloatParam(parameters.debugLightVolumeCS, _BorderRadiusShaderID, parameters.borderRadius);
|
|
|
|
// Texture dimensions
|
|
int texWidth = parameters.hdCamera.actualWidth; // m_ColorAccumulationBuffer.rt.width;
|
|
int texHeight = parameters.hdCamera.actualHeight; // m_ColorAccumulationBuffer.rt.width;
|
|
|
|
|
|
// Dispatch the compute
|
|
int lightVolumesTileSize = 8;
|
|
int numTilesX = (texWidth + (lightVolumesTileSize - 1)) / lightVolumesTileSize;
|
|
int numTilesY = (texHeight + (lightVolumesTileSize - 1)) / lightVolumesTileSize;
|
|
cmd.DispatchCompute(parameters.debugLightVolumeCS, parameters.debugLightVolumeKernel, numTilesX, numTilesY, parameters.hdCamera.viewCount);
|
|
|
|
// Blit this into the camera target
|
|
CoreUtils.SetRenderTarget(cmd, destination);
|
|
mpb.SetTexture(HDShaderIDs._BlitTexture, debugLightVolumesTexture);
|
|
cmd.DrawProcedural(Matrix4x4.identity, parameters.debugLightVolumeMaterial, 1, MeshTopology.Triangles, 3, 1, mpb);
|
|
}
|
|
|
|
static void RenderLightVolume(
|
|
CommandBuffer cmd,
|
|
in RenderLightVolumesParameters parameters,
|
|
HDAdditionalLightData currentHDRLight,
|
|
Light currentLegacyLight,
|
|
MaterialPropertyBlock mpb)
|
|
{
|
|
Matrix4x4 positionMat = Matrix4x4.Translate(currentLegacyLight.transform.position);
|
|
|
|
switch (currentHDRLight.ComputeLightType(currentLegacyLight))
|
|
{
|
|
case HDLightType.Point:
|
|
mpb.SetColor(_ColorShaderID, new Color(0.0f, 0.5f, 0.0f, 1.0f));
|
|
mpb.SetVector(_OffsetShaderID, new Vector3(0, 0, 0));
|
|
mpb.SetVector(_RangeShaderID, new Vector3(currentLegacyLight.range, currentLegacyLight.range, currentLegacyLight.range));
|
|
cmd.DrawMesh(DebugShapes.instance.RequestSphereMesh(), positionMat, parameters.debugLightVolumeMaterial, 0, 0, mpb);
|
|
break;
|
|
case HDLightType.Spot:
|
|
switch (currentHDRLight.spotLightShape)
|
|
{
|
|
case SpotLightShape.Cone:
|
|
float bottomRadius = Mathf.Tan(currentLegacyLight.spotAngle * Mathf.PI / 360.0f) * currentLegacyLight.range;
|
|
mpb.SetColor(_ColorShaderID, new Color(1.0f, 0.5f, 0.0f, 1.0f));
|
|
mpb.SetVector(_RangeShaderID, new Vector3(bottomRadius, bottomRadius, currentLegacyLight.range));
|
|
mpb.SetVector(_OffsetShaderID, new Vector3(0, 0, 0));
|
|
cmd.DrawMesh(DebugShapes.instance.RequestConeMesh(), currentLegacyLight.gameObject.transform.localToWorldMatrix, parameters.debugLightVolumeMaterial, 0, 0, mpb);
|
|
break;
|
|
case SpotLightShape.Box:
|
|
mpb.SetColor(_ColorShaderID, new Color(1.0f, 0.5f, 0.0f, 1.0f));
|
|
mpb.SetVector(_RangeShaderID, new Vector3(currentHDRLight.shapeWidth, currentHDRLight.shapeHeight, currentLegacyLight.range));
|
|
mpb.SetVector(_OffsetShaderID, new Vector3(0, 0, currentLegacyLight.range / 2.0f));
|
|
cmd.DrawMesh(DebugShapes.instance.RequestBoxMesh(), currentLegacyLight.gameObject.transform.localToWorldMatrix, parameters.debugLightVolumeMaterial, 0, 0, mpb);
|
|
break;
|
|
case SpotLightShape.Pyramid:
|
|
float bottomWidth = Mathf.Tan(currentLegacyLight.spotAngle * Mathf.PI / 360.0f) * currentLegacyLight.range;
|
|
mpb.SetColor(_ColorShaderID, new Color(1.0f, 0.5f, 0.0f, 1.0f));
|
|
mpb.SetVector(_RangeShaderID, new Vector3(currentHDRLight.aspectRatio * bottomWidth * 2, bottomWidth * 2, currentLegacyLight.range));
|
|
mpb.SetVector(_OffsetShaderID, new Vector3(0, 0, 0));
|
|
cmd.DrawMesh(DebugShapes.instance.RequestPyramidMesh(), currentLegacyLight.gameObject.transform.localToWorldMatrix, parameters.debugLightVolumeMaterial, 0, 0, mpb);
|
|
break;
|
|
}
|
|
break;
|
|
case HDLightType.Area:
|
|
switch (currentHDRLight.areaLightShape)
|
|
{
|
|
case AreaLightShape.Rectangle:
|
|
mpb.SetColor(_ColorShaderID, new Color(0.0f, 1.0f, 1.0f, 1.0f));
|
|
mpb.SetVector(_OffsetShaderID, new Vector3(0, 0, 0));
|
|
mpb.SetVector(_RangeShaderID, new Vector3(currentLegacyLight.range, currentLegacyLight.range, currentLegacyLight.range));
|
|
cmd.DrawMesh(DebugShapes.instance.RequestSphereMesh(), positionMat, parameters.debugLightVolumeMaterial, 0, 0, mpb);
|
|
break;
|
|
case AreaLightShape.Tube:
|
|
mpb.SetColor(_ColorShaderID, new Color(1.0f, 0.0f, 0.5f, 1.0f));
|
|
mpb.SetVector(_OffsetShaderID, new Vector3(0, 0, 0));
|
|
mpb.SetVector(_RangeShaderID, new Vector3(currentLegacyLight.range, currentLegacyLight.range, currentLegacyLight.range));
|
|
cmd.DrawMesh(DebugShapes.instance.RequestSphereMesh(), positionMat, parameters.debugLightVolumeMaterial, 0, 0, mpb);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|