(
&mut self,
pos_x: f32, pos_y: f32, pos_z: f32,
target_x: f32, target_y: f32, target_z: f32,
up_x: f32, up_y: f32, up_z: f32,
fovy: f32, projection: f32,
)
| 12083 | // ============================================================ |
| 12084 | |
| 12085 | pub fn begin_mode_3d( |
| 12086 | &mut self, |
| 12087 | pos_x: f32, pos_y: f32, pos_z: f32, |
| 12088 | target_x: f32, target_y: f32, target_z: f32, |
| 12089 | up_x: f32, up_y: f32, up_z: f32, |
| 12090 | fovy: f32, projection: f32, |
| 12091 | ) { |
| 12092 | let aspect = self.surface_config.width as f32 / self.surface_config.height as f32; |
| 12093 | let mut proj = if projection < 0.5 { |
| 12094 | mat4_perspective(fovy.to_radians(), aspect, 0.01, 1000.0) |
| 12095 | } else { |
| 12096 | let top = fovy / 2.0; |
| 12097 | mat4_ortho(-top * aspect, top * aspect, -top, top, 0.01, 1000.0) |
| 12098 | }; |
| 12099 | // Capture the pre-jitter projection for shadow cascade fitting. |
| 12100 | // TAA's sub-pixel nudge would otherwise change the cascade VPs |
| 12101 | // every frame and defeat the cache. |
| 12102 | self.current_proj_matrix_unjittered = proj; |
| 12103 | |
| 12104 | // TAA jitter: nudge the projection by a sub-pixel Halton |
| 12105 | // offset every frame. The TAA pass blends accumulated frames, |
| 12106 | // so this turns the jitter into per-pixel super-sampling. |
| 12107 | // Skipped when TAA is disabled to keep image stable. |
| 12108 | if self.taa_enabled { |
| 12109 | let i = (self.taa_frame_index % 16) + 1; |
| 12110 | let jx = halton(i, 2) - 0.5; |
| 12111 | let jy = halton(i, 3) - 0.5; |
| 12112 | // Jitter is sub-pixel in *render* space — at fractional |
| 12113 | // render_scale the G-buffer is smaller than the surface, |
| 12114 | // so each render pixel covers 1/scale surface pixels and |
| 12115 | // the offset must scale accordingly. render_extent() |
| 12116 | // already reflects render_scale. |
| 12117 | let (rw, rh) = self.render_extent(); |
| 12118 | let render_w = rw.max(1) as f32; |
| 12119 | let render_h = rh.max(1) as f32; |
| 12120 | // proj is column-major; column 2 row 0/1 are the |
| 12121 | // perspective / Z-coupling slots. Adding a constant NDC |
| 12122 | // offset there shifts the whole frustum by jitter px. |
| 12123 | proj[2][0] += (jx * 2.0) / render_w; |
| 12124 | proj[2][1] += (jy * 2.0) / render_h; |
| 12125 | } |
| 12126 | |
| 12127 | let view = mat4_look_at( |
| 12128 | [pos_x, pos_y, pos_z], |
| 12129 | [target_x, target_y, target_z], |
| 12130 | [up_x, up_y, up_z], |
| 12131 | ); |
| 12132 | let vp = mat4_multiply(proj, view); |
| 12133 | self.current_vp_matrix = vp; |
| 12134 | self.current_view_matrix = view; |
| 12135 | self.current_proj_matrix = proj; |
| 12136 | self.current_inv_proj_matrix = mat4_invert(proj); |
| 12137 | self.current_inv_vp_matrix = mat4_invert(vp); |
| 12138 | self.current_camera_pos = [pos_x, pos_y, pos_z]; |
| 12139 | |
| 12140 | // Mirror camera pos into lighting uniforms so the scene shader |
| 12141 | // can compute V for GGX specular. Preserve the .w slot — it |
| 12142 | // holds the env_intensity multiplier (set via load_env_from_hdr). |
no test coverage detected