Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion Sources/Satin/Cameras/PerspectiveCamera.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@ open class PerspectiveCamera: Camera {
}
}

public var lensShiftX: Float = 0.0 {
didSet {
updateProjectionMatrix = true
}
}

public var lensShiftY: Float = 0.0 {
didSet {
updateProjectionMatrix = true
}
}

public var enableFrustumShift: Bool = false {
didSet {
updateProjectionMatrix = true
}
}

override public var scale: simd_float3 {
didSet {
updateViewMatrix = true
Expand All @@ -50,7 +68,11 @@ open class PerspectiveCamera: Camera {
override public var projectionMatrix: matrix_float4x4 {
get {
if updateProjectionMatrix {
_projectionMatrix = perspectiveMatrixf(fov, aspect, near, far)
if enableFrustumShift {
_projectionMatrix = frustumShiftPerspectiveMatrixf(fov, aspect, near, far, lensShiftX, lensShiftY)
} else {
_projectionMatrix = perspectiveMatrixf(fov, aspect, near, far)
}
updateProjectionMatrix = false
}
return _projectionMatrix
Expand All @@ -67,6 +89,11 @@ open class PerspectiveCamera: Camera {
let sw = col3.z
far = sw / sz
near = sw / (1.0 + sz)

if enableFrustumShift {
lensShiftX = col2.x
lensShiftY = col2.y
}
}
}

Expand Down Expand Up @@ -103,25 +130,37 @@ open class PerspectiveCamera: Camera {
let values = try decoder.container(keyedBy: CodingKeys.self)
fov = try values.decode(Float.self, forKey: .fov)
aspect = try values.decode(Float.self, forKey: .aspect)
lensShiftX = try values.decodeIfPresent(Float.self, forKey: .lensShiftX) ?? 0.0
lensShiftY = try values.decodeIfPresent(Float.self, forKey: .lensShiftY) ?? 0.0
enableFrustumShift = try values.decodeIfPresent(Bool.self, forKey: .enableFrustumShift) ?? false
}

override open func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(fov, forKey: .fov)
try container.encode(aspect, forKey: .aspect)
try container.encode(lensShiftX, forKey: .lensShiftX)
try container.encode(lensShiftY, forKey: .lensShiftY)
try container.encode(enableFrustumShift, forKey: .enableFrustumShift)
}

private enum CodingKeys: String, CodingKey {
case fov
case aspect
case lensShiftX
case lensShiftY
case enableFrustumShift
}

override public func setFrom(object: Object, world: Bool = false) {
super.setFrom(object: object, world: world)
if let camera = object as? PerspectiveCamera {
fov = camera.fov
aspect = camera.aspect
lensShiftX = camera.lensShiftX
lensShiftY = camera.lensShiftY
enableFrustumShift = camera.enableFrustumShift
}
}

Expand All @@ -142,4 +181,17 @@ open class PerspectiveCamera: Camera {
_projectionMatrix.columns.2.z = sz
_projectionMatrix.columns.3.z = sw
}

// MARK: - Frustum Shift
public func setLensShift(_ x: Float, _ y: Float) {
lensShiftX = x
lensShiftY = y
enableFrustumShift = x != 0.0 || y != 0.0
}

public func resetLensShift() {
lensShiftX = 0.0
lensShiftY = 0.0
enableFrustumShift = false
}
}
20 changes: 20 additions & 0 deletions Sources/SatinCore/Transforms.mm
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,26 @@ simd_float4x4 perspectiveMatrixf(float fov, float aspect, float near, float far)
return simd_matrix(col0, col1, col2, col3);
}

// Frustum shift perspective projection matrix
simd_float4x4 frustumShiftPerspectiveMatrixf(float fov, float aspect, float near, float far, float lensShiftX, float lensShiftY) {

const float halfFovRad = degToRad(0.5 * fov);
const float top = near * tanf(halfFovRad);
const float bottom = -top;
const float right = top * aspect;
const float left = -right;

const float horizontalShift = lensShiftX * (right - left);
const float verticalShift = lensShiftY * (top - bottom);

const float shiftedLeft = left + horizontalShift;
const float shiftedRight = right + horizontalShift;
const float shiftedBottom = bottom + verticalShift;
const float shiftedTop = top + verticalShift;

return frustrumMatrixf(shiftedLeft, shiftedRight, shiftedBottom, shiftedTop, near, far);
}

simd_float4x4 lookAtMatrix3f(simd_float3 eye, simd_float3 at, simd_float3 up) {
simd_float4x4 result = matrix_identity_float4x4;

Expand Down
1 change: 1 addition & 0 deletions Sources/SatinCore/include/Transforms.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ frustrumMatrixf(float left, float right, float bottom, float top, float near, fl
simd_float4x4
orthographicMatrixf(float left, float right, float bottom, float top, float near, float far);
simd_float4x4 perspectiveMatrixf(float fov, float aspect, float near, float far);
simd_float4x4 frustumShiftPerspectiveMatrixf(float fov, float aspect, float near, float far, float lensShiftX, float lensShiftY);

simd_float4x4 lookAtMatrix3f(simd_float3 eye, simd_float3 at, simd_float3 up);

Expand Down