用webgl绘制一个彩色旋转立方体
2026-04-16 22:38:42
189
分类:WebGL
转载自:https://blog.csdn.net/qq_37338983/article/details/74502649
今天给大家分享一个用webgl写的简单的三维场景:转动的交互式彩色立方体,其六个面的颜色都不一样。
上次绘制二维彩色矩形时讲到,二维是三维场景的特殊情况,所以由二维向三维拓展也并不难,webgl里面提供了画三角形的方法,立方体有6个面,一个面由两个三角形组成,共计需要12个三角形,每个三角形又有3个顶点,故绘制立方体需要36个点,而实际上立方体只有8个顶点,这8个顶点有序组合成6个矩形面,如下图所示:
在程序里面有一个quad(a,b,c,d),表示一个矩形面,例如quad(v0,v1,v2,v3),表示第一个矩形面,其实为两个三角形构成,分别为(v1,v0,v3), (v1, v3,v2),按照这样的顶点索引顺序来画三角形,并最终构成整个立方体。
最终程序运行如下图:在最底下的三个按钮是用于控制立方体绕坐标轴旋转的交互式按钮。
下面是本例的代码:(如果大家需本例完整文件,可联系我,完全开源,用于交流学习)
cube.js:
/**
* Created by wjh on 2017/6/27.
*/
"use strict";
var canvas;
var gl;
var points = []; //顶点容器var colors = [];//颜色容器var control;var u_control=[0,0,0];var xAxis = 0;var yAxis = 1;var zAxis = 2;var axis = 0;
umVertices = 36; //立方体需要12个三角形,共36个顶点function init(){
canvas = document.getElementById("cube");
gl = WebGLUtils.setupWebGL(canvas);
if (!gl) {
alert("您的浏览器不支持WebGL!");
}
gl.viewport(0, 0, canvas.width, canvas.height); //设置视口大小
gl.clearColor(0.0, 0.0, 0.0, 1.0); //设置背景颜色
colorCube(); //彩色立方体
gl.enable(gl.DEPTH_TEST); //消除隐藏面
//初始化着色器
var program = initShaders(gl, "v-shader", "f-shader");
gl.useProgram(program); //创建缓冲区,并向缓冲区写入立方体每个面的颜色信息
var cBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW); //获取着色器中a_Color变量,并向其传递数据
var a_Color = gl.getAttribLocation(program, "a_Color");
gl.vertexAttribPointer(a_Color, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Color); //创建缓冲区,并向缓冲区写入立方体的顶点左边信息
var vBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW); //获取着色器中a_Position变量,并向其传递数据
var a_Position = gl.getAttribLocation(program, "a_Position");
gl.vertexAttribPointer(a_Position, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position); //设置正射投影,即盒状空间,获取着色器变量u_Matrix,并传递数据
var u_Matrix = gl.getUniformLocation(program, "u_Matrix");
if (!u_Matrix) {
alert("获取u_Matrix位置失败!")
}
var iMatrix = new Matrix4();
iMatrix.setOrtho(3, -3, -3, 3, 5, -5);
gl.uniformMatrix4fv(u_Matrix, false, iMatrix.elements);
control = gl.getUniformLocation(program, "u_control"); //添加窗口监听事件,在窗口底下的三个按钮,用于控制立方体绕坐标轴转动
document.getElementById("xButton").onclick = function() {
axis = xAxis;
};
document.getElementById("yButton").onclick = function() {
axis = yAxis;
};
document.getElementById("zButton").onclick = function() {
axis = zAxis;
};
render(); //执行绘图函数}//彩色立方体的顶点索引function colorCube(){
quad(1, 0, 3, 2); //第一个面
quad(2, 3, 7, 6); //第二个面
quad(3, 0, 4, 7); //第三个面
quad(6, 5, 1, 2); //第四个面
quad(4, 5, 6, 7); //第五个面
quad(5, 4, 0, 1); //第六个面}function quad(a,b,c,d){
//立方体的八个顶点(x,y,z,a)
var vertices = [
vec4(-1.0, -1.0, 1.0, 1.0),
vec4(-1.0, 1.0, 1.0, 1.0),
vec4(1.0, 1.0, 1.0, 1.0),
vec4(1.0, -1.0, 1.0, 1.0),
vec4(-1.0, -1.0, -1.0, 1.0),
vec4(-1.0, 1.0, -1.0, 1.0),
vec4(1.0, 1.0, -1.0, 1.0),
vec4(1.0, -1.0, -1.0, 1.0)
]; //立方体面的颜色信息(r,g,b,a)
var cubeColors = [
[0.0, 0.0, 0.0, 1.0], // 黑
[1.0, 0.0, 0.0, 1.0], // 红
[1.0, 1.0, 0.0, 1.0], // 黄
[0.0, 1.0, 0.0, 1.0], // 绿
[0.0, 0.0, 1.0, 1.0], // 蓝
[1.0, 0.0, 1.0, 1.0], // 品红
[0.0, 1.0, 1.0, 1.0], // 青色
[1.0, 1.0, 1.0, 1.0] //白色
];
var indices = [a, b, c, a, c, d]; //顶点索引顺序
//存取顶点余顶点索引信息算法
for (var i = 0; i < indices.length; ++i) {
points.push(vertices[indices[i]]); //quad(1,0,3,2)按照indice的索引,另points.push(vertices[1],vertices[0],
// vertices[3],vertices[1],vertices[3],vertices[2]);
//再执行quad()......,直到六个quad()全执行完
colors.push(cubeColors[a]);
}
} //绘制立方体function render(){
//清除缓存和深度清除
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); //控制立方体旋转
u_control[axis] += 2.0; //获取顶点着色器中u_control的位置
gl.uniform3fv(control, u_control); //画立方体
gl.drawArrays(gl.TRIANGLES, 0, NumVertices); //循环函数,用于无限执行和渲染动画,让立方体一直转动
requestAnimationFrame(render);
}
window.onload = init; //窗口加载init函数,使立方体最终显示在屏幕上cube.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>cube</title>
<!--顶点着色器-->
<script id="v-shader" type="x-shader/x-vertex">
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_Matrix;
uniform vec3 u_control;
varying vec4 v_Color;
void main() {
vec3 angles = radians(u_control);
vec3 c = cos(angles);
vec3 s = sin(angles); <!--旋转矩阵-->
mat4 rx = mat4(1.0, 0.0, 0.0, 0.0, 0.0, c.x, s.x, 0.0, 0.0, -s.x, c.x, 0.0, 0.0, 0.0, 0.0, 1.0);
mat4 ry = mat4(c.y, 0.0, -s.y, 0.0, 0.0, 1.0, 0.0, 0.0, s.y, 0.0, c.y, 0.0, 0.0, 0.0, 0.0, 1.0);
mat4 rz = mat4(c.z, s.z, 0.0, 0.0, -s.z, c.z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
gl_Position = u_Matrix * rz * ry * rx * a_Position;
gl_Position.z = -gl_Position.z;
v_Color = a_Color;
}
</script>
<!--片元着色器-->
<script id="f-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
</script>
<!--调用js文件-->
<script type="text/javascript" src="../../libs/webgl-utils.js"></script>
<script type="text/javascript" src="../../libs/MV.js"></script>
<script type="text/javascript" src="../../libs/initShaders.js"></script>
<script type="text/javascript" src="../../libs/cuon-matrix.js"></script>
<script type="text/javascript" src="cube.js"></script>
</head>
<body>
<canvas id="cube" width="618" height="618"></canvas>
<br/>
<!--在界面添加操作按钮-->
<button id="xButton">Rotate X</button>
<button id="yButton">Rotate Y</button>
<button id="zButton">Rotate Z</button>
</body>
</html>好了,今天就给大家分享到这里,请大家多多支持和交流。