Skip to content

Commit a847d9b

Browse files
Mask Volume visibility fixes (#84)
* Don't render Mask Volume hidden in scene. * Fixed Mask Volume flickering when two volume instances are trying to render the same asset.
1 parent ab393b2 commit a847d9b

File tree

7 files changed

+54
-103
lines changed

7 files changed

+54
-103
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public OrientedBBox ConstructOBBEngineData(Vector3 cameraOffset)
6060
}
6161

6262
#if UNITY_EDITOR
63-
public bool IsHiddesInScene() => m_List.IsHiddenInScene(m_Index);
63+
public bool IsHiddenInScene() => m_List.IsHiddenInScene(m_Index);
6464
#endif
6565
}
6666
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1228,7 +1228,7 @@ void PrepareVisibleProbeVolumeListBuffers(HDCamera hdCamera, CommandBuffer immed
12281228
if (
12291229
#if UNITY_EDITOR
12301230
volume.IsAssetCompatible() &&
1231-
!volume.IsHiddesInScene() &&
1231+
!volume.IsHiddenInScene() &&
12321232
#endif
12331233
volume.IsDataAssigned() &&
12341234
blendModeIsSupported &&
Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
using static UnityEngine.Rendering.HighDefinition.VolumeGlobalUniqueIDUtils;
2-
31
namespace UnityEngine.Rendering.HighDefinition
42
{
53
interface IMaskVolumeList
64
{
7-
void ReleaseRemovedVolumesFromAtlas();
85
int GetVolumeCount();
96

107
bool IsDataAssigned(int i);
@@ -15,13 +12,13 @@ interface IMaskVolumeList
1512
Quaternion GetRotation(int i);
1613

1714
ref MaskVolumeArtistParameters GetParameters(int i);
18-
19-
VolumeGlobalUniqueID GetAtlasID(int i);
2015
MaskVolume.MaskVolumeAtlasKey ComputeMaskVolumeAtlasKey(int i);
21-
MaskVolume.MaskVolumeAtlasKey GetMaskVolumeAtlasKeyPrevious(int i);
22-
void SetMaskVolumeAtlasKeyPrevious(int i, MaskVolume.MaskVolumeAtlasKey key);
2316

2417
int GetDataSHL0Length(int i);
2518
void SetDataSHL0(CommandBuffer cmd, int i, ComputeBuffer buffer);
19+
20+
#if UNITY_EDITOR
21+
bool IsHiddenInScene(int i);
22+
#endif
2623
}
2724
}

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

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.Runtime.CompilerServices;
43
using static UnityEngine.Rendering.HighDefinition.VolumeGlobalUniqueIDUtils;
54

@@ -347,6 +346,8 @@ internal MaskVolumeAtlasKey ComputeMaskVolumeAtlasKey()
347346
if (maskVolumeAsset == null)
348347
return MaskVolumeAtlasKey.zero;
349348

349+
// Use the payloadID, rather than the probe volume ID to uniquely identify data in the atlas.
350+
// This ensures that if 2 mask volumes exist that point to the same data, that data will only be uploaded once.
350351
return ComputeMaskVolumeAtlasKey(GetPayloadID(), maskVolumeAsset.resolutionX, maskVolumeAsset.resolutionY, maskVolumeAsset.resolutionZ);
351352
}
352353

@@ -361,30 +362,11 @@ internal static MaskVolumeAtlasKey ComputeMaskVolumeAtlasKey(VolumeGlobalUniqueI
361362
};
362363
}
363364

364-
private MaskVolumeAtlasKey maskVolumeAtlasKeyPrevious;
365-
366-
internal MaskVolumeAtlasKey GetMaskVolumeAtlasKeyPrevious()
367-
{
368-
return maskVolumeAtlasKeyPrevious;
369-
}
370-
371-
internal void SetMaskVolumeAtlasKeyPrevious(MaskVolumeAtlasKey key)
372-
{
373-
maskVolumeAtlasKeyPrevious = key;
374-
}
375-
376365
private VolumeGlobalUniqueID GetPayloadID()
377366
{
378367
return (maskVolumeAsset == null) ? VolumeGlobalUniqueID.zero : maskVolumeAsset.GetID();
379368
}
380369

