You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用滑块控制正方形旋转的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:00:49