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的方式主要是两种,一种是直接看高质量的源码,另一种是光看不行还要自己动手,自己写一些有代表性的小程序,这也 ...
随机推荐
- linux下apache2更换目录
修改apache2的默认文档目录(默认是在/var/www) 修改命令:sudo gedit /etc/apache2/sites-enabled/000-default 在文档中找到 Documen ...
- POJ 1265
主要利用PICK定理与边点数上的GCD的关系求解. 三角形一条边上的所有整数点(包括顶点)可以首先将这条边移到(0, 0)->(x, y).这时,(x/gcd(x, y), y/gcd(x, y ...
- IP地址的规划和设计方法(三)
九,内部网络专用IP地址规划与网络地址转换NAT方法 (1)内部网络的专用IP地址选择的根据 RFC1918在讨论内部网络的专用IP地址规划方法时任务.使用专用地址规划一个内部网络地址系统时.首选的方 ...
- html里显示中文乱码的解决的方法
在HTML开头统一规范下编码格式: <meta http-equiv="Content-Type" content="text/html; charset=utf- ...
- 浅析hybrid模式下地支付宝钱包和微信
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2VuY2hhbzEyNg==/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...
- DNS负载均衡 Nginx 负载均衡的种类
DNS负载均衡 当一个网站有足够多的用户的时候,假如每次请求的资源都位于同一台机器上面,那么这台机器随时可能会蹦掉.处理办法就是用DNS负载均衡技术,它的原理是在DNS服务器中为同一个主机名配置多个I ...
- Java面试-Struts2
1 Struts2工作原理 一个请求在Struts2框架中的处理大概分为下面几个步骤: 1.client初始化一个指向Servlet容器(比如Tomcat)的请求: 2.这个请求经过一系列的过滤器( ...
- Windows 10家庭版也能共享打印机(中)解除Guest账户网络登录限制,实现局域网共享
由于Windows系统默认是禁止Guest账户从网络登录的.我们须要解除这个限制.首先想到的是用组策略编辑器gpedit.msc. 可是Windows 10家庭版没有组策略编辑器,我们先尝试用U盘把W ...
- oc08--局部变量,全局变量,函数方法的区别
// // main.m // 局部变量和全局变量以及成员变量的区别 #import <Foundation/Foundation.h> @interface Person : NSObj ...
- Java:笔记-1
ylbtech-Java:笔记-1 1.返回顶部 1. /** * 简介请求 * @return */ @RequestMapping("/JJ") public String j ...