├── .gitignore ├── BoundingBoxOnScreen.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── README.md └── screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | 35 | # etc 36 | Framework/ 37 | *~ 38 | *.swp 39 | 40 | -------------------------------------------------------------------------------- /BoundingBoxOnScreen.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import PlaygroundSupport 2 | import AppKit 3 | import SpriteKit 4 | import SceneKit 5 | 6 | class BBView: SCNView, SCNSceneRendererDelegate { 7 | var trackingNode: SCNNode! 8 | var boundingBox: SKShapeNode! 9 | let bbSize: CGFloat = 20.0 10 | var sizeLabel: SKLabelNode! 11 | 12 | init() { 13 | super.init(frame: NSRect(x: 0, y: 0, width: 400, height: 250), options: nil) 14 | 15 | self.autoenablesDefaultLighting = true 16 | self.backgroundColor = SKColor.gray 17 | self.allowsCameraControl = true 18 | 19 | self.showsStatistics = true 20 | self.debugOptions = .showBoundingBoxes 21 | 22 | self.setupScene() 23 | self.setupSKScene() 24 | 25 | self.delegate = self 26 | } 27 | 28 | required init?(coder: NSCoder) { 29 | fatalError("init(coder:) has not been implemented") 30 | } 31 | 32 | func setupScene() { 33 | let scene = SCNScene() 34 | self.scene = scene 35 | 36 | // set camera node 37 | let cameraNode = SCNNode() 38 | let camera = SCNCamera() 39 | cameraNode.camera = camera 40 | scene.rootNode.addChildNode(cameraNode) 41 | self.pointOfView = cameraNode 42 | 43 | // create a sphere 44 | let sphere = SCNSphere(radius: 1.0) 45 | self.trackingNode = SCNNode(geometry: sphere) 46 | self.trackingNode.position = SCNVector3(0, 0, -10.0) 47 | scene.rootNode.addChildNode(self.trackingNode) 48 | } 49 | 50 | func setupSKScene() { 51 | let skScene = SKScene(size: self.bounds.size) 52 | self.overlaySKScene = skScene 53 | 54 | self.boundingBox = SKShapeNode(rect: CGRect(x: 0, y: 0, width: self.bbSize, height: self.bbSize)) 55 | self.boundingBox.strokeColor = SKColor.red 56 | self.boundingBox.lineWidth = 3 57 | 58 | skScene.addChild(self.boundingBox) 59 | 60 | self.sizeLabel = SKLabelNode(fontNamed: "Arial") 61 | self.sizeLabel.fontSize = 24 62 | self.sizeLabel.fontColor = SKColor.black 63 | self.sizeLabel.horizontalAlignmentMode = .left 64 | // I don't know why but "self.sizeLabel.position.y = 25.0" causes a compile error 65 | self.sizeLabel.position = CGPoint(x: self.sizeLabel.position.x, y: 25.0) 66 | 67 | skScene.addChild(self.sizeLabel) 68 | } 69 | 70 | func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { 71 | let (localMin, localMax) = self.trackingNode.boundingBox 72 | let min = self.trackingNode.convertPosition(localMin, to: nil) 73 | let max = self.trackingNode.convertPosition(localMax, to: nil) 74 | let vertices = [ 75 | SCNVector3(min.x, min.y, min.z), 76 | SCNVector3(max.x, min.y, min.z), 77 | SCNVector3(min.x, max.y, min.z), 78 | SCNVector3(max.x, max.y, min.z), 79 | SCNVector3(min.x, min.y, max.z), 80 | SCNVector3(max.x, min.y, max.z), 81 | SCNVector3(min.x, max.y, max.z), 82 | SCNVector3(max.x, max.y, max.z) 83 | ] 84 | let arr = vertices.map { self.projectPoint($0) } 85 | 86 | let minX: CGFloat = arr.reduce(CGFloat.infinity, { $0 > $1.x ? $1.x : $0 }) 87 | let minY: CGFloat = arr.reduce(CGFloat.infinity, { $0 > $1.y ? $1.y : $0 }) 88 | //let minZ: CGFloat = arr.reduce(CGFloat.infinity, { $0 > $1.z ? $1.z : $0 }) 89 | let maxX: CGFloat = arr.reduce(-CGFloat.infinity, { $0 < $1.x ? $1.x : $0 }) 90 | let maxY: CGFloat = arr.reduce(-CGFloat.infinity, { $0 < $1.y ? $1.y : $0 }) 91 | //let maxZ: CGFloat = arr.reduce(-CGFloat.infinity, { $0 < $1.z ? $1.z : $0 }) 92 | 93 | let width = maxX - minX 94 | let height = maxY - minY 95 | //let depth = maxZ - minZ 96 | 97 | self.boundingBox.position = CGPoint(x: minX, y: minY) 98 | self.boundingBox.xScale = width / self.bbSize 99 | self.boundingBox.yScale = height / self.bbSize 100 | 101 | self.sizeLabel.text = "W: \(width), H: \(height)" 102 | } 103 | } 104 | 105 | let view = BBView() 106 | 107 | PlaygroundSupport.PlaygroundPage.current.liveView = view 108 | PlaygroundSupport.PlaygroundPage.current.needsIndefiniteExecution = true 109 | 110 | -------------------------------------------------------------------------------- /BoundingBoxOnScreen.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /BoundingBoxOnScreen.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BoundingBoxOnScreen.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SceneKitBoundingBoxOnScreen 2 | Xcode Playground to show how to calculate the size of the bounding box in screen space 3 | 4 | ![screenshot](https://raw.githubusercontent.com/magicien/SceneKitBoundingBoxOnScreen/master/screenshot.png) 5 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicien/SceneKitBoundingBoxOnScreen/088dba274143de3c94598217bb8ff116796eb746/screenshot.png --------------------------------------------------------------------------------