WEBGL学习【十三】鼠标点击立方体改变颜色的原理与实现
// PickFace.js (c) 2012 matsuda and kanda
// Vertex shader program
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec4 a_Color;\n' +
'attribute float a_Face;\n' + // 表面的编号(1-6),不能使用int类型(当前顶点属于哪一个表面)【float类型】
'uniform mat4 u_MvpMatrix;\n' +
'uniform int u_PickedFace;\n' + // 被选中的表面编号【int类型】
'varying vec4 v_Color;\n' +
'void main() {\n' +
' gl_Position = u_MvpMatrix * a_Position;\n' + //对顶点的位置进行模型视图投影变换
' int face = int(a_Face);\n' + // 转换为int类型(鼠标一点击就会把他编码成颜色值得a分量)
' vec3 color = (face == u_PickedFace) ? vec3(1.0) : a_Color.rgb;\n' + //vec3(1.0)所有的分量都为1,此时为白色;否则顶点颜色还是以前的颜色
' if(u_PickedFace == 0) {\n' + // 前三个分量RGB, 通过第四个分量来判断是点击的是哪一个顶面
' v_Color = vec4(color, a_Face/255.0);\n' + // 颜色的第4个分量使得图形的透明度不一样
' } else {\n' +
' v_Color = vec4(color, a_Color.a);\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() {
// 获取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;
}
WEBGL学习【十三】鼠标点击立方体改变颜色的原理与实现的更多相关文章
- radio和label关联问题,点击label改变颜色
$(function () { $("#fangan :radio[name='price']").bind('click', function (event) { //$(thi ...
- css:鼠标点击出现有颜色的边框?如何解决
今天遇到上图这样出现有颜色的边框 解决办法: css设置属性 outline:none;
- WebGL学习笔记(十三):拾取
目前为止,我们还没有涉及到交互相关的内容,实际上,我们是需要知道我们点击的地方下面的第一个物体的信息,这个过程称为拾取. 简单拾取实现 我们可以通过颜色来获取是否成功点击,具体方式如下: 场景中有一个 ...
- Android 关于expandableListView childrenView 点击改变颜色
1.点击后改变颜色并保持颜色改变状态: <?xml version="1.0" encoding="utf-8"?> <selector xm ...
- JavaScript001,鼠标点击改变文字或图片
<h3>我的第一个Javascript</h3> <p id="demo1">1.点击按钮,改变内容!</p> <!-- 设置 ...
- vue列表渲染,以及鼠标点击改变样式的问题
在实际项目中,我们进场会遇到鼠标点击该表某个DOM元素的样式,在原生的js或者jquery中,我们会比较熟练的实现这个需求,但是在vue中怎么实现呢? 直接操作DOM?NO!NO! 既然我们的项目使用 ...
- 基于css3新属性transform及原生js实现鼠标拖动3d立方体旋转
基于css3新属性transform,实现3d立方体的旋转 通过原生JS,点击事件,鼠标按下.鼠标抬起和鼠标移动事件,实现3d立方体的拖动旋转,并将旋转角度实时的反应至界面上显示 实现原理:通过获取鼠 ...
- WEBGL学习笔记(七):实践练手1-飞行类小游戏之游戏控制
接上一节,游戏控制首先要解决的就是碰撞检测了 这里用到了学习笔记(三)射线检测的内容了 以鸟为射线原点,向前.上.下分别发射3个射线,射线的长度较短大概为10~30. 根据上一节场景的建设,我把y轴设 ...
- 【Unity3D基础】让物体动起来①--UGUI鼠标点击移动
背景 首先还是先声明自己是比较笨的一个人,总是找不到高效的学习方法,目前自己学习Unity3D的方式主要是两种,一种是直接看高质量的源码,另一种是光看不行还要自己动手,自己写一些有代表性的小程序,这也 ...
随机推荐
- java.lang.AbstractMethodError: org.apache.xerces.dom.DocumentImpl.getXmlStandalone()Z解决办法
2019-05-20 23:02:20.168 |-INFO [http-nio-8001-exec-2] com.xxx.ecc.cloudbiz.service.payment.impl.Wei ...
- 神经网络入门游戏推荐BugBrain
今天看到一款神经网络入门游戏.BugBrain.在游戏中,你能够通过连接神经元.设置神经元阈值等建造虫子的大脑,让瓢虫.蠕虫.蚂蚁等完毕各种任务.下载下来玩了玩,难度真不是入门级的= =! 真心佩服作 ...
- TRIZ系列-创新原理-8-重量补偿原理
重量补偿原理的表述例如以下: 1)将某一物体与还有一种提供上升力的物体组合,以补偿其重量:2)通过与环境(利用空气动力,流体动力或其他力等)的相互作用.实现对物体的重量补偿: 重力使得我们能够稳稳的依 ...
- iOS开发-自己定义重用机制给ScrollerView加入子视图
事实上这个问题我非常早就想过,仅仅是没有通过去写程序实现,昨天有人提起,我就巧了一下 不知道大家打印郭tableview:cellforrow中cell初始的次数,也就是重用池中的cell个数.这个是 ...
- [深入理解Android卷一全文-第七章]深入理解Audio系统
由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该由于纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容. ...
- 第14章3节《MonkeyRunner源代码剖析》 HierarchyViewer实现原理-HierarchyViewer实例化
既然要使用HierarchyViewer来获取控件信息,那么首先我们看下在脚本中.我们是怎么获得HierarchyViewer的,看以下一段脚本代码: 1 device = MonkeyRunner. ...
- 项目产品化——Excel数据库模板化导入(java)
Excel导入可能是代码开发中比較常见的功能,一个项目假设有多个地方须要excel导入数据库.那么开发的工作量也将比較大,项目产品化过程中,将这么一个类似的功能进行封装合并也是必要的.封装好的代码仅仅 ...
- 11gR2 Database Services for "Policy" and "Administrator" Managed Databases (文档 ID 1481647.1)
In this Document Purpose _afrLoop=1459311711568804&id=1481647.1&displayIndex=6&_afrW ...
- luogu1955 [NOI2015] 程序自动分析
题目大意 假设x1,x2,x3...代表程序中出现的变量,给定n个形如xi=xj或xi≠xj的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足.i, ...
- camera table表编译
mmm -j8 vendor/mediatek/proprietary/hardware/mtkcam/v1/common/paramsmgr/ 2>&1 | tee ft.lib.lo ...