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> <!--二维的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技术在网页上方显示三维物体的更多相关文章
- 强化学习(十四) Actor-Critic
在强化学习(十三) 策略梯度(Policy Gradient)中,我们讲到了基于策略(Policy Based)的强化学习方法的基本思路,并讨论了蒙特卡罗策略梯度reinforce算法.但是由于该算法 ...
- webgl学习笔记四-动画
写在前面 建议先阅读下前面我的三篇文章. webgl学习笔记一-绘图单点 webgl学习笔记二-绘图多点 webgl学习笔记三-平移旋转缩放 下面我们将讲解下如何让一个正方形动起来~不断擦除和重绘 ...
- Scala学习十四——模式匹配和样例类
一.本章要点 match表达式是更好的switch,不会有意外调入下一个分支 如果没有模式能够匹配,会抛出MatchError,可以用case _模式避免 模式可以包含一个随意定义的条件,称做守卫 你 ...
- Dynamic CRM 2013学习笔记(四十四)CRM技术支持
有时我们经常遇到一些CRM的问题,一时又无法解决,这时我们可能要找下外援,下面列出一些基本的技术支持. 1. CRM 论坛 https://community.dynamics.com/crm/f ...
- [WebGL入门]十四,绘制多边形
注意:文章翻译http://wgld.org/.原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:].另外,鄙人webgl研究还不够深入.一些专业词语,假设翻译有误,欢迎大家 ...
- android学习十四(android的接收短信)
收发短信是每一个手机主要的操作,android手机当然也能够接收短信了. android系统提供了一系列的API,使得我们能够在自己的应用程序里接收和发送短信. 事实上接收短信主要是利用我们前面学过的 ...
- 【转】机器学习教程 十四-利用tensorflow做手写数字识别
模式识别领域应用机器学习的场景非常多,手写识别就是其中一种,最简单的数字识别是一个多类分类问题,我们借这个多类分类问题来介绍一下google最新开源的tensorflow框架,后面深度学习的内容都会基 ...
- spring boot 学习(十四)SpringBoot+Redis+SpringSession缓存之实战
SpringBoot + Redis +SpringSession 缓存之实战 前言 前几天,从师兄那儿了解到EhCache是进程内的缓存框架,虽然它已经提供了集群环境下的缓存同步策略,这种同步仍然需 ...
- WEBGL学习【四】模型视图矩阵
<html lang="zh-CN"> <!--服务器运行地址:http://127.0.0.1:8080/webgl/LearnNeHeWebGL/NeHeWe ...
随机推荐
- js的map文件
什么是source map文件 source map文件是js文件压缩后,文件的变量名替换对应.变量所在位置等元信息数据文件,一般这种文件和min.js主文件放在同一个目录下. 比如压缩后原变量是ma ...
- axios 全攻略之基本介绍与使用(GET 与 POST)
axios axios 是一个基于 Promise 的 HTTP 客户端,专门为浏览器和 node.js 服务 Vue 2.0 官方推荐使用 axios 来代替原来的 Vue request,所以这里 ...
- bootstrap checkbox
在使用bootstrap库中的checkboxlistrow时,我想要依据checkbox是否至少选中了一个选项来确定页面的跳转,即须要在js中操作checkbox.这样就存在一个问题,一般的chec ...
- 当前插入的线段能完整覆盖存在的几条线段 树状数组 HDU 5372 Segment Game
http://acm.hdu.edu.cn/showproblem.php? pid=5372 Segment Game Time Limit: 3000/1500 MS (Java/Others) ...
- oralce sql 创建指定时间段内的日历信息
-- Create table create table TEMP_CALENDAR ( MONTH VARCHAR2(6), W_7 VARCHAR2(2), W_1 VARCH ...
- 【cl】基本数据类型
8种基本数据类型 整数的演示:任何数据在内存中都是2进制的数据 内存中没有10进制没有16进制 byte 范围: -128 ~127 short 范围:-32768 ~ 32768 int 范围:-2 ...
- 谈谈JavaScript深浅拷贝
浅拷贝 function shallowCopy(source){ var newObj = {}; for(var attr in source){ newObj[attr] = source[at ...
- python 下串口数据的读取,解析,和保存-
#!/usr/bin/python # -*-coding: utf-8 -*- import serial import threading import binascii from datetim ...
- 在ubuntu中安装Markdown神器Typora
title: 在ubuntu中安装Markdown神器Typora toc: false date: 2018-09-01 17:48:15 categories: methods tags: ubu ...
- LeetCode Weekly Contest 19
1.504. Base 7 水题,直接写.但是我错了一次,忘了处理0的情况. 没有考虑边界条件.写完代码,一般需要自己想几个边界测试用例进行测试. class Solution { public: s ...