2

REVISED PROBLEM:

I don't understand why the white node is centered when it's a box or sphere but not when it's text. You can comment/uncomment the whiteGeometry variable to see how each different geometry is displayed. I was originally thinking that I had to manually center the text by determining the width of the box and the text and calculating the position of the text. Do I need to do that? Why is the text behaving differently?

import SceneKit
import PlaygroundSupport

let scene = SCNScene()
let sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
sceneView.scene = scene
sceneView.backgroundColor = .darkGray
sceneView.autoenablesDefaultLighting = true
sceneView.allowsCameraControl = true
PlaygroundPage.current.liveView = sceneView

// Camera
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 0, y: 0, z: 25)
sceneView.pointOfView = cameraNode

let blackGeometry = SCNBox(width: 10.0, height: 10.0, length: 10.0, chamferRadius: 0)
blackGeometry.firstMaterial?.diffuse.contents = UIColor.black
print("blackGeometry min=\(blackGeometry.boundingBox.min)")
print("blackGeometry max=\(blackGeometry.boundingBox.max)")
let blackNode = SCNNode(geometry: blackGeometry)
blackNode.position = SCNVector3(x: 0, y: 0, z: 0)
scene.rootNode.addChildNode(blackNode)

// let whiteGeometry = SCNBox(width: 3.0, height: 3.0, length: 3.0, chamferRadius: 0)
let whiteGeometry = SCNText(string: "L", extrusionDepth: 0)
whiteGeometry.alignmentMode =  kCAAlignmentLeft
whiteGeometry.font = UIFont.systemFont(ofSize: 8.0)
// let whiteGeometry = SCNSphere(radius: 3.0)
whiteGeometry.firstMaterial?.diffuse.contents = UIColor.white
print("whiteGeometry min=\(whiteGeometry.boundingBox.min)")
print("whiteGeometry max=\(whiteGeometry.boundingBox.max)")
let whiteNode = SCNNode(geometry: whiteGeometry)

let boxWidth = blackGeometry.boundingBox.max.x - blackGeometry.boundingBox.min.x
let boxHeight = blackGeometry.boundingBox.max.y - blackGeometry.boundingBox.min.y
print("boxWidth=\(boxWidth)")
print("boxHeight=\(boxHeight)")

let txtWidth = whiteGeometry.boundingBox.max.x - whiteGeometry.boundingBox.min.x
let txtHeight = whiteGeometry.boundingBox.max.y - whiteGeometry.boundingBox.min.y
print("txtWidth=\(txtWidth)")
print("txtHeight=\(txtHeight)")

whiteNode.position = SCNVector3(x: -5.0, y: -5.0, z: 10)
scene.rootNode.addChildNode(whiteNode)
//blackNode.addChildNode(whiteNode)

print("done")

ORIGINAL PROBLEM (OLD):

Let's say I have two SCNBox nodes (I'm simplifying this to make it clear BUT the solution must work for other geometries). A large black box and a small white box. I want to center the white box in front of the black box.

To do this, I need to determine the width and height of the two nodes. Remember that the node could be something other than a box like a sphere or text. From what I can tell, the only way to determine width/height is via the boundingBox property on the geometry. It has a min and max value that is NOT clearly and fully described in Apple's reference manual. To get the height, it seems like I would calculate it based on boundingBox.max.y and boundingBox.min.y. So looking at the example below of a 10x10x10 box, I can't see how I can get 10.0 as the height because max.y 5.20507812

e.g.

let box = SCNBox(width: 10.0, height: 10.0, length: 10.0, chamferRadius: 0)
print("box min=\(box.boundingBox.min)")
print("box max=\(box.boundingBox.max)")

yields:

box min=SCNVector3(x: -5.0, y: -5.0, z: -5.0)
box max=SCNVector3(x: 5.0, y: 5.20507812, z: 5.0)

Why is max.y=5.20507812? How should I determine the height/width?

See also: SCNBoundingVolume

user3246173
  • 488
  • 6
  • 18
  • 1
    Is the white box a child node of the black box? Are you doing any translation, pivoting etc to make it appear in front? It would be helpful if you can you post more of your code. – sambro Mar 29 '17 at 19:12
  • 1
    I ran that code snippet in a playground and got +/- 5 for each value. – Hal Mueller Mar 29 '17 at 22:19
  • Yes, I made the white box a child of the black box. When it's not a child of the black box, the max.y value is 5.0. I'm reworking the code in a Swift playground to clarify the issue. – user3246173 Mar 30 '17 at 00:00

1 Answers1

2

I think I understand now.

It looks like you're trying to put some text in front of an object, with the text centered on the object relative to the camera. And this question isn't about bounding boxes per se. Right?

You see different behavior with the white geometry being a sphere or SCNText because SCNText's uses a different origin convention than the other concrete SCNGeometry classes. Other geometries put the origin at the center. SCNText puts it at the lower left of the text. If I remember correctly, "lower" means the bottom of the font (lowest descender), not the baseline.

So you'll need to compute the text's bounding box, and account for that when you position the text node, to get it centered. You don't need to do that for the other geometry types. If the covered object or the camera is moving, you'll need to compute the ray from the camera to the covered object in the render loop, and update the text's position.

Swift Scenekit - Centering SCNText - the getBoundingBoxMin:Max issue is relevant.

If you just want overlay text, you might find it easier to put the text in an SKScene overlay. An example of that is at https://github.com/halmueller/ImmersiveInterfaces/tree/master/Tracking%20Overlay (warning, bit rot may have set in, I haven't tried that code in a while).

Community
  • 1
  • 1
Hal Mueller
  • 7,019
  • 2
  • 24
  • 42
  • I read that other post before posting. It didn't help as it was out of date, incomplete, etc... I updated the code above. I added some calculations for box width/height and text width/height. I try to manually set the position of the text but it doesn't align correctly. It would be helpful if I could SEE the bounding box visually of the box and the text nodes. – user3246173 Mar 30 '17 at 18:49
  • One question I have is whether there is a sizeToFit for SCNText? When you set the text for a SCNText node, is it sized to the minimum size to fit the text or is it some other default? – user3246173 Mar 30 '17 at 19:02
  • I found `SKScene` overlay easy to do but horrible in performance. It wastefully uses CPU to convert coordinates. Static node is fine. However if you want 2d label to track the 3d node, it's an instant performance kill. In my experiment I displayed ~30 tracking labels in a scene and the frame rate insta-dropped to 20fps. – Ben Lu Apr 03 '17 at 21:27