diff --git a/package/Editor/GaussianSplatRendererEditor.cs b/package/Editor/GaussianSplatRendererEditor.cs index f5bad0d8..7ef13aff 100644 --- a/package/Editor/GaussianSplatRendererEditor.cs +++ b/package/Editor/GaussianSplatRendererEditor.cs @@ -25,18 +25,8 @@ public class GaussianSplatRendererEditor : UnityEditor.Editor SerializedProperty m_PropSplatScale; SerializedProperty m_PropOpacityScale; SerializedProperty m_PropSHOrder; - SerializedProperty m_PropSHOnly; - SerializedProperty m_PropSortNthFrame; - SerializedProperty m_PropRenderMode; - SerializedProperty m_PropPointDisplaySize; SerializedProperty m_PropCutouts; - SerializedProperty m_PropShaderSplats; - SerializedProperty m_PropShaderComposite; - SerializedProperty m_PropShaderDebugPoints; - SerializedProperty m_PropShaderDebugBoxes; - SerializedProperty m_PropCSSplatUtilities; - bool m_ResourcesExpanded = false; int m_CameraIndex = 0; bool m_ExportBakeTransform; @@ -65,16 +55,7 @@ public void OnEnable() m_PropSplatScale = serializedObject.FindProperty("m_SplatScale"); m_PropOpacityScale = serializedObject.FindProperty("m_OpacityScale"); m_PropSHOrder = serializedObject.FindProperty("m_SHOrder"); - m_PropSHOnly = serializedObject.FindProperty("m_SHOnly"); - m_PropSortNthFrame = serializedObject.FindProperty("m_SortNthFrame"); - m_PropRenderMode = serializedObject.FindProperty("m_RenderMode"); - m_PropPointDisplaySize = serializedObject.FindProperty("m_PointDisplaySize"); m_PropCutouts = serializedObject.FindProperty("m_Cutouts"); - m_PropShaderSplats = serializedObject.FindProperty("m_ShaderSplats"); - m_PropShaderComposite = serializedObject.FindProperty("m_ShaderComposite"); - m_PropShaderDebugPoints = serializedObject.FindProperty("m_ShaderDebugPoints"); - m_PropShaderDebugBoxes = serializedObject.FindProperty("m_ShaderDebugBoxes"); - m_PropCSSplatUtilities = serializedObject.FindProperty("m_CSSplatUtilities"); s_AllEditors.Add(this); } @@ -109,25 +90,8 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(m_PropSplatScale); EditorGUILayout.PropertyField(m_PropOpacityScale); EditorGUILayout.PropertyField(m_PropSHOrder); - EditorGUILayout.PropertyField(m_PropSHOnly); - EditorGUILayout.PropertyField(m_PropSortNthFrame); EditorGUILayout.Space(); - GUILayout.Label("Debugging Tweaks", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(m_PropRenderMode); - if (m_PropRenderMode.intValue is (int)GaussianSplatRenderer.RenderMode.DebugPoints or (int)GaussianSplatRenderer.RenderMode.DebugPointIndices) - EditorGUILayout.PropertyField(m_PropPointDisplaySize); - - EditorGUILayout.Space(); - m_ResourcesExpanded = EditorGUILayout.Foldout(m_ResourcesExpanded, "Resources", true, EditorStyles.foldoutHeader); - if (m_ResourcesExpanded) - { - EditorGUILayout.PropertyField(m_PropShaderSplats); - EditorGUILayout.PropertyField(m_PropShaderComposite); - EditorGUILayout.PropertyField(m_PropShaderDebugPoints); - EditorGUILayout.PropertyField(m_PropShaderDebugBoxes); - EditorGUILayout.PropertyField(m_PropCSSplatUtilities); - } bool validAndEnabled = gs && gs.enabled && gs.gameObject.activeInHierarchy && gs.HasValidAsset; if (validAndEnabled && !gs.HasValidRenderSetup) { diff --git a/package/Editor/GaussianSplatSettingsEditor.cs b/package/Editor/GaussianSplatSettingsEditor.cs new file mode 100644 index 00000000..0aee50ac --- /dev/null +++ b/package/Editor/GaussianSplatSettingsEditor.cs @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT + +using GaussianSplatting.Runtime; +using UnityEditor; +using UnityEngine; + +namespace GaussianSplatting.Editor +{ + [CustomEditor(typeof(GaussianSplatSettings))] + [CanEditMultipleObjects] + public class GaussianSplatSettingsEditor : UnityEditor.Editor + { + SerializedProperty m_Transparency; + SerializedProperty m_SortNthFrame; + SerializedProperty m_TemporalFilter; + SerializedProperty m_FrameInfluence; + SerializedProperty m_VarianceClampScale; + SerializedProperty m_RenderMode; + SerializedProperty m_PointDisplaySize; + SerializedProperty m_SHOnly; + + public void OnEnable() + { + m_Transparency = serializedObject.FindProperty("m_Transparency"); + m_SortNthFrame = serializedObject.FindProperty("m_SortNthFrame"); + m_TemporalFilter = serializedObject.FindProperty("m_TemporalFilter"); + m_FrameInfluence = serializedObject.FindProperty("m_FrameInfluence"); + m_VarianceClampScale = serializedObject.FindProperty("m_VarianceClampScale"); + m_RenderMode = serializedObject.FindProperty("m_RenderMode"); + m_PointDisplaySize = serializedObject.FindProperty("m_PointDisplaySize"); + m_SHOnly = serializedObject.FindProperty("m_SHOnly"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.Space(); + EditorGUILayout.PropertyField(m_Transparency); + if (m_Transparency.intValue is (int) TransparencyMode.SortedBlended) + { + EditorGUILayout.PropertyField(m_SortNthFrame); + } + if (m_Transparency.intValue == (int) TransparencyMode.Stochastic) + { + EditorGUILayout.PropertyField(m_TemporalFilter); + if (m_TemporalFilter.intValue != (int)TemporalFilter.None) + { + EditorGUILayout.PropertyField(m_FrameInfluence); + EditorGUILayout.PropertyField(m_VarianceClampScale); + } + } + + EditorGUILayout.Space(); + GUILayout.Label("Debugging Tweaks", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(m_RenderMode); + if (m_RenderMode.intValue is (int)DebugRenderMode.DebugPoints or (int)DebugRenderMode.DebugPointIndices) + EditorGUILayout.PropertyField(m_PointDisplaySize); + EditorGUILayout.PropertyField(m_SHOnly); + + serializedObject.ApplyModifiedProperties(); + } + } +} \ No newline at end of file diff --git a/package/Editor/GaussianSplatSettingsEditor.cs.meta b/package/Editor/GaussianSplatSettingsEditor.cs.meta new file mode 100644 index 00000000..3fb12f1b --- /dev/null +++ b/package/Editor/GaussianSplatSettingsEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1025a77da5ae3f94ebf0fcd93cf8b518 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Editor/GaussianSplatValidator.cs b/package/Editor/GaussianSplatValidator.cs index a1a1c4ea..63a24603 100644 --- a/package/Editor/GaussianSplatValidator.cs +++ b/package/Editor/GaussianSplatValidator.cs @@ -38,7 +38,7 @@ public static void ValidateD3D12() static unsafe void ValidateImpl(string refPrefix) { - var gaussians = Object.FindObjectOfType(typeof(GaussianSplatRenderer)) as GaussianSplatRenderer; + var gaussians = Object.FindAnyObjectByType(); { if (gaussians == null) { diff --git a/package/Runtime/GaussianSplatRenderer.cs b/package/Runtime/GaussianSplatRenderer.cs index 9e080b97..54cb9071 100644 --- a/package/Runtime/GaussianSplatRenderer.cs +++ b/package/Runtime/GaussianSplatRenderer.cs @@ -11,6 +11,7 @@ using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering; using UnityEngine.XR; +using Object = UnityEngine.Object; namespace GaussianSplatting.Runtime { @@ -30,6 +31,23 @@ class GaussianSplatRenderSystem readonly List<(GaussianSplatRenderer, MaterialPropertyBlock)> m_ActiveSplats = new(); CommandBuffer m_CommandBuffer; + GraphicsBuffer m_CubeIndexBuffer; + GraphicsBuffer m_GlobalUniforms; + Material m_MatSplats; + // ReSharper disable once MemberCanBePrivate.Global - used by HDRP/URP features that are not always compiled + internal Material m_MatComposite; + Material m_MatDebugPoints; + Material m_MatDebugBoxes; + uint m_FrameOffset; + GaussianSplatTemporalFilter m_TemporalFilter; + + struct SplatGlobalUniforms // match cbuffer SplatGlobalUniforms in shaders + { + // ReSharper disable once NotAccessedField.Local - used on shader side + public uint transparencyMode; + // ReSharper disable once NotAccessedField.Local - used on shader side + public uint frameOffset; + } public void RegisterSplat(GaussianSplatRenderer r) { @@ -48,25 +66,38 @@ public void UnregisterSplat(GaussianSplatRenderer r) return; m_Splats.Remove(r); if (m_Splats.Count == 0) + CleanupAfterAllSplatsDeleted(); + } + + void CleanupAfterAllSplatsDeleted() + { + if (m_CameraCommandBuffersDone != null) { - if (m_CameraCommandBuffersDone != null) + if (m_CommandBuffer != null) { - if (m_CommandBuffer != null) + foreach (var cam in m_CameraCommandBuffersDone) { - foreach (var cam in m_CameraCommandBuffersDone) - { - if (cam) - cam.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, m_CommandBuffer); - } + if (cam) + cam.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, m_CommandBuffer); } - m_CameraCommandBuffersDone.Clear(); } - - m_ActiveSplats.Clear(); - m_CommandBuffer?.Dispose(); - m_CommandBuffer = null; - Camera.onPreCull -= OnPreCullCamera; + m_CameraCommandBuffersDone.Clear(); } + + m_ActiveSplats.Clear(); + m_CubeIndexBuffer?.Dispose(); + m_CubeIndexBuffer = null; + m_CommandBuffer?.Dispose(); + m_CommandBuffer = null; + m_GlobalUniforms?.Dispose(); + m_GlobalUniforms = null; + Object.DestroyImmediate(m_MatSplats); + Object.DestroyImmediate(m_MatComposite); + Object.DestroyImmediate(m_MatDebugPoints); + Object.DestroyImmediate(m_MatDebugBoxes); + m_TemporalFilter?.Dispose(); + m_TemporalFilter = null; + Camera.onPreCull -= OnPreCullCamera; } // ReSharper disable once MemberCanBePrivate.Global - used by HDRP/URP features that are not always compiled @@ -105,36 +136,76 @@ public bool GatherSplatsForCamera(Camera cam) } // ReSharper disable once MemberCanBePrivate.Global - used by HDRP/URP features that are not always compiled - public Material SortAndRenderSplats(Camera cam, CommandBuffer cmb) + public void SortAllSplats(Camera cam, CommandBuffer cmb) { - Material matComposite = null; + if (cam.cameraType == CameraType.Preview) + return; + GaussianSplatSettings settings = GaussianSplatSettings.instance; + if (!settings.needSorting) + return; // no need to sort + foreach (var kvp in m_ActiveSplats) { var gs = kvp.Item1; - gs.EnsureMaterials(); - matComposite = gs.m_MatComposite; - var mpb = kvp.Item2; - - // sort var matrix = gs.transform.localToWorldMatrix; - if (gs.m_FrameCounter % gs.m_SortNthFrame == 0) + if (gs.m_FrameCounter % settings.m_SortNthFrame == 0) gs.SortPoints(cmb, cam, matrix); ++gs.m_FrameCounter; + } + } - // cache view - kvp.Item2.Clear(); - Material displayMat = gs.m_RenderMode switch - { - GaussianSplatRenderer.RenderMode.DebugPoints => gs.m_MatDebugPoints, - GaussianSplatRenderer.RenderMode.DebugPointIndices => gs.m_MatDebugPoints, - GaussianSplatRenderer.RenderMode.DebugBoxes => gs.m_MatDebugBoxes, - GaussianSplatRenderer.RenderMode.DebugChunkBounds => gs.m_MatDebugBoxes, - _ => gs.m_MatSplats - }; - if (displayMat == null) - continue; + // ReSharper disable once MemberCanBePrivate.Global - used by HDRP/URP features that are not always compiled + public void CacheViewDataForAllSplats(Camera cam, CommandBuffer cmb) + { + foreach (var kvp in m_ActiveSplats) + { + var gs = kvp.Item1; + cmb.BeginSample(s_ProfCalcView); + gs.CalcViewData(cmb, cam); + cmb.EndSample(s_ProfCalcView); + } + } + + // ReSharper disable once MemberCanBePrivate.Global - used by HDRP/URP features that are not always compiled + public void RenderAllSplats(Camera cam, CommandBuffer cmb) + { + EnsureMaterials(); + GaussianSplatSettings settings = GaussianSplatSettings.instance; + Material displayMat = settings.m_RenderMode switch + { + DebugRenderMode.DebugPoints => m_MatDebugPoints, + DebugRenderMode.DebugPointIndices => m_MatDebugPoints, + DebugRenderMode.DebugBoxes => m_MatDebugBoxes, + DebugRenderMode.DebugChunkBounds => m_MatDebugBoxes, + _ => m_MatSplats + }; + if (displayMat == null) + return; + + EnsureCubeIndexBuffer(); + + m_GlobalUniforms ??= new GraphicsBuffer(GraphicsBuffer.Target.Constant, 1, UnsafeUtility.SizeOf()); + NativeArray sgu = new(1, Allocator.Temp); + sgu[0] = new SplatGlobalUniforms { transparencyMode = (uint)settings.m_Transparency, frameOffset = m_FrameOffset }; + cmb.SetBufferData(m_GlobalUniforms, sgu); + m_FrameOffset++; + + bool stochastic = !settings.isDebugRender && settings.m_Transparency == TransparencyMode.Stochastic; + displayMat.SetInt(GaussianSplatRenderer.Props.SrcBlend, (int)(stochastic ? BlendMode.One : BlendMode.OneMinusDstAlpha)); + displayMat.SetInt(GaussianSplatRenderer.Props.DstBlend, (int)(stochastic ? BlendMode.Zero : BlendMode.One)); + displayMat.SetInt(GaussianSplatRenderer.Props.ZWrite, stochastic ? 1 : 0); + + foreach (var kvp in m_ActiveSplats) + { + var gs = kvp.Item1; + + var matrix = gs.transform.localToWorldMatrix; + + var mpb = kvp.Item2; + mpb.Clear(); gs.SetAssetDataOnMaterial(mpb); + mpb.SetBuffer(GaussianSplatRenderer.Props.SplatChunks, gs.m_GpuChunks); mpb.SetBuffer(GaussianSplatRenderer.Props.SplatViewData, gs.m_GpuView); @@ -142,30 +213,55 @@ public Material SortAndRenderSplats(Camera cam, CommandBuffer cmb) mpb.SetBuffer(GaussianSplatRenderer.Props.OrderBuffer, gs.m_GpuSortKeys); mpb.SetFloat(GaussianSplatRenderer.Props.SplatScale, gs.m_SplatScale); mpb.SetFloat(GaussianSplatRenderer.Props.SplatOpacityScale, gs.m_OpacityScale); - mpb.SetFloat(GaussianSplatRenderer.Props.SplatSize, gs.m_PointDisplaySize); + mpb.SetFloat(GaussianSplatRenderer.Props.SplatSize, settings.m_PointDisplaySize); mpb.SetInteger(GaussianSplatRenderer.Props.SHOrder, gs.m_SHOrder); - mpb.SetInteger(GaussianSplatRenderer.Props.SHOnly, gs.m_SHOnly ? 1 : 0); - mpb.SetInteger(GaussianSplatRenderer.Props.DisplayIndex, gs.m_RenderMode == GaussianSplatRenderer.RenderMode.DebugPointIndices ? 1 : 0); - mpb.SetInteger(GaussianSplatRenderer.Props.DisplayChunks, gs.m_RenderMode == GaussianSplatRenderer.RenderMode.DebugChunkBounds ? 1 : 0); - - cmb.BeginSample(s_ProfCalcView); - gs.CalcViewData(cmb, cam); - cmb.EndSample(s_ProfCalcView); + mpb.SetInteger(GaussianSplatRenderer.Props.SHOnly, settings.m_SHOnly ? 1 : 0); + mpb.SetInteger(GaussianSplatRenderer.Props.DisplayIndex, settings.m_RenderMode == DebugRenderMode.DebugPointIndices ? 1 : 0); + mpb.SetInteger(GaussianSplatRenderer.Props.DisplayChunks, settings.m_RenderMode == DebugRenderMode.DebugChunkBounds ? 1 : 0); + mpb.SetConstantBuffer(GaussianSplatRenderer.Props.SplatGlobalUniforms, m_GlobalUniforms, 0, m_GlobalUniforms.stride); - // draw int indexCount = 6; int instanceCount = gs.splatCount; MeshTopology topology = MeshTopology.Triangles; - if (gs.m_RenderMode is GaussianSplatRenderer.RenderMode.DebugBoxes or GaussianSplatRenderer.RenderMode.DebugChunkBounds) + if (settings.m_RenderMode is DebugRenderMode.DebugBoxes or DebugRenderMode.DebugChunkBounds) indexCount = 36; - if (gs.m_RenderMode == GaussianSplatRenderer.RenderMode.DebugChunkBounds) + if (settings.m_RenderMode == DebugRenderMode.DebugChunkBounds) instanceCount = gs.m_GpuChunksValid ? gs.m_GpuChunks.count : 0; cmb.BeginSample(s_ProfDraw); - cmb.DrawProcedural(gs.m_GpuIndexBuffer, matrix, displayMat, 0, topology, indexCount, instanceCount, mpb); + cmb.DrawProcedural(m_CubeIndexBuffer, matrix, displayMat, 0, topology, indexCount, instanceCount, mpb); cmb.EndSample(s_ProfDraw); } - return matComposite; + } + + // cube indices, most often we use only the first quad + void EnsureCubeIndexBuffer() + { + if (m_CubeIndexBuffer != null) + return; + m_CubeIndexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Index, 36, 2); + m_CubeIndexBuffer.SetData(new ushort[] + { + 0, 1, 2, 1, 3, 2, + 4, 6, 5, 5, 6, 7, + 0, 2, 4, 4, 2, 6, + 1, 5, 3, 5, 7, 3, + 0, 4, 1, 4, 5, 1, + 2, 3, 6, 3, 7, 6 + }); + } + + // ReSharper disable once MemberCanBePrivate.Global - used by HDRP/URP features that are not always compiled + internal void EnsureMaterials() + { + GaussianSplatSettings settings = GaussianSplatSettings.instance; + if (m_MatSplats == null && settings.resourcesFound) + { + m_MatSplats = new Material(settings.shaderSplats) {name = "GaussianSplats"}; + m_MatComposite = new Material(settings.shaderComposite) {name = "GaussianClearDstAlpha"}; + m_MatDebugPoints = new Material(settings.shaderDebugPoints) {name = "GaussianDebugPoints"}; + m_MatDebugBoxes = new Material(settings.shaderDebugBoxes) {name = "GaussianDebugBoxes"}; + } } // ReSharper disable once MemberCanBePrivate.Global - used by HDRP/URP features that are not always compiled @@ -189,39 +285,58 @@ void OnPreCullCamera(Camera cam) if (!GatherSplatsForCamera(cam)) return; - InitialClearCmdBuffer(cam); + EnsureMaterials(); + var matComposite = m_MatComposite; + if (!matComposite) + return; - m_CommandBuffer.GetTemporaryRT(GaussianSplatRenderer.Props.GaussianSplatRT, -1, -1, 0, FilterMode.Point, GraphicsFormat.R16G16B16A16_SFloat); - m_CommandBuffer.SetRenderTarget(GaussianSplatRenderer.Props.GaussianSplatRT, BuiltinRenderTextureType.CurrentActive); - m_CommandBuffer.ClearRenderTarget(RTClearFlags.Color, new Color(0, 0, 0, 0), 0, 0); + InitialClearCmdBuffer(cam); // We only need this to determine whether we're rendering into backbuffer or not. However, detection this // way only works in BiRP so only do it here. - m_CommandBuffer.SetGlobalTexture(GaussianSplatRenderer.Props.CameraTargetTexture, BuiltinRenderTextureType.CameraTarget); + m_CommandBuffer.SetGlobalTexture(GaussianSplatRenderer.Props.CameraTargetTexture, + BuiltinRenderTextureType.CameraTarget); + + GaussianSplatSettings settings = GaussianSplatSettings.instance; + if (!settings.isDebugRender) // Debug visualizations modes just render directly onto screen + { + m_CommandBuffer.GetTemporaryRT(GaussianSplatRenderer.Props.GaussianSplatRT, -1, -1, 0, FilterMode.Point, GraphicsFormat.R16G16B16A16_SFloat); + m_CommandBuffer.SetRenderTarget(GaussianSplatRenderer.Props.GaussianSplatRT, BuiltinRenderTextureType.CurrentActive); + m_CommandBuffer.ClearRenderTarget(RTClearFlags.Color, new Color(0, 0, 0, 0), 0, 0); + } - // add sorting, view calc and drawing commands for each splat object - Material matComposite = SortAndRenderSplats(cam, m_CommandBuffer); + // add sorting, view calc and drawing commands for all splat objects + SortAllSplats(cam, m_CommandBuffer); + CacheViewDataForAllSplats(cam, m_CommandBuffer); + RenderAllSplats(cam, m_CommandBuffer); // compose - m_CommandBuffer.BeginSample(s_ProfCompose); - m_CommandBuffer.SetRenderTarget(BuiltinRenderTextureType.CameraTarget); - m_CommandBuffer.DrawProcedural(Matrix4x4.identity, matComposite, 0, MeshTopology.Triangles, 3, 1); - m_CommandBuffer.EndSample(s_ProfCompose); - m_CommandBuffer.ReleaseTemporaryRT(GaussianSplatRenderer.Props.GaussianSplatRT); + if (!settings.isDebugRender) + { + m_CommandBuffer.BeginSample(s_ProfCompose); + if (settings.m_Transparency == TransparencyMode.Stochastic && settings.m_TemporalFilter != TemporalFilter.None) + { + m_TemporalFilter ??= new GaussianSplatTemporalFilter(); + m_TemporalFilter.Render(m_CommandBuffer, cam, matComposite, 1, + GaussianSplatRenderer.Props.GaussianSplatRT, + BuiltinRenderTextureType.CameraTarget, + settings.m_FrameInfluence, + settings.m_VarianceClampScale); + } + else + { + m_CommandBuffer.SetRenderTarget(BuiltinRenderTextureType.CameraTarget); + m_CommandBuffer.DrawProcedural(Matrix4x4.identity, matComposite, 0, MeshTopology.Triangles, 3, 1); + } + m_CommandBuffer.EndSample(s_ProfCompose); + m_CommandBuffer.ReleaseTemporaryRT(GaussianSplatRenderer.Props.GaussianSplatRT); + } } } [ExecuteInEditMode] public class GaussianSplatRenderer : MonoBehaviour { - public enum RenderMode - { - Splats, - DebugPoints, - DebugPointIndices, - DebugBoxes, - DebugChunkBounds, - } public GaussianSplatAsset m_Asset; [Tooltip("Rendering order compared to other splats. Within same order splats are sorted by distance. Higher order splats render 'on top of' lower order splats.")] @@ -233,23 +348,9 @@ public enum RenderMode public float m_OpacityScale = 1.0f; [Range(0, 3)] [Tooltip("Spherical Harmonics order to use")] public int m_SHOrder = 3; - [Tooltip("Show only Spherical Harmonics contribution, using gray color")] - public bool m_SHOnly; - [Range(1,30)] [Tooltip("Sort splats only every N frames")] - public int m_SortNthFrame = 1; - - public RenderMode m_RenderMode = RenderMode.Splats; - [Range(1.0f,15.0f)] public float m_PointDisplaySize = 3.0f; public GaussianCutout[] m_Cutouts; - public Shader m_ShaderSplats; - public Shader m_ShaderComposite; - public Shader m_ShaderDebugPoints; - public Shader m_ShaderDebugBoxes; - [Tooltip("Gaussian splatting compute shader")] - public ComputeShader m_CSSplatUtilities; - int m_SplatCount; // initially same as asset splat count, but editing can change this GraphicsBuffer m_GpuSortDistances; internal GraphicsBuffer m_GpuSortKeys; @@ -260,7 +361,6 @@ public enum RenderMode internal GraphicsBuffer m_GpuChunks; internal bool m_GpuChunksValid; internal GraphicsBuffer m_GpuView; - internal GraphicsBuffer m_GpuIndexBuffer; // these buffers are only for splat editing, and are lazily created GraphicsBuffer m_GpuEditCutouts; @@ -274,11 +374,6 @@ public enum RenderMode GpuSorting m_Sorter; GpuSorting.Args m_SorterArgs; - internal Material m_MatSplats; - internal Material m_MatComposite; - internal Material m_MatDebugPoints; - internal Material m_MatDebugBoxes; - internal int m_FrameCounter; GaussianSplatAsset m_PrevAsset; Hash128 m_PrevHash; @@ -288,6 +383,10 @@ public enum RenderMode internal static class Props { + public static readonly int SrcBlend = Shader.PropertyToID("_SrcBlend"); + public static readonly int DstBlend = Shader.PropertyToID("_DstBlend"); + public static readonly int ZWrite = Shader.PropertyToID("_ZWrite"); + public static readonly int SplatGlobalUniforms = Shader.PropertyToID("SplatGlobalUniforms"); public static readonly int SplatPos = Shader.PropertyToID("_SplatPos"); public static readonly int SplatOther = Shader.PropertyToID("_SplatOther"); public static readonly int SplatSH = Shader.PropertyToID("_SplatSH"); @@ -405,17 +504,6 @@ void CreateResourcesForAsset() } m_GpuView = new GraphicsBuffer(GraphicsBuffer.Target.Structured, m_Asset.splatCount, kGpuViewDataSize); - m_GpuIndexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Index, 36, 2); - // cube indices, most often we use only the first quad - m_GpuIndexBuffer.SetData(new ushort[] - { - 0, 1, 2, 1, 3, 2, - 4, 6, 5, 5, 6, 7, - 0, 2, 4, 4, 2, 6, - 1, 5, 3, 5, 7, 3, - 0, 4, 1, 4, 5, 1, - 2, 3, 6, 3, 7, 6 - }); InitSortBuffers(splatCount); } @@ -432,10 +520,11 @@ void InitSortBuffers(int count) m_GpuSortKeys = new GraphicsBuffer(GraphicsBuffer.Target.Structured, count, 4) { name = "GaussianSplatSortIndices" }; // init keys buffer to splat indices - m_CSSplatUtilities.SetBuffer((int)KernelIndices.SetIndices, Props.SplatSortKeys, m_GpuSortKeys); - m_CSSplatUtilities.SetInt(Props.SplatCount, m_GpuSortDistances.count); - m_CSSplatUtilities.GetKernelThreadGroupSizes((int)KernelIndices.SetIndices, out uint gsX, out _, out _); - m_CSSplatUtilities.Dispatch((int)KernelIndices.SetIndices, (m_GpuSortDistances.count + (int)gsX - 1)/(int)gsX, 1, 1); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cs.SetBuffer((int)KernelIndices.SetIndices, Props.SplatSortKeys, m_GpuSortKeys); + cs.SetInt(Props.SplatCount, m_GpuSortDistances.count); + cs.GetKernelThreadGroupSizes((int)KernelIndices.SetIndices, out uint gsX, out _, out _); + cs.Dispatch((int)KernelIndices.SetIndices, (m_GpuSortDistances.count + (int)gsX - 1)/(int)gsX, 1, 1); m_SorterArgs.inputKeys = m_GpuSortDistances; m_SorterArgs.inputValues = m_GpuSortKeys; @@ -444,25 +533,13 @@ void InitSortBuffers(int count) m_SorterArgs.resources = GpuSorting.SupportResources.Load((uint)count); } - bool resourcesAreSetUp => m_ShaderSplats != null && m_ShaderComposite != null && m_ShaderDebugPoints != null && - m_ShaderDebugBoxes != null && m_CSSplatUtilities != null && SystemInfo.supportsComputeShaders; - - public void EnsureMaterials() - { - if (m_MatSplats == null && resourcesAreSetUp) - { - m_MatSplats = new Material(m_ShaderSplats) {name = "GaussianSplats"}; - m_MatComposite = new Material(m_ShaderComposite) {name = "GaussianClearDstAlpha"}; - m_MatDebugPoints = new Material(m_ShaderDebugPoints) {name = "GaussianDebugPoints"}; - m_MatDebugBoxes = new Material(m_ShaderDebugBoxes) {name = "GaussianDebugBoxes"}; - } - } + bool resourcesAreSetUp => GaussianSplatSettings.instance.resourcesFound; public void EnsureSorterAndRegister() { if (m_Sorter == null && resourcesAreSetUp) { - m_Sorter = new GpuSorting(m_CSSplatUtilities); + m_Sorter = new GpuSorting(GaussianSplatSettings.instance.csUtilities); } if (!m_Registered && resourcesAreSetUp) @@ -478,15 +555,13 @@ public void OnEnable() if (!resourcesAreSetUp) return; - EnsureMaterials(); EnsureSorterAndRegister(); - CreateResourcesForAsset(); } void SetAssetDataOnCS(CommandBuffer cmb, KernelIndices kernel) { - ComputeShader cs = m_CSSplatUtilities; + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; int kernelIndex = (int) kernel; cmb.SetComputeBufferParam(cs, kernelIndex, Props.SplatPos, m_GpuPosData); cmb.SetComputeBufferParam(cs, kernelIndex, Props.SplatChunks, m_GpuChunks); @@ -540,7 +615,6 @@ void DisposeResourcesForAsset() DisposeBuffer(ref m_GpuChunks); DisposeBuffer(ref m_GpuView); - DisposeBuffer(ref m_GpuIndexBuffer); DisposeBuffer(ref m_GpuSortDistances); DisposeBuffer(ref m_GpuSortKeys); @@ -569,11 +643,6 @@ public void OnDisable() DisposeResourcesForAsset(); GaussianSplatRenderSystem.instance.UnregisterSplat(this); m_Registered = false; - - DestroyImmediate(m_MatSplats); - DestroyImmediate(m_MatComposite); - DestroyImmediate(m_MatDebugPoints); - DestroyImmediate(m_MatDebugBoxes); } internal void CalcViewData(CommandBuffer cmb, Camera cam) @@ -594,26 +663,25 @@ internal void CalcViewData(CommandBuffer cmb, Camera cam) // calculate view dependent data for each splat SetAssetDataOnCS(cmb, KernelIndices.CalcViewData); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixMV, matView * matO2W); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixObjectToWorld, matO2W); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixWorldToObject, matW2O); - - cmb.SetComputeVectorParam(m_CSSplatUtilities, Props.VecScreenParams, screenPar); - cmb.SetComputeVectorParam(m_CSSplatUtilities, Props.VecWorldSpaceCameraPos, camPos); - cmb.SetComputeFloatParam(m_CSSplatUtilities, Props.SplatScale, m_SplatScale); - cmb.SetComputeFloatParam(m_CSSplatUtilities, Props.SplatOpacityScale, m_OpacityScale); - cmb.SetComputeIntParam(m_CSSplatUtilities, Props.SHOrder, m_SHOrder); - cmb.SetComputeIntParam(m_CSSplatUtilities, Props.SHOnly, m_SHOnly ? 1 : 0); - - m_CSSplatUtilities.GetKernelThreadGroupSizes((int)KernelIndices.CalcViewData, out uint gsX, out _, out _); - cmb.DispatchCompute(m_CSSplatUtilities, (int)KernelIndices.CalcViewData, (m_GpuView.count + (int)gsX - 1)/(int)gsX, 1, 1); + GaussianSplatSettings settings = GaussianSplatSettings.instance; + ComputeShader cs = settings.csUtilities; + cmb.SetComputeMatrixParam(cs, Props.MatrixMV, matView * matO2W); + cmb.SetComputeMatrixParam(cs, Props.MatrixObjectToWorld, matO2W); + cmb.SetComputeMatrixParam(cs, Props.MatrixWorldToObject, matW2O); + + cmb.SetComputeVectorParam(cs, Props.VecScreenParams, screenPar); + cmb.SetComputeVectorParam(cs, Props.VecWorldSpaceCameraPos, camPos); + cmb.SetComputeFloatParam(cs, Props.SplatScale, m_SplatScale); + cmb.SetComputeFloatParam(cs, Props.SplatOpacityScale, m_OpacityScale); + cmb.SetComputeIntParam(cs, Props.SHOrder, m_SHOrder); + cmb.SetComputeIntParam(cs, Props.SHOnly, settings.m_SHOnly ? 1 : 0); + + cs.GetKernelThreadGroupSizes((int)KernelIndices.CalcViewData, out uint gsX, out _, out _); + cmb.DispatchCompute(cs, (int)KernelIndices.CalcViewData, (m_GpuView.count + (int)gsX - 1)/(int)gsX, 1, 1); } internal void SortPoints(CommandBuffer cmd, Camera cam, Matrix4x4 matrix) { - if (cam.cameraType == CameraType.Preview) - return; - Matrix4x4 worldToCamMatrix = cam.worldToCameraMatrix; worldToCamMatrix.m20 *= -1; worldToCamMatrix.m21 *= -1; @@ -621,16 +689,18 @@ internal void SortPoints(CommandBuffer cmd, Camera cam, Matrix4x4 matrix) // calculate distance to the camera for each splat cmd.BeginSample(s_ProfSort); - cmd.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.CalcDistances, Props.SplatSortDistances, m_GpuSortDistances); - cmd.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.CalcDistances, Props.SplatSortKeys, m_GpuSortKeys); - cmd.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.CalcDistances, Props.SplatChunks, m_GpuChunks); - cmd.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.CalcDistances, Props.SplatPos, m_GpuPosData); - cmd.SetComputeIntParam(m_CSSplatUtilities, Props.SplatFormat, (int)m_Asset.posFormat); - cmd.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixMV, worldToCamMatrix * matrix); - cmd.SetComputeIntParam(m_CSSplatUtilities, Props.SplatCount, m_SplatCount); - cmd.SetComputeIntParam(m_CSSplatUtilities, Props.SplatChunkCount, m_GpuChunksValid ? m_GpuChunks.count : 0); - m_CSSplatUtilities.GetKernelThreadGroupSizes((int)KernelIndices.CalcDistances, out uint gsX, out _, out _); - cmd.DispatchCompute(m_CSSplatUtilities, (int)KernelIndices.CalcDistances, (m_GpuSortDistances.count + (int)gsX - 1)/(int)gsX, 1, 1); + GaussianSplatSettings settings = GaussianSplatSettings.instance; + ComputeShader cs = settings.csUtilities; + cmd.SetComputeBufferParam(cs, (int)KernelIndices.CalcDistances, Props.SplatSortDistances, m_GpuSortDistances); + cmd.SetComputeBufferParam(cs, (int)KernelIndices.CalcDistances, Props.SplatSortKeys, m_GpuSortKeys); + cmd.SetComputeBufferParam(cs, (int)KernelIndices.CalcDistances, Props.SplatChunks, m_GpuChunks); + cmd.SetComputeBufferParam(cs, (int)KernelIndices.CalcDistances, Props.SplatPos, m_GpuPosData); + cmd.SetComputeIntParam(cs, Props.SplatFormat, (int)m_Asset.posFormat); + cmd.SetComputeMatrixParam(cs, Props.MatrixMV, worldToCamMatrix * matrix); + cmd.SetComputeIntParam(cs, Props.SplatCount, m_SplatCount); + cmd.SetComputeIntParam(cs, Props.SplatChunkCount, m_GpuChunksValid ? m_GpuChunks.count : 0); + cs.GetKernelThreadGroupSizes((int)KernelIndices.CalcDistances, out uint gsX, out _, out _); + cmd.DispatchCompute(cs, (int)KernelIndices.CalcDistances, (m_GpuSortDistances.count + (int)gsX - 1)/(int)gsX, 1, 1); // sort the splats EnsureSorterAndRegister(); @@ -681,19 +751,21 @@ public void ActivateCamera(int index) void ClearGraphicsBuffer(GraphicsBuffer buf) { - m_CSSplatUtilities.SetBuffer((int)KernelIndices.ClearBuffer, Props.DstBuffer, buf); - m_CSSplatUtilities.SetInt(Props.BufferSize, buf.count); - m_CSSplatUtilities.GetKernelThreadGroupSizes((int)KernelIndices.ClearBuffer, out uint gsX, out _, out _); - m_CSSplatUtilities.Dispatch((int)KernelIndices.ClearBuffer, (int)((buf.count+gsX-1)/gsX), 1, 1); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cs.SetBuffer((int)KernelIndices.ClearBuffer, Props.DstBuffer, buf); + cs.SetInt(Props.BufferSize, buf.count); + cs.GetKernelThreadGroupSizes((int)KernelIndices.ClearBuffer, out uint gsX, out _, out _); + cs.Dispatch((int)KernelIndices.ClearBuffer, (int)((buf.count+gsX-1)/gsX), 1, 1); } void UnionGraphicsBuffers(GraphicsBuffer dst, GraphicsBuffer src) { - m_CSSplatUtilities.SetBuffer((int)KernelIndices.OrBuffers, Props.SrcBuffer, src); - m_CSSplatUtilities.SetBuffer((int)KernelIndices.OrBuffers, Props.DstBuffer, dst); - m_CSSplatUtilities.SetInt(Props.BufferSize, dst.count); - m_CSSplatUtilities.GetKernelThreadGroupSizes((int)KernelIndices.OrBuffers, out uint gsX, out _, out _); - m_CSSplatUtilities.Dispatch((int)KernelIndices.OrBuffers, (int)((dst.count+gsX-1)/gsX), 1, 1); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cs.SetBuffer((int)KernelIndices.OrBuffers, Props.SrcBuffer, src); + cs.SetBuffer((int)KernelIndices.OrBuffers, Props.DstBuffer, dst); + cs.SetInt(Props.BufferSize, dst.count); + cs.GetKernelThreadGroupSizes((int)KernelIndices.OrBuffers, out uint gsX, out _, out _); + cs.Dispatch((int)KernelIndices.OrBuffers, (int)((dst.count+gsX-1)/gsX), 1, 1); } static float SortableUintToFloat(uint v) @@ -714,15 +786,16 @@ public void UpdateEditCountsAndBounds() return; } - m_CSSplatUtilities.SetBuffer((int)KernelIndices.InitEditData, Props.DstBuffer, m_GpuEditCountsBounds); - m_CSSplatUtilities.Dispatch((int)KernelIndices.InitEditData, 1, 1, 1); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cs.SetBuffer((int)KernelIndices.InitEditData, Props.DstBuffer, m_GpuEditCountsBounds); + cs.Dispatch((int)KernelIndices.InitEditData, 1, 1, 1); using CommandBuffer cmb = new CommandBuffer(); SetAssetDataOnCS(cmb, KernelIndices.UpdateEditData); - cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.UpdateEditData, Props.DstBuffer, m_GpuEditCountsBounds); - cmb.SetComputeIntParam(m_CSSplatUtilities, Props.BufferSize, m_GpuEditSelected.count); - m_CSSplatUtilities.GetKernelThreadGroupSizes((int)KernelIndices.UpdateEditData, out uint gsX, out _, out _); - cmb.DispatchCompute(m_CSSplatUtilities, (int)KernelIndices.UpdateEditData, (int)((m_GpuEditSelected.count+gsX-1)/gsX), 1, 1); + cmb.SetComputeBufferParam(cs, (int)KernelIndices.UpdateEditData, Props.DstBuffer, m_GpuEditCountsBounds); + cmb.SetComputeIntParam(cs, Props.BufferSize, m_GpuEditSelected.count); + cs.GetKernelThreadGroupSizes((int)KernelIndices.UpdateEditData, out uint gsX, out _, out _); + cmb.DispatchCompute(cs, (int)KernelIndices.UpdateEditData, (int)((m_GpuEditSelected.count+gsX-1)/gsX), 1, 1); Graphics.ExecuteCommandBuffer(cmb); uint[] res = new uint[m_GpuEditCountsBounds.count]; @@ -825,15 +898,16 @@ public void EditUpdateSelection(Vector2 rectMin, Vector2 rectMax, Camera cam, bo using var cmb = new CommandBuffer { name = "SplatSelectionUpdate" }; SetAssetDataOnCS(cmb, KernelIndices.SelectionUpdate); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixMV, matView * matO2W); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixObjectToWorld, matO2W); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixWorldToObject, matW2O); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cmb.SetComputeMatrixParam(cs, Props.MatrixMV, matView * matO2W); + cmb.SetComputeMatrixParam(cs, Props.MatrixObjectToWorld, matO2W); + cmb.SetComputeMatrixParam(cs, Props.MatrixWorldToObject, matW2O); - cmb.SetComputeVectorParam(m_CSSplatUtilities, Props.VecScreenParams, screenPar); - cmb.SetComputeVectorParam(m_CSSplatUtilities, Props.VecWorldSpaceCameraPos, camPos); + cmb.SetComputeVectorParam(cs, Props.VecScreenParams, screenPar); + cmb.SetComputeVectorParam(cs, Props.VecWorldSpaceCameraPos, camPos); - cmb.SetComputeVectorParam(m_CSSplatUtilities, "_SelectionRect", new Vector4(rectMin.x, rectMax.y, rectMax.x, rectMin.y)); - cmb.SetComputeIntParam(m_CSSplatUtilities, Props.SelectionMode, subtract ? 0 : 1); + cmb.SetComputeVectorParam(cs, "_SelectionRect", new Vector4(rectMin.x, rectMax.y, rectMax.x, rectMin.y)); + cmb.SetComputeIntParam(cs, Props.SelectionMode, subtract ? 0 : 1); DispatchUtilsAndExecute(cmb, KernelIndices.SelectionUpdate, m_SplatCount); UpdateEditCountsAndBounds(); @@ -846,7 +920,8 @@ public void EditTranslateSelection(Vector3 localSpacePosDelta) using var cmb = new CommandBuffer { name = "SplatTranslateSelection" }; SetAssetDataOnCS(cmb, KernelIndices.TranslateSelection); - cmb.SetComputeVectorParam(m_CSSplatUtilities, Props.SelectionDelta, localSpacePosDelta); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cmb.SetComputeVectorParam(cs, Props.SelectionDelta, localSpacePosDelta); DispatchUtilsAndExecute(cmb, KernelIndices.TranslateSelection, m_SplatCount); UpdateEditCountsAndBounds(); @@ -861,12 +936,13 @@ public void EditRotateSelection(Vector3 localSpaceCenter, Matrix4x4 localToWorld using var cmb = new CommandBuffer { name = "SplatRotateSelection" }; SetAssetDataOnCS(cmb, KernelIndices.RotateSelection); - cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.RotateSelection, Props.SplatPosMouseDown, m_GpuEditPosMouseDown); - cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.RotateSelection, Props.SplatOtherMouseDown, m_GpuEditOtherMouseDown); - cmb.SetComputeVectorParam(m_CSSplatUtilities, Props.SelectionCenter, localSpaceCenter); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixObjectToWorld, localToWorld); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixWorldToObject, worldToLocal); - cmb.SetComputeVectorParam(m_CSSplatUtilities, Props.SelectionDeltaRot, new Vector4(rotation.x, rotation.y, rotation.z, rotation.w)); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cmb.SetComputeBufferParam(cs, (int)KernelIndices.RotateSelection, Props.SplatPosMouseDown, m_GpuEditPosMouseDown); + cmb.SetComputeBufferParam(cs, (int)KernelIndices.RotateSelection, Props.SplatOtherMouseDown, m_GpuEditOtherMouseDown); + cmb.SetComputeVectorParam(cs, Props.SelectionCenter, localSpaceCenter); + cmb.SetComputeMatrixParam(cs, Props.MatrixObjectToWorld, localToWorld); + cmb.SetComputeMatrixParam(cs, Props.MatrixWorldToObject, worldToLocal); + cmb.SetComputeVectorParam(cs, Props.SelectionDeltaRot, new Vector4(rotation.x, rotation.y, rotation.z, rotation.w)); DispatchUtilsAndExecute(cmb, KernelIndices.RotateSelection, m_SplatCount); UpdateEditCountsAndBounds(); @@ -882,11 +958,12 @@ public void EditScaleSelection(Vector3 localSpaceCenter, Matrix4x4 localToWorld, using var cmb = new CommandBuffer { name = "SplatScaleSelection" }; SetAssetDataOnCS(cmb, KernelIndices.ScaleSelection); - cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.ScaleSelection, Props.SplatPosMouseDown, m_GpuEditPosMouseDown); - cmb.SetComputeVectorParam(m_CSSplatUtilities, Props.SelectionCenter, localSpaceCenter); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixObjectToWorld, localToWorld); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixWorldToObject, worldToLocal); - cmb.SetComputeVectorParam(m_CSSplatUtilities, Props.SelectionDelta, scale); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cmb.SetComputeBufferParam(cs, (int)KernelIndices.ScaleSelection, Props.SplatPosMouseDown, m_GpuEditPosMouseDown); + cmb.SetComputeVectorParam(cs, Props.SelectionCenter, localSpaceCenter); + cmb.SetComputeMatrixParam(cs, Props.MatrixObjectToWorld, localToWorld); + cmb.SetComputeMatrixParam(cs, Props.MatrixWorldToObject, worldToLocal); + cmb.SetComputeVectorParam(cs, Props.SelectionDelta, scale); DispatchUtilsAndExecute(cmb, KernelIndices.ScaleSelection, m_SplatCount); UpdateEditCountsAndBounds(); @@ -908,8 +985,9 @@ public void EditSelectAll() if (!EnsureEditingBuffers()) return; using var cmb = new CommandBuffer { name = "SplatSelectAll" }; SetAssetDataOnCS(cmb, KernelIndices.SelectAll); - cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.SelectAll, Props.DstBuffer, m_GpuEditSelected); - cmb.SetComputeIntParam(m_CSSplatUtilities, Props.BufferSize, m_GpuEditSelected.count); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cmb.SetComputeBufferParam(cs, (int)KernelIndices.SelectAll, Props.DstBuffer, m_GpuEditSelected); + cmb.SetComputeIntParam(cs, Props.BufferSize, m_GpuEditSelected.count); DispatchUtilsAndExecute(cmb, KernelIndices.SelectAll, m_GpuEditSelected.count); UpdateEditCountsAndBounds(); } @@ -927,8 +1005,9 @@ public void EditInvertSelection() using var cmb = new CommandBuffer { name = "SplatInvertSelection" }; SetAssetDataOnCS(cmb, KernelIndices.InvertSelection); - cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.InvertSelection, Props.DstBuffer, m_GpuEditSelected); - cmb.SetComputeIntParam(m_CSSplatUtilities, Props.BufferSize, m_GpuEditSelected.count); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cmb.SetComputeBufferParam(cs, (int)KernelIndices.InvertSelection, Props.DstBuffer, m_GpuEditSelected); + cmb.SetComputeIntParam(cs, Props.BufferSize, m_GpuEditSelected.count); DispatchUtilsAndExecute(cmb, KernelIndices.InvertSelection, m_GpuEditSelected.count); UpdateEditCountsAndBounds(); } @@ -947,11 +1026,12 @@ public bool EditExportData(GraphicsBuffer dstData, bool bakeTransform) using var cmb = new CommandBuffer { name = "SplatExportData" }; SetAssetDataOnCS(cmb, KernelIndices.ExportData); - cmb.SetComputeIntParam(m_CSSplatUtilities, "_ExportTransformFlags", flags); - cmb.SetComputeVectorParam(m_CSSplatUtilities, "_ExportTransformRotation", new Vector4(bakeRot.x, bakeRot.y, bakeRot.z, bakeRot.w)); - cmb.SetComputeVectorParam(m_CSSplatUtilities, "_ExportTransformScale", bakeScale); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, Props.MatrixObjectToWorld, tr.localToWorldMatrix); - cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.ExportData, "_ExportBuffer", dstData); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cmb.SetComputeIntParam(cs, "_ExportTransformFlags", flags); + cmb.SetComputeVectorParam(cs, "_ExportTransformRotation", new Vector4(bakeRot.x, bakeRot.y, bakeRot.z, bakeRot.w)); + cmb.SetComputeVectorParam(cs, "_ExportTransformScale", bakeScale); + cmb.SetComputeMatrixParam(cs, Props.MatrixObjectToWorld, tr.localToWorldMatrix); + cmb.SetComputeBufferParam(cs, (int)KernelIndices.ExportData, "_ExportBuffer", dstData); DispatchUtilsAndExecute(cmb, KernelIndices.ExportData, m_SplatCount); return true; @@ -1056,28 +1136,30 @@ public void EditCopySplats( using var cmb = new CommandBuffer { name = "SplatCopy" }; SetAssetDataOnCS(cmb, KernelIndices.CopySplats); - cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.CopySplats, "_CopyDstPos", dstPos); - cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.CopySplats, "_CopyDstOther", dstOther); - cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.CopySplats, "_CopyDstSH", dstSH); - cmb.SetComputeTextureParam(m_CSSplatUtilities, (int)KernelIndices.CopySplats, "_CopyDstColor", dstColor); - cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.CopySplats, "_CopyDstEditDeleted", dstEditDeleted); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cmb.SetComputeBufferParam(cs, (int)KernelIndices.CopySplats, "_CopyDstPos", dstPos); + cmb.SetComputeBufferParam(cs, (int)KernelIndices.CopySplats, "_CopyDstOther", dstOther); + cmb.SetComputeBufferParam(cs, (int)KernelIndices.CopySplats, "_CopyDstSH", dstSH); + cmb.SetComputeTextureParam(cs, (int)KernelIndices.CopySplats, "_CopyDstColor", dstColor); + cmb.SetComputeBufferParam(cs, (int)KernelIndices.CopySplats, "_CopyDstEditDeleted", dstEditDeleted); - cmb.SetComputeIntParam(m_CSSplatUtilities, "_CopyDstSize", dstSize); - cmb.SetComputeIntParam(m_CSSplatUtilities, "_CopySrcStartIndex", copySrcStartIndex); - cmb.SetComputeIntParam(m_CSSplatUtilities, "_CopyDstStartIndex", copyDstStartIndex); - cmb.SetComputeIntParam(m_CSSplatUtilities, "_CopyCount", copyCount); + cmb.SetComputeIntParam(cs, "_CopyDstSize", dstSize); + cmb.SetComputeIntParam(cs, "_CopySrcStartIndex", copySrcStartIndex); + cmb.SetComputeIntParam(cs, "_CopyDstStartIndex", copyDstStartIndex); + cmb.SetComputeIntParam(cs, "_CopyCount", copyCount); - cmb.SetComputeVectorParam(m_CSSplatUtilities, "_CopyTransformRotation", new Vector4(copyRot.x, copyRot.y, copyRot.z, copyRot.w)); - cmb.SetComputeVectorParam(m_CSSplatUtilities, "_CopyTransformScale", copyScale); - cmb.SetComputeMatrixParam(m_CSSplatUtilities, "_CopyTransformMatrix", copyMatrix); + cmb.SetComputeVectorParam(cs, "_CopyTransformRotation", new Vector4(copyRot.x, copyRot.y, copyRot.z, copyRot.w)); + cmb.SetComputeVectorParam(cs, "_CopyTransformScale", copyScale); + cmb.SetComputeMatrixParam(cs, "_CopyTransformMatrix", copyMatrix); DispatchUtilsAndExecute(cmb, KernelIndices.CopySplats, copyCount); } void DispatchUtilsAndExecute(CommandBuffer cmb, KernelIndices kernel, int count) { - m_CSSplatUtilities.GetKernelThreadGroupSizes((int)kernel, out uint gsX, out _, out _); - cmb.DispatchCompute(m_CSSplatUtilities, (int)kernel, (int)((count + gsX - 1)/gsX), 1, 1); + ComputeShader cs = GaussianSplatSettings.instance.csUtilities; + cs.GetKernelThreadGroupSizes((int)kernel, out uint gsX, out _, out _); + cmb.DispatchCompute(cs, (int)kernel, (int)((count + gsX - 1)/gsX), 1, 1); Graphics.ExecuteCommandBuffer(cmb); } diff --git a/package/Runtime/GaussianSplatRenderer.cs.meta b/package/Runtime/GaussianSplatRenderer.cs.meta index 5c089e16..0acc925f 100644 --- a/package/Runtime/GaussianSplatRenderer.cs.meta +++ b/package/Runtime/GaussianSplatRenderer.cs.meta @@ -3,13 +3,7 @@ guid: c12d929a7f62c48adbe9ff45c9a33ff0 MonoImporter: externalObjects: {} serializedVersion: 2 - defaultReferences: - - m_ShaderSplats: {fileID: 4800000, guid: ed800126ae8844a67aad1974ddddd59c, type: 3} - - m_ShaderComposite: {fileID: 4800000, guid: 7e184af7d01193a408eb916d8acafff9, type: 3} - - m_ShaderDebugPoints: {fileID: 4800000, guid: b44409fc67214394f8f47e4e2648425e, type: 3} - - m_ShaderDebugBoxes: {fileID: 4800000, guid: 4006f2680fd7c8b4cbcb881454c782be, type: 3} - - m_CSSplatUtilities: {fileID: 7200000, guid: ec84f78b836bd4f96a105d6b804f08bd, type: 3} - - m_CSFfxSort: {fileID: 7200000, guid: dec36776b6c843544a1f6f9b436a4474, type: 3} + defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: diff --git a/package/Runtime/GaussianSplatSettings.cs b/package/Runtime/GaussianSplatSettings.cs new file mode 100644 index 00000000..a16537fc --- /dev/null +++ b/package/Runtime/GaussianSplatSettings.cs @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT + +using UnityEngine; + +namespace GaussianSplatting.Runtime +{ + public enum TransparencyMode + { + // sort splats within each gaussian point cloud, blend back to front + SortedBlended, + // no sorting, transparency is stochastic (random) and noisy + Stochastic, + } + + public enum TemporalFilter + { + None, + TemporalNoMotion, + } + + public enum DebugRenderMode + { + Splats, + DebugPoints, + DebugPointIndices, + DebugBoxes, + DebugChunkBounds, + } + + // If an object with this script exists in the scene, then global 3DGS rendering options + // are used from that script. Otherwise, defaults are used. + // + [ExecuteInEditMode] // so that Awake is called in edit mode + [DefaultExecutionOrder(-100)] + public class GaussianSplatSettings : MonoBehaviour + { + public static GaussianSplatSettings instance + { + get + { + if (ms_Instance == null) + ms_Instance = FindAnyObjectByType(); + if (ms_Instance == null) + { + var go = new GameObject($"{nameof(GaussianSplatSettings)} (Defaults)") + { + hideFlags = HideFlags.HideAndDontSave + }; + ms_Instance = go.AddComponent(); + ms_Instance.EnsureResources(); + } + return ms_Instance; + } + } + static GaussianSplatSettings ms_Instance; + + [Tooltip("Gaussian splat transparency rendering algorithm")] + public TransparencyMode m_Transparency = TransparencyMode.SortedBlended; + + [Range(1,30)] [Tooltip("Sort splats only every N frames")] + public int m_SortNthFrame = 1; + + [Tooltip("How to filter temporal transparency")] + public TemporalFilter m_TemporalFilter = TemporalFilter.TemporalNoMotion; + [Tooltip("How much of new frame to blend in. Higher: more noise, lower: more ghosting.")] + [Range(0.001f, 1.0f)] public float m_FrameInfluence = 0.05f; + [Tooltip("Strength of history color rectification clamp. Lower: more flickering, higher: more blur/ghosting.")] + [Range(0.001f, 10.0f)] public float m_VarianceClampScale = 1.5f; + + public DebugRenderMode m_RenderMode = DebugRenderMode.Splats; + [Range(1.0f,15.0f)] public float m_PointDisplaySize = 3.0f; + [Tooltip("Show only Spherical Harmonics contribution, using gray color")] + public bool m_SHOnly; + + internal bool isDebugRender => m_RenderMode != DebugRenderMode.Splats; + + internal bool needSorting => + (!isDebugRender && m_Transparency == TransparencyMode.SortedBlended) || + m_RenderMode == DebugRenderMode.DebugBoxes; + + internal bool resourcesFound { get; private set; } + bool resourcesLoadAttempted; + internal Shader shaderSplats { get; private set; } + internal Shader shaderComposite { get; private set; } + internal Shader shaderDebugPoints { get; private set; } + internal Shader shaderDebugBoxes { get; private set; } + internal ComputeShader csUtilities { get; private set; } + + void Awake() + { + if (ms_Instance != null && ms_Instance != this) + DestroyImmediate(ms_Instance.gameObject); + ms_Instance = this; + EnsureResources(); + } + + void EnsureResources() + { + if (resourcesLoadAttempted) + return; + resourcesLoadAttempted = true; + + shaderSplats = Resources.Load("GaussianSplats"); + shaderComposite = Resources.Load("GaussianComposite"); + shaderDebugPoints = Resources.Load("GaussianDebugRenderPoints"); + shaderDebugBoxes = Resources.Load("GaussianDebugRenderBoxes"); + csUtilities = Resources.Load("GaussianSplatUtilities"); + + resourcesFound = + shaderSplats != null && shaderComposite != null && shaderDebugPoints != null && shaderDebugBoxes != null && + csUtilities != null && + SystemInfo.supportsComputeShaders; + UpdateGlobalOptions(); + } + + void OnValidate() + { + UpdateGlobalOptions(); + } + + void OnDidApplyAnimationProperties() + { + UpdateGlobalOptions(); + } + + void UpdateGlobalOptions() + { + // nothing just yet + } + } +} diff --git a/package/Runtime/GaussianSplatSettings.cs.meta b/package/Runtime/GaussianSplatSettings.cs.meta new file mode 100644 index 00000000..e9e32854 --- /dev/null +++ b/package/Runtime/GaussianSplatSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9344df23bed5464c9e1e40f77e03e0b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: -100 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Runtime/GaussianSplatTemporalFilter.cs b/package/Runtime/GaussianSplatTemporalFilter.cs new file mode 100644 index 00000000..6a9604d3 --- /dev/null +++ b/package/Runtime/GaussianSplatTemporalFilter.cs @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT + +using UnityEngine; +using UnityEngine.Experimental.Rendering; +using UnityEngine.Rendering; +using UnityEngine.XR; +using Object = UnityEngine.Object; + +namespace GaussianSplatting.Runtime +{ + public class GaussianSplatTemporalFilter + { + static class Props + { + public static readonly int _TaaAccumulationTex = Shader.PropertyToID("_TaaAccumulationTex"); + public static readonly int _TaaFrameInfluence = Shader.PropertyToID("_TaaFrameInfluence"); + public static readonly int _TaaVarianceClampScale = Shader.PropertyToID("_TaaVarianceClampScale"); + } + + int m_CurWidth = -1, m_CurHeight = -1; + RenderTexture m_AccumulationTexture; + RenderTexture m_TempTexture; + + public void Dispose() + { + Object.DestroyImmediate(m_AccumulationTexture); m_AccumulationTexture = null; + Object.DestroyImmediate(m_TempTexture); m_TempTexture = null; + m_CurWidth = -1; + m_CurHeight = -1; + } + + public void Render( + CommandBuffer cmb, + Camera camera, + Material material, + int passIndex, + RenderTargetIdentifier srcSplatColor, + RenderTargetIdentifier dstComposedColor, + float frameInfluence, + float varianceClampScale) + { + int screenW = camera.pixelWidth, screenH = camera.pixelHeight; + int eyeW = XRSettings.eyeTextureWidth, eyeH = XRSettings.eyeTextureHeight; + int width = eyeW != 0 ? eyeW : screenW; + int height = eyeH != 0 ? eyeH : screenH; + + float taaFrameInfluence = frameInfluence; + + if (width != m_CurWidth || height != m_CurHeight || m_AccumulationTexture == null || m_TempTexture == null) + { + Object.DestroyImmediate(m_AccumulationTexture); + Object.DestroyImmediate(m_TempTexture); + m_CurWidth = width; + m_CurHeight = height; + + RenderTextureDescriptor desc = default; + desc.width = m_CurWidth; + desc.height = m_CurHeight; + desc.msaaSamples = 1; + desc.volumeDepth = 1; + desc.graphicsFormat = GraphicsFormat.R16G16B16A16_SFloat; + desc.dimension = TextureDimension.Tex2D; + m_AccumulationTexture = new RenderTexture(desc); + m_TempTexture = new RenderTexture(desc); + taaFrameInfluence = 1.0f; // copy input into history when initializing/resizing + } + + // sample new frame & history -> output temp buffer + cmb.SetRenderTarget(m_TempTexture); + material.SetFloat(Props._TaaFrameInfluence, taaFrameInfluence); + material.SetFloat(Props._TaaVarianceClampScale, varianceClampScale); + material.SetTexture(Props._TaaAccumulationTex, m_AccumulationTexture); + cmb.DrawProcedural(Matrix4x4.identity, material, passIndex, MeshTopology.Triangles, 3, 1); + + // copy temp buffer -> into history + cmb.CopyTexture(m_TempTexture, m_AccumulationTexture); + + // composite temp buffer into output + cmb.CopyTexture(m_TempTexture, srcSplatColor); + cmb.SetRenderTarget(dstComposedColor); + cmb.DrawProcedural(Matrix4x4.identity, material, 0, MeshTopology.Triangles, 3, 1); + } + } +} \ No newline at end of file diff --git a/package/Runtime/GaussianSplatTemporalFilter.cs.meta b/package/Runtime/GaussianSplatTemporalFilter.cs.meta new file mode 100644 index 00000000..3198d18f --- /dev/null +++ b/package/Runtime/GaussianSplatTemporalFilter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b0c9c1792b905bf40b072ed9e007f375 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Runtime/GaussianSplatURPFeature.cs b/package/Runtime/GaussianSplatURPFeature.cs index cab17475..e22a893f 100644 --- a/package/Runtime/GaussianSplatURPFeature.cs +++ b/package/Runtime/GaussianSplatURPFeature.cs @@ -40,34 +40,61 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer { using var builder = renderGraph.AddUnsafePass(ProfilerTag, out PassData passData); + var settings = GaussianSplatSettings.instance; + var usingRT = !settings.isDebugRender; var cameraData = frameData.Get(); var resourceData = frameData.Get(); - RenderTextureDescriptor rtDesc = cameraData.cameraTargetDescriptor; - rtDesc.depthBufferBits = 0; - rtDesc.msaaSamples = 1; - rtDesc.graphicsFormat = GraphicsFormat.R16G16B16A16_SFloat; - var textureHandle = UniversalRenderer.CreateRenderGraphTexture(renderGraph, rtDesc, GaussianSplatRTName, true); - passData.CameraData = cameraData; + + if (usingRT) + { + RenderTextureDescriptor rtDesc = cameraData.cameraTargetDescriptor; + rtDesc.depthBufferBits = 0; + rtDesc.msaaSamples = 1; + rtDesc.graphicsFormat = GraphicsFormat.R16G16B16A16_SFloat; + var textureHandle = UniversalRenderer.CreateRenderGraphTexture(renderGraph, rtDesc, GaussianSplatRTName, true); + passData.GaussianSplatRT = textureHandle; + builder.UseTexture(textureHandle, AccessFlags.Write); + } passData.SourceTexture = resourceData.activeColorTexture; passData.SourceDepth = resourceData.activeDepthTexture; - passData.GaussianSplatRT = textureHandle; - builder.UseTexture(resourceData.activeColorTexture, AccessFlags.ReadWrite); builder.UseTexture(resourceData.activeDepthTexture); - builder.UseTexture(textureHandle, AccessFlags.Write); + builder.AllowPassCulling(false); builder.SetRenderFunc(static (PassData data, UnsafeGraphContext context) => { + var system = GaussianSplatRenderSystem.instance; + system.EnsureMaterials(); + var matComposite = system.m_MatComposite; + if (matComposite == null) + return; + + var settings = GaussianSplatSettings.instance; + var usingRT = !settings.isDebugRender; + var commandBuffer = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd); using var _ = new ProfilingScope(commandBuffer, s_profilingSampler); - commandBuffer.SetGlobalTexture(s_gaussianSplatRT, data.GaussianSplatRT); - CoreUtils.SetRenderTarget(commandBuffer, data.GaussianSplatRT, data.SourceDepth, ClearFlag.Color, Color.clear); - Material matComposite = GaussianSplatRenderSystem.instance.SortAndRenderSplats(data.CameraData.camera, commandBuffer); - commandBuffer.BeginSample(GaussianSplatRenderSystem.s_ProfCompose); - Blitter.BlitCameraTexture(commandBuffer, data.GaussianSplatRT, data.SourceTexture, matComposite, 0); - commandBuffer.EndSample(GaussianSplatRenderSystem.s_ProfCompose); + + if (usingRT) + { + commandBuffer.SetGlobalTexture(s_gaussianSplatRT, data.GaussianSplatRT); + CoreUtils.SetRenderTarget(commandBuffer, data.GaussianSplatRT, data.SourceDepth, ClearFlag.Color, Color.clear); + } + else + { + CoreUtils.SetRenderTarget(commandBuffer, data.SourceTexture, data.SourceDepth, ClearFlag.None); + } + system.SortAllSplats(data.CameraData.camera, commandBuffer); + system.CacheViewDataForAllSplats(data.CameraData.camera, commandBuffer); + system.RenderAllSplats(data.CameraData.camera, commandBuffer); + if (usingRT) + { + commandBuffer.BeginSample(GaussianSplatRenderSystem.s_ProfCompose); + Blitter.BlitCameraTexture(commandBuffer, data.GaussianSplatRT, data.SourceTexture, matComposite, 0); + commandBuffer.EndSample(GaussianSplatRenderSystem.s_ProfCompose); + } }); } } diff --git a/package/Shaders/Resources.meta b/package/Shaders/Resources.meta new file mode 100644 index 00000000..7ad08306 --- /dev/null +++ b/package/Shaders/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8a90b8b6029258c41848c5ad59c4021c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package/Shaders/DeviceRadixSort.hlsl b/package/Shaders/Resources/DeviceRadixSort.hlsl similarity index 100% rename from package/Shaders/DeviceRadixSort.hlsl rename to package/Shaders/Resources/DeviceRadixSort.hlsl diff --git a/package/Shaders/DeviceRadixSort.hlsl.meta b/package/Shaders/Resources/DeviceRadixSort.hlsl.meta similarity index 100% rename from package/Shaders/DeviceRadixSort.hlsl.meta rename to package/Shaders/Resources/DeviceRadixSort.hlsl.meta diff --git a/package/Shaders/GaussianComposite.shader b/package/Shaders/Resources/GaussianComposite.shader similarity index 52% rename from package/Shaders/GaussianComposite.shader rename to package/Shaders/Resources/GaussianComposite.shader index be1702c7..7916de44 100644 --- a/package/Shaders/GaussianComposite.shader +++ b/package/Shaders/Resources/GaussianComposite.shader @@ -1,16 +1,7 @@ // SPDX-License-Identifier: MIT Shader "Hidden/Gaussian Splatting/Composite" { - SubShader - { - Pass - { - ZWrite Off - ZTest Always - Cull Off - Blend SrcAlpha OneMinusSrcAlpha - -CGPROGRAM +CGINCLUDE #pragma vertex vert #pragma fragment frag #pragma require compute @@ -20,6 +11,7 @@ CGPROGRAM struct v2f { float4 vertex : SV_POSITION; + float2 uv : TEXCOORD0; }; v2f vert (uint vtxID : SV_VertexID) @@ -27,11 +19,25 @@ v2f vert (uint vtxID : SV_VertexID) v2f o; float2 quadPos = float2(vtxID&1, (vtxID>>1)&1) * 4.0 - 1.0; o.vertex = float4(quadPos, 1, 1); + o.uv = quadPos * 0.5 + 0.5; + o.uv.y = 1 - o.uv.y; return o; } +ENDCG + SubShader + { + ZWrite Off + ZTest Always + Cull Off -Texture2D _GaussianSplatRT; + // Composite rendered gaussian splats onto regularly rendered scene. + // Splats are rendered in sRGB, effectively, so need to decode that. + Pass + { + Blend SrcAlpha OneMinusSrcAlpha +CGPROGRAM +Texture2D _GaussianSplatRT; half4 frag (v2f i) : SV_Target { half4 col = _GaussianSplatRT.Load(int3(i.vertex.xy, 0)); @@ -39,6 +45,25 @@ half4 frag (v2f i) : SV_Target col.a = saturate(col.a * 1.5); return col; } +ENDCG + } + + // Do TAA-like temporal filter for gaussian splats + Pass + { + Blend Off + +CGPROGRAM +// Very Low: #define TAA_YCOCG 0, params 0,0,0 +// Low: #define TAA_YCOCG 0, params 0,1,1 +// Medium: params 2,2,1 +// High: params 2,2,2 +#include "TemporalFilter.hlsl" + +half4 frag (v2f i) : SV_Target +{ + return DoTemporalAA(i.uv, 2, 2, 2); +} ENDCG } } diff --git a/package/Shaders/GaussianComposite.shader.meta b/package/Shaders/Resources/GaussianComposite.shader.meta similarity index 100% rename from package/Shaders/GaussianComposite.shader.meta rename to package/Shaders/Resources/GaussianComposite.shader.meta diff --git a/package/Shaders/GaussianDebugRenderBoxes.shader b/package/Shaders/Resources/GaussianDebugRenderBoxes.shader similarity index 98% rename from package/Shaders/GaussianDebugRenderBoxes.shader rename to package/Shaders/Resources/GaussianDebugRenderBoxes.shader index 752ecd8e..70d6d077 100644 --- a/package/Shaders/GaussianDebugRenderBoxes.shader +++ b/package/Shaders/Resources/GaussianDebugRenderBoxes.shader @@ -93,6 +93,7 @@ v2f vert (uint vtxID : SV_VertexID, uint instID : SV_InstanceID) half4 frag (v2f i) : SV_Target { + i.col.rgb = GammaToLinearSpace(i.col.rgb); half4 res = half4(i.col.rgb * i.col.a, i.col.a); return res; } diff --git a/package/Shaders/GaussianDebugRenderBoxes.shader.meta b/package/Shaders/Resources/GaussianDebugRenderBoxes.shader.meta similarity index 100% rename from package/Shaders/GaussianDebugRenderBoxes.shader.meta rename to package/Shaders/Resources/GaussianDebugRenderBoxes.shader.meta diff --git a/package/Shaders/GaussianDebugRenderPoints.shader b/package/Shaders/Resources/GaussianDebugRenderPoints.shader similarity index 95% rename from package/Shaders/GaussianDebugRenderPoints.shader rename to package/Shaders/Resources/GaussianDebugRenderPoints.shader index d9732e08..6174a232 100644 --- a/package/Shaders/GaussianDebugRenderPoints.shader +++ b/package/Shaders/Resources/GaussianDebugRenderPoints.shader @@ -17,6 +17,7 @@ CGPROGRAM #pragma use_dxc #include "GaussianSplatting.hlsl" +#include "UnityCG.cginc" struct v2f { @@ -59,6 +60,7 @@ v2f vert (uint vtxID : SV_VertexID, uint instID : SV_InstanceID) half4 frag (v2f i) : SV_Target { + i.color.rgb = GammaToLinearSpace(i.color.rgb); return half4(i.color.rgb, 1); } ENDCG diff --git a/package/Shaders/GaussianDebugRenderPoints.shader.meta b/package/Shaders/Resources/GaussianDebugRenderPoints.shader.meta similarity index 100% rename from package/Shaders/GaussianDebugRenderPoints.shader.meta rename to package/Shaders/Resources/GaussianDebugRenderPoints.shader.meta diff --git a/package/Shaders/SplatUtilities.compute b/package/Shaders/Resources/GaussianSplatUtilities.compute similarity index 100% rename from package/Shaders/SplatUtilities.compute rename to package/Shaders/Resources/GaussianSplatUtilities.compute diff --git a/package/Shaders/SplatUtilities.compute.meta b/package/Shaders/Resources/GaussianSplatUtilities.compute.meta similarity index 100% rename from package/Shaders/SplatUtilities.compute.meta rename to package/Shaders/Resources/GaussianSplatUtilities.compute.meta diff --git a/package/Shaders/RenderGaussianSplats.shader b/package/Shaders/Resources/GaussianSplats.shader similarity index 58% rename from package/Shaders/RenderGaussianSplats.shader rename to package/Shaders/Resources/GaussianSplats.shader index 540a9f5b..017e0423 100644 --- a/package/Shaders/RenderGaussianSplats.shader +++ b/package/Shaders/Resources/GaussianSplats.shader @@ -1,14 +1,20 @@ // SPDX-License-Identifier: MIT Shader "Gaussian Splatting/Render Splats" { + Properties + { + _SrcBlend("Src Blend", Float) = 8 // OneMinusDstAlpha + _DstBlend("Dst Blend", Float) = 1 // One + _ZWrite("ZWrite", Float) = 0 // Off + } SubShader { Tags { "RenderType"="Transparent" "Queue"="Transparent" } Pass { - ZWrite Off - Blend OneMinusDstAlpha One + ZWrite [_ZWrite] + Blend [_SrcBlend] [_DstBlend] Cull Off CGPROGRAM @@ -25,9 +31,19 @@ struct v2f { half4 col : COLOR0; float2 pos : TEXCOORD0; + uint idx : TEXCOORD1; float4 vertex : SV_POSITION; }; +// reason for using a separate uniform buffer is DX12 +// stale uniform variable bug in Unity 2022.3/6000.0 at least, +// "IN-99220 - DX12 stale render state issue with a sequence of compute shader & DrawProcedural calls" +cbuffer SplatGlobalUniforms // match struct SplatGlobalUniforms in C# +{ + uint sgu_transparencyMode; + uint sgu_frameOffset; +} + StructuredBuffer _SplatViewData; ByteAddressBuffer _SplatSelectedBits; uint _SplatBitsValid; @@ -35,7 +51,9 @@ uint _SplatBitsValid; v2f vert (uint vtxID : SV_VertexID, uint instID : SV_InstanceID) { v2f o = (v2f)0; - instID = _OrderBuffer[instID]; + if (sgu_transparencyMode == 0) + instID = _OrderBuffer[instID]; + o.idx = instID + sgu_frameOffset; SplatViewData view = _SplatViewData[instID]; float4 centerClipPos = view.pos; bool behindCam = centerClipPos.w <= 0; @@ -76,6 +94,24 @@ v2f vert (uint vtxID : SV_VertexID, uint instID : SV_InstanceID) return o; } +// Hash Functions for GPU Rendering +// https://jcgt.org/published/0009/03/02/ +uint3 pcg3d16(uint3 v) +{ + v = v * 12829u + 47989u; + + v.x += v.y*v.z; + v.y += v.z*v.x; + v.z += v.x*v.y; + + v.x += v.y*v.z; + v.y += v.z*v.x; + v.z += v.x*v.y; + + v >>= 16u; + return v; +} + half4 frag (v2f i) : SV_Target { float power = -dot(i.pos, i.pos); @@ -103,7 +139,24 @@ half4 frag (v2f i) : SV_Target if (alpha < 1.0/255.0) discard; - half4 res = half4(i.col.rgb * alpha, alpha); + if (sgu_transparencyMode == 0) + { + i.col.rgb *= alpha; + } + else + { + // "Hashed Alpha Testing", Wyman, McGuire 2017 + // https://casual-effects.com/research/Wyman2017Hashed/index.html + // Uses pcg3d16 hash from https://jcgt.org/published/0009/03/02/ + uint3 coord = uint3(i.vertex.x, i.vertex.y, i.idx); + uint3 hash = pcg3d16(coord); + half cutoff = (hash.x & 0xFFFF) / 65535.0; + if (alpha <= cutoff) + discard; + //alpha = i.vertex.z / i.vertex.w; //@TODO: write depth to alpha for when we'll start doing motion + alpha = 1; + } + half4 res = half4(i.col.rgb, alpha); return res; } ENDCG diff --git a/package/Shaders/RenderGaussianSplats.shader.meta b/package/Shaders/Resources/GaussianSplats.shader.meta similarity index 100% rename from package/Shaders/RenderGaussianSplats.shader.meta rename to package/Shaders/Resources/GaussianSplats.shader.meta diff --git a/package/Shaders/GaussianSplatting.hlsl b/package/Shaders/Resources/GaussianSplatting.hlsl similarity index 100% rename from package/Shaders/GaussianSplatting.hlsl rename to package/Shaders/Resources/GaussianSplatting.hlsl diff --git a/package/Shaders/GaussianSplatting.hlsl.meta b/package/Shaders/Resources/GaussianSplatting.hlsl.meta similarity index 100% rename from package/Shaders/GaussianSplatting.hlsl.meta rename to package/Shaders/Resources/GaussianSplatting.hlsl.meta diff --git a/package/Shaders/SortCommon.hlsl b/package/Shaders/Resources/SortCommon.hlsl similarity index 100% rename from package/Shaders/SortCommon.hlsl rename to package/Shaders/Resources/SortCommon.hlsl diff --git a/package/Shaders/SortCommon.hlsl.meta b/package/Shaders/Resources/SortCommon.hlsl.meta similarity index 100% rename from package/Shaders/SortCommon.hlsl.meta rename to package/Shaders/Resources/SortCommon.hlsl.meta diff --git a/package/Shaders/SphericalHarmonics.hlsl b/package/Shaders/Resources/SphericalHarmonics.hlsl similarity index 100% rename from package/Shaders/SphericalHarmonics.hlsl rename to package/Shaders/Resources/SphericalHarmonics.hlsl diff --git a/package/Shaders/SphericalHarmonics.hlsl.meta b/package/Shaders/Resources/SphericalHarmonics.hlsl.meta similarity index 100% rename from package/Shaders/SphericalHarmonics.hlsl.meta rename to package/Shaders/Resources/SphericalHarmonics.hlsl.meta diff --git a/package/Shaders/Resources/TemporalFilter.hlsl b/package/Shaders/Resources/TemporalFilter.hlsl new file mode 100644 index 00000000..97f3d957 --- /dev/null +++ b/package/Shaders/Resources/TemporalFilter.hlsl @@ -0,0 +1,362 @@ +// Based on very trimmed down version of Unity's URP TAA, +// https://github.com/Unity-Technologies/Graphics/blob/81a1ed4/Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/TemporalAA.hlsl +// +// Currently none of motion stuff is used, so this is not much more than +// just a stupid accumulation buffer type of thing. + +#include "HLSLSupport.cginc" + +#ifndef TAA_YCOCG +#define TAA_YCOCG 1 +#endif + +#define TAA_GAMMA_SPACE_POST 1 // splats are rendered in sRGB + +#ifndef TAA_PERCEPTUAL_SPACE +#define TAA_PERCEPTUAL_SPACE 1 +#endif + +#define HALF_MIN 6.103515625e-5 // 2^-14, the same value for 10, 11 and 16-bit: https://www.khronos.org/opengl/wiki/Small_Float_Formats + +// This function take a rgb color (best is to provide color in sRGB space) +// and return a YCoCg color in [0..1] space for 8bit (An offset is apply in the function) +// Ref: http://www.nvidia.com/object/real-time-ycocg-dxt-compression.html +#define YCOCG_CHROMA_BIAS (128.0 / 255.0) +half3 RGBToYCoCg(half3 rgb) +{ + half3 YCoCg; + YCoCg.x = dot(rgb, half3(0.25, 0.5, 0.25)); + YCoCg.y = dot(rgb, half3(0.5, 0.0, -0.5)) + YCOCG_CHROMA_BIAS; + YCoCg.z = dot(rgb, half3(-0.25, 0.5, -0.25)) + YCOCG_CHROMA_BIAS; + return YCoCg; +} + +half3 YCoCgToRGB(half3 YCoCg) +{ + half Y = YCoCg.x; + half Co = YCoCg.y - YCOCG_CHROMA_BIAS; + half Cg = YCoCg.z - YCOCG_CHROMA_BIAS; + half3 rgb; + rgb.r = Y + Co - Cg; + rgb.g = Y + Cg; + rgb.b = Y - Co - Cg; + return rgb; +} + +half Max3(half a, half b, half c) { return max(max(a, b), c); } + +Texture2D _CameraDepthTexture; +Texture2D _GaussianSplatRT; +float4 _GaussianSplatRT_TexelSize; +Texture2D _TaaMotionVectorTex; +Texture2D _TaaAccumulationTex; + +cbuffer TemporalAAData { + float4 _TaaMotionVectorTex_TexelSize; // (1/w, 1/h, w, h) + float4 _TaaAccumulationTex_TexelSize; // (1/w, 1/h, w, h) + + half _TaaFrameInfluence; + half _TaaVarianceClampScale; +} +SamplerState sampler_LinearClamp, sampler_PointClamp; + +// Per-pixel camera backwards velocity +half2 GetVelocityWithOffset(float2 uv, half2 depthOffsetUv) +{ + // Unity motion vectors are forward motion vectors in screen UV space + half2 offsetUv = _TaaMotionVectorTex.Sample(sampler_LinearClamp, uv + _TaaMotionVectorTex_TexelSize.xy * depthOffsetUv).xy; + return -offsetUv; +} + +void AdjustBestDepthOffset(inout half bestDepth, inout half bestX, inout half bestY, float2 uv, half currX, half currY) +{ + // Half precision should be fine, as we are only concerned about choosing the better value along sharp edges, so it's + // acceptable to have banding on continuous surfaces + half depth = _CameraDepthTexture.Sample(sampler_PointClamp, uv.xy + _GaussianSplatRT_TexelSize.xy * half2(currX, currY)).r; + +#if UNITY_REVERSED_Z + depth = 1.0 - depth; +#endif + + bool isBest = depth < bestDepth; + bestDepth = isBest ? depth : bestDepth; + bestX = isBest ? currX : bestX; + bestY = isBest ? currY : bestY; +} + +float GetLuma(float3 color) +{ +#if TAA_YCOCG + // We work in YCoCg hence the luminance is in the first channel. + return color.x; +#else + return Luminance(color.xyz); +#endif +} + +float PerceptualWeight(float3 c) +{ +#if TAA_PERCEPTUAL_SPACE + return rcp(GetLuma(c) + 1.0); +#else + return 1; +#endif +} + +float PerceptualInvWeight(float3 c) +{ +#if TAA_PERCEPTUAL_SPACE + return rcp(1.0 - GetLuma(c)); +#else + return 1; +#endif +} + +float4 WorkingToPerceptual(float4 c) +{ + float scale = PerceptualWeight(c.xyz); + return c * scale; +} + +float4 PerceptualToWorking(float4 c) +{ + float scale = PerceptualInvWeight(c.xyz); + return c * scale; +} + +half4 PostFxSpaceToLinear(float4 src) +{ +// gamma 2.0 is a good enough approximation +#if TAA_GAMMA_SPACE_POST + return half4(src.xyz * src.xyz, src.w); +#else + return src; +#endif +} + +half4 LinearToPostFxSpace(float4 src) +{ +#if TAA_GAMMA_SPACE_POST + return half4(sqrt(src.xyz), src.w); +#else + return src; +#endif +} + +// Working Space: The color space that we will do the calculation in. +// Scene: The incoming/outgoing scene color. Either linear or gamma space +half4 SceneToWorkingSpace(half4 src) +{ + half4 linColor = PostFxSpaceToLinear(src); +#if TAA_YCOCG + half4 dst = half4(RGBToYCoCg(linColor.xyz), linColor.w); +#else + half4 dst = src; +#endif + return dst; +} + +half4 WorkingSpaceToScene(half4 src) +{ +#if TAA_YCOCG + half4 linColor = half4(YCoCgToRGB(src.xyz), src.w); +#else + half4 linColor = src; +#endif + + half4 dst = LinearToPostFxSpace(linColor); + return dst; +} + +half4 SampleColorPoint(float2 uv, int2 texelOffset) +{ + return _GaussianSplatRT.Sample(sampler_PointClamp, uv, texelOffset); +} + +void AdjustColorBox(inout half4 boxMin, inout half4 boxMax, inout half4 moment1, inout half4 moment2, float2 uv, int2 offset) +{ + half4 color = SceneToWorkingSpace(SampleColorPoint(uv, offset)); + boxMin = min(color, boxMin); + boxMax = max(color, boxMax); + moment1 += color; + moment2 += color * color; +} + +half4 ApplyHistoryColorLerp(half4 workingAccumColor, half4 workingCenterColor, float t) +{ + half4 perceptualAccumColor = WorkingToPerceptual(workingAccumColor); + half4 perceptualCenterColor = WorkingToPerceptual(workingCenterColor); + + half4 perceptualDstColor = lerp(perceptualAccumColor, perceptualCenterColor, t); + half4 workingDstColor = PerceptualToWorking(perceptualDstColor); + + return workingDstColor; +} + +// From Filmic SMAA presentation[Jimenez 2016] +// A bit more verbose that it needs to be, but makes it a bit better at latency hiding +// (half version based on HDRP impl) +half4 SampleBicubic5TapHalf(Texture2D sourceTexture, float2 UV, float4 sourceTexture_TexelSize) +{ + const float2 sourceTextureSize = sourceTexture_TexelSize.zw; + const float2 sourceTexelSize = sourceTexture_TexelSize.xy; + + float2 samplePos = UV * sourceTextureSize; + float2 tc1 = floor(samplePos - 0.5) + 0.5; + half2 f = samplePos - tc1; + half2 f2 = f * f; + half2 f3 = f * f2; + + half c = 0.5; + + half2 w0 = -c * f3 + 2.0 * c * f2 - c * f; + half2 w1 = (2.0 - c) * f3 - (3.0 - c) * f2 + 1.0; + half2 w2 = -(2.0 - c) * f3 + (3.0 - 2.0 * c) * f2 + c * f; + half2 w3 = c * f3 - c * f2; + + half2 w12 = w1 + w2; + float2 tc0 = sourceTexelSize * (tc1 - 1.0); + float2 tc3 = sourceTexelSize * (tc1 + 2.0); + float2 tc12 = sourceTexelSize * (tc1 + w2 / w12); + + half4 s0 = SceneToWorkingSpace(sourceTexture.Sample(sampler_LinearClamp, float2(tc12.x, tc0.y))); + half4 s1 = SceneToWorkingSpace(sourceTexture.Sample(sampler_LinearClamp, float2(tc0.x, tc12.y))); + half4 s2 = SceneToWorkingSpace(sourceTexture.Sample(sampler_LinearClamp, float2(tc12.x, tc12.y))); + half4 s3 = SceneToWorkingSpace(sourceTexture.Sample(sampler_LinearClamp, float2(tc3.x, tc12.y))); + half4 s4 = SceneToWorkingSpace(sourceTexture.Sample(sampler_LinearClamp, float2(tc12.x, tc3.y))); + + half cw0 = (w12.x * w0.y); + half cw1 = (w0.x * w12.y); + half cw2 = (w12.x * w12.y); + half cw3 = (w3.x * w12.y); + half cw4 = (w12.x * w3.y); + + s0 *= cw0; + s1 *= cw1; + s2 *= cw2; + s3 *= cw3; + s4 *= cw4; + + half4 historyFiltered = s0 + s1 + s2 + s3 + s4; + half weightSum = cw0 + cw1 + cw2 + cw3 + cw4; + + half4 filteredVal = historyFiltered * rcp(weightSum); + + return filteredVal; +} + +// From Playdead's TAA +// (half version of HDRP impl) +// +// Small color-volume min size seems to produce flicker/noise in YCoCg space, that can't be seen in RGB, +// when using low precision (RGB111110f) color textures. +half4 ClipToAABBCenter(half4 history, half4 minimum, half4 maximum) +{ + // note: only clips towards aabb center (but fast!) + half4 center = 0.5 * (maximum + minimum); + half4 extents = max(0.5 * (maximum - minimum), HALF_MIN); // Epsilon to avoid precision issues with empty volume. + + // This is actually `distance`, however the keyword is reserved + half4 offset = history - center; + half3 v_unit = offset.xyz / extents.xyz; + half3 absUnit = abs(v_unit); + half maxUnit = Max3(absUnit.x, absUnit.y, absUnit.z); + if (maxUnit > 1.0) + return center + (offset / maxUnit); + else + return history; +} + +// clampQuality: +// 0: Cross (5 taps) +// 1: 3x3 (9 taps) +// 2: Variance + MinMax 3x3 (9 taps) +// 3: Variance Clipping +// +// motionQuality: +// 0: None +// 1: 5 taps +// 2: 9 taps +// historyQuality: +// 0: Bilinear +// 1: Bilinear + discard history for UVs out of buffer +// 2: Bicubic (5 taps) +half4 DoTemporalAA(float2 uv, int clampQuality, int motionQuality, int historyQuality) +{ + half4 colorCenter = SceneToWorkingSpace(SampleColorPoint(uv, int2(0,0))); + + half4 boxMax = colorCenter; + half4 boxMin = colorCenter; + half4 moment1 = colorCenter; + half4 moment2 = colorCenter * colorCenter; + + AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, int2(0,-1)); + AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, int2(-1,0)); + AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, int2(1,0)); + AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, int2(0,1)); + + if (clampQuality >= 1) + { + AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, int2(-1,-1)); + AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, int2(1,-1)); + AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, int2(-1,1)); + AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, int2(1,1)); + } + + if(clampQuality >= 2) + { + half perSample = 1 / half(9); + half4 mean = moment1 * perSample; + half4 stdDev = sqrt(abs(moment2 * perSample - mean * mean)); + + half devScale = _TaaVarianceClampScale; + half4 devMin = mean - devScale * stdDev; + half4 devMax = mean + devScale * stdDev; + + // Ensure that the variance color box is not worse than simple neighborhood color box. + boxMin = max(boxMin, devMin); + boxMax = min(boxMax, devMax); + } + + /* @TODO motion stuff + half bestOffsetX = 0.0f; + half bestOffsetY = 0.0f; + half bestDepth = 1.0f; + if (motionQuality >= 1) + { + AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 0.0f, 0.0f); + AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 1.0f, 0.0f); + AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 0.0f, -1.0f); + AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, -1.0f, 0.0f); + AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 0.0f, 1.0f); + } + if (motionQuality >= 2) + { + AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, -1.0f, -1.0f); + AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 1.0f, -1.0f); + AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, -1.0f, 1.0f); + AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 1.0f, 1.0f); + } + + half2 depthOffsetUv = half2(bestOffsetX, bestOffsetY); + half2 velocity = GetVelocityWithOffset(uv, depthOffsetUv); + + float2 historyUv = uv + velocity * float2(1, 1); + */ + + float2 historyUv = uv; //@TODO: for now assume no motion at all + + half4 accumulation = (historyQuality >= 2) ? + SampleBicubic5TapHalf(_TaaAccumulationTex, historyUv, _TaaAccumulationTex_TexelSize.xyzw) : + SceneToWorkingSpace(_TaaAccumulationTex.Sample(sampler_LinearClamp, historyUv)); + + half4 clampedAccumulation = (clampQuality >= 3) ? ClipToAABBCenter(accumulation, boxMin, boxMax) : clamp(accumulation, boxMin, boxMax); + + half frameInfluence = _TaaFrameInfluence; + + half4 workingColor = ApplyHistoryColorLerp(clampedAccumulation, colorCenter, frameInfluence); + + half4 dstSceneColor = WorkingSpaceToScene(workingColor); + + return half4(max(dstSceneColor, 0.0)); +} diff --git a/package/Shaders/Resources/TemporalFilter.hlsl.meta b/package/Shaders/Resources/TemporalFilter.hlsl.meta new file mode 100644 index 00000000..10e43b62 --- /dev/null +++ b/package/Shaders/Resources/TemporalFilter.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 627db8b20f16f934780c190431a42342 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/projects/GaussianExample-HDRP/Assets/GSTestScene.unity b/projects/GaussianExample-HDRP/Assets/GSTestScene.unity index 147cb5e7..205333c2 100644 --- a/projects/GaussianExample-HDRP/Assets/GSTestScene.unity +++ b/projects/GaussianExample-HDRP/Assets/GSTestScene.unity @@ -657,18 +657,11 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Asset: {fileID: 11400000, guid: d3f8309727de6451db26cd6c10b2c913, type: 2} + m_RenderOrder: 0 m_SplatScale: 1 m_OpacityScale: 1 m_SHOrder: 3 - m_SortNthFrame: 1 - m_RenderMode: 0 - m_PointDisplaySize: 3 m_Cutouts: [] - m_ShaderSplats: {fileID: 4800000, guid: ed800126ae8844a67aad1974ddddd59c, type: 3} - m_ShaderComposite: {fileID: 4800000, guid: 7e184af7d01193a408eb916d8acafff9, type: 3} - m_ShaderDebugPoints: {fileID: 4800000, guid: b44409fc67214394f8f47e4e2648425e, type: 3} - m_ShaderDebugBoxes: {fileID: 4800000, guid: 4006f2680fd7c8b4cbcb881454c782be, type: 3} - m_CSSplatUtilities: {fileID: 7200000, guid: ec84f78b836bd4f96a105d6b804f08bd, type: 3} --- !u!4 &1609192435 Transform: m_ObjectHideFlags: 0 diff --git a/projects/GaussianExample-HDRP/Packages/manifest.json b/projects/GaussianExample-HDRP/Packages/manifest.json index e6699818..63cbf155 100644 --- a/projects/GaussianExample-HDRP/Packages/manifest.json +++ b/projects/GaussianExample-HDRP/Packages/manifest.json @@ -1,7 +1,7 @@ { "dependencies": { - "com.unity.ide.rider": "3.0.31", - "com.unity.render-pipelines.high-definition": "14.0.11", + "com.unity.ide.rider": "3.0.34", + "com.unity.render-pipelines.high-definition": "14.0.12", "org.nesnausk.gaussian-splatting": "file:../../../package", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", diff --git a/projects/GaussianExample-HDRP/Packages/packages-lock.json b/projects/GaussianExample-HDRP/Packages/packages-lock.json index 812185a3..078347d7 100644 --- a/projects/GaussianExample-HDRP/Packages/packages-lock.json +++ b/projects/GaussianExample-HDRP/Packages/packages-lock.json @@ -1,7 +1,7 @@ { "dependencies": { "com.unity.burst": { - "version": "1.8.17", + "version": "1.8.19", "depth": 1, "source": "registry", "dependencies": { @@ -29,7 +29,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.rider": { - "version": "3.0.31", + "version": "3.0.34", "depth": 0, "source": "registry", "dependencies": { @@ -52,7 +52,7 @@ "url": "https://packages.unity.com" }, "com.unity.render-pipelines.core": { - "version": "14.0.11", + "version": "14.0.12", "depth": 1, "source": "builtin", "dependencies": { @@ -63,7 +63,7 @@ } }, "com.unity.render-pipelines.high-definition": { - "version": "14.0.11", + "version": "14.0.12", "depth": 0, "source": "builtin", "dependencies": { @@ -73,18 +73,18 @@ "com.unity.modules.animation": "1.0.0", "com.unity.modules.imageconversion": "1.0.0", "com.unity.modules.terrain": "1.0.0", - "com.unity.render-pipelines.core": "14.0.11", - "com.unity.shadergraph": "14.0.11", - "com.unity.visualeffectgraph": "14.0.11", - "com.unity.render-pipelines.high-definition-config": "14.0.11" + "com.unity.render-pipelines.core": "14.0.12", + "com.unity.shadergraph": "14.0.12", + "com.unity.visualeffectgraph": "14.0.12", + "com.unity.render-pipelines.high-definition-config": "14.0.12" } }, "com.unity.render-pipelines.high-definition-config": { - "version": "14.0.11", + "version": "14.0.12", "depth": 1, "source": "builtin", "dependencies": { - "com.unity.render-pipelines.core": "14.0.11" + "com.unity.render-pipelines.core": "14.0.12" } }, "com.unity.searcher": { @@ -95,11 +95,11 @@ "url": "https://packages.unity.com" }, "com.unity.shadergraph": { - "version": "14.0.11", + "version": "14.0.12", "depth": 1, "source": "builtin", "dependencies": { - "com.unity.render-pipelines.core": "14.0.11", + "com.unity.render-pipelines.core": "14.0.12", "com.unity.searcher": "4.9.2" } }, @@ -113,12 +113,12 @@ } }, "com.unity.visualeffectgraph": { - "version": "14.0.11", + "version": "14.0.12", "depth": 1, "source": "builtin", "dependencies": { - "com.unity.shadergraph": "14.0.11", - "com.unity.render-pipelines.core": "14.0.11" + "com.unity.shadergraph": "14.0.12", + "com.unity.render-pipelines.core": "14.0.12" } }, "org.nesnausk.gaussian-splatting": { diff --git a/projects/GaussianExample-HDRP/ProjectSettings/ProjectVersion.txt b/projects/GaussianExample-HDRP/ProjectSettings/ProjectVersion.txt index d30043bf..75f98097 100644 --- a/projects/GaussianExample-HDRP/ProjectSettings/ProjectVersion.txt +++ b/projects/GaussianExample-HDRP/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2022.3.47f1 -m_EditorVersionWithRevision: 2022.3.47f1 (88c277b85d21) +m_EditorVersion: 2022.3.60f1 +m_EditorVersionWithRevision: 2022.3.60f1 (5f63fdee6d95) diff --git a/projects/GaussianExample-URP/Assets/GSTestScene.unity b/projects/GaussianExample-URP/Assets/GSTestScene.unity index b301aaa2..5aa58b21 100644 --- a/projects/GaussianExample-URP/Assets/GSTestScene.unity +++ b/projects/GaussianExample-URP/Assets/GSTestScene.unity @@ -13,7 +13,7 @@ OcclusionCullingSettings: --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 - serializedVersion: 9 + serializedVersion: 10 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 @@ -38,13 +38,12 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 - serializedVersion: 12 - m_GIWorkflowMode: 1 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 m_GISettings: serializedVersion: 2 m_BounceScale: 1 @@ -67,9 +66,6 @@ LightmapSettings: m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 m_TextureCompression: 1 - m_FinalGather: 0 - m_FinalGatherFiltering: 1 - m_FinalGatherRayCount: 256 m_ReflectionCompression: 2 m_MixedBakeMode: 2 m_BakeBackend: 1 @@ -149,9 +145,8 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 231550833} m_Enabled: 1 - serializedVersion: 10 + serializedVersion: 11 m_Type: 1 - m_Shape: 0 m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} m_Intensity: 1 m_Range: 10 @@ -201,8 +196,12 @@ Light: m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 m_ShadowRadius: 0 m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 --- !u!4 &231550835 Transform: m_ObjectHideFlags: 0 @@ -372,12 +371,12 @@ MonoBehaviour: m_RequiresColorTexture: 0 m_Version: 2 m_TaaSettings: - quality: 3 - frameInfluence: 0.1 - jitterScale: 1 - mipBias: 0 - varianceClampScale: 0.9 - contrastAdaptiveSharpening: 0 + m_Quality: 3 + m_FrameInfluence: 0.1 + m_JitterScale: 1 + m_MipBias: 0 + m_VarianceClampScale: 0.9 + m_ContrastAdaptiveSharpening: 0 --- !u!1 &1609192433 GameObject: m_ObjectHideFlags: 0 @@ -408,18 +407,11 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Asset: {fileID: 11400000, guid: 41cf1cc449f9448eeb45cbc741fcab97, type: 2} + m_RenderOrder: 0 m_SplatScale: 1 m_OpacityScale: 1 m_SHOrder: 3 - m_SortNthFrame: 1 - m_RenderMode: 0 - m_PointDisplaySize: 3 m_Cutouts: [] - m_ShaderSplats: {fileID: 4800000, guid: ed800126ae8844a67aad1974ddddd59c, type: 3} - m_ShaderComposite: {fileID: 4800000, guid: 7e184af7d01193a408eb916d8acafff9, type: 3} - m_ShaderDebugPoints: {fileID: 4800000, guid: b44409fc67214394f8f47e4e2648425e, type: 3} - m_ShaderDebugBoxes: {fileID: 4800000, guid: 4006f2680fd7c8b4cbcb881454c782be, type: 3} - m_CSSplatUtilities: {fileID: 7200000, guid: ec84f78b836bd4f96a105d6b804f08bd, type: 3} --- !u!4 &1609192435 Transform: m_ObjectHideFlags: 0 diff --git a/projects/GaussianExample-URP/Assets/UniversalRenderPipelineGlobalSettings.asset b/projects/GaussianExample-URP/Assets/UniversalRenderPipelineGlobalSettings.asset index b04b52e3..15fcc3af 100644 --- a/projects/GaussianExample-URP/Assets/UniversalRenderPipelineGlobalSettings.asset +++ b/projects/GaussianExample-URP/Assets/UniversalRenderPipelineGlobalSettings.asset @@ -54,6 +54,7 @@ MonoBehaviour: - rid: 1297627711732449298 - rid: 1297627711732449299 - rid: 1297627711732449300 + - rid: 4203572852048527360 m_RuntimeSettings: m_List: [] m_AssetVersion: 8 @@ -100,6 +101,9 @@ MonoBehaviour: m_CoreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3} m_CoreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3} m_SamplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + m_TerrainDetailLit: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3} + m_TerrainDetailGrassBillboard: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3} + m_TerrainDetailGrass: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3} - rid: 1297627711732449282 type: {class: Renderer2DResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} data: @@ -128,6 +132,7 @@ MonoBehaviour: m_DefaultLineMaterial: {fileID: 2100000, guid: e823cd5b5d27c0f4b8256e7c12ee3e6d, type: 2} m_DefaultTerrainMaterial: {fileID: 2100000, guid: 594ea882c5a793440b60ff72d896021e, type: 2} m_DefaultDecalMaterial: {fileID: 2100000, guid: 31d0dcc6f2dd4e4408d18036a2c93862, type: 2} + m_DefaultSpriteMaterial: {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, type: 2} - rid: 1297627711732449285 type: {class: UniversalRenderPipelineRuntimeXRResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} data: @@ -246,3 +251,7 @@ MonoBehaviour: m_ExportShaderVariants: 1 m_ShaderVariantLogLevel: 0 m_StripRuntimeDebugShaders: 1 + - rid: 4203572852048527360 + type: {class: UniversalRenderPipelineEditorAssets, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_DefaultSettingsVolumeProfile: {fileID: 11400000, guid: eda47df5b85f4f249abf7abd73db2cb2, type: 2} diff --git a/projects/GaussianExample-URP/Packages/manifest.json b/projects/GaussianExample-URP/Packages/manifest.json index 2372693e..2ba2cc2d 100644 --- a/projects/GaussianExample-URP/Packages/manifest.json +++ b/projects/GaussianExample-URP/Packages/manifest.json @@ -1,7 +1,7 @@ { "dependencies": { - "com.unity.ide.rider": "3.0.31", - "com.unity.render-pipelines.universal": "17.0.3", + "com.unity.ide.rider": "3.0.36", + "com.unity.render-pipelines.universal": "17.0.4", "org.nesnausk.gaussian-splatting": "file:../../../package", "com.unity.modules.accessibility": "1.0.0", "com.unity.modules.ai": "1.0.0", diff --git a/projects/GaussianExample-URP/Packages/packages-lock.json b/projects/GaussianExample-URP/Packages/packages-lock.json index a6016ba2..38e11a7d 100644 --- a/projects/GaussianExample-URP/Packages/packages-lock.json +++ b/projects/GaussianExample-URP/Packages/packages-lock.json @@ -1,7 +1,7 @@ { "dependencies": { "com.unity.burst": { - "version": "1.8.18", + "version": "1.8.19", "depth": 1, "source": "registry", "dependencies": { @@ -30,7 +30,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.rider": { - "version": "3.0.31", + "version": "3.0.36", "depth": 0, "source": "registry", "dependencies": { @@ -53,7 +53,7 @@ "url": "https://packages.unity.com" }, "com.unity.render-pipelines.core": { - "version": "17.0.3", + "version": "17.0.4", "depth": 1, "source": "builtin", "dependencies": { @@ -68,12 +68,12 @@ } }, "com.unity.render-pipelines.universal": { - "version": "17.0.3", + "version": "17.0.4", "depth": 0, "source": "builtin", "dependencies": { - "com.unity.render-pipelines.core": "17.0.3", - "com.unity.shadergraph": "17.0.3", + "com.unity.render-pipelines.core": "17.0.4", + "com.unity.shadergraph": "17.0.4", "com.unity.render-pipelines.universal-config": "17.0.3" } }, @@ -96,23 +96,23 @@ } }, "com.unity.searcher": { - "version": "4.9.2", + "version": "4.9.3", "depth": 2, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.shadergraph": { - "version": "17.0.3", + "version": "17.0.4", "depth": 1, "source": "builtin", "dependencies": { - "com.unity.render-pipelines.core": "17.0.3", - "com.unity.searcher": "4.9.2" + "com.unity.render-pipelines.core": "17.0.4", + "com.unity.searcher": "4.9.3" } }, "com.unity.test-framework": { - "version": "1.4.5", + "version": "1.4.6", "depth": 2, "source": "registry", "dependencies": { diff --git a/projects/GaussianExample-URP/ProjectSettings/MultiplayerManager.asset b/projects/GaussianExample-URP/ProjectSettings/MultiplayerManager.asset new file mode 100644 index 00000000..2a936644 --- /dev/null +++ b/projects/GaussianExample-URP/ProjectSettings/MultiplayerManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!655991488 &1 +MultiplayerManager: + m_ObjectHideFlags: 0 + m_EnableMultiplayerRoles: 0 + m_StrippingTypes: {} diff --git a/projects/GaussianExample-URP/ProjectSettings/ProjectVersion.txt b/projects/GaussianExample-URP/ProjectSettings/ProjectVersion.txt index 11b73a4b..041b8c87 100644 --- a/projects/GaussianExample-URP/ProjectSettings/ProjectVersion.txt +++ b/projects/GaussianExample-URP/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 6000.0.23f1 -m_EditorVersionWithRevision: 6000.0.23f1 (1c4764c07fb4) +m_EditorVersion: 6000.0.41f1 +m_EditorVersionWithRevision: 6000.0.41f1 (46e447368a18) diff --git a/projects/GaussianExample-URP/ProjectSettings/SceneTemplateSettings.json b/projects/GaussianExample-URP/ProjectSettings/SceneTemplateSettings.json index 5e97f839..1edced2a 100644 --- a/projects/GaussianExample-URP/ProjectSettings/SceneTemplateSettings.json +++ b/projects/GaussianExample-URP/ProjectSettings/SceneTemplateSettings.json @@ -61,6 +61,11 @@ "type": "UnityEngine.PhysicMaterial", "defaultInstantiationMode": 0 }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial", + "defaultInstantiationMode": 0 + }, { "userAdded": false, "type": "UnityEngine.PhysicsMaterial2D", diff --git a/projects/GaussianExample-URP/ProjectSettings/ShaderGraphSettings.asset b/projects/GaussianExample-URP/ProjectSettings/ShaderGraphSettings.asset index 59c4647f..df2f009a 100644 --- a/projects/GaussianExample-URP/ProjectSettings/ShaderGraphSettings.asset +++ b/projects/GaussianExample-URP/ProjectSettings/ShaderGraphSettings.asset @@ -15,3 +15,4 @@ MonoBehaviour: shaderVariantLimit: 2048 customInterpolatorErrorThreshold: 32 customInterpolatorWarningThreshold: 16 + customHeatmapValues: {fileID: 0} diff --git a/projects/GaussianExample-URP/ProjectSettings/URPProjectSettings.asset b/projects/GaussianExample-URP/ProjectSettings/URPProjectSettings.asset index cd7fd8c6..08faf033 100644 --- a/projects/GaussianExample-URP/ProjectSettings/URPProjectSettings.asset +++ b/projects/GaussianExample-URP/ProjectSettings/URPProjectSettings.asset @@ -12,4 +12,4 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 247994e1f5a72c2419c26a37e9334c01, type: 3} m_Name: m_EditorClassIdentifier: - m_LastMaterialVersion: 7 + m_LastMaterialVersion: 9 diff --git a/projects/GaussianExample/Assets/GSTestScene.unity b/projects/GaussianExample/Assets/GSTestScene.unity index 445173ab..8e7f82b5 100644 --- a/projects/GaussianExample/Assets/GSTestScene.unity +++ b/projects/GaussianExample/Assets/GSTestScene.unity @@ -38,7 +38,6 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -217,6 +216,58 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1196452938 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1196452940} + - component: {fileID: 1196452941} + m_Layer: 0 + m_Name: GaussianSettings + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1196452940 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1196452938} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1196452941 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1196452938} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b9344df23bed5464c9e1e40f77e03e0b, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Transparency: 0 + m_SortNthFrame: 1 + m_TemporalFilter: 0 + m_FrameInfluence: 0.05 + m_VarianceClampScale: 1.5 + m_RenderMode: 0 + m_PointDisplaySize: 3 + m_SHOnly: 0 --- !u!1 &1462254335 GameObject: m_ObjectHideFlags: 0 @@ -339,19 +390,11 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Asset: {fileID: 11400000, guid: 4317a613eb53b6c4a9996873a734dad3, type: 2} + m_RenderOrder: 0 m_SplatScale: 1 m_OpacityScale: 1 m_SHOrder: 3 - m_SHOnly: 0 - m_SortNthFrame: 1 - m_RenderMode: 0 - m_PointDisplaySize: 3 m_Cutouts: [] - m_ShaderSplats: {fileID: 4800000, guid: ed800126ae8844a67aad1974ddddd59c, type: 3} - m_ShaderComposite: {fileID: 4800000, guid: 7e184af7d01193a408eb916d8acafff9, type: 3} - m_ShaderDebugPoints: {fileID: 4800000, guid: b44409fc67214394f8f47e4e2648425e, type: 3} - m_ShaderDebugBoxes: {fileID: 4800000, guid: 4006f2680fd7c8b4cbcb881454c782be, type: 3} - m_CSSplatUtilities: {fileID: 7200000, guid: ec84f78b836bd4f96a105d6b804f08bd, type: 3} --- !u!4 &1609192435 Transform: m_ObjectHideFlags: 0 @@ -372,5 +415,6 @@ SceneRoots: m_ObjectHideFlags: 0 m_Roots: - {fileID: 231550835} - - {fileID: 1609192435} - {fileID: 1462254338} + - {fileID: 1196452940} + - {fileID: 1609192435}