以前の記事で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
各面が赤/青/黄/緑 に塗り分けられた三角錐のノードは、こんなふうに実装できる。