381-
internal VolumeGlobalUniqueID GetAtlasID()
382-
{
383-
// Use the payloadID, rather than the probe volume ID to uniquely identify data in the atlas.
384-
// This ensures that if 2 mask volumes exist that point to the same data, that data will only be uploaded once.
385-
return GetPayloadID();
386-
}
387-
388370
internal Vector3Int GetResolution()
389371
{
390372
return new Vector3Int(maskVolumeAsset.resolutionX, maskVolumeAsset.resolutionY, maskVolumeAsset.resolutionZ);
@@ -533,8 +515,6 @@ internal void ResampleAsset()
533515
}
534516
}
535517
}
536-
537-
MaskVolumeManager.manager.ReleaseVolumeFromAtlas(this);
538518
}
539519

540520
maskVolumeAsset.resolutionX = parameters.resolutionX;

com.unity.render-pipelines.high-definition/Runtime/Material/MaskVolume/MaskVolumeHandle.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using static UnityEngine.Rendering.HighDefinition.VolumeGlobalUniqueIDUtils;
2-
31
namespace UnityEngine.Rendering.HighDefinition
42
{
53
struct MaskVolumeHandle
@@ -21,13 +19,13 @@ public MaskVolumeHandle(IMaskVolumeList list, int index)
2119
public Quaternion rotation => m_List.GetRotation(m_Index);
2220

2321
public ref MaskVolumeArtistParameters parameters => ref m_List.GetParameters(m_Index);
24-
25-
public VolumeGlobalUniqueID GetAtlasID() => m_List.GetAtlasID(m_Index);
2622
public MaskVolume.MaskVolumeAtlasKey ComputeMaskVolumeAtlasKey() => m_List.ComputeMaskVolumeAtlasKey(m_Index);
27-
public MaskVolume.MaskVolumeAtlasKey GetMaskVolumeAtlasKeyPrevious() => m_List.GetMaskVolumeAtlasKeyPrevious(m_Index);
28-
public void SetMaskVolumeAtlasKeyPrevious(MaskVolume.MaskVolumeAtlasKey key) => m_List.SetMaskVolumeAtlasKeyPrevious(m_Index, key);
2923

3024
public int DataSHL0Length => m_List.GetDataSHL0Length(m_Index);
3125
public void SetDataSHL0(CommandBuffer cmd, ComputeBuffer buffer) => m_List.SetDataSHL0(cmd, m_Index, buffer);
26+
27+
#if UNITY_EDITOR
28+
public bool IsHiddenInScene() => m_List.IsHiddenInScene(m_Index);
29+
#endif
3230
}
3331
}

com.unity.render-pipelines.high-definition/Runtime/Material/MaskVolume/MaskVolumeManager.cs

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Collections.Generic;
2-
using static UnityEngine.Rendering.HighDefinition.VolumeGlobalUniqueIDUtils;
32

