feat(render): add scene environment pipeline

This commit is contained in:
Hakan Seven committed 2026-08-05 23:42:18 +03:00
1 parent b667eeeb05
commit c45daeffb6
17 files changed
+2236 -213

No files matched your search

+35 -9
View File
@@ -405,7 +405,7 @@ impl Scene {
model_space: bool,
) -> bool {
let _ = model_space;
let Some(cam) = self.camera_from_view(
let Some(cam) = self.camera_from_view_mode(
view.direction,
view.target,
acadrust::types::Vector2 {
@@ -414,6 +414,8 @@ impl Scene {
},
view.height,
view.twist_angle,
view.perspective,
view.lens_length,
) else {
return false;
};
@@ -463,16 +465,15 @@ impl Scene {
/// their already-effective `view_target` / `view_center` / `view_height`.
///
/// Returns `None` for a zero `view_height` (an uninitialised entry).
pub(super) fn camera_from_view(
pub(super) fn camera_from_view_mode(
&self,
view_direction: acadrust::types::Vector3,
view_target: acadrust::types::Vector3,
view_center: acadrust::types::Vector2,
view_height: f64,
twist: f64,
// Subtracted from `view_target` to reach wire-space. Model views pass
// `[0.0_f64; 3]`; paper-space views (whose entities carry no
// offset) pass `[0; 3]`.
perspective: bool,
lens_length: f64,
) -> Option<Camera> {
if view_height.abs() < 1e-9 {
return None;
@@ -516,14 +517,26 @@ impl Scene {
let target = base
+ view_right.as_dvec3() * view_center.x
+ view_up.as_dvec3() * view_center.y;
let fov_y = 45.0_f32.to_radians();
let lens_length = lens_length.max(1.0) as f32;
// The saved-view convention uses a 24 mm vertical aperture. This is
// the inverse of the projection path's documented
// `distance = view_height * lens / 24` relation.
let fov_y = if perspective {
2.0 * (12.0 / lens_length).atan()
} else {
45.0_f32.to_radians()
};
let distance = ((view_height as f32 / 2.0) / (fov_y * 0.5).tan()).max(0.001);
Some(Camera {
target,
rotation,
distance,
fov_y,
projection: view::camera::Projection::Orthographic,
projection: if perspective {
view::camera::Projection::Perspective
} else {
view::camera::Projection::Orthographic
},
yaw,
pitch,
// Sized from the saved view height (not a zoom-scaled range) so a
@@ -544,12 +557,14 @@ impl Scene {
/// Decode a VPort table entry (model-space tiled view) into a `Camera`.
fn camera_from_vport(&self, vp: &acadrust::tables::VPort) -> Option<Camera> {
self.camera_from_view(
self.camera_from_view_mode(
vp.view_direction,
vp.view_target,
vp.view_center,
vp.view_height,
vp.view_twist,
vp.perspective,
vp.lens_length,
)
}
@@ -580,6 +595,8 @@ impl Scene {
z: view_dir.z as f64,
};
entry.view_height = view_height as f64;
entry.perspective = cam.projection == view::camera::Projection::Perspective;
entry.lens_length = (12.0 / (cam.fov_y * 0.5).tan().max(1e-6)) as f64;
entry.view_center = acadrust::types::Vector2::ZERO;
// Stored twist = -roll, matching the decoder (roll = -twist).
entry.view_twist = -cam.roll() as f64;
@@ -796,7 +813,7 @@ impl Scene {
// Paper-space entities carry no world_offset → decode with a zero
// offset, through the same shared decoder (twist included).
let Some(cam) = self.camera_from_view(
let Some(cam) = self.camera_from_view_mode(
vp.view_direction,
vp.view_target,
acadrust::types::Vector2 {
@@ -805,6 +822,8 @@ impl Scene {
},
vp.view_height,
vp.twist_angle,
vp.status.perspective,
vp.lens_length,
) else {
return false;
};
@@ -847,6 +866,8 @@ impl Scene {
vp.view_direction = vd3;
vp.view_height = view_height as f64;
vp.view_twist = twist;
vp.perspective = cam.projection == view::camera::Projection::Perspective;
vp.lens_length = (12.0 / (cam.fov_y * 0.5).tan().max(1e-6)) as f64;
}
// Persist the tiled layout as duplicate `*Active` VPort entries.
@@ -878,6 +899,9 @@ impl Scene {
vp.view_direction = vd3;
vp.view_height = view_height as f64;
vp.twist_angle = twist;
vp.status.perspective =
cam.projection == view::camera::Projection::Perspective;
vp.lens_length = (12.0 / (cam.fov_y * 0.5).tan().max(1e-6)) as f64;
}
true
}
@@ -985,6 +1009,7 @@ impl Scene {
None,
scale,
self.annotation_all_visible(),
None,
) {
let is_infinite = Self::handle_from_wire_name(&wire.name)
.and_then(|handle| self.document.get_entity(handle))
@@ -1081,6 +1106,7 @@ impl Scene {
None,
scale,
self.annotation_all_visible(),
None,
);
// Ray / XLine tessellate as ±DISPLAY_EXTENT display segments
// (entities/ray.rs) — their endpoints are rendering artifacts, not