WebGL Lesson 1 – A triangle and a square | Learning WebGL のコードをできるだけシンプルに(したつもりで)書き直してみた。

なんというか、Hello, world 的にシンプルにしたかった。

とりあえず、関数に分離されたのをひとつにまとめたり、できるだけWebGLの元の機能だけに絞って、不要なプロパティを削ったりしてある。
あと、ちょっといじって色を変えてあったり、アニメーションするようにしてあったり。

修正したものは Google Chrome で見れる (Windows版 バージョン 10.0.648.204 で動作確認)。それ以外のブラウザでは不可。
三角形が小さくなりながら移動していくアニメーション。
flatten learning WebGL lesson 1

ソースコードは以下。


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>flatten learning WebGL lesson 1</title>
<!--
glmatrix - High performance matrix and vector operations for WebGL - Google Project Hosting
http://code.google.com/p/glmatrix/
 
vec3 - 3 Dimensional Vector
mat3 - 3x3 Matrix
mat4 - 4x4 Matrix
quat4 - Quaternions
-->
<script type="text/javascript" src="glMatrix.js"></script>
<script id="my-fragment-shader-source" type="x-shader/x-fragment">
  #ifdef GL_ES
  precision highp float;
  #endif
  void main(void){
    gl_FragColor = vec4(1.0, 0.5, 1.0, 1.0); // triangle color, RGB
  }
</script>
<script id="my-vertex-shader-source" type="x-shader/x-vertex">
  // attribute: read only value in shader source
  attribute vec3 myVertexPosition;
  // uniform: read only value in shader source
  uniform mat4 myPerspectiveMatrix;
  uniform mat4 myMoveMatrix;
  void main(void){
    gl_Position = myPerspectiveMatrix * myMoveMatrix * vec4(myVertexPosition, 1.0);
  }
</script>
</head>
<script type="text/javascript">
 
  var gl;
  var myViewportWidth;
  var myViewportHeight;
  var myVertexPositionBuffer;
  var myVertexPositionAttribute;
  var myPerspectiveMatrixUniform;
  var myMoveMatrixUniform;
  var myItemSize;
  var myNumItems;
  var intervalId;
  var x = 0.0;
  var y = 0.0;
  var z = 0.0;
 
  function webGLStart(){
    // get webgl context
    var canvas = document.getElementById("my-canvas");
    try{
      var contentIds = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
      for(var i=0; i<contentIds.length; i++){
        gl = canvas.getContext(contentIds[i]); // ex. experimental-webgl
        if(gl){
          break;
        }
      }
      myViewportWidth = canvas.width;
      myViewportHeight = canvas.height;
    }catch(e){
      alert(e);
    }
    if(!gl){
      alert("Could not initialize WebGL.");
    }
 
    // initialize fragment shader
    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, document.getElementById("my-fragment-shader-source").innerText);
    gl.compileShader(fragmentShader);
    if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
      alert(gl.getShaderInfoLog(fragmentShader));
    }
 
    // initialize vertex shader
    var vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, document.getElementById("my-vertex-shader-source").innerText);
    gl.compileShader(vertexShader);
    if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
      alert(gl.getShaderInfoLog(vertexShader));
    }
 
    // create program
    var shaderProgram = gl.createProgram();
 
    // attach shaders
    gl.attachShader(shaderProgram, fragmentShader);
    gl.attachShader(shaderProgram, vertexShader);
 
    // link frament and vertex shaders
    gl.linkProgram(shaderProgram);
    if(!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)){
      alert("Could not initialize shaders.");
    }
 
    // use
    gl.useProgram(shaderProgram);
 
    // get values of my-vertex-shader-source
    myVertexPositionAttribute = gl.getAttribLocation(shaderProgram, "myVertexPosition");
    gl.enableVertexAttribArray(myVertexPositionAttribute);
    myPerspectiveMatrixUniform = gl.getUniformLocation(shaderProgram, "myPerspectiveMatrix");
    myMoveMatrixUniform = gl.getUniformLocation(shaderProgram, "myMoveMatrix");
 
    // create buffer
    myVertexPositionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, myVertexPositionBuffer);
    myItemSize = 3; // 3 = x, y, z
    myNumItems = 3; // 3 = top, bottom left, bottom right
    var vertices = [
       0.0,  1.0,  0.0, // top
      -1.0, -1.0,  0.0, // bottom left
       1.0, -1.0,  0.0  // bottom right
    ];
    // Float32Array (old: WebGLFloatArray)
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
 
    // set color and then
    gl.clearColor(0.0, 0.0, 0.5, 1.0); // background color, RGBA
    gl.enable(gl.DEPTH_TEST);
 
    // begin animation :-)
    intervalId = setInterval(animation, 1000);
  }
 
  function animation(){
    x += 0.1;
    y += 0.2;
    z -= 1.0;
    drawScene(x, y, z);
  }
 
  function drawScene(x, y, z){
    try{
      gl.viewport(0, 0, myViewportWidth, myViewportHeight);
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
      // vertical field of view 45 degrees
      // 0.1 - 100
      // using mat4 of glmatrix
      var perspectivMatrix = mat4.create();
      var moveMatrix = mat4.create();// using mat4 of glmatrix
      mat4.perspective(45, myViewportWidth / myViewportHeight, 0.1, 100.0, perspectivMatrix);
      mat4.identity(moveMatrix);
      mat4.translate(moveMatrix, [x, y, z]); // ex. [x, y, z] = [-1.5, 0.0, -7.0]
      //gl.bindBuffer(gl.ARRAY_BUFFER, myVertexPositionBuffer);
      gl.vertexAttribPointer(myVertexPositionAttribute, myItemSize, gl.FLOAT, false, 0, 0)
      // matrix to WebGL
      gl.uniformMatrix4fv(myPerspectiveMatrixUniform, false, perspectivMatrix);
      gl.uniformMatrix4fv(myMoveMatrixUniform, false, moveMatrix);
      gl.drawArrays(gl.TRIANGLES, 0, myNumItems);
    }catch(e){
      alert(e);
    }
  }
</script>
 
<body onload="webGLStart();">
<canvas id="my-canvas" width="300" height="300"></canvas>
</body>
</html>

要らない変数や処理がまぎれこんでる気がするけどまだ理解できてないのでとりあえず放置で。

Ref.
- WebGL Lesson 1 – A triangle and a square | Learning WebGL
- WebGL Lesson 1 - 三角形と四角形 - Hack The WebGL (WebGL勉強会)
- WebGL勉強会 第5回で発表して来ました - 強火で進め (Learning WebGLで学ぶWebGL入門)
- JavaScript でリアルタイム 3DCG を実現する WebGL の使い方 - WebOS Goodies

tags: webgl

Posted by NI-Lab. (@nilab)