LoginSignup
29
35

More than 5 years have passed since last update.

WebGLプログラミングの基礎

Last updated at Posted at 2014-03-19

IBMのDeveloper Worksにて、WebGLの技術文書が公開されています。

WebGL による 3D 開発: 第 1 回 WebGL の紹介

こちらのページを参考に、WebGLの基礎的なサンプルの実装を行ってみました。

ソースコード

<!DOCTYPE html>
<html lang="jp">
<head>
  <meta charset="UTF-8">
  <title></title>
  <script src="gl-matrix.js"></script>

<script id="vertshader" type="x-shader/vertshader">
  attribute vec3 vertPos;
  attribute vec4 vertColor;
  uniform mat4 mvMatrix;
  uniform mat4 pjMatrix;
  varying lowp vec4 vColor;
  void main(void) {
    gl_Position = pjMatrix * mvMatrix * vec4(vertPos, 1.0);
    vColor = vertColor;
  }
</script>

<script id="fragshader" type="x-shader/fragshader">
  varying lowp vec4 vColor;
  void main(void) {
    gl_FragColor = vColor;
  }
</script>

<script>
var gl = null;
var vertBuffer, colorBuffer;
var shaderProg, shaderVertexPositionAttribute, shaderVertexColorAttribute,
    shaderProjectionMatrixUniform, shaderModelViewMatrixUniform;
var modelViewMatrix, rotationAxis, projectionMatrix;

function init() {
  // WebGLコンテキストの取得
  var canvas = document.getElementById("canvas");
  gl = canvas.getContext("webgl");

  // ビューポートの設定
  gl.viewport(0, 0, canvas.width, canvas.height);

  // 頂点バッファの作成
  vertBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
  var verts = [
    0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
    0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0,
    0.0, 1.0, 0.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0
  ];
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);

  // カラーバッファの作成
  colorBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
  var faceColors = [
    [0.0, 0.0, 1.0, 1.0], // front (blue)
    [1.0, 1.0, 0.0, 1.0], // right (yellow)
    [0.0, 1.0, 0.0, 1.0], // back  (green)
    [1.0, 0.0, 0.0, 1.0], // left  (red)
  ];
  var vertColors = [];
  faceColors.forEach(function(color) {
    [0, 1].forEach(function() {
      vertColors = vertColors.concat(color);
    });
    vertColors = vertColors.concat([1.0, 1.0, 1.0, 1.0]);
  });
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertColors), gl.STATIC_DRAW);

  // シェーダーコンパイル結果のチェック用関数
  var checkShader = function(shader, type) {
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
      var errmes = type + " shader compile failed: "
        + gl.getShaderInfoLog(shader);
      throw new Error(errmes);
    }
  };

  // 頂点シェーダー
  var vertShaderSource = document.getElementById("vertshader").textContent;
  var vertShader = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vertShader, vertShaderSource);
  gl.compileShader(vertShader);
  checkShader(vertShader, "vertex");

  // フラグメントシェーダー
  var fragShaderSource = document.getElementById("fragshader").textContent;
  var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fragShader, fragShaderSource);
  gl.compileShader(fragShader);
  checkShader(fragShader, "fragment");

  // シェーダーのリンク
  shaderProg = gl.createProgram();
  gl.attachShader(shaderProg, vertShader);
  gl.attachShader(shaderProg, fragShader);
  gl.linkProgram(shaderProg);

  // シェーダーのリンクのチェック
  if (!gl.getProgramParameter(shaderProg, gl.LINK_STATUS)) {
    var errmes = "failed to initialize shader with data matrices";
    throw new Error(errmes);
  }

  // シェーダーパラメータの設定
  shaderVertexPositionAttribute = gl.getAttribLocation(shaderProg, "vertPos");
  gl.enableVertexAttribArray(shaderVertexPositionAttribute);
  shaderVertexColorAttribute = gl.getAttribLocation(shaderProg, "vertColor");
  gl.enableVertexAttribArray(shaderVertexColorAttribute);
  shaderProjectionMatrixUniform = gl.getUniformLocation(shaderProg, "pjMatrix");
  shaderModelViewMatrixUniform = gl.getUniformLocation(shaderProg, "mvMatrix");

  // マトリクス
  modelViewMatrix = mat4.create();
  mat4.translate(modelViewMatrix, modelViewMatrix, [0, 0, -3]);
  projectionMatrix = mat4.create();
  mat4.perspective(projectionMatrix, Math.PI / 4, canvas.width / canvas.height, 1, 100);

  // 回転軸
  rotationAxis = vec3.create();
  vec3.normalize(rotationAxis, [0, 1, 0]);

  requestAnimationFrame(update);
}

function draw() {
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.enable(gl.DEPTH_TEST);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  gl.useProgram(shaderProg);

  // 頂点属性の位置情報の設定
  gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
  gl.vertexAttribPointer(shaderVertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
  gl.vertexAttribPointer(shaderVertexColorAttribute, 4, gl.FLOAT, false, 0, 0);

  // 行列の設定
  gl.uniformMatrix4fv(shaderProjectionMatrixUniform, false, projectionMatrix);
  gl.uniformMatrix4fv(shaderModelViewMatrixUniform, false, modelViewMatrix);

  // 描画
  gl.drawArrays(gl.TRIANGLES, 0, 12 /* num of vertex */);
}

var lastTime = null;
function update(time) {
  requestAnimationFrame(update);

  var elapsedTime = lastTime ? time - lastTime : 0;
  lastTime = time;

  // 回転
  var angle = Math.PI * elapsedTime / 10000;
  mat4.rotate(modelViewMatrix, modelViewMatrix, angle, rotationAxis);

  draw();
}

window.addEventListener("load", init);
</script>
</head>
<body>
  <canvas id="canvas" width="320" height="240"></canvas>
</body>
</html>

gl-matrix.jsに依存しているので、実行のためには同一ディレクトリにgl-matrix.jsを入れる必要があります。

実行結果は以下のようになります。

webgl_basic.png

ピラミッド型のポリゴンが回転します。

WebGL Basic

こちらのページでサンプルコードを実際に動かすことができます。(要WebGLに対応した環境)

使用したWebGLの関数と定数

この基礎的なサンプルで使用したWebGLの関数と定数は以下のとおりです。

関数

  • createBuffer
  • bindBuffer
  • bufferData
  • getShaderParameter
  • getShaderInfoLog
  • createShader
  • shaderSource
  • compileShader
  • createProgram
  • attachShader
  • linkProgram
  • getProgramParameter
  • getAttribLocation
  • enableVertexAttribArray
  • getUniformLocation
  • clearColor
  • enable
  • clear
  • useProgram
  • vertexAttribPointer
  • uniformMatrix4fv
  • drawArrays

定数

  • ARRAY_BUFFER
  • STATIC_DRAW
  • COMPILE_STATUS
  • VERTEX_SHADER
  • FRAGMENT_SHADER
  • LINK_STATUS
  • DEPTH_TEST
  • COLOR_BUFFER_BIT
  • DEPTH_BUFFER_BIT
  • FLOAT

上記のWebGLの関数と定数を理解しておくと、基礎的な部分を理解したと考えても良さそうです。

29
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
35