关键点:

<!--实现原理:要保证这两个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> <!--二维的HUD的canvas(主要用于绘制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;\n' +
'attribute vec4 a_Color;\n' +
'uniform mat4 u_MvpMatrix;\n' +
'uniform bool u_Clicked;\n' + // Mouse is pressed
'varying vec4 v_Color;\n' +
'void main() {\n' +
' gl_Position = u_MvpMatrix * a_Position;\n' +
' if (u_Clicked) {\n' + // Draw in red if mouse is pressed
' v_Color = vec4(1.0, 0.0, 0.0, 1.0);\n' +
' } else {\n' +
' v_Color = a_Color;\n' +
' }\n' +
'}\n'; // Fragment shader program
var FSHADER_SOURCE =
'#ifdef GL_ES\n' +
'precision mediump float;\n' +
'#endif\n' +
'varying vec4 v_Color;\n' +
'void main() {\n' +
' gl_FragColor = v_Color;\n' +
'}\n'; 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;
}

WEBGL学习【十四】利用HUD技术在网页上方显示三维物体的更多相关文章

  1. 强化学习(十四) Actor-Critic

    在强化学习(十三) 策略梯度(Policy Gradient)中,我们讲到了基于策略(Policy Based)的强化学习方法的基本思路,并讨论了蒙特卡罗策略梯度reinforce算法.但是由于该算法 ...

  2. webgl学习笔记四-动画

    写在前面 建议先阅读下前面我的三篇文章. webgl学习笔记一-绘图单点 webgl学习笔记二-绘图多点 webgl学习笔记三-平移旋转缩放   下面我们将讲解下如何让一个正方形动起来~不断擦除和重绘 ...

  3. Scala学习十四——模式匹配和样例类

    一.本章要点 match表达式是更好的switch,不会有意外调入下一个分支 如果没有模式能够匹配,会抛出MatchError,可以用case _模式避免 模式可以包含一个随意定义的条件,称做守卫 你 ...

  4. Dynamic CRM 2013学习笔记(四十四)CRM技术支持

    有时我们经常遇到一些CRM的问题,一时又无法解决,这时我们可能要找下外援,下面列出一些基本的技术支持.   1. CRM 论坛 https://community.dynamics.com/crm/f ...

  5. [WebGL入门]十四,绘制多边形

    注意:文章翻译http://wgld.org/.原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:].另外,鄙人webgl研究还不够深入.一些专业词语,假设翻译有误,欢迎大家 ...

  6. android学习十四(android的接收短信)

    收发短信是每一个手机主要的操作,android手机当然也能够接收短信了. android系统提供了一系列的API,使得我们能够在自己的应用程序里接收和发送短信. 事实上接收短信主要是利用我们前面学过的 ...

  7. 【转】机器学习教程 十四-利用tensorflow做手写数字识别

    模式识别领域应用机器学习的场景非常多,手写识别就是其中一种,最简单的数字识别是一个多类分类问题,我们借这个多类分类问题来介绍一下google最新开源的tensorflow框架,后面深度学习的内容都会基 ...

  8. spring boot 学习(十四)SpringBoot+Redis+SpringSession缓存之实战

    SpringBoot + Redis +SpringSession 缓存之实战 前言 前几天,从师兄那儿了解到EhCache是进程内的缓存框架,虽然它已经提供了集群环境下的缓存同步策略,这种同步仍然需 ...

  9. WEBGL学习【四】模型视图矩阵

    <html lang="zh-CN"> <!--服务器运行地址:http://127.0.0.1:8080/webgl/LearnNeHeWebGL/NeHeWe ...

随机推荐

  1. 洛谷 P2010 回文日期

    Noip2016普及组T2 题目描述 在日常生活中,通过年.月.日这三个要素可以表示出一个唯一确定的日期. 牛牛习惯用8位数字表示一个日期,其中,前4位代表年份,接下来2位代表月 份,最后2位代表日期 ...

  2. bootstrap-table 表头和内容对不齐

    问题: bootstrap-table.js 找到 BootstrapTable.prototype.resetView if (this.options.showHeader && ...

  3. MySQL出现no mycat database selected的问题分析

    1.先抛开mycat来处理 2.在查询表时,要指定是哪个数据库,然后再查询. ①.如果再MySQL Workbench中,先使用use tablename;,然后在执行操作语句:或者在语句上指定要查询 ...

  4. Linux排序命令sort(转)

    Linux sort命令用于将文本文件内容加以排序.sort可针对文本文件的内容,以行为单位来排序. 语法 sort [-bcdfimMnr][-o<输出文件>][-t<分隔字符&g ...

  5. Tomcat报错合集

    1.java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start c ...

  6. pod install fatal: unable to access 'https://chromium.googlesource.com/webm/libwebp/'

    1. 前往文件夹 /用户/aki/.cocoapods/repos/master/1/9/2/libwebp 2.编辑libwebp.podspec.json 将source git 改为 https ...

  7. php传值调用和传值调用和变量函数

    php传值调用和传值调用和变量函数 代码 <?php //传值调用,$m的值不改变 function text($i){ $i = 'Clive'; echo $i; } text(123); ...

  8. php创建简单的列表页

    php创建简单的列表页 样例 代码 <?php $userInfo[] = array( 'id'=>'1', 'username'=>'fry', 'sex'=>'nan', ...

  9. LeetCode Weekly Contest 19

    1.504. Base 7 水题,直接写.但是我错了一次,忘了处理0的情况. 没有考虑边界条件.写完代码,一般需要自己想几个边界测试用例进行测试. class Solution { public: s ...

  10. MySql数据库中乱码问题解决方案

    show variables like 'character%';    //查看当前各系统位置的字符编码格式 问题一: Incorrect string value: '\xB4\xF3\xB4\x ...