// 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学习【十三】鼠标点击立方体改变颜色的原理与实现
最新推荐文章于 2021-09-19 16:25:30 发布