マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

glMatrix-0.9.5.min.jsを使ってみた

WebGLで座標変換のプログラムを全部書くのは大変なのでglMatrix-0.9.5.min.jsを導入した。物体の移動、回転、透視投影変換がとても楽になった。ライティングは『OpenGL+GLSLによる3D‐CGアニメーション』を参考にした。わかってないところが多く、ほとんどそのままだったりするが

OpenGL+GLSLによる3D‐CGアニメーション (I・O BOOKS)

OpenGL+GLSLによる3D‐CGアニメーション (I・O BOOKS)

<html>
  <head>
    <title></title>
    <script type="text/javascript" src="glMatrix-0.9.5.min.js"></script>
    
    <script>
window.onload = function(){
    var canvas = document.getElementById("canvas");
    var gl = canvas.getContext("experimental-webgl");
    var vertexShader = createShader(gl, "2d-vertex-shader", gl.VERTEX_SHADER);
    var fragmentShader = createShader(gl, "2d-fragment-shader", gl.FRAGMENT_SHADER);

    program = createProgram(gl, vertexShader, fragmentShader);

    var mvMatrix = mat4.create();
    var pMatrix = mat4.create();
    var pMatrixLocation = gl.getUniformLocation(program, "u_PMatrix");
    var mvMatrixLocation = gl.getUniformLocation(program, "u_MVMatrix");
    
    var positionLocation = gl.getAttribLocation(program, "a_position");
    var buffer = gl.createBuffer();

    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, createArray(), gl.STATIC_DRAW);

    mat4.perspective(45, 300.0 / 300.0, 0.1, 100.0, pMatrix);
    mat4.identity(mvMatrix);
    mat4.translate(mvMatrix, [0.0, 0.0, -4.0]);
    mat4.rotate(mvMatrix, -80.0 * 3.1415 / 180.0, [1, 0, 0]);

    gl.uniformMatrix4fv(pMatrixLocation, false, pMatrix);
    gl.uniformMatrix4fv(mvMatrixLocation, false, mvMatrix);

    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
    drawArray(gl, positionLocation, 2, 6);
}

function createShader(gl, shaderId, type) {
    var shader = gl.createShader(type);
    var source = document.getElementById(shaderId).innerHTML;
    
    gl.shaderSource(shader, source);
    gl.compileShader(shader);
    
    return shader;
}

function createProgram(gl, vertexShader, fragmentShader){
    var program = gl.createProgram();

    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);

    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
        alert(gl.getShaderInfoLog(vertexShader));
        alert(gl.getShaderInfoLog(fragmentShader));
    }
    
    gl.useProgram(program);
    
    return program;
}

function createArray(){
    return new Float32Array([
            -1.0, -1.0, 
             1.0, -1.0, 
            -1.0,  1.0, 
            -1.0,  1.0, 
             1.0, -1.0, 
             1.0,  1.0])
}

function drawArray(gl, positionLocation, itemSize, itemCount){
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(positionLocation, itemSize, gl.FLOAT, false, 0, 0);
    gl.drawArrays(gl.TRIANGLES, 0, itemCount);
}
    </script>
    
    <script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
varying vec3 N;
varying vec3 P;

uniform mat4 u_MVMatrix;
uniform mat4 u_PMatrix;
    
void main(){
    P = vec3(vec4(a_position, 0, 1) * u_MVMatrix * u_PMatrix);
    N = vec3(0.0, 0.0, -1.0);
    gl_Position = u_PMatrix * u_MVMatrix * vec4(a_position, 0, 1);
}
    </script>

    <script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;

varying vec3 N;
varying vec3 P;

vec3 light_position = vec3(0.0, 0.0, -1.0);
vec4 light_ambient = vec4(0.8, 0.0, 0.0, 1.0);
vec4 light_diffuse = vec4(0.2, 0.2, 0.2, 1.0);
vec4 light_specular = vec4(0.2, 0.2, 0.2, 1.0);

void main(){
    vec3 L = normalize(light_position - P);
    vec3 normal = normalize(N);

    float dotNL = dot(N, L);
    vec4 diffuse = light_diffuse * max(0.0, dotNL);
    vec3 V = normalize(-P);
    vec3 H = normalize(L + V);
    float powNH = pow(max(dot(N, H), 0.0), 0.5);
    if(dotNL <= 0.0) powNH = 0.0;
    vec4 specular = light_specular * powNH;

    gl_FragColor = light_ambient + diffuse + specular;
}
      </script>
      
  </head>
  <body>
    <canvas id="canvas" width="300" height="300"></canvas>
  </body>
</html>