baobao
3/13/2018 - 12:02 AM

specular.html

<!DOCTYPE html>
<html>
<head>
<title>鏡面反射</title>
<meta charset="UTF-8">
<script src="minMatrix.js"></script>
<script src="specular.js"></script>
<script id="vs" type="x-shader/vertex">
attribute vec3 pos;
attribute vec4 color;
attribute vec3 normal;
uniform mat4 mvpMatrix;

varying vec4 vColor;
varying vec3 vNormal;

void main()
{
    vNormal = normal;
    vColor = color;
    gl_Position = mvpMatrix * vec4(pos, 1.0);
}
</script>
<script id="fs" type="x-shader/fragment">
precision mediump float;
// ライトの方向
uniform vec3 lightDir;
uniform vec3 eyeDir;
// モデル座標変換逆行列
uniform mat4 invMMatrix;
varying vec4 vColor;
varying vec3 vNormal;

void main()
{
    // モデル座標変換逆行列で変換したライト逆ベクトル
    vec3 invLightDir = normalize(invMMatrix * vec4(lightDir, 0.0)).xyz;
    vec3 invEyeDir = normalize(invMMatrix * vec4(eyeDir, 0.0)).xyz;
    vec3 halfVec = normalize(invLightDir + invEyeDir);
    
    // 法線ベクトルとライト逆ベクトルの内積で照度を算出してクランプする
    // 法線ベクトルはモデル座標変換行列で変換しても変換されていないことがポイント
    // あくまで頂点座標にのみ座標変換が走る。
    float lightStrength = clamp(dot(vNormal, invLightDir), 0.1, 1.0);
    
    float specular = pow(clamp(dot(halfVec, vNormal), 0.0, 1.0), 50.0);
    
    vec4 color = vec4(vec3(lightStrength), 1.0) + vec4(vec3(specular), 1.0);
    
    gl_FragColor = color ;
}
</script>
</head>
<body>
    <canvas id="canvas"></canvas>
</body>
</html>
/**
 * 鏡面反射トーラス
 * require:https://github.com/doxas/minMatrix.js
 */
window.onload = function()
{
    var canvas = document.getElementById('canvas');
    canvas.width = canvas.height = 500;
    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 cubeData = torus(120,120,0.5,1.2); //cube(1);
    
    
    var attrList = [];
    var strideList = [];
    
    attrList[0] = gl.getAttribLocation(prog, 'pos');
    attrList[1] = gl.getAttribLocation(prog, 'color');
    attrList[2] = gl.getAttribLocation(prog, 'normal');
    strideList[0] = 3;
    strideList[1] = 4;
    strideList[2] = 3;
    
    var uniLoc = [];
    uniLoc[0] = gl.getUniformLocation(prog, 'mvpMatrix');
    uniLoc[1] = gl.getUniformLocation(prog, 'invMMatrix');
    uniLoc[2] = gl.getUniformLocation(prog, 'lightDir');
    uniLoc[3] = gl.getUniformLocation(prog, 'eyeDir');
    
    // 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(cubeData['position']), gl.STATIC_DRAW);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    // color
    vbo = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
    gl.enableVertexAttribArray(attrList[1]);
    gl.vertexAttribPointer(attrList[1], strideList[1], gl.FLOAT, false, 0, 0);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeData['color']), gl.STATIC_DRAW);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    // normal
    vbo = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
    gl.enableVertexAttribArray(attrList[2]);
    gl.vertexAttribPointer(attrList[2], strideList[2], gl.FLOAT, false, 0, 0);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeData['normal']), gl.STATIC_DRAW);
    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(cubeData['index']), gl.STATIC_DRAW);
    
    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 eyeDir = [0, 2, 3];
    
    m.lookAt(eyeDir, [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);
    
    var count = 0;
    
    function draw()
    {
        gl.clearColor(0.1,0.1,0.1,1);
        gl.clear(gl.COLOR_BUFFER_BIT);
        
        m.identity(mMatrix);
        var angle = 3*count++ * Math.PI/180;
        m.rotate(mMatrix, angle, [2, 1, -0.5], mMatrix);
        m.multiply(vpMatrix, mMatrix, mvpMatrix);
        // モデル座標変換行列の逆行列を算出
        m.inverse(mMatrix, invMMatrix);
        
        gl.uniformMatrix4fv(uniLoc[0], false, mvpMatrix);
        gl.uniformMatrix4fv(uniLoc[1], false, invMMatrix);
        gl.uniform3fv(uniLoc[2], [0, 2, 2]);
        gl.uniform3fv(uniLoc[3], eyeDir);
        
        gl.drawElements(
                gl.TRIANGLES, 
                cubeData['index'].length, 
                gl.UNSIGNED_SHORT, 
                false, 0);
        
        setTimeout(draw, 1000/30);
    }
    draw();
};

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
    };
}


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]);
//            col.push(1,1,1,1);
        }
    }
    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 [pos, nor, col, idx];
    return {
          "position" : pos,
          "color" : col,
          "index" : idx,
          "normal" : nor
        };
}

// 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;
    }