SceneKitでカスタムジオメトリをつくる
SceneKitにはもともと立方体や球など基本となる形が用意されています。SceneKitを使う場合、これらの基本形状を利用するか、別の3Dモデリングツールで作成したモデルをインポートして利用する場合がほとんどです。
普通にSceneKitを使う分にはカスタムジオメトリをつくる動機はないのですが、ジオメトリについて深く理解したかったので、どのようにジオメトリを作成するのか調べてみました。例としてはSCNBoxと似た直方体を作成してみます。
カスタムジオメトリを作成するSCNGeometryのイニシャライザはSCNGeometry(sources: [SCNGeometrySource], elements: SCNGeometryElement]?)
となっていてSCNGeometrySourceのArrayとSCNGeometryElementのArrayを渡して作成する仕様となっています。
SCNGeometrySourceはいくつかイニシャライザが用意されていますが、頂点(vertices)のみでも作成できるので今回は頂点のみ作成します。他に法線(normal)やテクスチャを作成することができます。
以下のコードで作成したカスタムジオメトリをSCNNodeに渡せば直方体を描画できます。
static func Box(width: CGFloat, height: CGFloat, length: CGFloat) -> SCNGeometry { let w = width / 2 let h = height / 2 let l = length / 2 // 8つの頂点の座標を指定しています。 let vertices = SCNGeometrySource(vertices: [ // bottom SCNVector3(-w, -h, -l), SCNVector3(w, -h, -l), SCNVector3(w, -h, l), SCNVector3(-w, -h, l), // top SCNVector3(-w, h, -l), SCNVector3(w, h, -l), SCNVector3(w, h, l), SCNVector3(-w, h, l), ]) // 各頂点を結ぶ順番を指定します。8つの頂点を結ぶと12個の三角形で作成されます。 // 0,1,3はインデックスが0,1,3の頂点を結んで三角形を描画することを意味します。 // SceneKitでは反時計回りに頂点を結ぶ必要があります。 let indices: [UInt32] = [ // bottom 0, 1, 3, 3, 1, 2, // left 0, 3, 4, 4, 3, 7, // right 1, 5, 2, 2, 5, 6, // top 4, 7, 5, 5, 7, 6, // front 3, 2, 7, 7, 2, 6, // back 0, 4, 1, 1, 4, 5, ] // SCNGeometryElementは頂点(vertices)のインデックスとプリミティブのタイプを選択して作成します。 let inds = SCNGeometryElement(indices: indices, primitiveType: .triangles) return SCNGeometry(sources: [vertices], elements: [inds]) }