使用滑块控制正方形旋转的WebGL技术问询
实现滑块控制WebGL立方体旋转角度的解决方案
我帮你补全并调整了代码,完美实现用HTML滑块来控制立方体的旋转角度,同时修复了原代码里不完整的部分。下面是完整的实现步骤和代码:
第一步:HTML结构
首先我们需要在页面里添加WebGL画布和三个滑块,分别对应X、Y、Z轴的旋转控制,还加上了角度值实时显示:
<canvas id="gl-canvas" width="400" height="400"></canvas> <div style="margin-top: 10px;"> <label>X轴旋转角度: <span id="xValue">0</span>°</label> <input type="range" id="xSlider" min="0" max="360" value="0"> <br> <label>Y轴旋转角度: <span id="yValue">0</span>°</label> <input type="range" id="ySlider" min="0" max="360" value="0"> <br> <label>Z轴旋转角度: <span id="zValue">0</span>°</label> <input type="range" id="zSlider" min="0" max="360" value="0"> </div>
第二步:完整JavaScript代码
下面是补全后的完整代码,包含了立方体顶点生成、滑块事件监听和WebGL渲染逻辑:
"use strict"; var canvas; var gl; var NumVertices = 36; var points = []; var colors = []; var theta = [0, 0, 0]; // 存储三个轴的旋转弧度 var thetaLoc; // 顶点着色器代码 var vertexShaderSource = ` attribute vec4 vPosition; attribute vec4 vColor; uniform mat4 rotateMatrix; varying vec4 fColor; void main() { gl_Position = rotateMatrix * vPosition; fColor = vColor; } `; // 片元着色器代码 var fragmentShaderSource = ` precision mediump float; varying vec4 fColor; void main() { gl_FragColor = fColor; } `; window.onload = function init() { canvas = document.getElementById("gl-canvas"); gl = WebGLUtils.setupWebGL(canvas); if (!gl) { alert("WebGL isn't available"); return; } // 生成立方体顶点和颜色数据 colorCube(); // 初始化着色器程序 var vertexShader = loadShader(gl.VERTEX_SHADER, vertexShaderSource); var fragmentShader = loadShader(gl.FRAGMENT_SHADER, fragmentShaderSource); var program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); gl.useProgram(program); // 处理顶点颜色数据 var cBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer); gl.bufferData(gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW); var vColor = gl.getAttribLocation(program, "vColor"); gl.vertexAttribPointer(vColor, 4, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(vColor); // 处理顶点位置数据 var vBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer); gl.bufferData(gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW); var vPosition = gl.getAttribLocation(program, "vPosition"); gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(vPosition); // 获取旋转矩阵的uniform变量位置 thetaLoc = gl.getUniformLocation(program, "rotateMatrix"); // 设置画布视口和背景色 gl.viewport(0, 0, canvas.width, canvas.height); gl.clearColor(0.3921, 0.5843, 0.9294, 1.0); gl.enable(gl.DEPTH_TEST); // 绑定滑块事件监听 setupSliders(); // 启动渲染循环 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) { var vertices = [ vec4(-0.5, -0.5, 0.5, 1.0), vec4(-0.5, 0.5, 0.5, 1.0), vec4(0.5, 0.5, 0.5, 1.0), vec4(0.5, -0.5, 0.5, 1.0), vec4(-0.5, -0.5, -0.5, 1.0), vec4(-0.5, 0.5, -0.5, 1.0), vec4(0.5, 0.5, -0.5, 1.0), vec4(0.5, -0.5, -0.5, 1.0) ]; var vertexColors = [ [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]]); colors.push(vertexColors[a]); } } // 设置滑块的事件监听 function setupSliders() { const xSlider = document.getElementById('xSlider'); const ySlider = document.getElementById('ySlider'); const zSlider = document.getElementById('zSlider'); const xValue = document.getElementById('xValue'); const yValue = document.getElementById('yValue'); const zValue = document.getElementById('zValue'); // X轴滑块事件 xSlider.addEventListener('input', function() { theta[0] = this.value * Math.PI / 180; xValue.textContent = this.value; }); // Y轴滑块事件 ySlider.addEventListener('input', function() { theta[1] = this.value * Math.PI / 180; yValue.textContent = this.value; }); // Z轴滑块事件 zSlider.addEventListener('input', function() { theta[2] = this.value * Math.PI / 180; zValue.textContent = this.value; }); } // 渲染循环 function render() { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // 计算旋转矩阵:X*Y*Z轴旋转的组合 var rotateX = rotate(theta[0], [1, 0, 0]); var rotateY = rotate(theta[1], [0, 1, 0]); var rotateZ = rotate(theta[2], [0, 0, 1]); var rotateMatrix = mult(mult(rotateX, rotateY), rotateZ); // 将旋转矩阵传入着色器 gl.uniformMatrix4fv(thetaLoc, false, flatten(rotateMatrix)); // 绘制立方体 gl.drawArrays(gl.TRIANGLES, 0, NumVertices); // 请求下一次渲染 requestAnimationFrame(render); } // 辅助函数:加载着色器 function loadShader(type, source) { const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } return shader; } // 注意:这里假设你已经引入了WebGLUtils.js和MV.js(包含vec4、flatten、rotate、mult等工具函数)
关键逻辑说明
- 立方体顶点生成:
colorCube和quad函数负责生成立方体6个面的顶点坐标和对应颜色,每个面用两个三角形拼接,刚好对应你原代码里的NumVertices=36。 - 滑块事件处理:每个滑块绑定
input事件,拖动时将角度值转成WebGL需要的弧度,更新theta数组,同时实时显示当前角度值。 - 旋转矩阵计算:在渲染循环中,根据三个轴的旋转弧度计算组合旋转矩阵,传入顶点着色器,实现立方体的实时旋转。
- 渲染循环:用
requestAnimationFrame实现持续渲染,确保滑块拖动时立方体旋转实时更新。
内容的提问来源于stack exchange,提问作者user9516512
相关产品推荐
相关产品推荐

