簡體   English   中英

iOS上的Swift中的自定義SceneKit幾何不能正常工作但是等效的Objective C代碼可以

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM