7

Trying to figure out how I create a SCNGeometry with polygon as primitiveType, My goal is to add polygon shaped node as a child of a sphere node, and make it look like MKPolygon for map kit, like in this example.

MKPolygon

My current code is:

//Take an arbitrary array of vectors
let vertices: [SCNVector3] = [
SCNVector3Make(-0.1304485, 0.551937, 0.8236193),
SCNVector3Make(0.01393811, 0.601815, 0.7985139),
SCNVector3Make(0.2971005, 0.5591929, 0.7739732),
SCNVector3Make(0.4516893, 0.5150381, 0.7285002),
SCNVector3Make(0.4629132, 0.4383712, 0.7704169),
SCNVector3Make(0.1333823, 0.5224985, 0.8421428),
SCNVector3Make(-0.1684743, 0.4694716, 0.8667254)]

//Does polygon shape require indices?
let indices: [Int] = [0,1,2,3,4,5,6]

let vertexSource = SCNGeometrySource(vertices: vertices)
let indexData = Data(bytes: indices, count: indices.count * MemoryLayout<Int>.size)

//Note!!! I get compiler error if primitiveCount is greater than 0
let element = SCNGeometryElement(data: indexData, primitiveType: .polygon, primitiveCount: 0, bytesPerIndex: MemoryLayout<Int>.size)
let geometry = SCNGeometry(sources: [vertexSource], elements: [element])

let material = SCNMaterial()
material.diffuse.contents = UIColor.purple.withAlphaComponent(0.75)
material.isDoubleSided = true
geometry.firstMaterial = material

let node = SCNNode(geometry: geometry)

When using SCNGeometryElement like this I get an empty node.

ItayAmza
  • 819
  • 9
  • 21

1 Answers1

11

You have two problems:

  1. SceneKit (and Metal) only support 32 bit integers as indices (source). So the type of your indices array needs to be [Int32].

  2. SceneKit needs two pieces of information for polygons: The number of points in the polygon and the index of the point in the vertex array. From Apple's documentation on SCNGeometryPrimitiveTypePolygon (which only exists in Objective-C):

The element’s data property holds two sequences of values.

  • The first sequence has a number of values equal to the geometry element’s primitiveCount value. Each value in this sequence specifies the number of vertices in a polygon primitive. For example, if the first sequence is [5, 3], the geometry element contains a pentagon followed by a triangle.
  • The rest of the data is a sequence of vertex indices. Each entry in the first sequence specifies a corresponding number of entries in the second sequence. For example, if the first sequence includes the values [5, 3], the second sequence includes five indices for the pentagon, followed by three indices for the triangle.

You need to change your index array to:

let indices: [Int32] = [7, /* We have a polygon with seven points */,
                        0,1,2,3,4,5,6 /* The seven indices for our polygon */
                       ]

Then, set the primitiveCount to 1 (we have one polygon to draw) and change the size of the buffer:

let indexData = Data(bytes: indices, 
                     count: indices.count * MemoryLayout<Int32>.size)

// Now without runtime error
let element = SCNGeometryElement(data: indexData, 
                                 primitiveType: .polygon,
                                 primitiveCount: 1, 
                                 bytesPerIndex: MemoryLayout<Int32>.size)
Matt Hampel
  • 5,088
  • 12
  • 52
  • 78
jlsiewert
  • 3,494
  • 18
  • 41
  • Thanks, thats solve most of my problems, on playground though when I assign `primitiveCount: 1` I get an error : `The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.` does that means that I cannot create SCNGeometryElement with polygon as primitiveType on playground? – ItayAmza Jul 05 '17 at 10:45
  • I have tested my code in Xcode Playgrounds (although in Xcode 9b2). Try restarting Xcode or copy-paste the code in a new one, this is probably just a bug in Xcode. – jlsiewert Jul 05 '17 at 10:46
  • Restart helps, Tnx – ItayAmza Jul 05 '17 at 10:47
  • 2
    Some polygons are drawn but for some it says "Cannot create buffer of zero length." – khunshan Jan 26 '18 at 09:39
  • I'm also experiencing what @khunshan is describing, seems to crash more often when many vertices are used. I posted my own question regarding this issue [here](https://stackoverflow.com/questions/56773438/creating-a-custom-scngeometry-polygon-plane-with-scngeometryprimitivetype-polygo) – A. Claesson Jun 26 '19 at 13:53