Skip to content

Instantly share code, notes, and snippets.

@kylehowells
Last active December 8, 2022 17:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kylehowells/6cee5ee5cb016d6cf08fecd305f767fe to your computer and use it in GitHub Desktop.
Save kylehowells/6cee5ee5cb016d6cf08fecd305f767fe to your computer and use it in GitHub Desktop.
import SceneKit
struct SceneKitBoundingBox {
let backLeftTop: SCNVector3
let backLeftBottom: SCNVector3
let backRightTop: SCNVector3
let backRightBottom: SCNVector3
let frontLeftTop: SCNVector3
let frontLeftBottom: SCNVector3
let fromRightTop: SCNVector3
let fromRightBottom: SCNVector3
init(min: SCNVector3, max: SCNVector3) {
self.backLeftTop = SCNVector3(min.x, min.y, max.z)
self.backLeftBottom = SCNVector3(min.x, min.y, min.z)
self.backRightTop = SCNVector3(max.x, min.y, max.z)
self.backRightBottom = SCNVector3(max.x, min.y, min.z)
self.frontLeftTop = SCNVector3(min.x, max.y, max.z)
self.frontLeftBottom = SCNVector3(min.x, max.y, min.z)
self.fromRightTop = SCNVector3(max.x, max.y, max.z)
self.fromRightBottom = SCNVector3(max.x, max.y, min.z)
}
}
func convertToScreen(coord: SCNVector3, fromNode: SCNNode) -> CGPoint {
let converted: SCNVector3 = fromNode.convertPosition(coord, to: nil)
let projectedPoint: SCNVector3 = self.sceneView.projectPoint(converted)
let point = CGPoint(
x: CGFloat(projectedPoint.x),
y: CGFloat(projectedPoint.y)
)
return point
}
struct ScreenBoundingBox {
let backLeftTop: CGPoint
let backLeftBottom: CGPoint
let backRightTop: CGPoint
let backRightBottom: CGPoint
let frontLeftTop: CGPoint
let frontLeftBottom: CGPoint
let fromRightTop: CGPoint
let fromRightBottom: CGPoint
init(boundingBox: SceneKitBoundingBox, fromNode: SCNNode, convertToScreen: (SCNVector3, SCNNode) -> CGPoint) {
self.backLeftTop = convertToScreen(boundingBox.backLeftTop, fromNode)
self.backLeftBottom = convertToScreen(boundingBox.backLeftBottom, fromNode)
self.backRightTop = convertToScreen(boundingBox.backRightTop, fromNode)
self.backRightBottom = convertToScreen(boundingBox.backRightBottom, fromNode)
self.frontLeftTop = convertToScreen(boundingBox.frontLeftTop, fromNode)
self.frontLeftBottom = convertToScreen(boundingBox.frontLeftBottom, fromNode)
self.fromRightTop = convertToScreen(boundingBox.fromRightTop, fromNode)
self.fromRightBottom = convertToScreen(boundingBox.fromRightBottom, fromNode)
}
private var points: [CGPoint] {
return [
self.backLeftTop,
self.backLeftBottom,
self.backRightTop,
self.backRightBottom,
self.frontLeftTop,
self.frontLeftBottom,
self.fromRightTop,
self.fromRightBottom,
]
}
var minX: CGPoint {
return self.points.min(by: { $0.x < $1.x })!
}
var maxX: CGPoint {
return self.points.max(by: { $0.x < $1.x })!
}
var minY: CGPoint {
return self.points.min(by: { $0.y < $1.y })!
}
var maxY: CGPoint {
return self.points.max(by: { $0.y < $1.y })!
}
}
private func fixFieldOfView() {
guard let scene: SCNScene = self.scene else { return }
if let firstChild: SCNNode = scene.rootNode.childNodes.first {
let boundingBox = firstChild.boundingBox
let fullBoundingBox = SceneKitBoundingBox(min: boundingBox.min, max: boundingBox.max)
let screenBoundingBox = ScreenBoundingBox(
boundingBox: fullBoundingBox,
fromNode: firstChild,
convertToScreen: self.convertToScreen(coord:fromNode:)
)
let minX: CGFloat = screenBoundingBox.minX.x
let maxX: CGFloat = screenBoundingBox.maxX.x
let minY: CGFloat = screenBoundingBox.minY.y
let maxY: CGFloat = screenBoundingBox.maxY.y
print("minX: \(minX) - maxX: \(maxX)")
print("minY: \(minY) - maxY: \(maxY)")
let totalWidth: CGFloat = (maxX - minX)
let scaleX = totalWidth / self.screenWidth
print("totalWidth: \(totalWidth) - screenWidth: \(self.screenWidth) - scaleX: \(scaleX)")
if let cameraNode = self.sceneView.pointOfView, let camera = cameraNode.camera {
let fieldOfView = String(format: "%.3f", camera.fieldOfView)
print("camera: \(camera) - fieldOfView: \(fieldOfView) - position: \(cameraNode.position)")
if scaleX > 1 {
let fieldOfView: CGFloat = camera.fieldOfView
let newFieldOfView: CGFloat = fieldOfView / (1.0 / scaleX)
camera.fieldOfView = newFieldOfView
print("fieldOfView: \(fieldOfView) - newFieldOfView: \(newFieldOfView)")
}
}
}
DispatchQueue.main.async(execute: {
self.sceneView.alpha = 1
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment