SceneKitのプリミティブな形状のデータの中身を見る / magicien 

ARKitによってSceneKitの需要が多少なり増すかもしれないので、SceneKitについていくつかメモを残しておこう。
まずは、SCNBox、SCNSphereなどの頂点やテクスチャ座標などがどうなっているかを見るために生データを取得する方法について。

SceneKitの場合、3Dの形状はSCNGeometryクラスで表現する。元から用意されている、SCNBox、SCNSphere等はSCNGeometryを継承したもの。
JSceneKitでこれらのクラスを実装するために中身を覗いた時に使ったコードはこんな感じ。
let sphere = SCNSphere()

// 頂点番号の一覧表示
let element = sphere.geometryElement(at: 0)
element.data.withUnsafeBytes { (p: UnsafePointer<UInt16>) in
    for i in 0..<element.primitiveCount {
        let i1 = p[i*3 + 0]
        let i2 = p[i*3 + 1]
        let i3 = p[i*3 + 2]
        print("\(i): \(i1), \(i2), \(i3)")
    }
}

// 頂点座標の一覧表示
let v = sphere.getGeometrySources(for: .vertex)[0]
v.data.withUnsafeBytes { (p: UnsafePointer<Float32>) in
    for i in 0..<v.vectorCount {
        let index = (i * v.dataStride + v.dataOffset) / 4
        let i1 = p[index + 0]
        let i2 = p[index + 1]
        let i3 = p[index + 2]
        print("\(i): \(i1), \(i2), \(i3)")
    }
}

// 法線の一覧表示
let n = sphere.getGeometrySources(for: .normal)[0]
n.data.withUnsafeBytes { (p: UnsafePointer<Float32>) in
    for i in 0..<n.vectorCount {
        let index = (i * n.dataStride + n.dataOffset) / 4
        let i1 = p[index + 0]
        let i2 = p[index + 1]
        let i3 = p[index + 2]
        print("\(i): \(i1), \(i2), \(i3)")
    }
}

// テクスチャ座標の一覧表示
let t = sphere.getGeometrySources(for: .texcoord)[0]
t.data.withUnsafeBytes { (p: UnsafePointer<Float32>) in
    for i in 0..<t.vectorCount {
        let index = (i * t.dataStride + t.dataOffset) / 4
        let i1 = p[index + 0]
        let i2 = p[index + 1]
        print("\(i): \(i1), \(i2)")
    }
}
Appleのドキュメンテーションだと、getGeometrySourcesじゃなくて、sources(for semantic: SCNGeometrySource.Semantic) になってる...新APIだと関数名が変わっているかもしれない。
getGeometrySourcesで取得できる値の種類は他にもあったりするけれど、SCNBoxやSCNSphereが持っているデータは、vertex、normal、texcoordがそれぞれ1つずつだけ。
SCNGeometryの場合、materialsは空の配列になっているけれど、SCNBox等は、デフォルトのSCNMaterialが一つ入っているみたい。
新APIだと、このSCNGeometryにtesellatorなる変数が追加されていて、SCNBoxの角をめちゃくちゃ滑らかにして遊ぶこともできるようだ。

2017/06/18(Sun) 12:11:54