4

I have a programmatically created plane, and i would like to get the coordinates of one vertex that the plane has. Something like this: print(Plane.vertices[1].position) and it might print something like: (x: 1, y: 1), and print(Plane.vertices[2].position) prints (x - 1, y: 1)

enter image description here This is how i created the plane:

let positions = [SCNVector3Make(  0, -0.1,  0),
                         SCNVector3Make(  0.3, -0.1,  0),

                         SCNVector3Make(  0,  0.1,  0),
                         SCNVector3Make(  0.3,  0.1,  0),
                         ]
        let indices :[UInt16] = [

            0, 1, 2,
            1, 3, 2,
            ]

        let vertexSource = SCNGeometrySource(vertices: positions, count: 4)
        let indexData = NSData(bytes: indices, length: MemoryLayout<CInt>.size * indices.count)


        let newElement = SCNGeometryElement(data: NSData(bytes: indices, length: indices.count * MemoryLayout<Int16>.size) as Data, primitiveType: .triangles , primitiveCount: 2, bytesPerIndex: MemoryLayout<Int16>.size)

        let geometry = SCNGeometry(sources: [vertexSource], elements: [newElement])
        custom = SCNNode(geometry: geometry)
        scene.rootNode.addChildNode(custom!)
        custom?.position = SCNVector3Make(0, 0, 0)

I think that this could somehow be done with transform, but custom's transform has a lot of weird things like m11, m12, m13 which i don't understand.

Hal Mueller
  • 6,785
  • 2
  • 22
  • 40
Asphys
  • 167
  • 2
  • 14
  • I have googled the problem and looked at many stack overflow questions about the transform thing, but they do not explain what the scnmatrix m things mean. This post just probably sounds like i haven't read anything about scenekit because english is not my first language and it is hard to describe some things in english – Asphys Jan 14 '17 at 19:11
  • 1
    From this question and your other one about a plane's vertices, I still don't understand what effect you want to see. Can you draw us a rough pencil sketch and upload it? – Hal Mueller Jan 15 '17 at 02:39
  • 1
    @HalMueller I think he's after the scene coordinates of each of the vertices he's created to build his plane object. – Confused Jan 15 '17 at 07:02
  • I'm on a mac, and can't draw with this, but I have a plane (SCNPlane or a programmatically created plane) that has 4 vertices, so 4 corners. Now i want to get the coordinates of one vertex that the plane has. Something like this: print(Plane.vertices[1].position) and it might print something like: (x: 1, y: 1) and print(Plane.vertices[2].position) prints (x - 1, y: 1) – Asphys Jan 15 '17 at 07:39
  • @HalMueller [example](http://i.imgur.com/yoJSjQW.png) – Asphys Jan 15 '17 at 09:34

1 Answers1

6

This is a more complicated question than it seems at first glance.

SceneKit will store the coordinates for the geometry used to generate a node in the original scale/basis. Those don't change once the object is created. And for primitives like SCNPlane or SCNBox, those geometries are shared within a scene. So if you have a bunch of different planes or boxes, all at different positions, rotations, and scaling, you'll get the same vertices out when you query the SCNGeometrySource. There's a good discussion of that retrieval here: Extracting vertices from scenekit. But that approach won't give you the corners in your local coordinate space.

We have two functions that work on SCNNode and SCNGeometry: boundingBox and boundingSphere (they're defined in protocol SCNBoundingVolume). The boundingBox gives you two points, the minimum and the maximum. From those two opposite corners of a cube, you can figure out the corner vertices of your plane. There's another complication, though. Both of those functions return their answers in local coordinates, the coordinate system used by the node itself. So we're still stuck: every one of my planes or boxes will have the same bounding box.

The answer I came up with is to use SCNNode's convertPosition(_, to: node), passing the scene's root node. That finally gives me bounding boxes in the root node's coordinate space.

for node in [custom1, custom2, plainPlane1, plainPlane2] {
    print(node.name!)
    print(node.boundingBox.max)
    print(node.boundingBox.min)
    print(node.convertPosition(node.boundingBox.min, to: scene.rootNode))
    print(node.convertPosition(node.boundingBox.max, to: scene.rootNode))
}

producing

custom 1
SCNVector3(x: 0.300000011920929, y: 0.100000001490116, z: 0.0)
SCNVector3(x: 0.0, y: -0.100000001490116, z: 0.0)
SCNVector3(x: 0.0, y: -0.100000001490116, z: -1.0)
SCNVector3(x: 0.300000011920929, y: 0.100000001490116, z: -1.0)
custom 2
SCNVector3(x: 0.300000011920929, y: 0.100000001490116, z: 0.0)
SCNVector3(x: 0.0, y: -0.100000001490116, z: 0.0)
SCNVector3(x: 0.200000002980232, y: 0.429289322037836, z: -1.07071067796216)
SCNVector3(x: 0.500000014901161, y: 0.570710677962164, z: -0.929289322037836)
plain plane 1
SCNVector3(x: 0.5, y: 1.0, z: 0.0)
SCNVector3(x: -0.5, y: -1.0, z: 0.0)
SCNVector3(x: -0.5, y: -1.0, z: -2.0)
SCNVector3(x: 0.5, y: 1.0, z: -2.0)
plain plane 2
SCNVector3(x: 0.5, y: 1.0, z: 0.0)
SCNVector3(x: -0.5, y: -1.0, z: 0.0)
SCNVector3(x: -9.18485139438876e-18, y: -0.300000011920929, z: -1.84999999403954)
SCNVector3(x: 9.18485139438876e-18, y: 0.300000011920929, z: -2.15000000596046)

for this scene: enter image description here

Here's the full macOS playground below:

//: Playground - noun: a place where people can play

import Cocoa
import SceneKit
import PlaygroundSupport

let positions = [SCNVector3Make(  0, -0.1,  0),
                 SCNVector3Make(  0.3, -0.1,  0),
                 SCNVector3Make(  0,  0.1,  0),
                 SCNVector3Make(  0.3,  0.1,  0),
]
let indices :[UInt16] = [
    0, 1, 2,
    1, 3, 2,
]

let vertexSource = SCNGeometrySource(vertices: positions, count: 4)
let indexData = NSData(bytes: indices, length: MemoryLayout.size * indices.count)

let newElement = SCNGeometryElement(data: NSData(bytes: indices,
                                                 length: indices.count * MemoryLayout.size) as Data,
                                    primitiveType: .triangles ,
                                    primitiveCount: 2, 
                                    bytesPerIndex: MemoryLayout.size)

let sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 600, height: 400))
sceneView.allowsCameraControl = true
sceneView.autoenablesDefaultLighting = true
sceneView.backgroundColor = NSColor.darkGray
sceneView.showsStatistics = true
PlaygroundPage.current.liveView = sceneView

