MetalByTutorials/05-lighting-fundamentals/starter/Lighting/Lighting/Camera.swift

122 lines
3.8 KiB
Swift

//
/**
* Copyright (c) 2019 Razeware LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Notwithstanding the foregoing, you may not use, copy, modify, merge, publish,
* distribute, sublicense, create a derivative work, and/or sell copies of the
* Software in any work that is designed, intended, or marketed for pedagogical or
* instructional purposes related to programming, coding, application development,
* or information technology. Permission for such use, copying, modification,
* merger, publication, distribution, sublicensing, creation of derivative works,
* or sale is expressly withheld.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import Foundation
class Camera: Node {
var fovDegrees: Float = 70
var fovRadians: Float {
return fovDegrees.degreesToRadians
}
var aspect: Float = 1
var near: Float = 0.001
var far: Float = 100
var projectionMatrix: float4x4 {
return float4x4(projectionFov: fovRadians,
near: near,
far: far,
aspect: aspect)
}
var viewMatrix: float4x4 {
let translateMatrix = float4x4(translation: position)
let rotateMatrix = float4x4(rotation: rotation)
let scaleMatrix = float4x4(scaling: scale)
return (translateMatrix * scaleMatrix * rotateMatrix).inverse
}
func zoom(delta: Float) {}
func rotate(delta: float2) {}
}
class ArcballCamera: Camera {
var minDistance: Float = 0.5
var maxDistance: Float = 10
var target: float3 = [0, 0, 0] {
didSet {
_viewMatrix = updateViewMatrix()
}
}
var distance: Float = 0 {
didSet {
_viewMatrix = updateViewMatrix()
}
}
override var rotation: float3 {
didSet {
_viewMatrix = updateViewMatrix()
}
}
override var viewMatrix: float4x4 {
return _viewMatrix
}
private var _viewMatrix = float4x4.identity()
override init() {
super.init()
_viewMatrix = updateViewMatrix()
}
private func updateViewMatrix() -> float4x4 {
let translateMatrix = float4x4(translation: [target.x, target.y, target.z - distance])
let rotateMatrix = float4x4(rotationYXZ: [-rotation.x,
rotation.y,
0])
let matrix = (rotateMatrix * translateMatrix).inverse
position = rotateMatrix.upperLeft * -matrix.columns.3.xyz
return matrix
}
override func zoom(delta: Float) {
let sensitivity: Float = 0.05
distance -= delta * sensitivity
_viewMatrix = updateViewMatrix()
}
override func rotate(delta: float2) {
let sensitivity: Float = 0.005
rotation.y += delta.x * sensitivity
rotation.x += delta.y * sensitivity
rotation.x = max(-Float.pi/2,
min(rotation.x,
Float.pi/2))
_viewMatrix = updateViewMatrix()
}
}