Custom SceneKit Geometry in Swift on iOS not working but equivalent Objective C code does
Well, the two pieces of code doesn't translate exactly to one another. The int
in C is not the same as Int
in Swift. It's actually called CInt
in Swift:
/// The C 'int' type.
typealias CInt = Int32
If you change both occurrences to use CInt
instead, the error message that you previously got goes away (at least for me in an OS X Playground. However, it still doesn't render anything for me.
I don't think sizeofValue
is used to return the size of an array. It looks to me like it's returning the size of the pointer:
let indexes: CInt[] = [0, 1, 2]
sizeofValue(indexes) // is 8
sizeof(CInt) // is 4
sizeof(CInt) * countElements(indexes) // is 12
// compare to other CInt[]
let empty: CInt[] = []
let large: CInt[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sizeofValue(indexes) // is 8 (your array of indices again)
sizeofValue(empty) // is 8
sizeofValue(large) // is 8
So, for me the following code works (I've put the arguments on different lines to make it easier to point out my changes):
let src = SCNGeometrySource(vertices: &verts, count: 3)
let indexes: CInt[] = [0, 1, 2] // Changed to CInt
let dat = NSData(
bytes: indexes,
length: sizeof(CInt) * countElements(indexes) // Changed to size of CInt * count
)
let ele = SCNGeometryElement(
data: dat,
primitiveType: .Triangles,
primitiveCount: 1,
bytesPerIndex: sizeof(CInt) // Changed to CInt
)
let geo = SCNGeometry(sources: [src], elements: [ele])
let nd = SCNNode(geometry: geo)
scene.rootNode.addChildNode(nd)
With this result:
SceneKit – Custom geometry does not show up
Note: see Ash's answer, which is a much better approach for modern Swift than this one.
Your index array has the wrong size element. It's being inferred as [Int]
. You need [CInt]
.
I broke out your elements
setup into:
let indices = [0, 2, 3, 0, 1, 2] // [Int]
print(sizeof(Int)) // 8
print(sizeof(CInt)) // 4
let elements = [
SCNGeometryElement(indices: indices, primitiveType: .Triangles)
]
To get the indices to be packed like the expected C array, declare the type explicitly:
let indices: [CInt] = [0, 2, 3, 0, 1, 2]
Custom SceneKit Geometry in Swift on iOS not working but equivalent Objective C code does goes into more detail, but it's written against Swift 1, so you'll have to do some translation.
SCNGeometryElement(indices:, primitiveType:)
doesn't appear to be documented anywhere, although it does appear in the headers.
How to solve SceneKit double not supported error?
My guess would be an issue with SCNVector3
being defined in terms of CGFloat
for desktop (which can be either 32 or 64 bit depending on the host) and Float
for iOS devices -- the iOS Simulator platform (which is what you get when targeting iOS in a playground) is neither quite like a device nor quite like OS X. Filing a bug with Apple would be a good idea.
In the meantime, a good workaround might be to use the more detailed initializer (that starts with init(data:semantic:...
) to create your geometry source.
SceneKit – Drawing a line between two points
There are lots of ways to do this.
As noted, your custom geometry approach has some disadvantages. You should be able to correct the problem of it being invisible from one side by giving its material the doubleSided
property. You still may have issues with it being two-dimensional, though.
You could also modify your custom geometry to include more triangles, so you get a tube shape with three or more sides instead of a flat rectangle. Or just have two points in your geometry source, and use the SCNGeometryPrimitiveTypeLine
geometry element type to have Scene Kit draw a line segment between them. (Though you won't get as much flexibility in rendering styles with line drawing as with shaded polygons.)
You can also use the SCNCylinder
approach you mentioned (or any of the other built-in primitive shapes). Remember that geometries are defined in their own local (aka Model) coordinate space, which Scene Kit interprets relative to the coordinate space defined by a node. In other words, you can define a cylinder (or box or capsule or plane or whatever) that's 1.0 units wide in all dimensions, then use the rotation/scale/position or transform of the SCNNode
containing that geometry to make it long, thin, and stretching between the two points you want. (Also note that since your line is going to be pretty thin, you can reduce the segmentCount
s of whichever built-in geometry you're using, because that much detail won't be visible.)
Yet another option is the SCNShape
class that lets you create an extruded 3D object from a 2D Bézier path. Working out the right transform to get a plane connecting two arbitrary points sounds like some fun math, but once you do it you could easily connect your points with any shape of line you choose.
Related Topics
How to Determine If a User Has an iOS App Installed
How to Find Out What View a Touch Event Ended At
Detect When a Unicode Character Cannot Be Displayed Correctly
Uiscrollview with Dynamically Sized Content
Keep Bluetooth Sound When Initializing Avaudiosession
API Facebook iPhone , Possible to Post to a Friend's Wall
Is Char Signed or Unsigned by Default on iOS
Skspritenode Position Changes to 0,0 for No Reason
Ios: Usage of Self and Underscore(_) with Variable
How to Access an Iboutlet from Another Class
How to Draw on an Image in Swift
Removing Wkwebview Accesory Bar in Swift
Member Operator '%' Must Have at Least One Argument of Type 'Viewcontroller'
Uitableviewcell Textlabel Color Not Changing
Swipe Left or Right to Load the View Controller with the Collection View Cell Highlight