let scene = SCNScene()
sceneView.scene = scene

let geometry = SCNGeometry(sources: [vertexSource], elements: [newElement])
geometry.firstMaterial?.diffuse.contents = NSColor.red
geometry.firstMaterial?.isDoubleSided = true
let custom1 = SCNNode(geometry: geometry)
custom1.position = SCNVector3Make(0, 0, -1)
custom1.name = "custom 1"
scene.rootNode.addChildNode(custom1)

let custom2 = SCNNode(geometry: geometry)
custom2.position = SCNVector3Make(0.2, 0.5, -1)
custom2.rotation = SCNVector4Make(1, 0, 0, CGFloat(M_PI_4))
custom2.name = "custom 2"
scene.rootNode.addChildNode(custom2)

let plainPlaneGeometry = SCNPlane(width: 1, height: 2)
plainPlaneGeometry.firstMaterial?.diffuse.contents = NSColor.yellow
plainPlaneGeometry.firstMaterial?.isDoubleSided = true
let plainPlane1 = SCNNode(geometry: plainPlaneGeometry)
plainPlane1.position = SCNVector3Make(0, 0, -2)
plainPlane1.name = "plain plane 1"
scene.rootNode.addChildNode(plainPlane1)

let plainPlane2 = SCNNode(geometry: plainPlaneGeometry)
plainPlane2.position = SCNVector3Make(0, 0, -2)
plainPlane2.rotation = SCNVector4Make(0, 1, 0, CGFloat(M_PI_2))
plainPlane2.scale = SCNVector3Make(0.3, 0.3, 0.3)
plainPlane2.name = "plain plane 2"
scene.rootNode.addChildNode(plainPlane2)

for node in [custom1, custom2, plainPlane1, plainPlane2] {
    print(node.name!)
    print(node.boundingBox.max)
    print(node.boundingBox.min)
//  print(node.transform)
    print(node.convertPosition(node.boundingBox.min, to: scene.rootNode))
    print(node.convertPosition(node.boundingBox.max, to: scene.rootNode))
}

You mentioned the transformation matrix. There's a nice explanation of what it looks like and how it works at Need better and simpler understanding of CATransform3D (with citations to two good Wikipedia articles), and an easy to digest overview at http://sketchytech.blogspot.com/2014/12/explaining-catransform3d-matrix.html.

Community
  • 1
  • 1
Hal Mueller
  • 6,785
  • 2
  • 22
  • 40