@@ -42,6 +42,7 @@ layout(push_constant) uniform PushConstants {
4242
4343layout (local_size_x = 256) in;
4444
45+ // --- UTILS ---
4546float hash(uint x) {
4647 x = ((x >> 16) ^ x) * 0x45d9f3b;
4748 x = ((x >> 16) ^ x) * 0x45d9f3b;
@@ -54,6 +55,11 @@ float get_noise(uint seed) {
5455 return fract(raw + hash(seed));
5556}
5657
58+ vec3 safe_normalize(vec3 v) {
59+ float len = length(v);
60+ return len > 0.00001 ? v / len : vec3(0, 1, 0);
61+ }
62+
5763vec4 quatFromDir(vec3 dir) {
5864 vec3 v = normalize(dir);
5965 vec3 up = abs(v.y) > 0.9 ? vec3(1,0,0) : vec3(0,1,0);
@@ -81,88 +87,132 @@ vec3 computeCov2D(vec3 pos_view, vec3 scale, vec4 rot) {
8187 mat3 R = quatToMat3(rot);
8288 mat3 S = mat3(scale.x, 0, 0, 0, scale.y, 0, 0, 0, scale.z);
8389 mat3 Sigma3D = (R * S) * transpose(R * S);
84- float x = pos_view.x, y = pos_view.y, z = -pos_view.z; // Use positive depth
90+ float x = pos_view.x, y = pos_view.y, z = -pos_view.z;
8591 mat3 J = mat3(pc.focal/z, 0, -(pc.focal*x)/(z*z), 0, pc.focal/z, -(pc.focal*y)/(z*z), 0, 0, 0);
8692 mat3 Sigma2D = J * mat3(pc.view) * Sigma3D * transpose(mat3(pc.view)) * transpose(J);
8793 return vec3(Sigma2D[0][0] + 0.3, Sigma2D[0][1], Sigma2D[1][1] + 0.3);
8894}
8995
90- void splatCylinder(uint i, uint count, vec3 base, vec3 top, float radius, inout vec3 pos, inout vec3 scale, inout vec4 rot) {
96+ // --- SYMBOLIC PRIMITIVES ---
97+
98+ void splatCylinder(uint i, uint count, vec3 base, vec3 top, float radius, float jitter, inout vec3 pos, inout vec3 scale, inout vec4 rot) {
9199 vec3 dir = top - base;
92- pos = base + normalize(dir) * (float(i)/float(count)) * length(dir);
93- scale = vec3(radius, radius, radius * 1.5);
100+ float h = (float(i)/float(count));
101+ // Add radial jitter to turn the line into a tube
102+ float angle = get_noise(i + 500) * 6.28;
103+ float r = radius * pow(get_noise(i + 600), 0.5);
104+ vec3 tangent = normalize(abs(dir.y) > 0.9 ? vec3(1,0,0) : vec3(0,1,0));
105+ tangent = normalize(cross(dir, tangent));
106+ vec3 bitangent = cross(dir, tangent);
107+
108+ pos = base + dir * h + (tangent * cos(angle) + bitangent * sin(angle)) * r;
109+ scale = vec3(radius * 0.5 + jitter); // Thicker splats
94110 rot = quatFromDir(dir);
95111}
96112
97- vec3 safe_normalize(vec3 v) {
98- float len = length(v);
99- return len > 0.00001 ? v / len : vec3(0, 1, 0);
113+ void splatBox(uint i, uint count, vec3 center, vec3 size, inout vec3 pos, inout vec3 scale, inout vec4 rot) {
114+ float x = get_noise(i) - 0.5;
115+ float y = get_noise(i + 1) - 0.5;
116+ float z = get_noise(i + 2) - 0.5;
117+ pos = center + vec3(x, y, z) * size;
118+ scale = vec3(0.15); // Larger splats for better coverage
119+ rot = vec4(1, 0, 0, 0);
100120}
101121
102122void main() {
103123 uint global_i = gl_GlobalInvocationID.x;
104- uint lid = gl_LocalInvocationID.x;
105-
106124 if (global_i >= pc.count) return;
107125
108- uint p_asset = 16384;
126+ uint p_asset = 4096;
109127 uint asset_idx = global_i / p_asset;
110128 uint i = global_i % p_asset;
111129
112- vec3 pos = vec3(0.0); vec3 scale = vec3(0.05); vec4 rot = vec4(1, 0, 0, 0);
113- vec3 color = vec3(1.0); float opacity = 0.005;
114- float x_offset = (float(asset_idx) - 1.0) * 5.0;
115- vec3 normal = vec3(0, 1, 0);
116-
117- if (asset_idx == 0) {
118- if (i < 2000) {
119- splatCylinder(i, 2000, vec3(0, 0, 0), vec3(0, 3, 0), 0.25, pos, scale, rot);
120- color = vec3(0.3, 0.15, 0.05);
121- normal = safe_normalize(vec3(pos.x, 0.0, pos.z)); // Fixed: Trunk radial normal
122- if (length(vec3(pos.x, 0, pos.z)) < 0.001) normal = vec3(1, 0, 0);
130+ vec3 pos = vec3(0.0); vec3 scale = vec3(0.1); vec4 rot = vec4(1, 0, 0, 0);
131+ vec3 color = vec3(1.0); float opacity = 0.004; // Lower opacity for better blending
132+ vec3 normal = vec3(0, 1, 0);
133+
134+ if (asset_idx == 0) { // FLOOR
135+ splatBox(i, p_asset, vec3(0, -0.2, 0), vec3(40.0, 0.4, 40.0), pos, scale, rot);
136+ color = vec3(0.02, 0.03, 0.02) * (0.8 + 0.2 * get_noise(i));
137+ normal = vec3(0, 1, 0);
138+ scale = vec3(0.4, 0.1, 0.4); // Much larger splats for the floor
139+ opacity = 0.008;
140+ } else if (asset_idx < 6) { // TREES
141+ uint t_idx = asset_idx - 1;
142+ float tx = (get_noise(t_idx * 10) - 0.5) * 20.0;
143+ float tz = (get_noise(t_idx * 20) - 0.5) * 20.0;
144+ vec3 center = vec3(tx, 0.0, tz);
145+ if (i < 1500) {
146+ float h = float(i)/1500.0;
147+ float angle = h * 3.0 + float(t_idx);
148+ vec3 top = center + vec3(sin(angle)*1.2, 6.0, cos(angle)*1.2);
149+ splatCylinder(i, 1500, center, top, 0.4 * (1.0 - h*0.6), 0.1, pos, scale, rot);
150+ color = vec3(0.1, 0.08, 0.05);
151+ normal = safe_normalize(vec3(pos.x - center.x, 0, pos.z - center.z));
152+ } else {
153+ uint b_i = i - 1500; uint b_idx = b_i / 600; uint b_sub = b_i % 600;
154+ float b_angle = float(b_idx) * 1.57 + pc.time * 0.05 + float(t_idx);
155+ vec3 b_start = center + vec3(0, 3.0 + float(b_idx)*0.8, 0);
156+ vec3 b_end = b_start + vec3(sin(b_angle)*3.0, 2.5, cos(b_angle)*3.0);
157+ splatCylinder(b_sub, 600, b_start, b_end, 0.15, 0.08, pos, scale, rot);
158+ color = vec3(0.08, 0.06, 0.04);
159+ normal = safe_normalize(b_end - b_start);
160+ }
161+ } else if (asset_idx < 26) { // TOMBSTONES
162+ uint tomb_idx = asset_idx - 6;
163+ float row = floor(float(tomb_idx) / 5.0);
164+ float col = mod(float(tomb_idx), 5.0);
165+ vec3 center = vec3(-8.0 + col * 4.0 + get_noise(tomb_idx)*0.5, 0.0, -8.0 + row * 5.0 + get_noise(tomb_idx+10)*0.5);
166+ if (i < 3000) {
167+ splatBox(i, 3000, center + vec3(0, 0.8, 0), vec3(1.2, 1.6, 0.3), pos, scale, rot);
168+ color = vec3(0.25, 0.25, 0.27);
169+ } else {
170+ uint t_i = i - 3000;
171+ splatCylinder(t_i, 1096, center + vec3(-0.6, 1.6, 0), center + vec3(0.6, 1.6, 0), 0.3, 0.1, pos, scale, rot);
172+ color = vec3(0.22, 0.22, 0.24);
123173 }
124- else if (i < 5000) { uint b = i-2000; float a = (b%4)*1.57; splatCylinder(b, 3000, vec3(0, 2, 0), vec3(sin(a)*1.5, 3.5, cos(a)*1.5), 0.12, pos, scale, rot); color = vec3(0.3, 0.15, 0.05); normal = safe_normalize(pos.xyz); }
125- else {
126- uint l = i-5000; float r = 2.0*pow(get_noise(l), 0.6), phi = get_noise(l+1)*6.28;
127- pos = vec3(sin(phi)*r, 3.5+get_noise(l+2)*2.0, cos(phi)*r); scale = vec3(0.3, 0.1, 0.3);
128- color = vec3(0.1, 0.5, 0.1); normal = safe_normalize(pos - vec3(0, 4.5, 0));
174+ normal = vec3(0, 0, 1);
175+ } else if (asset_idx == 26 || asset_idx == 27) { // CROSSES
176+ vec3 center = (asset_idx == 26) ? vec3(-10, 0, -10) : vec3(10, 0, -10);
177+ if (i < 2500) splatCylinder(i, 2500, center, center + vec3(0, 4.0, 0), 0.2, 0.1, pos, scale, rot);
178+ else if (i < 3500) splatCylinder(i-2500, 1000, center + vec3(-1.0, 2.8, 0), center + vec3(1.0, 2.8, 0), 0.18, 0.08, pos, scale, rot);
179+ else {
180+ uint r_i = i - 3500; float angle = (float(r_i)/596.0) * 6.28;
181+ pos = center + vec3(sin(angle)*0.8, 2.8 + cos(angle)*0.8, 0);
182+ pos += (vec3(get_noise(i), get_noise(i+1), get_noise(i+2)) - 0.5) * 0.15; // Ring jitter
183+ scale = vec3(0.15); rot = vec4(1,0,0,0);
129184 }
130- } else if (asset_idx == 1) {
131- if (i < 4000) { uint l = i%4; vec3 lp = vec3((l<2?1:-1)*0.8, 0, (l%2==0?1:-1)*0.8); splatCylinder(i, 4000, lp, lp+vec3(0, 1.5, 0), 0.1, pos, scale, rot); color = vec3(0.5, 0.3, 0.1); normal = safe_normalize(vec3(lp.x, 0, lp.z)); }
132- else if (i < 6000) { uint s = i-4000; pos = vec3(get_noise(s)*2.0-1.0, 1.6, get_noise(s+1)*2.0-1.0); scale = vec3(0.15, 0.01, 0.15); color = vec3(0.6, 0.4, 0.2); normal = vec3(0, 1, 0); }
133- else { uint b = i-6000; pos = vec3(get_noise(b)*2.0-1.0, 1.6+get_noise(b+1)*2.5, -0.9); scale = vec3(0.1, 0.1, 0.01); color = vec3(0.5, 0.3, 0.1); normal = vec3(0, 0, 1); }
134- } else {
135- float u = float(i)/16384.0, t = pc.time, v = (float(i%1024)/1024.0)*6.28;
136- if (u < 0.2) { float phi = (u/0.2)*3.14, r = 1.2+0.1*sin(t*4.0+v*3.0); pos = vec3(r*sin(phi)*cos(v), 4.5+r*cos(phi), r*sin(phi)*sin(v)); normal = safe_normalize(pos - vec3(0, 4.5, 0)); }
137- else if (u < 0.7) { float h = (u-0.2)/0.5, vertical = mix(4.0, 0.0, h), radius = 1.5*(1.0-h*0.4), wave = sin(h*4.0-t*3.0)*(h*1.5); pos = vec3(radius*cos(v)+wave, vertical, radius*sin(v)); normal = safe_normalize(vec3(cos(v), 0, sin(v))); }
138- else { float h = (u-0.7)/0.3; bool left = (v<3.14); float aw = sin(t*5.0)*0.8; vec3 s = vec3(left?-1:1, 3.8, 0), e = vec3(left?-3:3, 2.5+aw, 1); pos = mix(s, e, h); float r = 0.3*(1.0-h*0.5); pos.y += r*cos(v*4.0); pos.z += r*sin(v*4.0); normal = safe_normalize(pos - s); }
139- scale = vec3(0.08); color = mix(vec3(0,1,1), vec3(1,0,1), sin(t+u*5.0)*0.5+0.5) * 2.5;
185+ color = vec3(0.35, 0.35, 0.35); normal = vec3(0,0,1);
186+ } else { // GHOSTS
187+ float t = pc.time;
188+ uint g_idx = asset_idx - 28;
189+ vec3 center = vec3(sin(t*0.5 + float(g_idx))*6.0, 3.5 + cos(t*0.8 + float(g_idx))*1.5, cos(t*0.6 + float(g_idx))*6.0);
190+ float u = float(i)/float(p_asset); float v = (float(i%1024)/1024.0)*6.28;
191+ if (u < 0.2) { float phi = (u/0.2)*3.14, r = 0.8; pos = center + vec3(r*sin(phi)*cos(v), r*cos(phi), r*sin(phi)*sin(v)); normal = safe_normalize(pos - center); }
192+ else { float h = (u-0.2)/0.8, vertical = mix(0.0, -2.5, h), radius = 0.8*(1.0-h*0.7), wave = sin(h*5.0-t*4.0)*(h*1.0); pos = center + vec3(radius*cos(v)+wave, vertical, radius*sin(v)); normal = safe_normalize(vec3(cos(v), 0, sin(v))); }
193+
194+ // Ghost jitter for "whispiness"
195+ pos += (vec3(get_noise(i), get_noise(i+1), get_noise(i+2)) - 0.5) * 0.2;
196+ scale = vec3(0.12); color = mix(vec3(0,1,1), vec3(0.7,0.3,1), sin(t+u*5.0+float(g_idx))*0.5+0.5) * 4.0; opacity = 0.003;
140197 }
141198
142- pos.x += x_offset; pos += pc.world_offset.xyz;
199+ pos += pc.world_offset.xyz;
143200 vec3 ldir = normalize(pc.light_dir.xyz);
144201 vec3 view_dir = safe_normalize(pc.cam_pos.xyz - pos);
145202
146- // LIGHTING: Half-Lambert (Wrap) to preserve volume and saturation
147203 float diff = dot(normal, ldir);
148- float wrap = diff * 0.5 + 0.5 ;
149- vec3 lit_color = color * (wrap * 1.4 );
204+ float wrap = diff * 0.4 + 0.6 ;
205+ vec3 lit_color = color * (wrap * 1.1 + 0.1 );
150206
151- // RIM: Golden "Glint" instead of Blue wash
152207 float rim = pow(1.0 - max(0.0, dot(normal, view_dir)), 4.0);
153- lit_color += vec3(1.0, 0.9, 0.7) * rim * 0.5;
154-
155- // SH: 1st Order (Subtle Color Shift)
156- float SH_C1 = 0.48860251190291992;
157- lit_color *= (1.0 + SH_C1 * (view_dir.x * 0.2 + view_dir.y * 0.1));
158- lit_color = max(vec3(0.0), lit_color);
208+ lit_color += vec3(0.7, 0.8, 1.0) * rim * 0.6;
159209
160210 vec4 pos_v = pc.view * vec4(pos, 1.0);
161- if (pos_v.z > -0.1 || opacity < 0.001 ) return;
211+ if (pos_v.z > -0.1 || opacity < 0.0001 ) return;
162212
163213 vec3 cov2d = computeCov2D(pos_v.xyz, scale, rot);
164214 vec4 clip_p = pc.proj * pos_v; vec2 ndc = clip_p.xy / clip_p.w;
165- if (abs(ndc.x) > 1.2 || abs(ndc.y) > 1.2 ) return;
215+ if (abs(ndc.x) > 1.4 || abs(ndc.y) > 1.4 ) return;
166216
167217 uint packed_idx = atomicAdd(all_counts[pc.count_id].count, 1);
168218 if (packed_idx >= 131072) return;
@@ -176,13 +226,11 @@ void main() {
176226 all_projected[pc.p_id].p[packed_idx].inv_cov = vec4(i_cov.x * -0.5, i_cov.y * -1.0, i_cov.z * -0.5, 0.0);
177227 all_projected[pc.p_id].p[packed_idx].color_alpha = vec4(lit_color, opacity * 10.0);
178228
179- // Linearize depth for perfectly stable 2-pass sorting (0.0 to 51.2 meters)
180229 float depth = -pos_v.z;
181- uint linearized_depth = uint(clamp(depth * 5 .0, 0.0, 65535.0));
230+ uint linearized_depth = uint(clamp(depth * 50 .0, 0.0, 65535.0));
182231 all_sort_bufs[pc.s_id].entries[packed_idx].depth_key = linearized_depth;
183232 all_sort_bufs[pc.s_id].entries[packed_idx].splat_id = packed_idx;
184233
185- // Fix: First-pass histogram (Pass 0, Bits 0-7)
186234 uint bucket = (linearized_depth >> 0) & 0xFF;
187235 atomicAdd(all_histograms[pc.hist_id].histogram[bucket], 1);
188236
0 commit comments