Bas*_*Man 11 xcode objective-c ios scenekit swift
我很想采用新的Swift语言,因为这似乎是Apple开发的前进方向.我对iOS 8中的新SceneKit支持印象深刻.我想在运行时以编程方式创建自定义几何,但我很难让Swift代码工作.然而,Objective C中的等效代码工作正常.
这可能是一个错误,或者我做错了什么.
我只是想创建并渲染一个三角形.为简单起见,我将忽略法线和纹理等.所以我只期待看到一个黑色的三角形.
Swift代码(不工作)
var verts = [SCNVector3(x: 0,y: 0,z: 0),SCNVector3(x: 1,y: 0,z: 0),SCNVector3(x: 0,y: 1,z: 0)]
let src = SCNGeometrySource(vertices: &verts, count: 3)
let indexes:Int[]=[0,1,2]
let dat = NSData(bytes: indexes, length: sizeofValue(indexes))
let ele = SCNGeometryElement(data:dat, primitiveType: .Triangles, primitiveCount: 1, bytesPerIndex: sizeof(Int))
let geo = SCNGeometry(sources: [src], elements: [ele])
let nd = SCNNode(geometry: geo)
scene.rootNode.addChildNode(nd)
Run Code Online (Sandbox Code Playgroud)
Objective C Code(确实有效)
SCNVector3 verts[] = { SCNVector3Make(0, 0, 0), SCNVector3Make(1, 0, 0), SCNVector3Make(0, 1, 0) };
SCNGeometrySource *src = [SCNGeometrySource geometrySourceWithVertices:verts count:3];
int indexes[] = { 0, 1, 2 };
NSData *datIndexes = [NSData dataWithBytes:indexes length:sizeof(indexes)];
SCNGeometryElement *ele = [SCNGeometryElement geometryElementWithData:datIndexes primitiveType:SCNGeometryPrimitiveTypeTriangles primitiveCount:1 bytesPerIndex:sizeof(int)];
SCNGeometry *geo = [SCNGeometry geometryWithSources:@[src] elements:@[ele]];
SCNNode *nd = [SCNNode nodeWithGeometry:geo];
d
[scene.rootNode addChildNode:nd];
Run Code Online (Sandbox Code Playgroud)
任何指针将不胜感激.
好吧,这两段代码并没有完全相互转换.该int
在C是不一样Int
的斯威夫特.它实际上是CInt
在Swift中调用的:
/// The C 'int' type.
typealias CInt = Int32
Run Code Online (Sandbox Code Playgroud)
如果你改为使用两个匹配项CInt
,那么你之前得到的错误信息就会消失(至少对我来说是OS X Playground.但是,它仍然没有为我渲染任何东西.
我不认为sizeofValue
用于返回数组的大小.它看起来像它返回指针的大小:
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
Run Code Online (Sandbox Code Playgroud)
所以,对我来说,下面的代码是有效的(我已经将参数放在不同的行上,以便更容易指出我的更改):
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)
Run Code Online (Sandbox Code Playgroud)
有了这个结果:
大卫的答案非常好,但要提供更完整的图片......
结构的迅速阵列包其数据一起像C数组结构的,而不是一个ObjC NSArray
的NSValue
-wrapped结构.并且您可以将Swift数组传递给(Obj)C API,这些API采用CMutablePointer
或类似,因此NSData
从Swift数组构造一个非常酷.
结构的/结构数组也是如此,只要它们最终都归结为标量类型.
即使在ObjC中,制作数组也SCNVector3
可能会有问题,因为该结构的元素类型在32/64位体系结构之间变化.
sizeOfValue
对于Beta 2中的数组似乎没有按预期工作,所以我建议提交一个错误.
如果ArrayLiteralConvertible
在自定义结构中实现协议,则可以简明地声明嵌套结构值的数组.
如果您意识到这些问题,您可以在Swift中使用(Obj)C中的顶点/索引缓冲区管理的大多数相同技巧.例如,这是一个片段,它使用交错的顶点和普通数据构建自定义几何体(这有利于iOS设备GPU上的性能):
struct Float3 : ArrayLiteralConvertible {
typealias Element = GLfloat
var x, y, z: GLfloat
init(arrayLiteral elements: Element...) {
self.x = elements[0]
self.y = elements[1]
self.z = elements[2]
}
}
struct Vertex: ArrayLiteralConvertible {
typealias Element = Float3
var position, normal: Float3
init(arrayLiteral elements: Element...) {
self.position = elements[0]
self.normal = elements[1]
}
}
// This must be a var, not a let, because it gets passed to a CMutablePointer
var vertices: Vertex[] = [
[ [+0.5, -0.5, -0.5], [+1.0, +0.0, +0.0] ],
[ [+0.5, +0.5, -0.5], [+1.0, +0.0, +0.0] ],
// ... lots more vertices here!
]
let data = NSData(bytes: vertices, length: vertices.count * sizeof(Vertex))
let vertexSource = SCNGeometrySource(data: data,
semantic: SCNGeometrySourceSemanticVertex,
vectorCount: vertices.count,
floatComponents: true,
componentsPerVector: 3,
bytesPerComponent: sizeof(GLfloat),
dataOffset: 0,
dataStride: sizeof(Vertex))
let normalSource = SCNGeometrySource(data: data,
semantic: SCNGeometrySourceSemanticNormal,
vectorCount: vertices.count,
floatComponents: true,
componentsPerVector: 3,
bytesPerComponent: sizeof(GLfloat),
// no offsetof() in Swift, but Vertex has one Float3 before normal
dataOffset: sizeof(Float3),
dataStride: sizeof(Vertex))
// use a Swift Range to quickly construct a sequential index buffer
let indexData = NSData(bytes: Array<UInt8>(0..<UInt8(vertices.count)),
length: vertices.count * sizeof(UInt8))
let element = SCNGeometryElement(data: indexData,
primitiveType: .Triangles,
primitiveCount: vertices.count / 3,
bytesPerIndex: sizeof(UInt8))
let cube = SCNGeometry(sources: [vertexSource, normalSource], elements: [element])
Run Code Online (Sandbox Code Playgroud)