feat: Orthographic 카메라 추가 — 실측 확인용

사용자 피드백: 거더 높이 변경 시 차이가 미미해 보이는 것은 원근 투영의
시각 효과일 수 있음. 평행(Orthographic) 투영으로 보면 거리 무관 실측
크기가 그대로 보여 모델이 실제로 변하는지 객관적으로 확인 가능.

변경:
- camera.rs: Projection enum (Perspective / Orthographic) 추가.
  - Camera.projection 필드 + view_proj() 분기.
  - Ortho 반높이 = radius * tan(fov_y/2) → 전환 시 시각 스케일 일치.
  - toggle_projection() 메서드.
- lib.rs:
  - 카메라 초기값 projection: Perspective.
  - 키 O → 투영 토글.
  - egui 표시 섹션에 투영 버튼 추가 (◇ Perspective / ■ Ortho).

사용: 거더 높이 슬라이더 조정 → Apply → O 키로 Ortho 전환 → 모델 치수
실측 확인.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
minsung
2026-04-15 10:20:59 +09:00
parent e986604f49
commit 2cb549fd9f
2 changed files with 56 additions and 2 deletions

View File

@@ -32,6 +32,16 @@ pub enum StandardView {
Iso, // Home
}
/// Camera projection mode.
///
/// - `Perspective`: 원근 투영. 멀수록 작게 보임. 일반 3D 뷰.
/// - `Orthographic`: 평행 투영. 거리 무관 실측 크기. 치수 검증·도면 스타일 뷰.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Projection {
Perspective,
Orthographic,
}
/// Orbit camera — spherical coordinates around a fixed target point.
///
/// All distances in millimetres (scene units).
@@ -48,6 +58,8 @@ pub struct Camera {
pub aspect: f32,
pub znear: f32,
pub zfar: f32,
/// 투영 모드 (원근 / 평행). 토글 O.
pub projection: Projection,
}
impl Camera {
@@ -62,6 +74,7 @@ impl Camera {
aspect: 16.0 / 9.0,
znear: 10.0, // 10 mm
zfar: 10_000_000.0, // 10 km
projection: Projection::Perspective,
}
}
@@ -81,10 +94,29 @@ impl Camera {
/// View-projection matrix (right-handed, depth 0→1).
pub fn view_proj(&self) -> Mat4 {
let view = Mat4::look_at_rh(self.eye(), self.target, Vec3::Y);
let proj = Mat4::perspective_rh(self.fov_y, self.aspect, self.znear, self.zfar);
let proj = match self.projection {
Projection::Perspective => {
Mat4::perspective_rh(self.fov_y, self.aspect, self.znear, self.zfar)
}
Projection::Orthographic => {
// Ortho 수직 반높이: 같은 radius·FOV 의 원근 뷰와 시각 스케일 일치 →
// target 평면에서 보이던 크기를 그대로 유지한 채 평행 투영.
let half_h = self.radius * (self.fov_y * 0.5).tan();
let half_w = half_h * self.aspect;
Mat4::orthographic_rh(-half_w, half_w, -half_h, half_h, self.znear, self.zfar)
}
};
proj * view
}
/// Perspective ↔ Orthographic 토글.
pub fn toggle_projection(&mut self) {
self.projection = match self.projection {
Projection::Perspective => Projection::Orthographic,
Projection::Orthographic => Projection::Perspective,
};
}
/// Build GPU uniform from current state.
pub fn to_uniform(&self) -> CameraUniform {
CameraUniform { view_proj: self.view_proj().to_cols_array_2d() }