关键点:

<!--实现原理:要保证这两个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. poj 1734 floyd求最小环,可得到环上的每个点

    #include<stdio.h> #include<string.h> #define inf  100000000 #define N 110 #define min(a, ...

  2. 如何让 Windows 上的命令行工具更好用

    侯爵老师视频详解:如何让 Windows 上的命令行工具更好用 很多 Windows 用户在打开这个小黑窗时,都会情不自禁的感慨,「实在是太丑了--」 实际上如果你用的是 Windows 8 或 Wi ...

  3. tomcat日志采集

    1. 采集tomcat确实比之前的需求复杂很多,我在搭建了一个tomcat的环境,然后产生如下报错先贴出来: Jan 05, 2017 10:53:35 AM org.apache.catalina. ...

  4. [jQuery]$.get跨域提交不发送原因

    使用 $.ajax({ url: "http://pastebin.com/embed_js.php?i=sy9gt3FR", dataType: "jsonp" ...

  5. 多个线程运行结束之后主线程再执行CountDownLatch

    多个线程运行结束之后主线程再执行CountDownLatch 学习了:http://blog.csdn.net/lvyuanj/article/details/50737123  这个要膜拜一下! h ...

  6. openstack中Nova组件Networks的全部python API 汇总

    感谢朋友支持本博客.欢迎共同探讨交流.因为能力和时间有限.错误之处在所难免,欢迎指正! 假设转载,请保留作者信息. 博客地址:http://blog.csdn.net/qq_21398167 原博文地 ...

  7. Scala入门到精通——第一节 Scala语言初步

    本节主要内容 Scala简单介绍 为什么要学习Scala Scala语言初步 1. Scala简单介绍 Scala(Scala Language的简称)语言是一种能够执行于JVM和.Net平台之上的通 ...

  8. C++开发人脸性别识别教程(19)——界面美化

    在这篇博文中将完毕<C++开发人脸性别识别>的收尾工作.主要内容分为两部分:加入视频暂定功能.界面规范化. 一 视频暂停功能 严格来说这个视频暂定功能算是视频人脸性别识别的一个遗留问题,本 ...

  9. URAL 1826. Minefield(数学 递归)

    题目链接:http://acm.timus.ru/problem.aspx? space=1&num=1826 1826. Minefield Time limit: 0.5 second M ...

  10. js自定义回调函数

      JavaScript允许开发人员像传递任何类型的数据一样传递函数,也就是说,函数也是一种数据类型,通过typeof就知道. 例子1: var CallbackFun = function(){ t ...