43
namespace UnityEngine.Rendering.HighDefinition
54
{
@@ -32,7 +31,6 @@ internal List<MaskVolumeHandle> CollectVolumesToRender()
3231
m_VolumeHandles.Add(new MaskVolumeHandle(this, i));
3332
foreach (var list in m_AdditionalMaskLists)
3433
{
35-
list.ReleaseRemovedVolumesFromAtlas();
3634
count = list.GetVolumeCount();
3735
for (int i = 0; i < count; i++)
3836
m_VolumeHandles.Add(new MaskVolumeHandle(list, i));
@@ -54,24 +52,8 @@ internal void DeRegisterVolume(MaskVolume volume)
5452
if (index == -1)
5553
return;
5654

57-
ReleaseVolumeFromAtlas(new MaskVolumeHandle(this, index));
5855
m_Volumes.RemoveAt(index);
5956
}
60-
61-
public void ReleaseVolumeFromAtlas(MaskVolume volume)
62-
{
63-
var index = m_Volumes.IndexOf(volume);
64-
if (index == -1)
65-
return;
66-
67-
ReleaseVolumeFromAtlas(new MaskVolumeHandle(this, index));
68-
}
69-
70-
public void ReleaseVolumeFromAtlas(MaskVolumeHandle volume)
71-
{
72-
if (RenderPipelineManager.currentPipeline is HDRenderPipeline hdrp)
73-
hdrp.ReleaseMaskVolumeFromAtlas(volume);
74-
}
7557

7658
public void AddMaskList(IMaskVolumeList list)
7759
{
@@ -82,8 +64,7 @@ public void RemoveMaskList(IMaskVolumeList list)
8264
{
8365
m_AdditionalMaskLists.Remove(list);
8466
}
85-
86-
void IMaskVolumeList.ReleaseRemovedVolumesFromAtlas() { }
67+
8768
int IMaskVolumeList.GetVolumeCount() => m_Volumes.Count;
8869
bool IMaskVolumeList.IsDataAssigned(int i) => m_Volumes[i].IsDataAssigned();
8970
bool IMaskVolumeList.IsDataUpdated(int i) => m_Volumes[i].dataUpdated;
@@ -92,12 +73,13 @@ void IMaskVolumeList.ReleaseRemovedVolumesFromAtlas() { }
9273
Vector3 IMaskVolumeList.GetPosition(int i) => m_Volumes[i].transform.position;
9374
Quaternion IMaskVolumeList.GetRotation(int i) => m_Volumes[i].transform.rotation;
9475
ref MaskVolumeArtistParameters IMaskVolumeList.GetParameters(int i) => ref m_Volumes[i].parameters;
95-
VolumeGlobalUniqueID IMaskVolumeList.GetAtlasID(int i) => m_Volumes[i].GetAtlasID();
9676
MaskVolume.MaskVolumeAtlasKey IMaskVolumeList.ComputeMaskVolumeAtlasKey(int i) => m_Volumes[i].ComputeMaskVolumeAtlasKey();
97-
MaskVolume.MaskVolumeAtlasKey IMaskVolumeList.GetMaskVolumeAtlasKeyPrevious(int i) => m_Volumes[i].GetMaskVolumeAtlasKeyPrevious();
98-
void IMaskVolumeList.SetMaskVolumeAtlasKeyPrevious(int i, MaskVolume.MaskVolumeAtlasKey key) => m_Volumes[i].SetMaskVolumeAtlasKeyPrevious(key);
9977

10078
int IMaskVolumeList.GetDataSHL0Length(int i) => m_Volumes[i].GetPayload().dataSHL0.Length;
10179
void IMaskVolumeList.SetDataSHL0(CommandBuffer cmd, int i, ComputeBuffer buffer) => cmd.SetComputeBufferData(buffer, m_Volumes[i].GetPayload().dataSHL0);
80+
81+
#if UNITY_EDITOR
82+
bool IMaskVolumeList.IsHiddenInScene(int i) => UnityEditor.SceneVisibilityManager.instance.IsHidden(m_Volumes[i].gameObject);
83+
#endif
10284
}
10385
}

com.unity.render-pipelines.high-definition/Runtime/Material/MaskVolume/MaskVolumeRendering.cs

Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Collections.Generic;
33
using System.Runtime.InteropServices;
44
using UnityEngine.Experimental.Rendering.RenderGraphModule;
5-
using static UnityEngine.Rendering.HighDefinition.VolumeGlobalUniqueIDUtils;
65

76
namespace UnityEngine.Rendering.HighDefinition
87
{
@@ -122,6 +121,7 @@ public partial class HDRenderPipeline
122121
static int s_MaxMaskVolumeMaskCount;
123122
RTHandle m_MaskVolumeAtlasSHRTHandle;
124123

124+
List<MaskVolume.MaskVolumeAtlasKey> keysInAtlas;
125125
Texture3DAtlasDynamic<MaskVolume.MaskVolumeAtlasKey> maskVolumeAtlas = null;
126126

127127
bool isClearMaskVolumeAtlasRequested = false;
@@ -207,6 +207,7 @@ internal void CreateMaskVolumeBuffers()
207207
name: "MaskVolumeAtlasSH"
208208
);
209209

