baobao
3/17/2018 - 4:01 PM

mesh.js

function torus(row, column, irad, orad)
{
    var pos = new Array(), nor = new Array(),
        col = new Array(), idx = new Array();
    for(var i = 0; i <= row; i++){
        var r = Math.PI * 2 / row * i;
        var rr = Math.cos(r);
        var ry = Math.sin(r);
        for(var ii = 0; ii <= column; ii++){
            var tr = Math.PI * 2 / column * ii;
            var tx = (rr * irad + orad) * Math.cos(tr);
            var ty = ry * irad;
            var tz = (rr * irad + orad) * Math.sin(tr);
            var rx = rr * Math.cos(tr);
            var rz = rr * Math.sin(tr);
            pos.push(tx, ty, tz);
            nor.push(rx, ry, rz);
            var tc = hsva(360 / column * ii, 1, 1, 1);
            col.push(tc[0], tc[1], tc[2], tc[3]);
        }
    }
    for(i = 0; i < row; i++){
        for(ii = 0; ii < column; ii++){
            r = (column + 1) * i + ii;
            idx.push(r, r + column + 1, r + 1);
            idx.push(r + column + 1, r + column + 2, r + 1);
        }
    }
    return {
          "position" : pos,
          "color" : col,
          "index" : idx,
          "normal" : nor
        };
}


function cube(size)
{
    var len = size * 0.5;
    var pos = [
        -len, len, len,
        len, len, len,
        len, -len, len,
        -len, -len, len,
        
        -len, len, -len,
        len, len, -len,
        len, -len, -len,
        -len, -len, -len
    ];
    
    var index = [
        0, 1, 3,
        1, 2, 3,
        
        1, 5, 2,
        5, 6, 2,
        
        4, 0,7,
        0, 3, 7,
        
        5, 4, 6,
        4, 7, 6,
        
        0, 4, 5,
        1, 0, 5,
        
        3, 2, 7,
        2, 6, 7
    ];
    
    var color = [
      1, 1, 1, 1,
      1, 0, 0, 1,
      0, 1, 0, 1,
      0, 0, 1, 1,
      
      0, 1, 0, 1,
      0, 0, 1, 1,
      1, 1, 1, 1,
      1, 0, 0, 1
      
    ];
    
    return {
        "position":pos,
        "index" : index,
        "color" : color,
        "normal" : pos
    };
}

// HSVカラー取得用関数
function hsva(h, s, v, a){
    if(s > 1 || v > 1 || a > 1){return;}
    var th = h % 360;
    var i = Math.floor(th / 60);
    var f = th / 60 - i;
    var m = v * (1 - s);
    var n = v * (1 - s * f);
    var k = v * (1 - s * (1 - f));
    var color = new Array();
    if(!s > 0 && !s < 0){
        color.push(v, v, v, a); 
    } else {
        var r = new Array(v, n, m, m, k, v);
        var g = new Array(k, v, v, n, m, m);
        var b = new Array(m, m, k, v, v, n);
        color.push(r[i], g[i], b[i], a);
    }
    return color;
}
<!DOCTYPE html>
<html>
<head>
<title>鏡面反射</title>
<meta charset="UTF-8">
<script src="mesh.js"></script>
<script src="minMatrix.js"></script>
<script src="specular.js"></script>
<script id="vs" type="x-shader/vertex">
attribute vec3 pos;
attribute vec3 normal;
uniform mat4 mvpMatrix;
varying vec3 vNormal;
void main()
{
    vNormal = normal;
    gl_Position = mvpMatrix * vec4(pos, 1.0);
}
</script>
<script id="fs" type="x-shader/fragment">
precision mediump float;
uniform vec3 lightPos;
uniform vec3 eyePos;
uniform mat4 invMMatrix;
varying vec3 vNormal;

