Blender4iOS/Sources/Math/MathUtils.swift

113 lines
3 KiB
Swift
Raw Normal View History

2026-04-10 21:34:23 -07:00
// MathUtils.swift
// Matrix and vector utilities for the viewport camera.
import simd
enum MathUtils {
// MARK: - Projection
static func perspective(
fovYRadians fov: Float,
aspect: Float,
near: Float,
far: Float
) -> simd_float4x4 {
let y = 1.0 / tanf(fov * 0.5)
let x = y / aspect
let z = far / (near - far)
return simd_float4x4(columns: (
SIMD4<Float>(x, 0, 0, 0),
SIMD4<Float>(0, y, 0, 0),
SIMD4<Float>(0, 0, z, -1),
SIMD4<Float>(0, 0, z * near, 0)
))
}
// MARK: - View
static func lookAt(
eye: SIMD3<Float>,
center: SIMD3<Float>,
up: SIMD3<Float>
) -> simd_float4x4 {
let f = normalize(center - eye)
let s = normalize(cross(f, up))
let u = cross(s, f)
return simd_float4x4(columns: (
SIMD4<Float>(s.x, u.x, -f.x, 0),
SIMD4<Float>(s.y, u.y, -f.y, 0),
SIMD4<Float>(s.z, u.z, -f.z, 0),
SIMD4<Float>(-dot(s, eye), -dot(u, eye), dot(f, eye), 1)
))
}
// MARK: - Model transforms
static func translation(_ t: SIMD3<Float>) -> simd_float4x4 {
var m = matrix_identity_float4x4
m.columns.3 = SIMD4<Float>(t.x, t.y, t.z, 1)
return m
}
static func scale(_ s: SIMD3<Float>) -> simd_float4x4 {
return simd_float4x4(diagonal: SIMD4<Float>(s.x, s.y, s.z, 1))
}
static func rotationX(_ angle: Float) -> simd_float4x4 {
let c = cosf(angle)
let s = sinf(angle)
return simd_float4x4(columns: (
SIMD4<Float>(1, 0, 0, 0),
SIMD4<Float>(0, c, s, 0),
SIMD4<Float>(0, -s, c, 0),
SIMD4<Float>(0, 0, 0, 1)
))
}
static func rotationY(_ angle: Float) -> simd_float4x4 {
let c = cosf(angle)
let s = sinf(angle)
return simd_float4x4(columns: (
SIMD4<Float>( c, 0, s, 0),
SIMD4<Float>( 0, 1, 0, 0),
SIMD4<Float>(-s, 0, c, 0),
SIMD4<Float>( 0, 0, 0, 1)
))
}
static func rotationZ(_ angle: Float) -> simd_float4x4 {
let c = cosf(angle)
let s = sinf(angle)
return simd_float4x4(columns: (
SIMD4<Float>( c, s, 0, 0),
SIMD4<Float>(-s, c, 0, 0),
SIMD4<Float>( 0, 0, 1, 0),
SIMD4<Float>( 0, 0, 0, 1)
))
}
static func normalMatrix(from model: simd_float4x4) -> simd_float4x4 {
let upper3x3 = simd_float3x3(
model.columns.0.xyz,
model.columns.1.xyz,
model.columns.2.xyz
)
let inv = upper3x3.inverse.transpose
return simd_float4x4(columns: (
SIMD4<Float>(inv.columns.0, 0),
SIMD4<Float>(inv.columns.1, 0),
SIMD4<Float>(inv.columns.2, 0),
SIMD4<Float>(0, 0, 0, 1)
))
}
}
// MARK: - SIMD helpers
extension SIMD4 where Scalar == Float {
var xyz: SIMD3<Float> { .init(x, y, z) }
}