Skip to content

Commit 3498973

Browse files
committed
Mask Volume:
Mask Volume Feature Parity: Mask Volumes use Global Unique ID system … (#32) * Mask Volume Feature Parity: Mask Volumes use Global Unique ID system just like Probe Volumes, follow the same eviction scheme as probe volumes, have the same debug rendering options as probe volumes (where relevant) and have dead code paths cleaned out. Global Distance Fade Start / End exposed on the Volume System Probe Volume Controller and new Mask Volume Controller to limit atlas subscription when zoomed way out in large scenes. Volumes are now evicted from the atlas when they are culled in the prepare probe volume / mask volume lists stage. * Add atlas allocation stats for Mask Volumes Co-authored-by: pastasfuture <[email protected]> Mask Volumes: Cleanup the state when HDRP has Mask Volumes disabled in the HDRenderPipelineAsset or FrameSettings. Previously we would hit some null reference errors because the disabled paths were not well tested. These fixes should improve the process of setting up Probe Volumes / Mask Volumes in a new project
1 parent 0718f13 commit 3498973

29 files changed

+725
-1375
lines changed

com.unity.render-pipelines.high-definition/Editor/Material/MaskVolume/MaskVolumeEditor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ protected void OnSceneGUI()
117117
{
118118
MaskVolume maskVolume = target as MaskVolume;
119119

120-
/* if (Event.current.type == EventType.Layout)
121-
maskVolume.DrawSelectedMasks(); */
120+
if (Event.current.type == EventType.Layout)
121+
maskVolume.DrawSelectedMasks();
122122

123123
if (!blendBoxes.TryGetValue(maskVolume, out HierarchicalBox blendBox)) { return; }
124124
if (!shapeBoxes.TryGetValue(maskVolume, out HierarchicalBox shapeBox)) { return; }
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
Shader "Hidden/Debug/MaskVolumeSamplePreview"
2+
{
3+
Properties
4+
{
5+
_Exposure("_Exposure", Range(-10.0,10.0)) = 0.0
6+
_MaskVolumeResolution("_MaskVolumeResolution", Vector) = (0, 0, 0, 0)
7+
_MaskVolumeProbeDisplayRadiusWS("_MaskVolumeProbeDisplayRadiusWS", Float) = 1.0
8+
_MaskVolumeAtlasBiasTexels("_MaskVolumeAtlasBiasTexels", Vector) = (0, 0, 0, 0)
9+
_MaskVolumeIsResidentInAtlas("_MaskVolumeIsResidentInAtlas", Float) = 0.0
10+
_MaskVolumeDrawWeightThresholdSquared("_MaskVolumeDrawWeightThresholdSquared", Float) = 0.0
11+
}
12+
13+
SubShader
14+
{
15+
Tags{ "RenderPipeline" = "HDRenderPipeline" "RenderType" = "Opaque" "Queue" = "Transparent" }
16+
ZWrite On
17+
Cull Front
18+
19+
Pass
20+
{
21+
Name "ForwardUnlit"
22+
Tags{ "LightMode" = "Forward" }
23+
24+
HLSLPROGRAM
25+
26+
#pragma editor_sync_compilation
27+
28+
#pragma vertex vert
29+
#pragma fragment frag
30+
31+
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
32+
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
33+
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
34+
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
35+
36+
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaskVolume/MaskVolumeShaderVariables.hlsl"
37+
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaskVolume/MaskVolumeAtlas.hlsl"
38+
39+
struct appdata
40+
{
41+
uint vertexID : SV_VertexID;
42+
};
43+
44+
struct v2f
45+
{
46+
float4 positionCS : SV_POSITION;
47+
float2 uv : TEXCOORD0;
48+
float3 probeIndex3D : TEXCOORD1;
49+
};
50+
51+
float _Exposure;
52+
53+
float3 _MaskVolumeResolution;
54+
float4x4 _ProbeIndex3DToPositionWSMatrix;
55+
float _MaskVolumeProbeDisplayRadiusWS;
56+
float3 _MaskVolumeAtlasBiasTexels;
57+
int _MaskVolumeIsResidentInAtlas;
58+
float _MaskVolumeDrawWeightThresholdSquared;
59+
60+
uint3 ComputeWriteIndexFromReadIndex(uint readIndex, float3 resolution)
61+
{
62+
// _MaskVolumeAtlasReadBuffer[z * resolutionY * resolutionX + y * resolutionX + x]
63+
// TODO: Could implement as floating point operations, which is likely faster.
64+
// Would need to verify precision.
65+
uint x = readIndex % (uint)resolution.x;
66+
uint y = (readIndex / (uint)resolution.x) % (uint)resolution.y;
67+
uint z = readIndex / ((uint)resolution.y * (uint)resolution.x);
68+
69+
return uint3(x, y, z);
70+
}
71+
72+
v2f vert(appdata v)
73+
{
74+
v2f o;
75+
76+
uint probeIndex1D = v.vertexID / 6u;
77+
uint probeTriangleIndex = (v.vertexID / 3u) & 1u;
78+
uint probeVertexIndex = v.vertexID - probeIndex1D * 6u - probeTriangleIndex * 3u;
79+
80+
float2 vertexPositionOS = (probeTriangleIndex == 1u)
81+
? float2((probeVertexIndex & 1u), saturate(probeVertexIndex))
82+
: float2(saturate(probeVertexIndex), saturate((float)probeVertexIndex - 1.0));
83+
o.uv = vertexPositionOS;
84+
vertexPositionOS = vertexPositionOS * 2.0 - 1.0;
85+
vertexPositionOS *= _MaskVolumeProbeDisplayRadiusWS;
86+
87+
o.probeIndex3D = ComputeWriteIndexFromReadIndex(probeIndex1D, _MaskVolumeResolution);
88+
float3 probeOriginWS = mul(_ProbeIndex3DToPositionWSMatrix, float4(o.probeIndex3D, 1.0)).xyz;
89+
float3 probeOriginRWS = GetCameraRelativePositionWS(probeOriginWS);
90+
91+
float3 cameraRightWS = mul(float4(1.0, 0.0, 0.0, 0.0), UNITY_MATRIX_V).xyz;
92+
float3 cameraUpWS = mul(float4(0.0, 1.0, 0.0, 0.0), UNITY_MATRIX_V).xyz;
93+
94+
float3 positionRWS = (cameraRightWS * vertexPositionOS.x + cameraUpWS * vertexPositionOS.y) + probeOriginRWS;
95+
o.positionCS = TransformWorldToHClip(positionRWS);
96+
97+
return o;
98+
}
99+
100+
void ClipProbeSphere(float2 uv)
101+
{
102+
float2 positionProbeCard = uv * 2.0 - 1.0;
103+
clip(dot(positionProbeCard, positionProbeCard) < 1.0 ? 1.0 : -1.0);
104+
}
105+
106+
float3 ComputeProbeNormalWSFromCameraFacingOrtho(float2 uv)
107+
{
108+
// Reconstruct a surface normal vector for our virtual probe sphere using the knowledge that
109+
// our card is camera aligned, and we can project from the 2D disc coordinate to 3D sphere surface coordinate.
110+
// This will not take into account perspective - but as a method to preview probe SH data, this limitation fine visually.
111+
float2 normalOSXY = uv * 2.0 - 1.0;
112+
float normalOSZ = (1.0 - dot(normalOSXY, normalOSXY));
113+
114+
float3 normalWS = mul(float4(normalOSXY, normalOSZ, 0.0), UNITY_MATRIX_V).xyz;
115+
return normalWS;
116+
}
117+
118+
float3 SampleProbeMaskData(int3 probeIndexAtlas3D, float3 normalWS)
119+
{
120+
float3 mask = 0.0;
121+
122+
MaskVolumeData coefficients;
123+
ZERO_INITIALIZE(MaskVolumeData, coefficients);
124+
MaskVolumeLoadAccumulate(probeIndexAtlas3D, 1.0f, coefficients);
125+
mask = coefficients.data[0].rgb;
126+
127+
return mask;
128+
}
129+
130+
float3 SampleMaskData(int3 probeIndexAtlas3D, float3 normalWS)
131+
{
132+
float3 mask = SampleProbeMaskData(probeIndexAtlas3D, normalWS);
133+
mask = max(0.0, mask);
134+
return mask;
135+
}
136+
137+
void ClipDrawWeightThreshold(float3 mask)
138+
{
139+
clip((dot(mask, mask) >= (_MaskVolumeDrawWeightThresholdSquared)) ? 1.0 : -1.0);
140+
}
141+
142+
float4 frag(v2f i) : SV_Target
143+
{
144+
ClipProbeSphere(i.uv);
145+
float3 normalWS = ComputeProbeNormalWSFromCameraFacingOrtho(i.uv);
146+
147+
float3 mask = 0.0;
148+
149+
if (_MaskVolumeIsResidentInAtlas)
150+
{
151+
// Due to probeIndex3D getting stored as a float and interpolated, we need to round before converting to int.
152+
// Otherwise our texel coordinate will oscillate between probes randomly (based on precision).
153+
int3 probeIndexAtlas3D = (int3)(i.probeIndex3D + 0.5 + _MaskVolumeAtlasBiasTexels);
154+
155+
mask = SampleMaskData(probeIndexAtlas3D, normalWS);
156+
}
157+
158+
ClipDrawWeightThreshold(mask);
159+
160+
mask *= exp2(_Exposure) * GetCurrentExposureMultiplier();
161+
162+
return float4(mask, 1.0);
163+
}
164+
ENDHLSL
165+
}
166+
}
167+
}

com.unity.render-pipelines.high-definition/Editor/Material/MaskVolume/MaskVolumeSamplePreview.shader.meta

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

com.unity.render-pipelines.high-definition/Editor/Material/MaskVolume/MaskVolumeUI.Drawer.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ static void ChannelField(ref bool enabled, ref float value, string label, bool i
143143
static void Drawer_PrimarySettings(SerializedMaskVolume serialized, Editor owner)
144144
{
145145
EditorGUILayout.PropertyField(serialized.drawGizmos, Styles.s_DrawGizmosLabel);
146+
if (serialized.drawGizmos.boolValue)
147+
{
148+
EditorGUILayout.Slider(serialized.drawWeightThreshold, 0.0f, 1.0f, Styles.s_DrawWeightThreshold);
149+
}
150+
146151
EditorGUILayout.PropertyField(serialized.maskSpacingMode, Styles.s_MaskSpacingModeLabel);
147152
switch ((MaskSpacingMode)serialized.maskSpacingMode.enumValueIndex)
148153
{
@@ -331,7 +336,6 @@ static void Drawer_VolumeContent(SerializedMaskVolume serialized, Editor owner)
331336
}
332337

333338
EditorGUILayout.PropertyField(serialized.lightLayers);
334-
EditorGUILayout.PropertyField(serialized.blendMode, Styles.s_VolumeBlendModeLabel);
335339
EditorGUILayout.Slider(serialized.weight, 0.0f, 1.0f, Styles.s_WeightLabel);
336340
{
337341
EditorGUI.BeginChangeCheck();

com.unity.render-pipelines.high-definition/Editor/Material/MaskVolume/MaskVolumeUI.Skin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ internal static class Styles
2727
internal static readonly GUIContent s_Size = new GUIContent("Size", "Modify the size of this Mask Volume. This is independent of the Transform's Scale.");
2828
internal static readonly GUIContent s_DebugColorLabel = new GUIContent("Debug Color", "This color is used to visualize per-pixel mask volume weights in the render pipeline debugger.");
2929
internal static readonly GUIContent s_DrawGizmosLabel = new GUIContent("Draw Gizmos", "Enable or disable drawing gizmos.");
30+
internal static readonly GUIContent s_DrawWeightThreshold = new GUIContent("Draw Weight Threshold", "Probes with a total mask weight less than Draw Weight Threshold will be hidden. Debug / Editor Only.");
3031
internal static readonly GUIContent s_BlendLabel = new GUIContent("Blend Distance", "Interior distance from the Size where the contribution fades in completely.");
3132
internal static readonly GUIContent s_NormalModeContent = new GUIContent("Normal", "Exposes standard parameters.");
3233
internal static readonly GUIContent s_AdvancedModeContent = new GUIContent("Advanced", "Exposes advanced parameters.");
@@ -42,7 +43,6 @@ internal static class Styles
4243
internal static readonly GUIContent s_DensityYLabel = new GUIContent("Density Y", "Modify the density (number of masks per unit in Y). Resolution will be automatically computed based on density.");
4344
internal static readonly GUIContent s_DensityZLabel = new GUIContent("Density Z", "Modify the density (number of masks per unit in Z). Resolution will be automatically computed based on density.");
4445

45-
internal static readonly GUIContent s_VolumeBlendModeLabel = new GUIContent("Volume Blend Mode", "A blending mode for the entire volume when overlapping others.");
4646
internal static readonly GUIContent s_WeightLabel = new GUIContent("Weight", "Weigh the mask contribution for the entire volume.");
4747
internal static readonly GUIContent s_NormalBiasWSLabel = new GUIContent("Normal Bias", "Controls the distance in world space units to bias along the surface normal to mitigate light leaking and self-shadowing artifacts.\nA value of 0.0 is physically accurate, but can result in self shadowing artifacts on surfaces that contribute to GI.\nIncrease value to mitigate self shadowing artifacts.\nSignificantly large values can have performance implications, as normal bias will dilate a mask volumes bounding box, causing it to be sampled in additional neighboring tiles / clusters.");
4848

com.unity.render-pipelines.high-definition/Editor/Material/MaskVolume/SerializedMaskVolume.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ class SerializedMaskVolume
66
internal SerializedProperty maskVolumeAsset;
77
internal SerializedProperty debugColor;
88
internal SerializedProperty drawGizmos;
9+
internal SerializedProperty drawWeightThreshold;
910

1011
internal SerializedProperty maskSpacingMode;
1112

@@ -17,7 +18,6 @@ class SerializedMaskVolume
1718
internal SerializedProperty densityY;
1819
internal SerializedProperty densityZ;
1920

20-
internal SerializedProperty blendMode;
2121
internal SerializedProperty weight;
2222
internal SerializedProperty normalBiasWS;
2323

@@ -47,6 +47,7 @@ internal SerializedMaskVolume(SerializedObject serializedObject)
4747

4848
debugColor = maskVolumeParams.FindPropertyRelative("debugColor");
4949
drawGizmos = maskVolumeParams.FindPropertyRelative("drawGizmos");
50+
drawWeightThreshold = maskVolumeParams.FindPropertyRelative("drawWeightThreshold");
5051

5152
maskSpacingMode = maskVolumeParams.FindPropertyRelative("maskSpacingMode");
5253

@@ -58,7 +59,6 @@ internal SerializedMaskVolume(SerializedObject serializedObject)
5859
densityY = maskVolumeParams.FindPropertyRelative("densityY");
5960
densityZ = maskVolumeParams.FindPropertyRelative("densityZ");
6061

61-
blendMode = maskVolumeParams.FindPropertyRelative("blendMode");
6262
weight = maskVolumeParams.FindPropertyRelative("weight");
6363
normalBiasWS = maskVolumeParams.FindPropertyRelative("normalBiasWS");
6464

com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ public class DebugData
288288
internal int grayscaleDebugModeIndex;
289289
internal int probeVolumeDebugModeEnumIndex;
290290
internal int probeVolumeAtlasSliceModeEnumIndex;
291+
internal int maskVolumeDebugModeEnumIndex;
291292

292293
// When settings mutually exclusives enum values, we need to reset the other ones.
293294
internal void ResetExclusiveEnumIndices()
@@ -733,6 +734,15 @@ internal void SetProbeVolumeAtlasSliceMode(ProbeVolumeAtlasSliceMode value)
733734
data.lightingDebugSettings.probeVolumeAtlasSliceMode = value;
734735
}
735736

737+
/// <summary>
738+
/// Set the current Mask Volume Debug Mode.
739+
/// </summary>
740+
/// <param name="value">Desired Probe Volume Debug Mode.</param>
741+
internal void SetMaskVolumeDebugMode(MaskVolumeDebugMode value)
742+
{
743+
data.lightingDebugSettings.maskVolumeDebugMode = value;
744+
}
745+
736746
/// <summary>
737747
/// Set the current Exposure Debug Mode.
738748
/// </summary>
@@ -1152,6 +1162,14 @@ void RegisterLightingDebug()
11521162
}
11531163
});
11541164

1165+
lighting.children.Add(new DebugUI.Foldout
1166+
{
1167+
displayName = "Mask Volumes",
1168+
children = {
1169+
new DebugUI.EnumField { displayName = "Mask Volume Debug Mode", getter = () => (int)data.lightingDebugSettings.maskVolumeDebugMode, setter = value => SetMaskVolumeDebugMode((MaskVolumeDebugMode)value), autoEnum = typeof(MaskVolumeDebugMode), onValueChanged = RefreshLightingDebug, getIndex = () => data.maskVolumeDebugModeEnumIndex, setIndex = value => data.maskVolumeDebugModeEnumIndex = value }
1170+
}
1171+
});
1172+
11551173
var exposureFoldout = new DebugUI.Foldout
11561174
{
11571175
displayName = "Exposure ",

com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,14 @@ internal enum ProbeVolumeAtlasSliceMode
223223
OctahedralDepth
224224
}
225225

226-
/// <summary>
226+
[GenerateHLSL]
227+
internal enum MaskVolumeDebugMode
228+
{
229+
None,
230+
VisualizeAtlas
231+
}
232+
233+
/// <summary>
227234
/// Lighting Debug Settings.
228235
/// </summary>
229236
[Serializable]
@@ -245,7 +252,8 @@ public bool IsDebugDisplayEnabled()
245252
|| overrideSpecularColor
246253
|| overrideEmissiveColor
247254
|| shadowDebugMode == ShadowMapDebugMode.SingleShadow
248-
|| probeVolumeDebugMode != ProbeVolumeDebugMode.None;
255+
|| probeVolumeDebugMode != ProbeVolumeDebugMode.None
256+
|| maskVolumeDebugMode != MaskVolumeDebugMode.None;
249257
}
250258

