zoukankan      html  css  js  c++  java
  • WEBGL学习【十三】鼠标点击立方体改变颜色的原理与实现

    // PickFace.js (c) 2012 matsuda and kanda
    // Vertex shader program
    var VSHADER_SOURCE =
        'attribute vec4 a_Position;
    ' +
        'attribute vec4 a_Color;
    ' +
        'attribute float a_Face;
    ' +   // 表面的编号(1-6),不能使用int类型(当前顶点属于哪一个表面)【float类型】
        'uniform mat4 u_MvpMatrix;
    ' +
        'uniform int u_PickedFace;
    ' + // 被选中的表面编号【int类型】
        'varying vec4 v_Color;
    ' +
        'void main() {
    ' +
        '  gl_Position = u_MvpMatrix * a_Position;
    ' + //对顶点的位置进行模型视图投影变换
        '  int face = int(a_Face);
    ' + // 转换为int类型(鼠标一点击就会把他编码成颜色值得a分量)
        '  vec3 color = (face == u_PickedFace) ? vec3(1.0) : a_Color.rgb;
    ' +   //vec3(1.0)所有的分量都为1,此时为白色;否则顶点颜色还是以前的颜色
        '  if(u_PickedFace == 0) {
    ' + // 前三个分量RGB, 通过第四个分量来判断是点击的是哪一个顶面
        '    v_Color = vec4(color, a_Face/255.0);
    ' +  // 颜色的第4个分量使得图形的透明度不一样
        '  } else {
    ' +
        '    v_Color = vec4(color, a_Color.a);
    ' +
        '  }
    ' +
        '}
    ';
    
    // Fragment shader program
    var FSHADER_SOURCE =
        '#ifdef GL_ES
    ' +
        'precision mediump float;
    ' +
        '#endif
    ' +
        'varying vec4 v_Color;
    ' +
        'void main() {
    ' +
        '  gl_FragColor = v_Color;
    ' +
        '}
    ';
    
    //旋转的速度
    var ANGLE_STEP = 20.0; // Rotation angle (degrees/second)
    
    function main() {
       // 获取canvas
        var canvas = document.getElementById('webgl');
    
        // 获取上下文信息
        var gl = getWebGLContext(canvas);
        if (!gl) {
            console.log('Failed to get the rendering context for WebGL');
            return;
        }
    
        // 初始化着色器
        if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
            console.log('Failed to intialize shaders.');
            return;
        }
    
        // 设置顶点的信息
        var n = initVertexBuffers(gl);
        if (n < 0) {
            console.log('Failed to set the vertex information');
            return;
        }
    
        // 用白色清空背景色,启动深度测试
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.enable(gl.DEPTH_TEST);
    
        // 获取模型视图投影矩阵的存储地址,获取点击面的位置
        var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
        var u_PickedFace = gl.getUniformLocation(gl.program, 'u_PickedFace');
        if (!u_MvpMatrix || !u_PickedFace) {
            console.log('Failed to get the storage location of uniform variable');
            return;
        }
    
        // 计算模型视图投影矩阵
        var viewProjMatrix = new Matrix4();
        viewProjMatrix.setPerspective(30.0, canvas.width / canvas.height, 1.0, 100.0);
        viewProjMatrix.lookAt(0.0, 0.0, 7.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    
    
        // 初始化被选中的表面(刚开始没有那个面被选中,还是以前的颜色)
        gl.uniform1i(u_PickedFace, -1);
    
        var currentAngle = 0.0; // Current rotation angle
        // Register the event handler
        canvas.onmousedown = function (ev) {   // Mouse is pressed
            var x = ev.clientX, y = ev.clientY;
            var rect = ev.target.getBoundingClientRect();
            if (rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom) {
                // 获取鼠标当前点击的位置,转换为canvas元素中的坐标
                var x_in_canvas = x - rect.left, y_in_canvas = rect.bottom - y;
    
                //调用这个函数区检测里方法体的哪一个面被点击了(face这个分量此时存储的是第四个a分量, read(pixes[3]) ;
                var face = checkFace(gl, n, x_in_canvas, y_in_canvas, currentAngle, u_PickedFace, viewProjMatrix, u_MvpMatrix);
                //console.log("The current face is"+face.toString());
                var num = parseFloat(face)/255.0;       //这里除255等价于 <===> a/255, 得到的其实是一个唯一编号,就是把一个在缓冲区中改变了颜色的那个面的第四个分量
                console.log("当前点击的面为"+num.toString()+" "+face.toString());
    
    
                //把当前选中的一面传给顶点着色器()
                gl.uniform1i(u_PickedFace, face); // Pass the surface number to u_PickedFace
    
                //用选中的编号重新绘制立方体
                draw(gl, n, currentAngle, viewProjMatrix, u_MvpMatrix);
            }
        }
    
        var tick = function () {   // Start drawing
            currentAngle = animate(currentAngle);
            draw(gl, n, currentAngle, viewProjMatrix, u_MvpMatrix);
            requestAnimationFrame(tick, canvas);
        };
        tick();
    }
    
    function initVertexBuffers(gl) {
        // Create a cube
        //    v6----- v5
        //   /|      /|
        //  v1------v0|
        //  | |     | |
        //  | |v7---|-|v4
        //  |/      |/
        //  v2------v3
    
        var vertices = new Float32Array([   // Vertex coordinates
            1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0,    // v0-v1-v2-v3 front
            1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0,    // v0-v3-v4-v5 right
            1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0,    // v0-v5-v6-v1 up
            -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0,    // v1-v6-v7-v2 left
            -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,    // v7-v4-v3-v2 down
            1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0     // v4-v7-v6-v5 back
        ]);
    
        var colors = new Float32Array([   // Colors
            0.32, 0.18, 0.56, 0.32, 0.18, 0.56, 0.32, 0.18, 0.56, 0.32, 0.18, 0.56, // v0-v1-v2-v3 front
            0.5, 0.41, 0.69, 0.5, 0.41, 0.69, 0.5, 0.41, 0.69, 0.5, 0.41, 0.69,  // v0-v3-v4-v5 right
            0.78, 0.69, 0.84, 0.78, 0.69, 0.84, 0.78, 0.69, 0.84, 0.78, 0.69, 0.84, // v0-v5-v6-v1 up
            0.0, 0.32, 0.61, 0.0, 0.32, 0.61, 0.0, 0.32, 0.61, 0.0, 0.32, 0.61,  // v1-v6-v7-v2 left
            0.27, 0.58, 0.82, 0.27, 0.58, 0.82, 0.27, 0.58, 0.82, 0.27, 0.58, 0.82, // v7-v4-v3-v2 down
            0.73, 0.82, 0.93, 0.73, 0.82, 0.93, 0.73, 0.82, 0.93, 0.73, 0.82, 0.93, // v4-v7-v6-v5 back
        ]);
    
        //把我的表面编号传进去
        var faces = new Uint8Array([   // Faces
            1, 1, 1, 1,     // v0-v1-v2-v3 front
            2, 2, 2, 2,     // v0-v3-v4-v5 right
            3, 3, 3, 3,     // v0-v5-v6-v1 up
            4, 4, 4, 4,     // v1-v6-v7-v2 left
            5, 5, 5, 5,     // v7-v4-v3-v2 down
            6, 6, 6, 6,     // v4-v7-v6-v5 back
        ]);
    
        var indices = new Uint8Array([   // Indices of the vertices
            0, 1, 2, 0, 2, 3,    // front
            4, 5, 6, 4, 6, 7,    // right
            8, 9, 10, 8, 10, 11,    // up
            12, 13, 14, 12, 14, 15,    // left
            16, 17, 18, 16, 18, 19,    // down
            20, 21, 22, 20, 22, 23     // back
        ]);
    
        // Create a buffer object
        var indexBuffer = gl.createBuffer();
        if (!indexBuffer) {
            return -1;
        }
    
        // Write vertex information to buffer object
        if (!initArrayBuffer(gl, vertices, gl.FLOAT, 3, 'a_Position')) return -1; // Coordinates Information
        if (!initArrayBuffer(gl, colors, gl.FLOAT, 3, 'a_Color')) return -1;      // Color Information
        if (!initArrayBuffer(gl, faces, gl.UNSIGNED_BYTE, 1, 'a_Face')) return -1;// Surface Information
    
        // Unbind the buffer object
        gl.bindBuffer(gl.ARRAY_BUFFER, null);
    
        // Write the indices to the buffer object
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
    
        return indices.length;
    }
    
    //检测哪一个面被选中了(【根据点中的位置返回表面编号】)
    function checkFace(gl, n, x, y, currentAngle, u_PickedFace, viewProjMatrix, u_MvpMatrix) {
        var pixels = new Uint8Array(4); // Array for storing the pixel value
    
        //将表面编号写入到a分量(如果选中了)
        //鼠标一旦点击,就把u_PickedFace变量从-1变为0
        gl.uniform1i(u_PickedFace, 0);  // Draw by writing surface number into alpha value
    
        //此时每个表面的a值就取决于表面的编号(这一步绘制工作会在颜色缓冲区中执行,不会显示在屏幕上)
        draw(gl, n, currentAngle, viewProjMatrix, u_MvpMatrix);
    
        // 读取(x y)处的像素颜色. pixels[3] 存储了表面编号
        gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    
        //var num = pixels[3].toString();
        //console.log("pixels[3] is "+num/255);
        for (var i=0; i<pixels.length; i++){
            console.log(pixels[i]);
        }
        //a分量返回出去(pixels[3]此时存储了表面的编号)
        return pixels[3];
    }
    
    var g_MvpMatrix = new Matrix4(); // Model view projection matrix
    function draw(gl, n, currentAngle, viewProjMatrix, u_MvpMatrix) {
        // Caliculate The model view projection matrix and pass it to u_MvpMatrix
        g_MvpMatrix.set(viewProjMatrix);
        g_MvpMatrix.rotate(currentAngle, 1.0, 0.0, 0.0); // Rotate appropriately
        g_MvpMatrix.rotate(currentAngle, 0.0, 1.0, 0.0);
        g_MvpMatrix.rotate(currentAngle, 0.0, 0.0, 1.0);
        gl.uniformMatrix4fv(u_MvpMatrix, false, g_MvpMatrix.elements);
    
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);     // Clear buffers
        gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);   // Draw
    }
    
    var last = Date.now();  // Last time that this function was called
    function animate(angle) {
        var now = Date.now(); // Calculate the elapsed time
        var elapsed = now - last;
        last = now;
        // Update the current rotation angle (adjusted by the elapsed time)
        var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0;
        return newAngle % 360;
    }
    
    function initArrayBuffer(gl, data, type, num, attribute) {
        // Create a buffer object
        var buffer = gl.createBuffer();
        if (!buffer) {
            console.log('Failed to create the buffer object');
            return false;
        }
        // Write date into the buffer object
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
        // Assign the buffer object to the attribute variable
        var a_attribute = gl.getAttribLocation(gl.program, attribute);
        if (a_attribute < 0) {
            console.log('Failed to get the storage location of ' + attribute);
            return false;
        }
        gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
        // Enable the assignment to a_attribute variable
        gl.enableVertexAttribArray(a_attribute);
    
        return true;
    }
    
  • 相关阅读:
    linux 中实现两列数据的互换
    linux中 sort h的作用
    max 内置函数,管理uv 编辑器下面的窗口的显示情况
    时时设定 uv 面板的位置,还有就是 关于属性打开界面的大小
    判断贴图大小很好 同时可以判断文件大小
    两条线中画终点
    锁定控制器,一般在绑定的时候很多用到
    用 脚本编辑器读脚本 也是编辑脚本
    进行随机旋转用于和并东西并
    排列顶点 uv 不过有很大问题
  • 原文地址:https://www.cnblogs.com/52tech/p/9325111.html
Copyright © 2011-2022 走看看