[英]Custom SceneKit Geometry in Swift on iOS not working but equivalent Objective C code does
我很想采用新的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)
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];
任何指針將不勝感激。
好吧,這兩段代碼並沒有完全相互轉換。 該int
在C是不一樣的Int
斯威夫特。 它實際上在Swift中被稱為CInt
:
/// The C 'int' type.
typealias CInt = Int32
如果你改變這兩種情況而不是使用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
所以,對我來說,下面的代碼是有效的(我已經將參數放在不同的行上,以便更容易指出我的更改):
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)
有了這個結果:
大衛的答案非常好,但要提供更完整的圖片......
Swift數組結構將其數據打包在一起,就像一個C數組結構,而不是NSValue
-wrapped結構的ObjC NSArray
。 並且您可以將Swift數組傳遞給采用CMutablePointer
或類似的(Obj)C API ,因此從Swift數組構造NSData
非常酷。
結構的/結構數組也是如此,只要它們最終都歸結為標量類型。
即使在ObjC,使得陣列SCNVector3
可能是有問題的,因為第32/64位體系結構之間的結構變化的元素類型。
對於Beta 2中的數組, sizeOfValue
似乎沒有按預期工作,所以我建議提交一個bug 。
如果在自定義結構中實現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])
我不太了解swift,但我希望你的版本“verts”和“index”在swift和ObjC(實際上是C)中完全不同。
在您的C版本中,您將獲得C結構的C數組。 在swift中,我假設你得到一個包含在NSValues中的SCNVector3的快速“數組”(相當於NSArray)。 因此,使用“索引”字節構建的NSData不包含像C一樣的浮點值的平緩沖區。對於“verts”數組也是如此。
看起來像這樣的C和swift互操作性問題在這里討論: Swift使用c struct
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.