@@ -31,6 +31,15 @@ class GaussianSplatRenderSystem
31
31
32
32
CommandBuffer m_CommandBuffer ;
33
33
34
+ // Keep track of the prepared splats for stereo rendering
35
+ public class PreparedRenderData
36
+ {
37
+ public Material matComposite ;
38
+ public List < ( GaussianSplatRenderer gs , Material displayMat , MaterialPropertyBlock mpb , int indexCount , int instanceCount , MeshTopology topology ) > renderItems = new ( ) ;
39
+ }
40
+
41
+ private PreparedRenderData m_LastPreparedData ;
42
+
34
43
public void RegisterSplat ( GaussianSplatRenderer r )
35
44
{
36
45
if ( m_Splats . Count == 0 )
@@ -104,24 +113,32 @@ public bool GatherSplatsForCamera(Camera cam)
104
113
return true ;
105
114
}
106
115
116
+ // New optimized method that prepares everything once for stereo rendering
117
+ // This does the sorting and calculates view data, but doesn't actually render
107
118
// ReSharper disable once MemberCanBePrivate.Global - used by HDRP/URP features that are not always compiled
108
- public Material SortAndRenderSplats ( Camera cam , CommandBuffer cmb , int eyeIndex = - 1 )
119
+ public PreparedRenderData PrepareSplats ( Camera cam , CommandBuffer cmb )
109
120
{
121
+ if ( m_LastPreparedData == null )
122
+ m_LastPreparedData = new PreparedRenderData ( ) ;
123
+ else
124
+ m_LastPreparedData . renderItems . Clear ( ) ;
125
+
110
126
Material matComposite = null ;
127
+
111
128
foreach ( var kvp in m_ActiveSplats )
112
129
{
113
130
var gs = kvp . Item1 ;
114
131
gs . EnsureMaterials ( ) ;
115
132
matComposite = gs . m_MatComposite ;
116
133
var mpb = kvp . Item2 ;
117
134
118
- // sort
135
+ // Sort the splats
119
136
var matrix = gs . transform . localToWorldMatrix ;
120
137
if ( gs . m_FrameCounter % gs . m_SortNthFrame == 0 )
121
138
gs . SortPoints ( cmb , cam , matrix ) ;
122
139
++ gs . m_FrameCounter ;
123
140
124
- // cache view
141
+ // Prepare material and view data
125
142
kvp . Item2 . Clear ( ) ;
126
143
Material displayMat = gs . m_RenderMode switch
127
144
{
@@ -134,11 +151,10 @@ public Material SortAndRenderSplats(Camera cam, CommandBuffer cmb, int eyeIndex
134
151
if ( displayMat == null )
135
152
continue ;
136
153
137
- gs . SetAssetDataOnMaterial ( mpb , eyeIndex ) ;
154
+ // Set up everything except eye-specific parameters
155
+ gs . SetAssetDataOnMaterial ( mpb , - 1 ) ; // -1 for initial setup without eye index
138
156
mpb . SetBuffer ( GaussianSplatRenderer . Props . SplatChunks , gs . m_GpuChunks ) ;
139
-
140
157
mpb . SetBuffer ( GaussianSplatRenderer . Props . SplatViewData , gs . m_GpuView ) ;
141
-
142
158
mpb . SetBuffer ( GaussianSplatRenderer . Props . OrderBuffer , gs . m_GpuSortKeys ) ;
143
159
mpb . SetFloat ( GaussianSplatRenderer . Props . SplatScale , gs . m_SplatScale ) ;
144
160
mpb . SetFloat ( GaussianSplatRenderer . Props . SplatOpacityScale , gs . m_OpacityScale ) ;
@@ -148,11 +164,12 @@ public Material SortAndRenderSplats(Camera cam, CommandBuffer cmb, int eyeIndex
148
164
mpb . SetInteger ( GaussianSplatRenderer . Props . DisplayIndex , gs . m_RenderMode == GaussianSplatRenderer . RenderMode . DebugPointIndices ? 1 : 0 ) ;
149
165
mpb . SetInteger ( GaussianSplatRenderer . Props . DisplayChunks , gs . m_RenderMode == GaussianSplatRenderer . RenderMode . DebugChunkBounds ? 1 : 0 ) ;
150
166
167
+ // Calculate view data once for stereo (will calculate for both eyes)
151
168
cmb . BeginSample ( s_ProfCalcView ) ;
152
169
gs . CalcViewData ( cmb , cam ) ;
153
170
cmb . EndSample ( s_ProfCalcView ) ;
154
171
155
- // draw
172
+ // Set up draw parameters
156
173
int indexCount = 6 ;
157
174
int instanceCount = gs . splatCount ;
158
175
MeshTopology topology = MeshTopology . Triangles ;
@@ -161,11 +178,45 @@ public Material SortAndRenderSplats(Camera cam, CommandBuffer cmb, int eyeIndex
161
178
if ( gs . m_RenderMode == GaussianSplatRenderer . RenderMode . DebugChunkBounds )
162
179
instanceCount = gs . m_GpuChunksValid ? gs . m_GpuChunks . count : 0 ;
163
180
181
+ // Store the prepared data for rendering later
182
+ m_LastPreparedData . renderItems . Add ( ( gs , displayMat , mpb , indexCount , instanceCount , topology ) ) ;
183
+ }
184
+
185
+ m_LastPreparedData . matComposite = matComposite ;
186
+ return m_LastPreparedData ;
187
+ }
188
+
189
+ // New optimized method that just draws the prepared splats for a specific eye
190
+ // ReSharper disable once MemberCanBePrivate.Global - used by HDRP/URP features that are not always compiled
191
+ public void RenderPreparedSplats ( CommandBuffer cmb , int eyeIndex )
192
+ {
193
+ if ( m_LastPreparedData == null || m_LastPreparedData . renderItems . Count == 0 )
194
+ return ;
195
+
196
+ foreach ( var ( gs , displayMat , mpb , indexCount , instanceCount , topology ) in m_LastPreparedData . renderItems )
197
+ {
198
+ // Set the eye index for this specific render
199
+ mpb . SetInteger ( GaussianSplatRenderer . Props . EyeIndex , eyeIndex ) ;
200
+ mpb . SetInteger ( GaussianSplatRenderer . Props . IsStereo , 1 ) ;
201
+
202
+ // Draw
164
203
cmb . BeginSample ( s_ProfDraw ) ;
165
- cmb . DrawProcedural ( gs . m_GpuIndexBuffer , matrix , displayMat , 0 , topology , indexCount , instanceCount , mpb ) ;
204
+ cmb . DrawProcedural ( gs . m_GpuIndexBuffer , gs . transform . localToWorldMatrix , displayMat , 0 , topology , indexCount , instanceCount , mpb ) ;
166
205
cmb . EndSample ( s_ProfDraw ) ;
167
206
}
168
- return matComposite ;
207
+ }
208
+
209
+ // ReSharper disable once MemberCanBePrivate.Global - used by HDRP/URP features that are not always compiled
210
+ public Material SortAndRenderSplats ( Camera cam , CommandBuffer cmb )
211
+ {
212
+ // Prepare the splats (sort and calculate view data)
213
+ var renderData = PrepareSplats ( cam , cmb ) ;
214
+
215
+ // Render the prepared splats
216
+ RenderPreparedSplats ( cmb , - 1 ) ;
217
+
218
+ // Return the composite material
219
+ return renderData . matComposite ;
169
220
}
170
221
171
222
// ReSharper disable once MemberCanBePrivate.Global - used by HDRP/URP features that are not always compiled
@@ -200,7 +251,7 @@ void OnPreCullCamera(Camera cam)
200
251
m_CommandBuffer . SetGlobalTexture ( GaussianSplatRenderer . Props . CameraTargetTexture , BuiltinRenderTextureType . CameraTarget ) ;
201
252
202
253
// add sorting, view calc and drawing commands for each splat object
203
- Material matComposite = SortAndRenderSplats ( cam , m_CommandBuffer , - 1 ) ;
254
+ Material matComposite = SortAndRenderSplats ( cam , m_CommandBuffer ) ;
204
255
205
256
// compose
206
257
m_CommandBuffer . BeginSample ( s_ProfCompose ) ;
0 commit comments