注意
記事を書いている人の線形代数・数学に関する理解は完全ではありません。よってこの記事は「こうすればうまくいく」というのを備忘録的なノリで書いただけのものと思ってください。
OpenTK側とGLSL側の違い
OpenTKでは行列が行優先であるのに対し、GLSLでは列優先となっています。
例えば、頂点座標の各成分を$ (x_1, y_1, z_1) $だけ平行移動するためのモデル行列$M$は一般に以下のように表されます。
M=
\begin{pmatrix}
1 & 0 & 0 & x_1 \\
0 & 1 & 0 & y_1 \\
0 & 0 & 1 & z_1 \\
0 & 0 & 0 & 1
\end{pmatrix}
これは列優先行列の場合であり、OpenTKのMatrix4.CreateTranslation
メソッドにベクトル$ (x_1, y_1, z_1) $を渡して返される行列$M'$は
M'=
\begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
x_1 & y_1 & z_1 & 1
\end{pmatrix}
のような形をしています。これはOpenTKの扱う行列が行優先であるためです。
したがって、GLSL内に行列を渡す際、転置してやる必要があります。$M'$の転置行列は$M$に一致します。ビュー行列、射影行列も同様です。
バーテックスシェーダ内では以下のようにして普通に頂点座標を変換してやれば良いです。
gl_Position = projMatrix * viewMatrix * modelMatrix * vec4(position, 1);
なお、OpenTK側で提供されているメソッドを利用せずに自分で行列を構築すれば、転置の必要はありません。(ただし、OpenTKのベクトルとの演算は上手く出来ない可能性があります)