210+
keysInAtlas = new List<MaskVolume.MaskVolumeAtlasKey>();
210211
maskVolumeAtlas = new Texture3DAtlasDynamic<MaskVolume.MaskVolumeAtlasKey>(s_MaskVolumeAtlasResolution, s_MaskVolumeAtlasResolution, s_MaskVolumeAtlasResolution, k_MaxVisibleMaskVolumeCount, m_MaskVolumeAtlasSHRTHandle);
211212
}
212213

@@ -221,6 +222,7 @@ internal void DestroyMaskVolumeBuffers()
221222
if (m_MaskVolumeAtlasSHRTHandle != null)
222223
RTHandles.Release(m_MaskVolumeAtlasSHRTHandle);
223224

225+
keysInAtlas = null;
224226
if (maskVolumeAtlas != null)
225227
maskVolumeAtlas.Release();
226228

@@ -332,36 +334,8 @@ private static void DoPushMaskVolumesGlobalParams(
332334
cmd.SetGlobalTexture(HDShaderIDs._MaskVolumeAtlasSH, maskVolumeAtlas);
333335
}
334336

335-
internal void ReleaseMaskVolumeFromAtlas(MaskVolumeHandle volume)
337+
bool EnsureMaskVolumeInAtlas(CommandBuffer immediateCmd, RenderGraph renderGraph, ref MaskVolumesResources resources, MaskVolumeHandle volume)
336338
{
337-
if (!m_SupportMaskVolume)
338-
return;
339-
340-
MaskVolume.MaskVolumeAtlasKey key = volume.ComputeMaskVolumeAtlasKey();
341-
MaskVolume.MaskVolumeAtlasKey keyPrevious = volume.GetMaskVolumeAtlasKeyPrevious();
342-
343-
if (maskVolumeAtlas.IsTextureSlotAllocated(key)) { maskVolumeAtlas.ReleaseTextureSlot(key); }
344-
if (maskVolumeAtlas.IsTextureSlotAllocated(keyPrevious)) { maskVolumeAtlas.ReleaseTextureSlot(keyPrevious); }
345-
}
346-
347-
internal void EnsureStaleDataIsFlushedFromAtlases(MaskVolumeHandle volume)
348-
{
349-
MaskVolume.MaskVolumeAtlasKey key = volume.ComputeMaskVolumeAtlasKey();
350-
MaskVolume.MaskVolumeAtlasKey keyPrevious = volume.GetMaskVolumeAtlasKeyPrevious();
351-
if (!key.Equals(keyPrevious))
352-
{
353-
if (maskVolumeAtlas.IsTextureSlotAllocated(keyPrevious))
354-
{
355-
maskVolumeAtlas.ReleaseTextureSlot(keyPrevious);
356-
}
357-
358-
volume.SetMaskVolumeAtlasKeyPrevious(key);
359-
}
360-
}
361-
362-
internal bool EnsureMaskVolumeInAtlas(CommandBuffer immediateCmd, RenderGraph renderGraph, ref MaskVolumesResources resources, MaskVolumeHandle volume)
363-
{
364-
VolumeGlobalUniqueID id = volume.GetAtlasID();
365339
var resolution = volume.GetResolution();
366340
int size = resolution.x * resolution.y * resolution.z;
367341
Debug.Assert(size > 0, "MaskVolume: Encountered mask volume with resolution set to zero on all three axes.");
@@ -376,14 +350,13 @@ internal bool EnsureMaskVolumeInAtlas(CommandBuffer immediateCmd, RenderGraph re
376350

377351
if (isSlotAllocated)
378352
{
353+
// Sync local key list with any allocated slot, no matter if we will actually upload anything to it.
354+
// Needed to identify and free the slot later when no volumes with this key is present in a frame.
355+
if (!keysInAtlas.Contains(key))
356+
keysInAtlas.Add(key);
357+
379358
if (isUploadNeeded || volume.IsDataUpdated())
380359
{
381-
if (!volume.IsDataAssigned())
382-
{
383-
ReleaseMaskVolumeFromAtlas(volume);
384-
return false;
385-
}
386-
387360
int sizeSHCoefficientsL0 = size * MaskVolumePayload.GetDataSHL0Stride();
388361
Debug.AssertFormat(volume.DataSHL0Length == sizeSHCoefficientsL0, "MaskVolume: The mask volume data and its resolution are out of sync! Volume data length is {0}, but resolution * SH stride size is {1}.", volume.DataSHL0Length, sizeSHCoefficientsL0);
389362

@@ -432,14 +405,13 @@ internal bool EnsureMaskVolumeInAtlas(CommandBuffer immediateCmd, RenderGraph re
432405
}
433406

434407
return true;
435-
436408
}
437409
return false;
438410
}
439411

440412
if (!isSlotAllocated)
441413
{
442-
Debug.LogWarningFormat("MaskVolume: Texture Atlas failed to allocate space for texture (id: {0}, width: {1}, height: {2}, depth: {3})", id, resolution.x, resolution.y, resolution.z);
414+
Debug.LogWarningFormat("MaskVolume: Texture Atlas failed to allocate space for texture (id: {0}, width: {1}, height: {2}, depth: {3})", key.id, resolution.x, resolution.y, resolution.z);
443415
}
444416

445417
return false;
@@ -497,6 +469,7 @@ internal void ClearMaskVolumeAtlasIfRequested(CommandBuffer immediateCmd, Render
497469
if (!isClearMaskVolumeAtlasRequested) { return; }
498470
isClearMaskVolumeAtlasRequested = false;
499471

472+
keysInAtlas.Clear();
500473
maskVolumeAtlas.ResetAllocator();
501474

502475
if (renderGraph != null)
@@ -614,7 +587,12 @@ void PrepareVisibleMaskVolumeListBuffers(HDCamera hdCamera, CommandBuffer immedi
614587
{
615588
MaskVolumeHandle volume = volumes[maskVolumesIndex];
616589

617-
var isVisible = volume.parameters.weight >= 1e-5f && volume.IsDataAssigned();
590+
var isVisible =
591+
volume.parameters.weight >= 1e-5f &&
592+
#if UNITY_EDITOR
593+
!volume.IsHiddenInScene() &&
594+
#endif
595+
volume.IsDataAssigned();
618596

619597
// When hdCamera is null we are preparing for some view-independent baking, so we consider all valid volumes visible.
620598
if (isViewDependent && isVisible)
@@ -640,9 +618,27 @@ void PrepareVisibleMaskVolumeListBuffers(HDCamera hdCamera, CommandBuffer immedi
640618
var logVolume = CalculateMaskVolumeLogVolume(volume.parameters.size);
641619
m_MaskVolumeSortKeys[sortCount++] = PackMaskVolumeSortKey(logVolume, maskVolumesIndex);
642620
}
643-
else
621+
}
622+
623+
for (int keyIndex = keysInAtlas.Count - 1; keyIndex >= 0; keyIndex--)
624+
{
625+
var key = keysInAtlas[keyIndex];
626+
var dataIsNeededInAtlas = false;
627+
for (int sortIndex = 0; sortIndex < sortCount; sortIndex++)
628+
{
629+
var sortKey = m_MaskVolumeSortKeys[sortIndex];
630+
UnpackMaskVolumeSortKey(sortKey, out var maskVolumesIndex);
631+
var volumeKey = volumes[maskVolumesIndex].ComputeMaskVolumeAtlasKey();
632+
if (volumeKey.Equals(key))
633+
{
634+
dataIsNeededInAtlas = true;
635+
break;
636+
}
637+
}
638+
if (!dataIsNeededInAtlas)
644639
{
645-
ReleaseMaskVolumeFromAtlas(volume);
640+
keysInAtlas.RemoveAt(keyIndex);
641+
maskVolumeAtlas.ReleaseTextureSlot(key);
646642
}
647643
}
648644

@@ -688,8 +684,6 @@ void PrepareVisibleMaskVolumeListBuffers(HDCamera hdCamera, CommandBuffer immedi
688684

689685
MaskVolumeHandle volume = volumes[maskVolumesIndex];
690686

691-
EnsureStaleDataIsFlushedFromAtlases(volume);
692-
693687
if (volumeUploadedToAtlasSHCount < volumeUploadedToAtlasCapacity)
694688
{
695689
bool volumeWasUploaded = EnsureMaskVolumeInAtlas(immediateCmd, renderGraph, ref maskVolumes.resources, volume);

0 commit comments

Comments
 (0)