DIR : /home/kozerus/public_html/jkwii/js/jsdoit/water/index.js

/home/kozerus/public_html/jkwii/js/jsdoit/water

    function initGL(canvas) {
        try {
            gl = canvas.getContext("experimental-webgl");
            gl.viewportWidth = canvas.width;
            gl.viewportHeight = canvas.height;
        } catch (e) {
        }
        if (!gl) {
	    showMessage(err_img_url, 'WebGL is not supported.');
        }
    }

    function showMessage( img_url, msg ) 
    {
	document.write('\
	<style>body { background-color: #DDDDDD; overflow: hidden; padding: 0px; margin: 0px; }</style>\
	<div id="alt">\
	<img id="captureImg" src="'+img_url+'"/>\
	<div style="position: absolute; top: 350px; left: 0px; margin: 15px; padding: 15px;line-height: 15px;background:#eee;opacity:0.9;\
	filter:alpha(opacity=90);">\
	<h4 style="margin: 0px; font: 22px Arial;">'+msg+'</h4>\
	<a style=" font: 10px Arial;" target="_blank" href="http://learningwebgl.com/cookbook/index.php/WebGL:_Frequently_Asked_Questions">\
	<font size="-1">how to use WebGL</font></a>\
	</div>\
	</div>\
	');
    }

    function getShader(gl, id) {
        var shaderScript = document.getElementById(id);
        if (!shaderScript) {
            return null;
        }

        var str = "";
        var k = shaderScript.firstChild;
        while (k) {
            if (k.nodeType == 3) {
                str += k.textContent;
            }
            k = k.nextSibling;
        }

        var shader;
        if (shaderScript.type == "x-shader/x-fragment") {
            shader = gl.createShader(gl.FRAGMENT_SHADER);
        } else if (shaderScript.type == "x-shader/x-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;
    }

    function initShaders() {
        var fragmentShader = getShader(gl, "shader-fs");
        var vertexShader = getShader(gl, "shader-vs");

        shaderProgram = gl.createProgram();
        gl.attachShader(shaderProgram, vertexShader);
        gl.attachShader(shaderProgram, fragmentShader);
        gl.linkProgram(shaderProgram);

        if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
	    showMessage(err_img_url, 'Fail to compile.');
            alert("Could not initialise shaders");
        }

        gl.useProgram(shaderProgram);

        shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
        gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

        shaderProgram.texture0CoordAttribute = gl.getAttribLocation(shaderProgram, "aTexture0Coord");
        gl.enableVertexAttribArray(shaderProgram.texture0CoordAttribute);

        shaderProgram.texture1CoordAttribute = gl.getAttribLocation(shaderProgram, "aTexture1Coord");
        gl.enableVertexAttribArray(shaderProgram.texture1CoordAttribute);

        shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
        shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
        shaderProgram.texture0Uniform = gl.getUniformLocation(shaderProgram, "texture0");
        shaderProgram.texture1Uniform = gl.getUniformLocation(shaderProgram, "texture1");
    }

    function handleLocalTexture(texture, img)
    {
	gl.bindTexture(gl.TEXTURE_2D, texture);
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.bindTexture(gl.TEXTURE_2D, null);
    }

    function initTexture() {
        refractionTexture = gl.createTexture();
	var img0 = document.getElementById('texture0');
	handleLocalTexture(refractionTexture, img0);
        reflectionTexture = gl.createTexture();
	var img1 = document.getElementById('texture1');
	handleLocalTexture(reflectionTexture, img1);
    }

    function initWaterBuffers()
    {
        // create vertice buffer
        waterVertexPositionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, waterVertexPositionBuffer);

        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
        waterVertexPositionBuffer.itemSize = 3;
        waterVertexPositionBuffer.numItems = vertices.length / 3;

        // create uvt buffer
        waterVertexTexture0CoordBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, waterVertexTexture0CoordBuffer);

        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(uvt), gl.STATIC_DRAW);
        waterVertexTexture0CoordBuffer.itemSize = 2;
        waterVertexTexture0CoordBuffer.numItems = vertices.length / 3;

        // create uvt2 buffer
        waterVertexTexture1CoordBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, waterVertexTexture1CoordBuffer);

        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(uvt2), gl.STATIC_DRAW);
        waterVertexTexture1CoordBuffer.itemSize = 2;
        waterVertexTexture1CoordBuffer.numItems = vertices.length / 3;

        // create indices buffer
        waterVertexIndexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, waterVertexIndexBuffer);

        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
        waterVertexIndexBuffer.itemSize = 1;
        waterVertexIndexBuffer.numItems = indices.length;
    }

    function mvPushMatrix() {
        var copy = mat4.create();
        mat4.set(mvMatrix, copy);
        mvMatrixStack.push(copy);
    }

    function mvPopMatrix() {
        if (mvMatrixStack.length == 0) {
            throw "Invalid popMatrix!";
        }
        mvMatrix = mvMatrixStack.pop();
    }


    function setMatrixUniforms() {
        gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
        gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
    }


    function degToRad(degrees) {
        return degrees * Math.PI / 180;
    }

    function animate() {
        var timeNow = new Date().getTime();
        if (lastTime != 0) {
            var elapsed = timeNow - lastTime;

            xRot += (90 * elapsed) / 1000.0;
            yRot += (90 * elapsed) / 1000.0;
            zRot += (90 * elapsed) / 1000.0;
        }
        lastTime = timeNow;
    }

    function drawWater()
    {
        gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 500.0, pMatrix);

        mat4.rotate(pMatrix, degToRad(180), [1, 0, 0]);

        mat4.identity(mvMatrix);

        mat4.translate(mvMatrix, [0.0, 0.0, 150.0]);
        mat4.rotate(mvMatrix, degToRad(-viewedAngleV*57.29577951308232), [1, 0, 0]);
        mat4.rotate(mvMatrix, degToRad(-viewedAngleH*57.29577951308232), [0, 1, 0]);

        // bind position buffer
        gl.bindBuffer(gl.ARRAY_BUFFER, waterVertexPositionBuffer);
        gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, waterVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

        // bind texture0 buffer
        gl.bindBuffer(gl.ARRAY_BUFFER, waterVertexTexture0CoordBuffer);
        gl.vertexAttribPointer(shaderProgram.texture0CoordAttribute, waterVertexTexture0CoordBuffer.itemSize, gl.FLOAT, false, 0, 0);

        // upload texture0 buffer
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, refractionTexture);
        gl.uniform1i(shaderProgram.texture0Uniform, 0);

        // bind texture1 buffer
        gl.bindBuffer(gl.ARRAY_BUFFER, waterVertexTexture1CoordBuffer);
        gl.vertexAttribPointer(shaderProgram.texture1CoordAttribute, waterVertexTexture1CoordBuffer.itemSize, gl.FLOAT, false, 0, 0);

        // upload texture1 buffer
        gl.activeTexture(gl.TEXTURE1);
        gl.bindTexture(gl.TEXTURE_2D, reflectionTexture);
        gl.uniform1i(shaderProgram.texture1Uniform, 1);

        // reflectionRatio
        gl.uniform1f(gl.getUniformLocation(shaderProgram, "reflectionRatio"), reflectionRatio); // <- uniform1f, "f" for float

        // bind indice buffer
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, waterVertexIndexBuffer);
        setMatrixUniforms();
        gl.drawElements(gl.TRIANGLES, waterVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

       // textfield.value = "updating ..."+lastTime;
    }

    function tick() {
        requestAnimFrame(tick);

        //drawScene();
        move();
        setMesh();
        initWaterBuffers();
        drawWater();
        animate();
    }

    function webGLStart() {
        var canvas = document.getElementById("canvasView");
        initGL(canvas);
        initShaders();
        initWater();
        initTexture();

        gl.clearColor(0.2, 0.2, 0.2, 1.0);
        gl.enable(gl.DEPTH_TEST);

        tick();

        // exxxxxxxxxxxtra
        var win = document.getElementById("window");
        refractionSlider = new mc.HSlider(win, 30, 20, onRefractionChanged).bindLabel(new mc.Label(win, 145, 20), 0);
        reflectionSlider = new mc.HSlider(win, 30, 40, onReflectionChanged).bindLabel(new mc.Label(win, 145, 40), 0);
        refractionSlider.setSliderParams(1, 3, 1.4);
        reflectionSlider.setSliderParams(0, 1, 0.4);
        win.onmousemove = onMouseMove;
    }

    function onRefractionChanged(e)
    {
        refractiveIndex = refractionSlider.getValue();
    }

    function onReflectionChanged(e)
    {
        reflectionRatio = reflectionSlider.getValue();
    }

    function onMouseMove(e)
    {
        var point = whereAt(e);
        mouseX = point[0];
        mouseY = point[1];
        ripple(-(500/2 - mouseY)/ 500 * MESH_SIZE, (mouseX - 500/2)/ 500 * MESH_SIZE, 3);
    }

    // from - http://stackoverflow.com/questions/3011418/onmousemove-get-mouse-position
    var whereAt = (function(){
        if(window.pageXOffset!= undefined){
            return function(ev){
                return [ev.clientX+window.pageXOffset,
                ev.clientY+window.pageYOffset];
            }
        }
        else return function(){
            var ev= window.event,
            d= document.documentElement, b= document.body;
            return [ev.clientX+d.scrollLeft+ b.scrollLeft,
            ev.clientY+d.scrollTop+ b.scrollTop];
        }
    })();

    // constants
    var NUM_DETAILS = 64; // 48;
    var INV_NUM_DETAILS = 1 / NUM_DETAILS;
    var MESH_SIZE = 100; // 100;
    var SURFACE_DETAILS = NUM_DETAILS-4;
    var VCOUNT = SURFACE_DETAILS * SURFACE_DETAILS;

    var WIDTH = 465;
    var HEIGHT = 465;

    //
    var err_img_url = 'http://dl.dropbox.com/u/56320860/water.png';

    // variables
    var mouseX = 0;
    var mouseY = 0;
    var viewedAngleH = 0, rotH = 0;
    var viewedAngleV = -20 * 0.017453292519943295, rotV = 0;
    var cameraDistance = MESH_SIZE;
    var focalLength = MESH_SIZE * 4;
    var boxHeight = MESH_SIZE*0.75;
    var refractiveIndex = 1.4;
    var reflectionRatio = 0.4;
    var cameraPosition = {x: 0, y: 0, z:0};
    var cameraPos = [0, 0, 0];

    // GL
    var gl;
    var shaderProgram;

    // data
    var heights = [];
    var velocity = [];
    var indices = [];
    var uvt = [], uvt2 = [];

    // buffers
    var waterVertexPositionBuffer;
    var waterVertexTexture0CoordBuffer;
    var waterVertexTexture1CoordBuffer;
    var waterVertexIndexBuffer;

    var cubeVertexPositionBuffer;
    var cubeVertexTextureCoordBuffer;
    var cubeVertexIndexBuffer;

    var refractionTexture;
    var reflectionTexture;

    // matrix
    var mvMatrix = mat4.create();
    var mvMatrixStack = [];
    var pMatrix = mat4.create();

    var _invmat = mat4.create();
    var mat = mat4.create();

    // minimalcomps
    var refractionSlider;
    var reflectionSlider;

    var lastTime = 0;

    function initWater()
    {
        var i, j, idx;
        vertices = []; // new Vector.<Number>(VCOUNT * 7, true);
        transformedVertices = []; // new Vector.<Number>(VCOUNT * 2, true);
        uvt = []; // new Vector.<Number>(VCOUNT * 2, true);
        uvt2 = []; // new Vector.<Number>(VCOUNT * 2, true);
        for (i = 0; i < VCOUNT; i++) {
            /*
            vertices[i]   = ((Math.floor(i/SURFACE_DETAILS)+2) * INV_NUM_DETAILS - 0.5) * MESH_SIZE;
            vertices[i+1] = ((Math.floor(i%SURFACE_DETAILS)+2) * INV_NUM_DETAILS - 0.5) * MESH_SIZE;
            vertices[i+2] = 0;
            //*/
            vertices.push(((Math.floor(i/SURFACE_DETAILS)+2) * INV_NUM_DETAILS - 0.5) * MESH_SIZE, ((Math.floor(i%SURFACE_DETAILS)+2) * INV_NUM_DETAILS - 0.5) * MESH_SIZE, 0);
            uvt.push(0,0);
            uvt2.push(0,0);
        }
        indices = []; // new Vector.<int>();
        for (i=1; i<SURFACE_DETAILS; i++) for (j=1; j<SURFACE_DETAILS; j++) {
            idx = j * SURFACE_DETAILS + i;
            indices.push(idx-SURFACE_DETAILS-1, idx-SURFACE_DETAILS, idx,
                         idx-SURFACE_DETAILS-1, idx, idx-1);
        }

        // create field
        heights = []; // new Vector.<Number>(NUM_DETAILS * NUM_DETAILS, true);
        velocity = []; // new Vector.<Number>(NUM_DETAILS * NUM_DETAILS, true);
        for (i = 0; i < NUM_DETAILS * NUM_DETAILS; i++) //velocity[i] = heights[i] = 0;
        {
            velocity.push(0);
            heights.push(0);
        }
    }

    function ripple(mx, my, intensity) {
        var i, j, idx, dx, dy, acc, imin, jmin, imax, jmax;
        mx = (mx / MESH_SIZE + 0.5) * NUM_DETAILS;
        my = (my / MESH_SIZE + 0.5) * NUM_DETAILS;
        imin = (mx > 5) ? Math.floor(mx - 3) : 2;
        jmin = (my > 5) ? Math.floor(my - 3) : 2;
        imax = (mx < NUM_DETAILS-5) ? Math.floor(mx + 4) : (NUM_DETAILS - 1);
        jmax = (my < NUM_DETAILS-5) ? Math.floor(my + 4) : (NUM_DETAILS - 1);
        for (i=imin; i<imax; i++) for (j=jmin; j<jmax; j++) {
            dx = mx - i;
            dy = my - j;
            acc = 3 - Math.sqrt(dx * dx + dy * dy);
            if (acc > 0) velocity[j*NUM_DETAILS+i] += acc*intensity;
        }
    }

    function setMesh()
    {
        var i, j, index, index2, len, u, v,
            t, s, r, hitz, sign,
            vx, vy, vz,
            nx, ny, nz,
            dx, dy, dz,
            rimo = refractiveIndex - 1,
            xymax = MESH_SIZE * 0.45, //MESH_SIZE * 0.5,
            ixymax = 1 / xymax;

        for (i = 0; i < SURFACE_DETAILS; i++) {
            for (j = 0; j < SURFACE_DETAILS; j++) {
                index = (j * SURFACE_DETAILS + i) * 3;// * 7;
                index2 = (j * SURFACE_DETAILS + i) * 2;
                len = heights[(j+2)*NUM_DETAILS+i+2];
                /*
                vx = vertices[index]; index++;
                vy = vertices[index]; index++;
                vz = vertices[index] = len * 0.25; index++;
                //*/
                vx = vertices[index  ];
                vy = vertices[index+1];
                vz = vertices[index+2] = len * 0.15;//0.25;
                //*/

                // ---Sphere map---
                nx = (len - heights[(j+2)*NUM_DETAILS+i+1]) * 0.25;
                ny = (len - heights[(j+1)*NUM_DETAILS+i+2]) * 0.25;
                nz = 1 / Math.sqrt(nx * nx + ny * ny + 1);
                nx *= nz;
                ny *= nz;


                // [modification] Refraction map
                // incident vector (you can calculate them in the setup if you want faster)
                dx = vx - cameraPosition.x;
                dy = vy - cameraPosition.y;
                dz = vz - cameraPosition.z;
                len = 1 / Math.sqrt(dx * dx + dy * dy + dz * dz);
                dx *= len;
                dy *= len;
                dz *= len;
                // output vector
                t = (dx * nx + dy * ny + dz) * rimo;
                dx += nx * t;
                dy += ny * t;
                dz += nz * t;
                // in this calculation, we can omit normalization of output vector !
                //len = 1 / Math.sqrt(dx * dx + dy * dy + dz * dz);
                //dx *= len;
                //dy *= len;
                //dz *= len;
                // uv coordinate
                if (dx == 0) {
                    if (dy == 0) {
                        u = v = 0.5;
                        sign = 0;
                    } else sign = (dy < 0) ? -1 : 1;
                } else {
                    sign = (dx < 0) ? -1 : 1;
                    t = (sign * xymax - vx) / dx;
                    s = t * dy + vy;
                    if (-xymax < s && s < xymax) {
                        hitz = t * dz + vz;
                        if (hitz > boxHeight) {
                            r = (boxHeight-vz) / dz;
                            u = (dx * r + vx) * ixymax * 0.25 + 0.5;
                            v = (dy * r + vy) * ixymax * 0.25 + 0.5;
                        } else {
                            r = boxHeight / (hitz + boxHeight);
                            u = sign       * r * 0.5 + 0.5;
                            v = s * ixymax * r * 0.5 + 0.5;
                        }
                        sign = 0;
                    } else sign = (dy < 0) ? -1 : 1;
                }
                if (sign != 0) {
                    t = (sign * xymax - vy) / dy;
                    s = t * dx + vx;
                    hitz = t * dz + vz;
                    if (hitz > boxHeight) {
                        r = (boxHeight-vz) / dz;
                        u = (dx * r + vx) * ixymax * 0.25 + 0.5;
                        v = (dy * r + vy) * ixymax * 0.25 + 0.5;
                    } else {
                        r = boxHeight / (hitz + boxHeight);
                        u = s * ixymax * r * 0.5 + 0.5;
                        v = sign       * r * 0.5 + 0.5;
                    }
                }
                /*
                vertices[index] = nx * 0.5 + 0.5 + ((i - NUM_DETAILS * 0.5) * INV_NUM_DETAILS * 0.25); index++;
                vertices[index] = ny * 0.5 + 0.5 + ((NUM_DETAILS * 0.5 - j) * INV_NUM_DETAILS * 0.25); index++;
                vertices[index] = u; index++;
                vertices[index] = v;
                //*/

                uvt[index2  ] = nx * 0.5 + 0.5 + ((i - NUM_DETAILS * 0.5) * INV_NUM_DETAILS * 0.25); // index++;
                uvt[index2+1] = ny * 0.5 + 0.5 + ((NUM_DETAILS * 0.5 - j) * INV_NUM_DETAILS * 0.25); // index++;
                uvt2[index2  ] = u; // index++;
                uvt2[index2+1] = v;
                //*/
            }
        }
    }


    function move()
    {
        // ---Water simulation---
        var i, j, idx, v, imax, jmax;
        imax = jmax = NUM_DETAILS - 1;
        for (i=1; i<imax; i++) for (j=1; j<jmax; j++) {
            idx = j * NUM_DETAILS + i;
            heights[idx] += velocity[idx];
            if (heights[idx] > 100) heights[idx] = 100;
            else if (heights[idx] < -100) heights[idx] = -100;
        }
        for (i=1; i<imax; i++) for (j=1; j<jmax; j++) {
            idx = j * NUM_DETAILS + i;
            v = -heights[idx] * 4; idx-=NUM_DETAILS;
            v += heights[idx];     idx+=NUM_DETAILS-1;
            v += heights[idx];     idx+=2;
            v += heights[idx];     idx+=NUM_DETAILS-1;
            v += heights[idx];     idx-=NUM_DETAILS;
            velocity[idx] = (velocity[idx] + v * 0.5) * 0.9;
        }
        /*
        // why dont I use Matrix3D !?
        var targetAngleH:Number = (mouseX -232.5) / 465 * 40 * 0.017453292519943295,
            targetAngleV:Number = -((mouseY -232.5) / 465 * 40 + 40) * 0.017453292519943295;
        rotH += (targetAngleH - viewedAngleH) * 0.01;
        rotV += (targetAngleV - viewedAngleV) * 0.01;
        //viewedAngleH += (rotH *= 0.9);
        //viewedAngleV += (rotV *= 0.9);
        modelviewMatrix.identity();
        modelviewMatrix.prependTranslation(0, 0, cameraDistance);
        modelviewMatrix.prependRotation(-viewedAngleV*57.29577951308232, Vector3D.X_AXIS);
        modelviewMatrix.prependRotation(-viewedAngleH*57.29577951308232, Vector3D.Y_AXIS);
        _invmat.copyFrom(modelviewMatrix);
        _invmat.invert();
        _invmat.copyRowTo(3, cameraPosition);
        //cameraPosition.negate();
        //*/
        var targetAngleH = ((mouseX -WIDTH/2) / WIDTH * 80) * 0.017453292519943295,
            targetAngleV = ((mouseY -HEIGHT/2) / HEIGHT * 80) * 0.017453292519943295;
        rotH += (targetAngleH - viewedAngleH) * 0.01;
        rotV += (targetAngleV - viewedAngleV) * 0.01;
        viewedAngleH += (rotH *= 0.9);
        viewedAngleV += (rotV *= 0.9);

        mat4.identity(mat);
        //mat4.translate(mat, [0.0, 0.0, -100.0]);
        mat4.rotate(mat, degToRad(-viewedAngleV*57.29577951308232), [1, 0, 0]);
        mat4.rotate(mat, degToRad(-viewedAngleH*57.29577951308232), [0, 1, 0]);
        mat4.inverse(mat);
        mat4.multiplyVec3(mat, [0.0, 0.0, -100.0], cameraPos);

        cameraPosition.x = cameraPos[0];
        cameraPosition.y = cameraPos[1];
        cameraPosition.z = cameraPos[2];
    }

    window.onload = webGLStart;
//


koh5_pano



Your browser does not support the HTML5 canvas element.


Drag mouse to navigate.

Navigation





17.Aug.2010, Martin Wengenmayer