void main()
{
    vec3 nInvLightDir = normalize(invMMatrix * vec4(normalize(lightPos), 0)).xyz;
    vec3 nInvEyeDir = normalize(invMMatrix * vec4(normalize(eyePos), 0)).xyz;
    float diffuse = dot(nInvLightDir, normalize(vNormal));
    vec3 halfVec = normalize(nInvLightDir + nInvEyeDir);
    float specular = pow(clamp(dot(halfVec, vNormal), 0.1, 1.0), 50.0);
    vec3 color = vec3(diffuse) + specular;
    gl_FragColor = vec4(color, 1.0);
}
</script>
</head>
<body>
    <canvas id="canvas"></canvas>
</body>
</html>
window.onload = function()
{
    var canvas = document.getElementById('canvas');
    canvas.width = canvas.height = 300;
    var gl = canvas.getContext('webgl');
    var vs = gl.createShader(gl.VERTEX_SHADER);
    var fs = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(vs, document.getElementById('vs').text);
    gl.shaderSource(fs, document.getElementById('fs').text);
    gl.compileShader(vs);
    gl.compileShader(fs);
    var prog = gl.createProgram();
    gl.attachShader(prog, vs);
    gl.attachShader(prog, fs);
    gl.linkProgram(prog);
    if (gl.getProgramParameter(prog, gl.LINK_STATUS))
    {
        gl.useProgram(prog);
    }else{
        console.log(gl.getProgramInfoLog(prog));
        return;
    }
    
    var attrList = [];
    var strideList = [];
    var uniformList = [];
    attrList[0] = gl.getAttribLocation(prog, 'pos');
    attrList[1] = gl.getAttribLocation(prog, 'normal');
    console.log(attrList);
    strideList[0] = 3;
    strideList[1] = 3;
    uniformList[0] = gl.getUniformLocation(prog, 'mvpMatrix');
    uniformList[1] = gl.getUniformLocation(prog, 'invMMatrix');
    uniformList[2] = gl.getUniformLocation(prog, 'lightPos');
    uniformList[3] = gl.getUniformLocation(prog, 'eyePos');
    
    var mesh = new torus(30, 30, 0.5, 1.0);
    // position
    var vbo = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
    gl.enableVertexAttribArray(attrList[0]);
    gl.vertexAttribPointer(attrList[0], strideList[0], gl.FLOAT, false, 0, 0);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(mesh['position']), gl.STATIC_DRAW);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    
    // normal
    vbo = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(mesh['normal']), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(attrList[1]);
    gl.vertexAttribPointer(attrList[1], strideList[1], gl.FLOAT, false, 0, 0);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    
    // ibo
    var ibo = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array(mesh['index']), gl.STATIC_DRAW);
    
    // matrix
    var m = new matIV();
    var mMatrix = m.identity(m.create());
    var vMatrix = m.identity(m.create());
    var pMatrix = m.identity(m.create());
    var vpMatrix = m.identity(m.create());
    var mvpMatrix = m.identity(m.create());
    var invMMatrix = m.identity(m.create());
    
    var eyePos =[0, 0, 3]; 
    var lightPos = [0, 3, 0];
    
    m.lookAt(eyePos, [0,0,0], [0,1,0], vMatrix);
    m.perspective(90, 1, 0.1, 100, pMatrix);
    m.multiply(pMatrix, vMatrix, vpMatrix);
    
    gl.enable(gl.DEPTH_TEST);
    
    draw();
    var count = 0;
    function draw()
    {
        gl.clearColor(0,0,0,1);
        gl.clear(gl.COLOR_BUFFER_BIT);
        
        m.identity(mMatrix);
        m.rotate(mMatrix, 2*count++*Math.PI/180, [1,0.5,-0.3],mMatrix);
        m.multiply(vpMatrix, mMatrix, mvpMatrix);
        gl.uniformMatrix4fv(uniformList[0], false, mvpMatrix);
        
        // ワールド座標変換逆行列
        m.inverse(mMatrix, invMMatrix);
        gl.uniformMatrix4fv(uniformList[1], false, invMMatrix);
        
        gl.uniform3fv(uniformList[2], lightPos);
        gl.uniform3fv(uniformList[3], eyePos);
        
        gl.drawElements(gl.TRIANGLES, mesh['index'].length, gl.UNSIGNED_SHORT, false, 0);
        setTimeout(draw, 1000/30);
    }
};