質問: 現在OpenGLを勉強中で、床井氏のサイトを参考に進めています。 そこで分からない部分がありまして、 このページでは、position(attribute変数)を頂点法線ベクトルとしてシェーダー内で扱っていますが、 positionではなく3Dモデルデータから取り出した頂点法線ベクトル・面法線ベクトルをシェーダー内で使うには どのようにすればいいのでしょうか。 また、フラットシェーディングを行いたいのですが、その場合は面法線ベクトルを使用するのでしょうか。 ご教授ください。お願いします。
回答: 頂点単位で渡したいデータが複数ある場合は、必要な分だけattribute変数を足してやれば大丈夫です。 第13回 テクスチャ座標の生成まで読み進められますと、attributeを追加する丁度いい例が載っていましたので、ご参考になるかと思います。 例ではテクスチャ座標の追加ということで、追加した要素は2要素のvec2ですが、法線の場合でも要素数が3個になるだけで大差はありません。 肝になる部分は、 * バーテックスシェーダーに法線用のattribute変数を追加する * シェーダーリンク時に`glBindAttribLocation`でシェーダー内の変数に一意な番号を付ける(または、シェーダーをリンクした後で、自動的に設定された番号を`glGetAttribLocation`で調べる) * その番号を`glEnableVertexAttribArray`を使って使用可能にする(初期状態ではすべての番号は使用不能に設定されているので、明示的に使用可能にします) * `glVertexAttribPointer`で、その番号と対応する属性の要素数(floatやintなら1、vec2やivec2なら2...ここでは法線なので、vec3が適当でしょう。その場合は3です)、要素の成分のデータ型(vec3は3つのfloatからなるのでGL_FLOAT)、整数で与えられたデータを正規化するか(もし法線でなく、例えば色の情報を追加するとして、しかも与える側のデータが0〜255の整数...などという状況の場合、これを設定するとシェーダー側では0.0〜1.0に変換された値として取り出されるので便利)、ストライド(ある頂点の頂点データの先頭から、次の頂点の頂点データの先頭まで何バイト読み進めればいいか...今まで位置しか属性を使用していなかった場合は0を設定していたかもしれませんが、0の場合は自動的に「1つの属性だけが密に詰まっている」と解釈してくれるため正しく指定されますが、今回のように複数の属性を交互に詰める場合、読み進める量を正しく渡してやる必要があります)、オフセット(この属性が頂点データの先頭から何バイト先にあるか...今回の場合、法線データの前には位置データが入っていますので、float3つ分で4*3=12バイトのずれがあります)を指定する といった事項でしょうか。これでシェーダーに位置に加えて法線も渡せるようになるでしょう。 頂点法線の場合は特に問題ないでしょうが、面法線の場合は、書き出されたデータ形式によっては、頂点の数と法線の数が一対一対応していないかも知れません。OpenGLは頂点の各属性が頂点の数と一対一対応していることを期待しているので、その場合は詰めるデータを加工して一対一対応させた上でVBOに送らなければならないかもしれません。 面法線を送り込むことができれば、あとは頂点法線の場合と同様に光源と法線で内積計算して色を決めれば、フラットシェーディングらしい描画結果が得られるでしょう。