Yes, that wasn't the issue. It doesn't like the order and there is overlap. It's easier to see when you reduce the nProfiles and print the arrays to visually inspect them. I don't even remember why I started using .makeVerticesUniqueAndReturnError() but it's not even needed here.
let controlPoints: [(x: Float, y: Float)] = [
(0.728,-0.237), (0.176,-0.06), (0.202,0.475), (0.989,0.842),
(-0.066,1.093), (-0.726,0.787) ]
let pairs = bsplinePath(controlPoints)
var knobProfile = [SCNVector3]()
for (x,y) in pairs {
knobProfile += [ SCNVector3(x: Float(x), y: Float(y), z: 0)]
}
let nProfiles = 20
let aIncrement: CGFloat = 2 * CGFloat.pi / CGFloat(nProfiles)
var knobVertices: [SCNVector3] = []
for i in 0..<nProfiles {
let angle = aIncrement * CGFloat(i)
let rotatedProfile = knobProfile.map { $0.rotate(about: .y, by: Float(angle)) }
knobVertices.append(contentsOf: rotatedProfile)
}
let source = SCNGeometrySource(vertices: knobVertices)
var indices = [UInt16]()
let profileCount = knobProfile.count
for i in 0..<nProfiles {
let nextProfileIndex = (i + 1) % nProfiles
for j in 0..<profileCount - 1 {
let currentIndex = UInt16(i * profileCount + j)
let nextIndex = UInt16(nextProfileIndex * profileCount + j)
let nextIndexNext = UInt16(nextProfileIndex * profileCount + j + 1)
let currentIndexNext = UInt16(i * profileCount + j + 1)
indices.append(contentsOf: [currentIndex, nextIndex, currentIndexNext])
indices.append(contentsOf: [currentIndexNext, nextIndex, nextIndexNext])
}
}
let element = SCNGeometryElement(indices: indices, primitiveType: .triangles)
let surfaceGeometry = SCNGeometry(sources: [source], elements: [element])
let modelMesh = MDLMesh(scnGeometry: surfaceGeometry)
let aluminum = SCNMaterial()
aluminum.lightingModel = .physicallyBased
aluminum.diffuse.contents = UIColor.green
aluminum.roughness.contents = 0.2
aluminum.metalness.contents = 0.9
aluminum.isDoubleSided = true
surfaceGeometry.materials = [aluminum]
//let knobNode = SCNNode(geometry: surfaceGeometry)
//return knobNode
do{
try modelMesh.makeVerticesUniqueAndReturnError()
modelMesh.addNormals(withAttributeNamed: "normal", creaseThreshold: 0.1)
let flattenedGeom = SCNGeometry(mdlMesh: modelMesh)
let flattenedNode = SCNNode(geometry: flattenedGeom)
flattenedNode.geometry?.materials = [aluminum]
return flattenedNode
}catch{
fatalError("mesh vert error")
}
}