Blender4iOS/Sources/Viewport/OrbitalCamera.swift

56 lines
1.6 KiB
Swift
Raw Normal View History

2026-04-10 21:34:23 -07:00
// OrbitalCamera.swift
// Blender-style orbit camera with pan, orbit, and dolly zoom.
import Observation
import simd
@Observable
final class OrbitalCamera {
var azimuth: Float = Float.pi * 0.25
var elevation: Float = Float.pi * 0.2
var target: SIMD3<Float> = .zero
var distance: Float = 7.0
private let minDistance: Float = 0.5
private let maxDistance: Float = 200.0
private let minElevation: Float = -Float.pi * 0.49
private let maxElevation: Float = Float.pi * 0.49
var eye: SIMD3<Float> {
let x = distance * cosf(elevation) * sinf(azimuth)
let y = distance * sinf(elevation)
let z = distance * cosf(elevation) * cosf(azimuth)
return target + SIMD3<Float>(x, y, z)
}
var viewMatrix: simd_float4x4 {
MathUtils.lookAt(eye: eye, center: target, up: SIMD3<Float>(0, 1, 0))
}
func orbit(deltaX: Float, deltaY: Float) {
azimuth -= deltaX * 0.008
elevation += deltaY * 0.008
elevation = min(max(elevation, minElevation), maxElevation)
}
func pan(deltaX: Float, deltaY: Float) {
let right = SIMD3<Float>(cosf(azimuth), 0, -sinf(azimuth))
let up = SIMD3<Float>(0, 1, 0)
let speed: Float = distance * 0.002
target += right * (-deltaX * speed) + up * (deltaY * speed)
}
func zoom(scale: Float) {
distance /= scale
distance = min(max(distance, minDistance), maxDistance)
}
func reset() {
azimuth = Float.pi * 0.25
elevation = Float.pi * 0.2
distance = 7.0
target = .zero
}
}