11

新しい 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 コード (動作します)

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];

任意のポインタをいただければ幸いです。

4

3 に答える 3

9

2 つのコードは、相互に正確に変換されるわけではありません。CのはSwiftintと同じではありません。Int実際にCIntはSwiftで呼び出されます:

/// 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)

この結果:

ここに画像の説明を入力

于 2014-06-30T15:45:22.203 に答える
8

デビッドの答えはかなり良いですが、より完全な全体像を提示するには...

  • NSArray構造体の Swift 配列は、ラップされた構造体のObjC ではなく、構造体の C 配列のようにデータをまとめNSValueます。また、Swift 配列を (Obj)C API に渡すことができるため、 CMutablePointerSwift配列からを構築するのは非常にクールNSDataです。

  • 最終的にすべてがスカラー型になる限り、構造体の配列や構造体の構造体についても同じことが言えます。

  • ObjC でも、SCNVector3構造体の要素の型が 32/64 ビット アーキテクチャ間で変化するため、配列を作成すると問題が発生する可能性があります。

  • sizeOfValueBeta 2 の配列では期待どおりに動作していないようです。そのため、バグを報告することをお勧めします。

  • カスタム構造体にプロトコルを実装するArrayLiteralConvertibleと、ネストされた構造体値の配列を簡潔に宣言できます。

これらの問題を認識している場合は、(Obj)C で使用する頂点/インデックス バッファー管理とほとんど同じトリックを、いくつかのバリエーションを使用して Swift で使用できます。たとえば、インターリーブされた頂点と法線データを使用してカスタム ジオメトリを構築するスニペットを次に示します (これは、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])
于 2014-06-30T19:52:06.780 に答える
0

私はswiftについてあまり知りませんが、あなたのバージョンの「verts」と「indexes」はswiftとObjC(実際にはC)で完全に異なると思います。

C バージョンでは、C 構造体の C 配列を取得します。迅速に、NSValues にラップされた SCNVector3 の迅速な「配列」(NSArray に相当) を取得すると仮定します。したがって、「indexes」バイトで作成した NSData には、C のような float 値のフラット バッファは含まれません。「verts」配列についても同じです。

そのような C と迅速な相互運用性の問題がここで議論されているように見えます: Swift use c struct

于 2014-06-30T15:53:27.827 に答える