"Vertex attribute {index} is not defined in the vertex descriptor."エラー
SCNProgramをあるマテリアルに適用しようとしたところ、こんなエラーが出た。
Error Domain=AGXMetalA11 Code=3 "Vertex attribute 6 is not defined in the vertex descriptor."
「Vertex attribbute 6がvertex descriptorで定義されてない」とのこと。「Vertex attribute」(Vertex属性)の一覧はSCNProgramのドキュメント内にある。
- SCNVertexSemanticPosition
- SCNVertexSemanticNormal
- SCNVertexSemanticTangent
- SCNVertexSemanticColor
- SCNVertexSemanticSkinJoints
- SCNVertexSemanticSkinWeights
- SCNVertexSemanticTexcoord0
- SCNVertexSemanticTexcoord1
- SCNVertexSemanticTexcoord2
- SCNVertexSemanticTexcoord3
リストを0から数えていって6にあたるものを見ると、SCNVertexSemanticTexcoord0
が該当する。
で、確かに自分のコードではSCNProgramで処理するシェーダ内で
float2 texCoords [[attribute(SCNVertexSemanticTexcoord0)]];
を頂点シェーダの入力の構造体の要素に指定していた。
struct VertexInput {
float3 position [[ attribute(SCNVertexSemanticPosition) ]];
float2 texCoords [[attribute(SCNVertexSemanticTexcoord0)]];
};
vertex ColorInOut vertexShader(VertexInput in [[ stage_in ]],
...
原因はカスタムジオメトリ
試しにSCNVertexSemanticNormal
属性の要素を追加してみると、
struct VertexInput {
float3 position [[ attribute(SCNVertexSemanticPosition) ]];
float3 normal [[ attribute(SCNVertexSemanticNormal) ]];
};
それに準じたインデックスのエラーが出る。
"Vertex attribute 1 is not defined in the vertex descriptor."
問題発生要因を切り分けていった結果、どうやらこのVertex属性がカスタムジオメトリでは効いてないようだった。
ドキュメントで明言されているかはわからないが、SCNGeometrySource
, SCNGeometryElement
を使用して独自のジオメトリを形成している場合に、法線情報やテクスチャ座標情報を自動でシェーダに渡してくれない、というのは確かにそれはそうだろうな、という挙動ではある。
対策: 必要なセマンティックのジオメトリソースを用意する
上にも載せたSCNVertexSemanticNormal
の解説をちゃんと読むと、
The surface normal vector at the vertex, provided by the geometry source for the normal semantic.
とあって、ジオメトリソースから供給されるようだ。
試しに
let source = SCNGeometrySource(vertices: vertices)
print("semantic: \(source.semantic)")
をやってみると
semantic: Semantic(_rawValue: kGeometrySourceSemanticVertex)
と出力されたので、normal semanticなGeometrySourceを追加しないといけないということらしい。
実装
法線ベクトルを自前で計算し(ここはまた別の長い話になるので割愛)、SCNGeometrySource
を作成する。
let sourceNormal = SCNGeometrySource(normals: normals)
SCNGeometry
を初期化する歳にジオメトリソースとして渡す。
geometry = SCNGeometry(sources: [sourceVertices, sourceNormal], elements: [element])
所感
3Dプログラミングに慣れている人には「何を当たり前なことを。。」という話なのかもしれないが、SceneKitが知らないうちにどういうことをやってくれているのか、というところへの理解が進んだのでなかなか良いエラーに出会えたなと。