見出し画像

十五、複数の点に別々の色を付ける。

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

■このプログラムの解説は、次のExcelファイルをご覧下さい。
尚、今回は見出し画像の右側の紙風船の様な模様の図形のプログラムも次のExcelファイルの中に入れています。(見出し画像の左側の色相環の様な図形のプログラムとほぼ同じコードであるため)



■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="colored-dots.js"></script>
  </body>
</html>


■JavaScriptのコードです。↓


// 頂点シェーダのプログラム
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute vec4 a_Color;\n' +
  'varying vec4 v_Color;\n' +
  'void main() {\n' +
  '  gl_Position = a_Position;\n' +
  '  gl_PointSize = 30.0;\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);

  // Canvasをクリアする
  gl.clear(gl.COLOR_BUFFER_BIT);

  // 3点描画する
  gl.drawArrays(gl.POINTS, 0, n);

}

function initVertexBuffers(gl) {
  var verticesColors = new Float32Array([
    // 頂点座標、色https://iro-color.com/colorchart/munsell-color-system.html
0.5, 0.0,  0.56,  0.76,  0.12,
0.433, 0.25,  1.0,  0.98,  0.0,
0.25, 0.433,  0.95,  0.6,  0.0,
0.0,  0.5,  0.91,  0.0,  0.07, 
-0.25, 0.433,  0.9,  0.0,  0.31,
-0.433, 0.25,  0.89,  0.0,  0.5,
-0.5, 0.0,  0.57,  0.03,  0.51,
-0.433, -0.25,  0.11,  0.13,  0.53,
-0.25, -0.433,  0.0,  0.41,  0.72,
0.0,  -0.5,  0.0,  0.63,  0.91,
0.25, -0.433,  0.0,  0.62,  0.59,
0.433, -0.25,  0.0,  0.6,  0.27,
  ]);
  var n = 12;

  // バッファオブジェクトを作成する
  var vertexColorBuffer = gl.createBuffer();  
  if (!vertexColorBuffer) {
    console.log('バッファオブジェクトの生成に失敗');
    return false;
  }

  // 頂点の座標を書き込み、有効化する
  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, 2, gl.FLOAT, false, FSIZE * 5, 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 * 5, FSIZE * 2);
  gl.enableVertexAttribArray(a_Color);  // バッファオブジェクトの割り当ての有効化

  // バッファオブジェクトのバインドを解除する
  gl.bindBuffer(gl.ARRAY_BUFFER, null);

  return n;
}




■紙風船の様な図形のサンプルページはコチラ↓

■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="hanabi-fan.js"></script>
  </body>
</html>


■JavaScriptのコードです。↓


// 頂点シェーダのプログラム
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute vec4 a_Color;\n' +
  'varying vec4 v_Color;\n' +
  'void main() {\n' +
  '  gl_Position = a_Position;\n' +
  '  gl_PointSize = 30.0;\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);

  // Canvasをクリアする
  gl.clear(gl.COLOR_BUFFER_BIT);

  // 3点描画する
  gl.drawArrays(gl.TRIANGLE_FAN, 0, n);

}

function initVertexBuffers(gl) {
  var verticesColors = new Float32Array([
    // 頂点座標、色https://iro-color.com/colorchart/munsell-color-system.html
0.0, 0.0, 1.0, 1.0, 1.0,
0.5, 0.0,  0.56,  0.76,  0.12,
0.433, 0.25,  1.0,  0.98,  0.0,
0.25, 0.433,  0.95,  0.6,  0.0,
0.0,  0.5,  0.91,  0.0,  0.07, 
-0.25, 0.433,  0.9,  0.0,  0.31,
-0.433, 0.25,  0.89,  0.0,  0.5,
-0.5, 0.0,  0.57,  0.03,  0.51,
-0.433, -0.25,  0.11,  0.13,  0.53,
-0.25, -0.433,  0.0,  0.41,  0.72,
0.0,  -0.5,  0.0,  0.63,  0.91,
0.25, -0.433,  0.0,  0.62,  0.59,
0.433, -0.25,  0.0,  0.6,  0.27,
0.5, 0.0,  0.56,  0.76,  0.12,
  ]);
  var n = 14;

  // バッファオブジェクトを作成する
  var vertexColorBuffer = gl.createBuffer();  
  if (!vertexColorBuffer) {
    console.log('バッファオブジェクトの生成に失敗');
    return false;
  }

  // 頂点の座標を書き込み、有効化する
  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, 2, gl.FLOAT, false, FSIZE * 5, 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 * 5, FSIZE * 2);
  gl.enableVertexAttribArray(a_Color);  // バッファオブジェクトの割り当ての有効化

  // バッファオブジェクトのバインドを解除する
  gl.bindBuffer(gl.ARRAY_BUFFER, null);

  return n;
}

■参考文献:WebGL+HTML5 3DCGプログラミング入門 (良い本ですが、絶版です。中古で購入される場合はCD-ROMがちゃんと付いているか確認して下さい)

■以下は私が検索する時に使うヤツです。(先程のExcelファイルに載っているので、読まなくて大丈夫です)

varying vec4 v_Color; が、頂点シェーダとフラグメントシェーダで2回出てくるのはなぜか?
→頂点シェーダとフラグメントシェーダの間でデータを渡す為。
uniform変数の場合、点ごとに色を分けることができない。

v_Color に a_Color のデータを代入。→v_Color は各頂点の色情報を保持。
→v_Color はフラグメントシェーダに渡される。

フラグメントシェーダでは、先程のv_Color を受け取り、各ピクセルの色として、gl_FragColor に代入します。

色のデータを、頂点シェーダからフラグメントシェーダへ渡すには、フラグメントシェーダ内で、同じ名前 (今回はv_Color) と、同じ型で変数を宣言すればOK。

verticesColors は頂点座標と色の配列。

X, Y, R, G, Bの5個のデータでひとまとまりなので、FSIZE * 5

頂点シェーダのデータ

行列の計算

フラグメントシェーダのデータ

グローバル。

html内の、webglという名前の<canvas>要素を取得する

WebGLUtils.setupWebGLは、webgl-utils.jsの一部で、その中のWebGLコンテキストを取得。

X, Y, R, G, B のデータ。

vertexColorBuffer を gl.ARRAY_BUFFER にバインドします。vertexColorBuffer は著者の方が付けた名前です。 今回は頂点と色のデータが入っている為だと思います。

verticesColors のデータがバッファに供給され、その後の動作で使用されます。

バイトの大きさを取得。

頂点属性配列を有効にする。頂点属性がシェーダに送られる。

' gl_PointSize = 30.0;\n' + ←PointSizeは使わないので、よけておく。

前のプログラムでは、gl.drawArrays(gl.POINTS, 0, n); だった箇所。

gl.TRIANGLE_FAN については、下記を参照。
https://note.com/sanorx78/n/n5f4d7cffb46c
前のプログラムの頂点だけでは下図の様な意図した物と違う感じの図形になるので、頂点を2つ追加。

以上です。

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