これ
gl_Position = projection * model * view * vec4(vertexData, 1);
間違っている。行列の乗算は可換ではありません。つまり、演算の順序が重要です。頂点の位置の変換は次のとおりです。
OpenGL で使用される列ベクトルの行列乗算は、左結合です。つまり、右から左に進みます。したがって、ステートメントの R 側の式は次のようになります。
gl_Position = projection * view * model * vec4(vertexPosition, 1);
ただし、ビューとモデル変換を複合モデルビュー (最初のモデル、次にビュー) 変換に縮小できます。これにより、完全な行列乗算が節約されます
gl_Position = projection * modelview * vec4(vertexPosition, 1);
他のシェーディング ステップでは、投影が適用されていない結果である頂点の視点空間位置が必要になる場合があるため、投影は個別に保持する必要がありますmodelview * position
。
ところで:データではなく、頂点の位置を変換しています。頂点は (位置だけでなく) より多くの属性で構成されているため、「データ」と呼ぶのは意味的に間違っています。
オブジェクトを移動および回転する最良の方法は何ですか?
これらはモデルビュー変換の一部です。CPU で変換行列を1回だけ作成し、それを GPU に渡す必要があります。シェーダーでこれを行うと、GPU は頂点ごとに計算全体をやり直すことになります。あなたはこれをしたくありません。
コメントがあったので更新
私の→linmath.hを使用しているとしましょう。次に、描画関数で、シーンの足場を設定します。つまり、ビューポートを設定し、投影とビュー マトリックスを作成します。
#include <linmath.h>
/* ... */
void display(void)
{
mat4x4 projection;
mat4x4 view;
glClear(…),
glViewport(…);
mat4x4_frustum(projection, …);
// linmath.h doesn't have a look_at function... yet
// I'll add it soon
mat4x4_look_at(view, …);
次に、オブジェクトごとに位置と向き (平行移動と回転) を設定します。向きはクォータニオンに格納するのが最も便利ですが、ベクトルを処理するには行列表現の方がうまく機能します。そのため、シーン内のオブジェクトを反復処理します
for(int i_object = 0; i_object < scene->n_objects; i++) {
Object * const obj = scene->objects + i;
mat4x4 translation, orientation, model_view;
mat4x4_translate(translation, obj->pos.x, obj->pos.y, obj->pos.z);
mat4x4_from_quat(orientation, obj->orientation);
mat4x4_mul(model_view, translation, orientation);
model_view
モデルマトリックスが含まれるようになりました。次にview
行列を掛けます。行列の乗算は右から左に行われることに注意してください (mat4x4_mul は入力オペランドの 1 つに出力できます)。
mat4x4_mul(model_view, view, model_view);
model_view
完全なコンパウンド モデルの向きと変換およびビュー マトリックスが含まれるようになりました。あとは、オブジェクトに使用するシェーダー プログラムをバインドするだけです。
glUseProgram(obj->shader->program);
ユニフォームをセット
glUniformMatrix4f(obj->shader->location.projection, 1, GL_FALSE, projection);
glUniformMatrix4f(obj->shader->location.modelview, 1, GL_FALSE, model_view);
// and a few others...
そして、オブジェクトを描画します
object_draw(obj);
}
/* ... */
}