@@ -74,9 +74,9 @@ fn vs_main_3d(in: VertexInput) -> VertexOutput3D {
7474 // Camera rotation matches the original 3D CRT Oscilloscope
7575 let rot_angle = sin (audio . time * 0 .2 ) * 0 .15 ;
7676 let cam_dist_val = 3 .2 ;
77- let cam_height = 1 .8 ;
77+ let cam_height = 1 .7 ; // Adjusted camera height to match others
7878 let ro = vec3 <f32 >(sin (rot_angle ) * cam_dist_val , cam_height , - cos (rot_angle ) * cam_dist_val );
79- let cam_target = vec3 <f32 >(0 .0 , 0 .0 , 0 .0 );
79+ let cam_target = vec3 <f32 >(0 .0 , 0 .0 , 0 .8 ); // Target adjusted to match others (Depth Z = 0.8, Height Y = 0.0)
8080
8181 let f = normalize (cam_target - ro );
8282 let s = normalize (cross (f , vec3 <f32 >(0 .0 , 1 .0 , 0 .0 )));
@@ -89,7 +89,18 @@ fn vs_main_3d(in: VertexInput) -> VertexOutput3D {
8989 vec4 <f32 >(- dot (s , ro ), - dot (u , ro ), dot (f , ro ), 1 .0 )
9090 );
9191
92- let clip_pos = camera . proj_matrix * view_matrix * vec4 <f32 >(p3 , 1 .0 );
92+ let view_pos = view_matrix * vec4 <f32 >(p3 , 1 .0 );
93+ // Custom projection matrix to match the 116 degree horizontal / 84 degree vertical FOV of the raymarched versions
94+ let p_00 = 1 .0 / (0 .9 * audio . aspect_ratio );
95+ let p_11 = 1 .11111111 ;
96+ let p_22 = - 1 .0001 ;
97+ let p_32 = - 0 .10001 ;
98+ let clip_pos = vec4 <f32 >(
99+ view_pos . x * p_00 ,
100+ view_pos . y * p_11 ,
101+ view_pos . z * p_22 + p_32 ,
102+ - view_pos . z
103+ );
93104
94105 // Apply barrel distortion in clip space (NDC) to match the curved CRT glass
95106 let ndc = clip_pos . xy / max (clip_pos . w , 0 .0001 );
@@ -124,8 +135,10 @@ fn fs_main(in: VertexOutput3D) -> @location(0) vec4<f32> {
124135 // UV derivative-based wireframe grid shader
125136 // Width has 128 lines, depth has 72 lines
126137 let grid_res = vec2 <f32 >(128 .0 , 72 .0 );
127- let fwidth_uv = fwidth (in . uv * grid_res ) + 0 .0001 ;
128-
138+
139+ // Use the continuous world-space Z for the vertical grid coordinate to eliminate temporal jitter
140+ let uv_g = vec2 <f32 >(in . uv . x , (in . world_pos . z + 1 .8 ) / 10 .8 );
141+
129142 // Amplitude-reactive bloom width and brightness
130143 let wave_height = clamp (abs (in . hit_val ) * 2 .0 , 0 .0 , 1 .0 );
131144 let bloom_boost = 1 .0 + wave_height * 0 .8 ;
@@ -134,22 +147,23 @@ fn fs_main(in: VertexOutput3D) -> @location(0) vec4<f32> {
134147 let offset_r = vec2 <f32 >(0 .0005 , 0 .0003 );
135148 let offset_b = vec2 <f32 >(- 0 .0005 , - 0 .0003 );
136149
150+ let fwidth_uv = fwidth (uv_g * grid_res ) + 0 .0001 ;
151+
137152 // Red Channel Grid
138- let uv_r = in . uv + offset_r ;
153+ let uv_r = uv_g + offset_r ;
139154 let grid_r = abs (fract (uv_r * grid_res - 0 .5 ) - 0 .5 ) / fwidth_uv ;
140155 let line_r = min (grid_r . x , grid_r . y ) / (1 .0 + total_coc );
141156 let wire_r = exp (- line_r * 1 .8 ) / (1 .0 + total_coc * 0 .5 ) +
142157 (exp (- line_r * 0 .15 ) * 0 .45 / (1 .0 + total_coc * 0 .2 ) + exp (- line_r * 0 .04 ) * 0 .2 / (1 .0 + total_coc * 0 .1 )) * bloom_boost ;
143158
144159 // Green/Amber Channel Grid (center)
145- let uv_g = in . uv ;
146160 let grid_g = abs (fract (uv_g * grid_res - 0 .5 ) - 0 .5 ) / fwidth_uv ;
147161 let line_g = min (grid_g . x , grid_g . y ) / (1 .0 + total_coc );
148162 let wire_g = exp (- line_g * 1 .8 ) / (1 .0 + total_coc * 0 .5 ) +
149163 (exp (- line_g * 0 .15 ) * 0 .45 / (1 .0 + total_coc * 0 .2 ) + exp (- line_g * 0 .04 ) * 0 .2 / (1 .0 + total_coc * 0 .1 )) * bloom_boost ;
150164
151165 // Blue Channel Grid
152- let uv_b = in . uv + offset_b ;
166+ let uv_b = uv_g + offset_b ;
153167 let grid_b = abs (fract (uv_b * grid_res - 0 .5 ) - 0 .5 ) / fwidth_uv ;
154168 let line_b = min (grid_b . x , grid_b . y ) / (1 .0 + total_coc );
155169 let wire_b = exp (- line_b * 1 .8 ) / (1 .0 + total_coc * 0 .5 ) +
0 commit comments