第 8 次大作业进展报告
4/18/25About 3 min
问题
请编写带有图形界面的普通三阶魔方模拟程序.
要求:
- 实现平移、放大、缩小和自适应大小的魔方展示功能.
- 请自定义编码表示魔方的各种可能操作, 每种编码表示其中 1 种操作.
- 实现打开文本文件的功能, 该文本文件由一系列编码组成, 对应魔方操作.
- 实现魔方操作功能: 可以交互实现每个操作, 也可以通过动画自动播放魔方的系列操作.
- 在操作或转动魔方时, 必须以动画的形式展示, 从而方便看清如何操作或转动.
- 可以保存魔方操作, 保存结果是由一系列编码组成文本文件.
- 编写文档详细介绍模拟算法与图形界面等内容.
参考:
- 雍俊海. 清华教授的小课堂魔方真好玩. 北京: 清华大学出版社.
当前操作实现机制
1. 输入事件处理
- 通过 ImGui 的键盘事件监听实现操作触发
- 使用 F/R/U/B/L/D 六个按键分别对应前、右、上、后、左、下面操作
- 按键触发后立即执行
rotate()进行坐标变换
if (ImGui::IsKeyPressed(ImGuiKey_F)) {
animator.action = 'f';
animator.rotate();
} // 其他按键类似2. 旋转轴确定
- 根据操作字符返回对应的三维旋转轴
glm::vec3 Animator::rotation_axis() {
switch (action) {
case 'f': return {0, 0, 1}; // 前后面绕Z轴
case 'r': return {1, 0, 0}; // 右左面绕X轴
case 'u': return {0, 1, 0}; // 上下面绕Y轴
// ...其他情况类似
}
}3. 选择操作对象
- 根据操作面选择对应的魔方块组:
vector<Group*> select_groups(char action) {
switch (action) {
case 'f': // 前表面所有块
for (x, y) 生成组名 "xy2"
case 'r': // 右表面所有块
for (y, z) 生成组名 "2yz"
// 其他面类似
}
}4. 执行变换
- 直接应用旋转变换矩阵:
auto transform = glm::rotate(glm::half_pi<float>(), axis); // 90度旋转
transform = transform * mesh->getTransform(); // 累加变换
mesh->setTransform(transform);当前动画问题分析
问题描述
错误现象:旋转操作后再次操作时, 选择的方块组与实际可见位置不匹配
Bug 根本原因
静态分组策略:
- 初始化时通过
create_groups()按初始坐标创建固定分组
// 初始分组策略(setup.cc) glm::ivec3 grid = glm::floor((center - scene_bound_min) / cube_length);- 分组信息在旋转后不会更新
- 初始化时通过
变换矩阵叠加:
- 每次旋转直接修改网格的变换矩阵
transform = transform * mesh->getTransform(); // 变换矩阵累加- 但分组仍基于初始坐标, 未考虑累积变换后的实际位置
具体错误示例
- 执行 F(前面顺时针旋转)后:
- 实际前面块已经旋转到新位置
- 但分组仍标记为原始 z=2 的块
- 再次执行 U(上面旋转)时:
- 选择 y=2 的原始上层块
- 但经过前次旋转后, 实际上层块可能已不在原始坐标位置
TODO
引入动画系统:
class RotationAnimation { float progress = 0.0f; // 0~1 进度 glm::vec3 axis; vector<SurfaceMesh*> targets; void update(float dt) { progress += dt/speed; apply_partial_rotation(); } };使用四元数插值:
glm::quat start_rot = current_rotation; glm::quat end_rot = glm::angleAxis(glm::half_pi(), axis); glm::quat interp = glm::slerp(start_rot, end_rot, progress);
下一步计划
- 实现动态分组计算
- 添加动画插值系统
- 完善文档中的坐标变换说明
当前实现已基本完成操作响应机制, 但需要解决空间状态同步问题才能实现正确的连续操作. 动画系统的缺失也导致操作缺乏可视化连续性, 这是后续需要重点改进的方向.