二十二、モデルビュー行列。
■サンプルページはコチラ↓
■このプログラムの解説は、次のExcelファイルをご覧下さい。
.oOo..oOo..oOo.
■htmlのコードです。↓
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>モデルビュー行列。</title>
</head>
<body onload="main()">
<canvas id="webgl" width="400" height="400">
Canvasをサポートしているブラウザを使用してください。
</canvas>
<script src="webgl-utils.js"></script>
<script src="webgl-debug.js"></script>
<script src="sano-func.js"></script>
<script src="gyouretsu-7-1-6.js"></script>
<script src="Model-View-Matrix.js"></script>
</body>
</html>
■JavaScriptのコードです。↓
// 頂点シェーダのプログラム
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec4 a_Color;\n' +
'uniform mat4 u_ModelViewMatrix;\n' +
'varying vec4 v_Color;\n' +
'void main() {\n' +
' gl_Position = u_ModelViewMatrix * a_Position;\n' +
' v_Color = a_Color;\n' +
'}\n';
// フラグメントシェーダのプログラム
var FSHADER_SOURCE =
'#ifdef GL_ES\n' +
'precision mediump float;\n' +
'#endif\n' +
'varying vec4 v_Color;\n' +
'void main() {\n' +
' gl_FragColor = v_Color;\n' +
'}\n';
function main() {
// Canvas要素を取得する
var canvas = document.getElementById('webgl');
// WebGL描画用のコンテキストを取得する
var gl = getWebGLContext(canvas);
if (!gl) {
console.log('WebGLコンテキストの取得に失敗');
return;
}
// シェーダを初期化する
if (!initShaders2(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('シェーダの初期化に失敗');
return;
}
// 頂点座標と色を設定する(青い三角形が手前にある)
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('頂点属性の設定に失敗');
return;
}
// Canvasをクリアする色を設定する
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// u_ModelViewMatrix変数とu_ModelMatrix変数の格納場所を取得する
var u_ModelViewMatrix = gl.getUniformLocation(gl.program, 'u_ModelViewMatrix');
if(!u_ModelViewMatrix) {
console.log('u_ModelViewMatrixの格納場所の取得に失敗');
return;
}
// 視点の位置、方向を設定する
var viewMatrix = new Matrix4();
viewMatrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1, 0);
// 回転の行列を計算する
var modelMatrix = new Matrix4();
modelMatrix.setRotate(-45, 0, 0, 1); // z軸周りに回転
// それぞれの行列を乗算する
var modelViewMatrix = viewMatrix.multiply(modelMatrix);
// モデルビュー行列をu_ModelViewMatrix変数に設定する
gl.uniformMatrix4fv(u_ModelViewMatrix, false, modelViewMatrix.elements);
// Canvasをクリアする
gl.clear(gl.COLOR_BUFFER_BIT);
// 三角形を描画する
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function initVertexBuffers(gl) {
var verticesColors = new Float32Array([
// 頂点座標(X, Y, Z)、 色(RGBA)
-0.41, -0.26, -0.4, 0.1, 0.1, 0.3, //一番奥。ハンブラビみたいな色の図形。
0.0, 0.67, -0.4, 0.3, 0.5, 0.9,
0.0, 0.0, -0.4, 0.1, 0.1, 0.3,
0.41, -0.26, -0.4, 0.1, 0.1, 0.3,
0.0, 0.67, -0.4, 0.3, 0.5, 0.9,
0.0, 0.0, -0.4, 0.1, 0.1, 0.3,
-0.41, -0.26, -0.2, 0.6, 0.9, 0.7, //真ん中。クィン・マンサみたいな色の図形。
0.0, 0.67, -0.2, 0.8, 0.7, 0.5,
0.0, 0.0, -0.2, 0.6, 0.9, 0.7,
0.41, -0.26, -0.2, 0.6, 0.9, 0.7,
0.0, 0.67, -0.2, 0.8, 0.7, 0.5,
0.0, 0.0, -0.2, 0.6, 0.9, 0.7,
-0.41, -0.26, 0.0, 0.4, 0.2, 0.3, // 一番前。シーマ専用機みたいな色の図形。
0.0, 0.67, 0.0, 0.9, 0.9, 0.5,
0.0, 0.0, 0.0, 0.4, 0.2, 0.3,
0.41, -0.26, 0.0, 0.4, 0.2, 0.3,
0.0, 0.67, 0.0, 0.9, 0.9, 0.5,
0.0, 0.0, 0.0, 0.4, 0.2, 0.3,
]);
var n = 18;
// バッファオブジェクトを作成する
var vertexColorBuffer = gl.createBuffer();
if (!vertexColorBuffer) {
console.log('バッファオブジェクトの作成に失敗');
return -1;
}
// 頂点の座標と色をバッファオブジェクトに書き込む
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var FSIZE = verticesColors.BYTES_PER_ELEMENT;
// a_Positionにバッファオブジェクトを割り当て、有効化する
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if(a_Position < 0) {
console.log('a_Positionの格納場所の取得に失敗');
return -1;
}
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
// a_Colorにバッファオブジェクトを割り当て、有効化する
var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
if(a_Color < 0) {
console.log('a_Colorの格納場所の取得に失敗');
return -1;
}
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
// バッファオブジェクトのバインドを解除する
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return n;
}
■参考文献:WebGL+HTML5 3DCGプログラミング入門
(良い本ですが、絶版です。中古で購入される場合はCD-ROMがちゃんと付いているか確認して下さい)
■以下は私が検索する時に使うヤツです。このまま読むと意味が分からないと思います。この記事の中盤にあるExcelファイルをご覧下さい。
前回のプログラムでは、頂点シェーダの中で、頂点ごとにビュー行列とモデル行列の乗算を行っていた。
こういう風に。→gl_Position = u_ViewMatrix * u_ModelMatrix * a_Position
この場合、頂点が多くなると効率的ではありません。
今回のプログラムでは、JavaScript側で、予めビュー行列×モデル行列(※)を計算しておく。 ※これをモデルビュー行列と言うそうです。
頂点シェーダの中では、モデルビュー行列×頂点を行えばよく、前回のプログラムより効率的になります。
"gyouretsu-7.js"を参照。
書籍には、「視体積の設定をしていないので、この角度(-10°)以外では見切れることがあります」という様なことが書いてあったが、-45°でも大丈夫だった。
-45°の方が回転した感じがよく分かるので、此方を採用。
Matrix4(配列名)と書いた場合、その配列がコピーされる。それ以外は単位行列。
otherには、他の行列が入る。otherは引数の様に使われている。(予約語ではない)
concat → concatenate (連結する) の略と思われる。
かけられる方の行列の要素。elements の中身は15行目から。elementsは任意の名前。
上の行と同じ物を入れているのは、後で計算に使う為。
右からかける方の行列。
こう書くことにより、multiply メソッドは concat メソッドの引数を受け取ることができます。
書籍では、注視点(atX, atY, atZ) と書かれている。
(注視点) - (視点) 。カメラの視点から注視点への方向(ベクトル)を計算している。
つまり、カメラの向き。
rlfはReciprocal of Length of "f" の略だと思われます。Reciprocal は逆数の意味。
カメラの向きとカメラの上方向の外積を計算することにより、カメラの右方向を計算している。
カメラの右方向とカメラの向きの外積を計算し、カメラの上方向を計算している。
upX, upY, upZ はカメラが上を向いている大まかな方向を示すベクトルであり、カメラの座標系における正確な上方向ベクトル(ux, uy, uz)とは必ずしも一致しません。
upX, upY, upZ は、カメラの「初期上方向」を表す目安でしかなく、これがカメラの視線ベクトルや右方向ベクトルと正確に直交する保証はありません。
そのため、視線ベクトル(f)と右方向ベクトル(s)が確定した後、これらと直交する形でカメラの正確な上方向ベクトル(ux, uy, uz)を再計算する必要があります。
fにマイナスをかけるのは、視線ベクトルは通常「負のZ軸」に沿って定義されることが多いためです。
これは、物体が「負のZ軸」方向にあることが多いためです。
後で、3D座標の行列と掛け算するので、カメラの視点を原点に移動させる。
.oOo..oOo..oOo.
この記事はここまでです。
頂戴したサポートは、レンタルサーバーの費用に充てさせて頂きます🙇 心より感謝いたします❤️