WebGL:マウスクリックで回転、ホイールでズームするワイヤーキューブデモ

webgl-wirecube.png

デモ

クリックで回転、ホイールでズームインorアウトします。

コード

<script src="http://miffysora.wikidot.com/local--files/webgl/gl-matrix-min.js" type="text/javascript"></script>
<script type='text/javascript' >
var gl;
function initGL(canvas) {
    try {
        gl = canvas.getContext("experimental-webgl");
        gl.viewportWidth = canvas.width;
        gl.viewportHeight = canvas.height;
    } catch (e) {
    }
    if (!gl) {
        alert("Could not initialise WebGL, sorry :-(");
    }
}
 
function createShader(gl, str, type) {
    var shader;
    if (type == "fragment") {
        shader = gl.createShader(gl.FRAGMENT_SHADER);
    } else if (type == "vertex") {
        shader = gl.createShader(gl.VERTEX_SHADER);
    } else {
        return null;
    }
 
    gl.shaderSource(shader, str);
    gl.compileShader(shader);
 
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        alert(gl.getShaderInfoLog(shader));
        return null;
    }
 
    return shader;
}
var vertexShaderSource =
         " attribute vec3 aVertexPosition;\n" +
         "uniform vec4 uVertexColor;\n" +
         "varying lowp vec4 vColor;" +
            " uniform mat4 uMVMatrix;\n" +
            " uniform mat4 uPMatrix;\n" +
            " void main(void) {\n" +
            " gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\n" +
            " vColor = vec4(aVertexPosition,1.0);//uVertexColor;\n" +
            "gl_PointSize=8.0;" +
            " }\n";
 
var fragmentShaderSource =
    "precision mediump float;\n" +
          "varying vec4 vColor;\n" +
            "void main(void) {\n" +
           "gl_FragColor =vColor;\n" +
            "}\n";
var shaderProgram;
 
function initShaders() {
    var fragmentShader = createShader(gl, fragmentShaderSource, "fragment");
    var vertexShader = createShader(gl, vertexShaderSource, "vertex");
    shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);
    //シェーダのリンクが成功したかどうか
    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
        alert("Could not initialise shaders");
    }
 
    gl.useProgram(shaderProgram);
    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
    shaderProgram.vertexColorUniform = gl.getUniformLocation(shaderProgram, "uVertexColor");
 
    shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
    shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
}
var previous_x, previous_y = 0;
var  drag = 0;
var xRot = yRot = 0;
var transl = -6;
var mvMatrix = mat4.create();
var pMatrix = mat4.create();
var rotMatrix = mat4.create();
var current_quaternion = new quat4.create([0, 0, 0, 1]);
var target_quaternion;
function setMatrixUniforms() {
    gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
    gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}
 
var cubeVertexPositionBuffer;
var indexBuffer;
function initGeometry() {//
var cubeVertices = [ -1.0, -1.0,  1.0,
                         1.0, -1.0,  1.0,
                        -1.0,  1.0,  1.0,
                         1.0,  1.0,  1.0,
                        -1.0, -1.0, -1.0,
                         1.0, -1.0, -1.0,
                        -1.0,  1.0, -1.0,
                         1.0,  1.0, -1.0,];
    var cubeLineIndices = [0,1,3,2,
                            0,4,6,2,
                            3,1,5,7,
                            3,2,6,7,
                            5,4];
    cubeVertexPositionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeVertices), gl.STATIC_DRAW);
    cubeVertexPositionBuffer.itemSize = 3; //頂点一個あたりは3データ(xyz)
    cubeVertexPositionBuffer.numItems = 8; //頂点の数
    indexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeLineIndices), gl.STATIC_DRAW);
    indexBuffer.numItems = 18;
}
var canvas;
function wheelHandler(ev) {
    var del = 1.1;
    if (ev.shiftKey) del = 1.01;
    var ds = ((ev.detail || ev.wheelDelta) > 0) ? del : (1 / del);
    transl *= ds;
    display();
    ev.preventDefault();
}
function initCamera() {
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 1000.0, pMatrix);
    mat4.identity(rotMatrix);
}
function mousedown(ev) {
    drag = 1;
    previous_x = ev.clientX;
    previous_y = ev.clientY;
    display();
}
function mouseup(ev) {
    drag = 0;
    quat4.set(target_quaternion,current_quaternion); //姿勢を保存
    display();
}
function move(ev) {
    canvas.style.cursor = "pointer";
    if (drag == 0) return;
     //移動量を計算 画面の中で何%ぐらい動いたか?
    var dx = (ev.clientX - previous_x) * 1.0 / canvas.width;
    var dy = (ev.clientY - previous_y) * 1.0 / canvas.height;
 
        //クォータニオンの長さ
        var length = Math.sqrt(dx * dx + dy * dy);
 
        if (length != 0.0) {
            //M_PIは適当な換算係数 piにしておくと、画面いっぱい動かした時にちょうど一回転になる
            var radian = length * Math.PI;
            var theta = Math.sin(radian) / length;
            var after = new quat4.create([dy * theta, dx * theta, 0.0, Math.cos(radian)]); //回転後の姿勢
            target_quaternion = quat4.multiply(after, current_quaternion, quat4.create());
            quat4.toMat4(target_quaternion, rotMatrix);
 
        }
    display();
 
}
function display() {
 
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    yRot = 0; xRot = 0;
     mat4.identity(mvMatrix); 
 
    mat4.translate(mvMatrix, [0.0, 0.0, transl]); 
    mat4.multiply(mvMatrix,rotMatrix, mvMatrix);
 
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    gl.uniform4f(shaderProgram.vertexColorUniform, 0.0, 0.0, 0.0, 1.0);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
    setMatrixUniforms();
     gl.drawElements(gl.LINE_LOOP, indexBuffer.numItems, gl.UNSIGNED_SHORT, indexBuffer);
 
}
function onLoad() {
     canvas = document.getElementById("webglcanvas");
     initGL(canvas);
     initCamera();
    initShaders();
    initGeometry();
    gl.enable(gl.DEPTH_TEST);
 
    display();
    canvas.onblur = mouseup;
    canvas.onmousedown =mousedown;
    canvas.onmouseup = mouseup;
    canvas.onmousemove = move;
    canvas.addEventListener('DOMMouseScroll', wheelHandler, false);
    canvas.addEventListener('mousewheel', wheelHandler, false);
 
}
</script>
<body onload="onLoad()">
</script><canvas id="webglcanvas" style="border: none;" width="200" height="200"></canvas>

サポートサイト Wikidot.com