見出し画像

二十一、ビュー行列と回転行列(モデル行列)の両方を使ってみる。

■サンプルページはコチラ↓

■このプログラムの解説は、次の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.js"></script>
    <script src="View-Model-Rotation.js"></script>
<p><a href="https://sano-rx78.sakura.ne.jp/ms/24T16_View-Triangle/View-Triangle.html" target="_blank">操作前のモデルは此方です。</a></p>
  </body>
</html>


■JavaScriptのコードです。↓


// 頂点シェーダのプログラム
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute vec4 a_Color;\n' +
  'uniform mat4 u_ViewMatrix;\n' +
  'uniform mat4 u_ModelMatrix;\n' +
  'varying vec4 v_Color;\n' +
  'void main() {\n' +
  '  gl_Position = u_ViewMatrix * u_ModelMatrix * 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_ViewMatrix変数とu_ModelMatrix変数の格納場所を取得する
  var u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
  var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
  if(!u_ViewMatrix || !u_ModelMatrix) { 
    console.log('u_ViewMatrixかu_ModelMatrixの格納場所の取得に失敗');
    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軸周りに回転

  // それぞれの行列をuniform変数に設定する
  gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
  gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.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_Colorにバッファオブジェクトを割り当て、有効化する ←誤記かな?
  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ファイルをご覧下さい。

u_ViewMatrix はビュー行列。これによりビューの角度が変わる。
ビュー行列×モデル行列×頂点座標

"gyouretsu-7.js"を参照。

書籍には、「視体積の設定をしていないので、この角度(-10°)以外では見切れることがあります」という様なことが書いてあったが、-45°でも大丈夫だった。
-45°の方が回転した感じがよく分かるので、此方を採用。

viewMatrix.elements は、Matrix4.prototype.setLookAt の中で作られる。

vertexColorbufferという頂点バッファオブジェクトを、現在のバッファとしてバインドすることを意味します。
gl.ARRAY_BUFFERに、verticesColorsの情報を書き込む。

←書籍には誤記があり、a_Colorとなっていた。
a_Position がシェーダー内のどの「位置」に存在しているかを探し、その位置(インデックス)を返します。
この位置は、後でバッファデータをこの属性変数に関連付けるために必要です。
var a_Positionにはこのインデックスが入る。
そのインデックスを使ってバッファデータをシェーダープログラムにバインドすることができます。
バッファデータは、vertexColorbuffer。vertexColorbufferの中身はverticesColors(頂点座標と色)。

さっきは位置を入力したので、次は色。

.oOo..oOo..oOo.

書籍では、注視点(atX, atY, atZ) と書かれている。

(注視点) - (視点) 。カメラの視点から注視点への方向(ベクトル)を計算している。
つまり、カメラの向き。

カメラの向きとカメラの上方向の外積を計算することにより、カメラの右方向を計算している。

カメラの右方向とカメラの向きの外積を計算し、カメラの上方向を計算している。
upX, upY, upZ はカメラが上を向いている大まかな方向を示すベクトルであり、カメラの座標系における正確な上方向ベクトル(ux, uy, uz)とは必ずしも一致しません。
upX, upY, upZ は、カメラの「初期上方向」を表す目安でしかなく、これがカメラの視線ベクトルや右方向ベクトルと正確に直交する保証はありません。
そのため、視線ベクトル(f)と右方向ベクトル(s)が確定した後、これらと直交する形でカメラの正確な上方向ベクトル(ux, uy, uz)を再計算する必要があります。

fにマイナスをかけるのは、視線ベクトルは通常「負のZ軸」に沿って定義されることが多いためです。
これは、物体が「負のZ軸」方向にあることが多いためです。

↑eは列優先の配列になっていることに注意。

後で、3D座標の行列と掛け算するので、カメラの視点を原点に移動させる。

以上です。

頂戴したサポートは、レンタルサーバーの費用に充てさせて頂きます🙇 心より感謝いたします❤️