How to determine normal vector to an SCNPlane in Apple SceneKit

617 views Asked by At

I have an SCNode which is dynamically created using the SCNPlane geometry to draw a plane using SceneKit.

How do I determine the normal vector to this plane?

Here is a playground demonstrating what I have tried. I have attached a screenshot of the resulting scene that is drawn. I don't think any of the cylinders, which represent the vectors obtained at the normal vector to this red plane.

enter image description here

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

import UIKit
import SceneKit
import PlaygroundSupport

// Set up the scene view
let frame = CGRect(
    x: 0,
    y: 0,
    width: 500,
    height: 300)
let sceneView = SCNView(frame: frame)
sceneView.showsStatistics = true
sceneView.autoenablesDefaultLighting = true
sceneView.allowsCameraControl = true
sceneView.scene = SCNScene()

// Setup our view into the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 3)
sceneView.scene!.rootNode.addChildNode(cameraNode)

// Add a plane to the scene
let plane = SCNNode(geometry: SCNPlane(width: 3,height: 3))
plane.geometry?.firstMaterial!.diffuse.contents = UIColor.red.withAlphaComponent(0.5)
plane.geometry?.firstMaterial?.isDoubleSided = true
sceneView.scene!.rootNode.addChildNode(plane)

/*
 
 normalSource = [SCNGeometrySource geometrySourceWithData:data
                                                 semantic:SCNGeometrySourceSemanticNormal
                                              vectorCount:VERTEX_COUNT
                                          floatComponents:YES
                                      componentsPerVector:3 // nx, ny, nz
                                        bytesPerComponent:sizeof(float)
                                               dataOffset:offsetof(MyVertex, nx)
                                               dataStride:sizeof(MyVertex)];
 
*/
let dataBuffer = plane.geometry?.sources(for: SCNGeometrySource.Semantic.normal)[0].data
let colorArray = [UIColor.red, UIColor.orange, UIColor.yellow, UIColor.green, UIColor.blue, UIColor.systemIndigo, UIColor.purple, UIColor.brown, UIColor.black, UIColor.systemPink]
let sceneGeometrySource = dataBuffer!.withUnsafeBytes {
    (vertexBuffer: UnsafePointer<SCNVector3>) -> SCNGeometrySource in
    let sceneVectors = Array(UnsafeBufferPointer(start: vertexBuffer, count: dataBuffer!.count/MemoryLayout<SCNVector3>.stride))
    var i=0
    for vector in sceneVectors{
        let cyl = SCNCylinder(radius: 0.05, height: 3)
        cyl.firstMaterial!.diffuse.contents = colorArray[i].withAlphaComponent(0.8)
        let lineNode = SCNNode(geometry: cyl)
        lineNode.eulerAngles = vector
        sceneView.scene!.rootNode.addChildNode(lineNode)
    }
    return SCNGeometrySource(vertices: sceneVectors)
}


PlaygroundSupport.PlaygroundPage.current.liveView = sceneView

enter image description here

1

There are 1 answers

0
Chris On

in the apple documentation https://developer.apple.com/documentation/accelerate/working_with_vectors in "Calculate the Normal of a Triangle" you can find the solution. You just need 3 points which are not on one line and then use this:

The following code defines the three vertices of the triangle:

let vertex1 = simd_float3(-1.5, 0.5, 0) let vertex2 = simd_float3(1, 0, 3) let vertex3 = simd_float3(0.5, -0.5, -1.5) Your first step in calculating the normal of the triangle is to create two vectors defined by the difference between the vertices—representing two sides of the triangle:

let vector1 = vertex2 - vertex3 let vector2 = vertex2 - vertex1 The simd_cross function returns the vector that's perpendicular to the two vectors you pass it. In this example, the returned vector is the normal of the triangle. Because the normal represents a direction, you can normalize the value to get a unit vector:

let normal = simd_normalize(simd_cross(vector1, vector2))