ARKit: 複数要素でSCNGeometryを構成する

p0dee
Jun 13, 2021

--

以前の記事でSceneKitにおけるノード、ジオメトリ、マテリアルについて調べたことを記したが、その際のおおきな気づきとして、オブジェクトの形状を定義するSCNGeometryが複数の要素で構成されるということだった。

ちなみに、ジオメトリは複数のSCNMaterialを持つmaterialsというプロパティが存在し、それはジオメトリが包含する複数のelementに対応するという。つまりドキュメントの例をとると、ティカップの胴/取手/蓋/注ぎ口をそれぞれのelementとし、この集合体をひとつのジオメトリとして定義できるようだ。

この要素は、SCNGeometryElementクラスによって表現される。ひとつのジオメトリが複数の要素を持つことで、各要素が個別に異なるマテリアル、つまり外観を持つことができる。

SCNGeometryには、複数のelementを渡せるイニシャライザがある。

# SCNGeometry
convenience
init(sources: [SCNGeometrySource], elements: [SCNGeometryElement]?)

SCNGeometrySource

A container for vertex data forming part of the definition for a three-dimensional object, or geometry.
SCNGeometrySource

Geometry Sourceは3次元形状を構成するすべての頂点データをもつ。頂点座標はSCNVector3で表現され、ジオメトリのもつすべての頂点座標を配列として初期化する。

convenience init(vertices: [SCNVector3])

ここでは、ジオメトリ要素(SCNGeometryElement)が含む頂点群のみを渡すのではなく、その要素を含むジオメトリ(SCNGeometry)を構成するすべての頂点群を渡す必要があることに注意。

SCNGeometryElement

A container for index data describing how vertices connect to define a three-dimensional object, or geometry.
SCNGeometryElement

Geometry Elementはジオメトリ要素(SCNGeometryElement)について、ジオメトリ中のどの頂点が接続しあってポリゴンを構成するかを定義する。

convenience init<IndexType>(indices: [IndexType], primitiveType: SCNGeometryPrimitiveType) where IndexType : FixedWidthInteger

IndexTypeは、Geometry Sourceに渡したvertices配列における頂点座標のインデックスを表し、たとえばverticesにおける1番目、3番目、4番目の頂点によって構成されるポリゴンなら、[1, 3, 4] as [Int32]である。

indices内は以下を満たす必要がある

  • 順序: ポリゴン表面から見て反時計回りの順番と対応する
  • 要素数: primitiveTypeの要する頂点数の倍数(e.g. .triangleなら3の倍数)

たとえば、頂点ABCDからなる三角錐について、SCNGeometrySourceのイニシャライザに渡すverticesはこのようになり、

SCNGeometryElementに渡すindicesは、このvertices配列に従って、頂点A→0、B→1、C→2、D→3 となる。

例えば頂点ABDから成る三角形(下図黄)をひとつのジオメトリ要素とするならindices=[0, 1, 3]、頂点BCDから成る三角形(下図緑)ならindices=[1, 2, 3]のように定義する。

あるいは三角錐すべてをひとつのジオメトリ要素とするなら、4面を含めて以下のようになる。

indices = [0, 1, 3, //頂点ABD
1, 2, 3, //頂点BCD
1, 2, 0, //頂点BAC
0, 3, 2] //頂点ADC

各面が赤/青/黄/緑 に塗り分けられた三角錐のノードは、こんなふうに実装できる。

--

--