zoukankan      html  css  js  c++  java
  • WEBGL学习【十四】利用HUD技术在网页上方显示三维物体

    关键点:

    <!--实现原理:要保证这两个canvas相互重叠;z-index表示了两个画布的上下层关系-->
    <!--WEBGL的三维图形Canvas(主要用于绘制三维场景)-->
    <canvas id="webgl" width="400" height="400" style="position: absolute; z-index: 0">
        Please use a browser that supports "canvas"
    </canvas>
    
    <!--二维的HUDcanvas(主要用于绘制HUD信息)-->
    <canvas id="hud" width="400" height="400" style="position: absolute; z-index: 1"></canvas>

    js核心代码:

    // HUD.js (c) 2012 matsuda
    // Vertex shader program
    var VSHADER_SOURCE =
        'attribute vec4 a_Position;
    ' +
        'attribute vec4 a_Color;
    ' +
        'uniform mat4 u_MvpMatrix;
    ' +
        'uniform bool u_Clicked;
    ' + // Mouse is pressed
        'varying vec4 v_Color;
    ' +
        'void main() {
    ' +
        '  gl_Position = u_MvpMatrix * a_Position;
    ' +
        '  if (u_Clicked) {
    ' + //  Draw in red if mouse is pressed
        '    v_Color = vec4(1.0, 0.0, 0.0, 1.0);
    ' +
        '  } else {
    ' +
        '    v_Color = a_Color;
    ' +
        '  }
    ' +
        '}
    ';
    
    // 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() {
        // Retrieve <canvas> element
        var canvas = document.getElementById('webgl');
        var hud = document.getElementById('hud');
    
        if (!canvas || !hud) {
            console.log('Failed to get HTML elements');
            return false;
        }
    
        // Get the rendering context for WebGL
        var gl = getWebGLContext(canvas);
        // Get the rendering context for 2DCG
        var ctx = hud.getContext('2d');
        if (!gl || !ctx) {
            console.log('Failed to get rendering context');
            return;
        }
    
        // Initialize shaders
        if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
            console.log('Failed to intialize shaders.');
            return;
        }
    
        // Set the vertex information
        var n = initVertexBuffers(gl);
        if (n < 0) {
            console.log('Failed to set the vertex information');
            return;
        }
    
        // Set the clear color and enable the depth test
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.enable(gl.DEPTH_TEST);
    
        // Get the storage locations of uniform variables
        var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
        var u_Clicked = gl.getUniformLocation(gl.program, 'u_Clicked');
        if (!u_MvpMatrix || !u_Clicked) {
            console.log('Failed to get the storage location of uniform variables');
            return;
        }
    
        // Calculate the view projection matrix
        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_Clicked, 0); // Pass false to u_Clicked
    
        var currentAngle = 0.0; // Current rotation angle
        // 鼠标在HUD画布中如果有动作将就响应
        hud.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) {
                // If pressed position is inside <canvas>, check if it is above object
                var x_in_canvas = x - rect.left, y_in_canvas = rect.bottom - y;
                var picked = check(gl, n, x_in_canvas, y_in_canvas, currentAngle, u_Clicked, viewProjMatrix, u_MvpMatrix);
                if (picked) alert('The cube was selected! '); }
        }
    
        var tick = function() {   // Start drawing
            currentAngle = animate(currentAngle);
            //重复绘制二维图形(不断更新角度值)
            draw2D(ctx, currentAngle); // Draw 2D
            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.2, 0.58, 0.82,   0.2, 0.58, 0.82,   0.2,  0.58, 0.82,  0.2,  0.58, 0.82, // 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.0,  0.32, 0.61,  0.0, 0.32, 0.61,   0.0, 0.32, 0.61,   0.0, 0.32, 0.61,  // v0-v5-v6-v1 up
            0.78, 0.69, 0.84,  0.78, 0.69, 0.84,  0.78, 0.69, 0.84,  0.78, 0.69, 0.84, // v1-v6-v7-v2 left
            0.32, 0.18, 0.56,  0.32, 0.18, 0.56,  0.32, 0.18, 0.56,  0.32, 0.18, 0.56, // 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
        ]);
    
        // Indices of the vertices
        var indices = new Uint8Array([
            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
        ]);
    
        // Write the vertex property to buffers (coordinates and normals)
        if (!initArrayBuffer(gl, vertices, 3, gl.FLOAT, 'a_Position')) return -1; // Coordinates
        if (!initArrayBuffer(gl, colors, 3, gl.FLOAT, 'a_Color')) return -1;      // Color Information
    
        // Create a buffer object
        var indexBuffer = gl.createBuffer();
        if (!indexBuffer) {
            return -1;
        }
        // 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 check(gl, n, x, y, currentAngle, u_Clicked, viewProjMatrix, u_MvpMatrix) {
        var picked = false;
        gl.uniform1i(u_Clicked, 1);  // Pass true to u_Clicked(Draw cube with red)
        draw(gl, n, currentAngle, viewProjMatrix, u_MvpMatrix);
        // Read pixel at the clicked position
        var pixels = new Uint8Array(4); // Array for storing the pixel value
        gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    
        if (pixels[0] == 255) // If red = 255, clicked on cube
            picked = true;
    
        gl.uniform1i(u_Clicked, 0);  // Pass false to u_Clicked(Draw cube with specified color)
        draw(gl, n, currentAngle, viewProjMatrix, u_MvpMatrix);
    
        return picked;
    }
    
    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 (color and depth)
        gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);   // Draw
    }
    
    
    //实现二维图形的绘制工作
    function draw2D(ctx, currentAngle) {
        //传入左上角坐标,宽度和高度,清空绘图区
        ctx.clearRect(0, 0, 400, 400); // Clear <hud>
        // Draw triangle with white lines
        ctx.beginPath();                      // Start drawing
        ctx.moveTo(120, 10); ctx.lineTo(200, 150); ctx.lineTo(40, 150);
        ctx.closePath();
        ctx.strokeStyle = 'rgba(255, 255, 255, 1)'; // Set white to color of lines
        ctx.stroke();                           // Draw Triangle with white lines
        // Draw white letters
        ctx.font = '18px "Times New Roman"';
        ctx.fillStyle = 'rgba(255, 255, 255, 1)'; // Set white to the color of letters
        ctx.fillText('HUD: Head Up Display', 40, 180);
        ctx.fillText('Triangle is drawn by Canvas 2D API.', 40, 200);
        ctx.fillText('Cube is drawn by WebGL API.', 40, 220);
        //Math.floor截掉了小数部分(这里也需要重绘)
        ctx.fillText('Current Angle: '+ Math.floor(currentAngle), 40, 240);
    }
    
    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, num, type, 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 of the buffer object to the attribute variable
        gl.enableVertexAttribArray(a_attribute);
        // Unbind the buffer object
        gl.bindBuffer(gl.ARRAY_BUFFER, null);
    
        return true;
    }
    

  • 相关阅读:
    Css的transform和transition
    移动端事件
    回流和重绘
    Swift更新至2.2版本 语言变化
    编程中遇到的 问题 总结
    NSNotificationCenter
    iOS中boolean、Boolean、BOOL、bool的区别
    推送的 代码实战写法
    MKNetworkKit的使用
    MKNetworkKit 的介绍
  • 原文地址:https://www.cnblogs.com/52tech/p/9325110.html
Copyright © 2011-2022 走看看