251259
/// <summary>Current Light Filtering.</summary>
@@ -272,7 +280,9 @@ public bool IsDebugDisplayEnabled()
272280
[SerializeField] internal float probeVolumeMinValue = 0.0f;
273281
/// <summary>The maximum display threshold for atlas slices.</summary>
274282
[SerializeField] internal float probeVolumeMaxValue = 1.0f;
275-
/// <summary>True if Shadow Map debug mode should be displayed for the currently selected light.</summary>
283+
/// <summary>Current Mask Volume Debug Mode.</summary>
284+
[SerializeField] internal MaskVolumeDebugMode maskVolumeDebugMode = MaskVolumeDebugMode.None;
285+
/// <summary>True if Shadow Map debug mode should be displayed for the currently selected light.</summary>
276286
public bool shadowDebugUseSelection = false;
277287
/// <summary>Index in the list of currently visible lights of the shadow map to display.</summary>
278288
public uint shadowMapIndex = 0;

com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs.hlsl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@
9696
#define PROBEVOLUMEATLASSLICEMODE_VALIDITY (9)
9797
#define PROBEVOLUMEATLASSLICEMODE_OCTAHEDRAL_DEPTH (10)
9898

99+
//
100+
// UnityEngine.Rendering.HighDefinition.MaskVolumeDebugMode: static fields
101+
//
102+
#define MASKVOLUMEDEBUGMODE_NONE (0)
103+
#define MASKVOLUMEDEBUGMODE_VISUALIZE_ATLAS (1)
99104

100105

101106
#endif

com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,7 @@ enum ClusterDepthSource : int
744744
Material m_DebugHDShadowMapMaterial;
745745
Material m_DebugBlitMaterial;
746746
Material m_DebugDisplayProbeVolumeMaterial;
747+
Material m_DebugDisplayMaskVolumeMaterial;
747748

748749
HashSet<HDAdditionalLightData> m_ScreenSpaceShadowsUnion = new HashSet<HDAdditionalLightData>();
749750

@@ -873,6 +874,7 @@ void InitializeLightLoop(IBLFilterBSDF[] iBLFilterBSDFArray)
873874
m_DebugHDShadowMapMaterial = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugHDShadowMapPS);
874875
m_DebugBlitMaterial = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugBlitQuad);
875876
m_DebugDisplayProbeVolumeMaterial = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugDisplayProbeVolumePS);
877+
m_DebugDisplayMaskVolumeMaterial = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugDisplayMaskVolumePS);
876878

877879
m_MaxDirectionalLightsOnScreen = lightLoopSettings.maxDirectionalLightsOnScreen;
878880
m_MaxPunctualLightsOnScreen = lightLoopSettings.maxPunctualLightsOnScreen;

0 commit comments

Comments
 (0)