第 11 次大作业进展报告
5/9/25About 7 min
问题
请编写带有图形界面的普通三阶魔方模拟程序.
要求:
- 实现平移、放大、缩小和自适应大小的魔方展示功能.
- 请自定义编码表示魔方的各种可能操作, 每种编码表示其中 1 种操作.
- 实现打开文本文件的功能, 该文本文件由一系列编码组成, 对应魔方操作.
- 实现魔方操作功能: 可以交互实现每个操作, 也可以通过动画自动播放魔方的系列操作.
- 在操作或转动魔方时, 必须以动画的形式展示, 从而方便看清如何操作或转动.
- 可以保存魔方操作, 保存结果是由一系列编码组成文本文件.
- 编写文档详细介绍模拟算法与图形界面等内容.
参考:
- 雍俊海. 清华教授的小课堂魔方真好玩. 北京: 清华大学出版社.
1. 项目概述
本项目旨在开发一个带有图形界面的普通三阶魔方模拟程序. 程序需要能够展示魔方, 并允许用户通过交互或预设指令序列对魔方进行操作. 所有操作都应以动画形式展现, 以提供清晰的可视化反馈. 此外, 程序还需支持操作序列的加载和保存功能.
2. 当前已实现功能
根据提供的代码库, 目前项目已取得以下进展:
- 魔方模型的加载与基础显示 (基本完成)
- 模型加载: 通过
tinyobjloader库在src/assets.cc(load_cube函数) 中加载了assets/cube.obj魔方模型及其材质文件 (assets/cube.mtl). - 图形界面与可视化: 使用
Polyscope库进行图形显示.src/main.cc初始化Polyscope, 并调用src/setup.cc中的函数进行场景设置. - 魔方单元 (Cubie)的表示:
src/cubie.h和src/cubie.cc定义了Cubie类, 每个Cubie代表魔方的一个小块, 并记录其初始位置 (_location_initial) 和当前逻辑位置 (_location).Cubie类通过Polyscope的Group和SurfaceMesh进行管理和变换.group_name函数 (src/utils.cc) 用于生成每个Cubie在Polyscope中的唯一名称.
- 魔方整体 (Cube)的表示:
src/cube.h和src/cube.cc定义了Cube类, 它管理着所有Cubie对象 (27 个).Cube类负责处理魔方整体的动画状态 (_animating,_animation_start,_duration) 和当前执行的动作 (_action).
- 模型加载: 通过
- 魔方操作的自定义编码 (已实现)
src/action.h和src/action.cc定义了Action类.- 该类通过枚举
Side(FRONT, BACK, UP, DOWN, LEFT, RIGHT) 和布尔值_clockwise来编码魔方的基本操作. 例如,Action (Action::FRONT, true)表示顺时针转动前面. Action类还包含了计算旋转轴 (rotate_axis ())、旋转角度 (rotate_angle ()) 以及根据动作更新Cubie逻辑位置 (Action::rotate (const glm::ivec3 location)) 和物理变换矩阵 (Action::rotate (const glm::mat4x4 transform, const float progress)) 的方法.
- 交互式魔方操作与动画展示 (已实现)
- 交互输入:
src/main.cc中的callback函数使用ImGui监听键盘输入 (F, B, U, D, L, R 键, 配合 Shift 键判断顺/逆时针). - 触发操作: 按下相应按键后, 会创建一个
Action对象, 并调用Cube::start(action)方法来启动一个魔方操作. - 动画实现:
Cube::start()方法会标记哪些Cubie参与当前动画 (animating_cubies()), 并记录动画开始时间.Cube::update()方法在Polyscope的每帧回调中被调用, 计算动画进度 (progress).Cubie::update(action, progress)方法根据进度更新参与动画的Cubie的Polyscope网格变换 (mesh->setTransform()), 从而实现平滑的旋转动画.- 动画结束时,
Cube::end()方法会调用Cubie::end(action)来更新受影响Cubie的逻辑位置 (_location).
- 动画时长: 动画的持续时间由
Cube::_duration控制.
- 交互输入:
- 基础视图控制 (部分依赖 Polyscope)
Polyscope本身提供了平移、缩放 (通过鼠标滚轮)、旋转 (通过鼠标拖拽)等视图控制功能.src/setup.cc中的setup_ground()函数根据魔方模型的包围盒 (bounding box)自适应地设置了地面高度, 间接实现了部分自适应大小的展示效果.
3. 核心技术栈
- C++20: 主要编程语言.
- Polyscope: 用于 3D 可视化和 GUI 框架.
- glm: 用于处理向量和矩阵等图形学数学运算.
- Eigen: 用于更复杂的线性代数运算 (在
setup.cc中加载顶点和颜色时使用). - tinyobjloader: 用于加载
.obj格式的 3D 模型. - spdlog: 用于日志记录.
- fmt: 用于字符串格式化.
- ImGui: (通过 Polyscope) 用于处理键盘输入以触发魔方操作.
- xmake: 作为项目构建系统.
4. 代码结构简介
src/main.cc: 程序入口, 初始化Polyscope, 加载资源, 设置回调函数, 处理用户输入.src/action.h/.cc: 定义魔方操作的编码方式及其相关的旋转逻辑.src/cubie.h/.cc: 定义魔方小块 (Cubie) 的行为和状态, 包括其在Polyscope中的表示和变换.src/cube.h/.cc: 定义魔方整体, 管理所有Cubie, 并控制动画的生命周期和状态更新.src/assets.h/.cc: 负责加载外部资源, 如.obj模型.src/setup.h/.cc: 负责将加载的资源注册到Polyscope中, 创建Cubie的分组, 并进行场景的初始设置.src/utils.h/.cc: 包含一些辅助函数, 如生成Cubie的唯一名称.
5. 尚待实现的功能 (根据大作业要求)
- 完整的自适应大小功能: 虽然
Polyscope提供了视图控制, 但可能需要更明确的"自适应大小到窗口"或"重置视图到最佳观察点"的功能. - 打开文本文件加载操作序列: 目前没有实现读取包含操作编码的文本文件的功能.
- 自动播放魔方系列操作: 基于上一条, 需要实现解析文件中的操作编码, 并按顺序自动播放动画.
- 保存魔方操作序列: 目前没有实现将用户进行的操作 (
Action序列)保存到文本文件的功能. - 详细文档: 需要撰写包含模拟算法、图形界面设计、自定义编码说明等内容的详细文档.
6. 后续工作计划
- 文件操作模块:
- 设计操作编码在文本文件中的表示格式 (例如, 每行一个操作, 如
F代表前面顺时针,U'代表上面逆时针). - 实现文件读取功能, 解析操作序列.
- 实现文件写入功能, 保存当前操作历史或特定序列.
- 设计操作编码在文本文件中的表示格式 (例如, 每行一个操作, 如
- 自动播放控制模块:
- 在
Cube类或一个新的管理类中添加队列来存储从文件加载或手动输入的操作序列. - 修改
Cube::update()或主回调逻辑, 使其在当前动画结束后, 能自动从队列中取出下一个操作并执行Cube::start(). - 可能需要在
ImGui界面添加播放、暂停、停止等控制按钮.
- 在
- UI 增强:
- 考虑在
ImGui界面中添加按钮来触发旋转, 作为键盘操作的补充. - 添加文件打开和保存的对话框或按钮.
- 添加用于控制自动播放的 UI 元素.
- 考虑在
- 文档撰写:
- 开始撰写项目文档, 详细描述算法设计 (特别是动画插值、状态更新逻辑)、
Action编码方案、Polyscope的使用、ImGui交互设计等. - 记录开发过程中遇到的问题和解决方案.
- 开始撰写项目文档, 详细描述算法设计 (特别是动画插值、状态更新逻辑)、
7. 总结
项目已成功搭建了三阶魔方模拟的基础框架, 包括模型加载、基于 Polyscope 的可视化、自定义操作编码以及交互式的单步操作动画. 核心的旋转逻辑和动画更新机制已经实现. 接下来的主要工作将集中在文件 I/O、操作序列的自动播放以及完善用户界面和项目文档. 目前进展顺利, 预计能够按时完成大作业要求.