Dandelion 2.0.0
A light-weight 3D builder for educational usage
载入中...
搜索中...
未找到
scene.h
浏览该文件的文档.
1#ifndef DANDELION_SCENE_SCENE_H
2#define DANDELION_SCENE_SCENE_H
3
4#include <memory>
5#include <string>
6#include <vector>
7#include <list>
8#include <chrono>
9#include <string_view>
10
11#include <spdlog/spdlog.h>
12
13#include "group.h"
14#include "camera.h"
15#include "light.h"
16#include "selection_helper.h"
17#include "../geometry/mesh.hpp"
19
20/*!
21 * \file scene/scene.h
22 * \ingroup rendering
23 * \ingroup simulation
24 * \~chinese
25 * \brief 包含场景的类。
26 */
27
28/*! \~chinese 约束 `F` 必须是对单个物体进行的读写操作。 */
29template<typename F>
30concept ObjectOp = std::invocable<F, Object&> && std::is_void_v<std::invoke_result_t<F, Object&>>;
31
32/*! \~chinese 约束 `F` 必须是对单个物体进行的只读操作。 */
33template<typename F>
34concept ObjectReadOp =
35 std::invocable<F, const Object&> && std::is_void_v<std::invoke_result_t<F, const Object&>>;
36
37/*!
38 * \ingroup rendering
39 * \ingroup simulation
40 * \~chinese
41 * \brief 表示一个包含相机、光源、物体等对象的完整场景。
42 *
43 * `Scene` 是一个对象语义的类,它既包含完成图形设计和渲染所需的全部数据,
44 * 也具有渲染自身预览效果的功能。当前的设计是:控制器 (Controller) 在 OpenGL
45 * 上下文被创建后即创建场景实例,该实例在程序的整个生命周期中都是唯一的。因此,
46 * 复制或移动 `Scene` 实例都是错误的行为,因为这有可能导致场景数据不一致。
47 * 未来加入修改历史记录时,此设计思路有可能被改变。
48 *
49 * 场景可以是空的,如果它非空,则可以包含若干个物体组 (Group);
50 * 每个组也可以为空或包含若干物体 (Object),物体是场景中的最小单元,不能再分了。
51 * 各种数据遵循“尽可能存储到更小单元中”的原则,因此 `Scene` 类中只存储相机、
52 * 光源这些与任何物体都无关的数据,而材质、mesh 等数据则存储到物体中。
53 * 所有物体都由 `Scene` 对象创建并持有,当 `Scene` 对象析构时,所有的组、
54 * 物体都会自行析构。
55 */
56class Scene
57{
58public:
59
60 Scene();
61 ///@{
62 /*! \~chinese 禁止复制场景。 */
63 Scene(Scene& other) = delete;
64 Scene(const Scene& other) = delete;
65 ///@}
66 /*! \~chinese 禁止移动场景。 */
67 Scene(Scene&& other) = delete;
68 ~Scene() = default;
69 /*!
70 * \~chinese
71 * \brief 从指定路径导入模型文件到这个场景中。
72 *
73 * 这个函数只会根据文件名创建一个物体组,然后调用物体组的 `load_models` 方法加载文件。
74 *
75 * \param file_path 要导入的模型文件路径
76 * \returns 加载是否成功
77 */
78 bool import_model(const std::string& file_path);
79 /*!
80 * \~chinese
81 * \brief 保存所有场景数据到指定的目录中。
82 *
83 * 保存场景时涉及两类数据:
84 * - 模型数据(包括几何数据和材质数据),会被保存为通用模型文件格式
85 * - 元数据,Dandelion 特有的组、物体信息等,会被保存为 metadata.json 文件
86 *
87 * \param directory 场景文件夹路径
88 * \returns 是否保存成功
89 */
90 bool save(const std::string_view directory);
91 /*!
92 * \~chinese
93 * \brief 从指定目录中加载保存的场景数据。
94 *
95 * 与 `save` 方法相对应,`load` 会从保存的数据中恢复模型、物体、组、相机、
96 * 光源等全部信息。
97 * \param directory 要加载的场景文件夹路径
98 * \returns 是否加载成功
99 */
100 bool load(const std::string_view directory);
101 /*!
102 * \~chinese
103 * \brief 清除场景中所有元素
104 */
105 void clear();
106 /*! \~chinese 备份物体当前状态并开始模拟,此后每一帧都会调用所有物体的 `update` 方法。 */
107 void start_simulation();
108 /*! \~chinese 停止模拟,此后不再调用物体的 `update` 方法。 */
109 void stop_simulation();
110 /*! \~chinese 恢复物体在动画开始前的状态。 */
111 void reset_simulation();
112 /*! \~chinese 查询当前是否正在进行物理模拟。 */
114 /*!
115 * \~chinese
116 * \brief 计算场景中所有物体下一帧要渲染的运动状态。
117 *
118 * 这个函数按照固定的时间步长模拟物体运动。
119 *
120 * 每一帧的渲染过程可以概括为更新数据(几何、运动等等)和渲染图像两步。
121 * 约定当前屏幕上显示的是上一帧的图像,正在计算的是当前帧的数据。
122 * 更新运动状态时首先用当前时间减去 `last_update` 得到上一帧和之前帧剩余时长之和;
123 * 再循环模拟物体运动。每循环一次走过一个长度为 `time_step` 的时间步、
124 * 剩余时长减去 `time_step` ;当剩余时长不足一个 `time_step` 时停止模拟,
125 * 并将这一帧模拟走过的总时长累加到 `last_update` 上。
126 */
127 void simulation_update();
128
129 /*!
130 * \~chinese
131 * 对每个物体执行同样的操作,允许读写物体数据。
132 * \param op 要执行的操作,其函数签名必须满足 `ObjectOp` 的要求。
133 */
134 template<ObjectOp F>
135 void for_each_object(F&& op)
136 {
137 for (std::unique_ptr<Group>& group: this->groups)
138 for (std::unique_ptr<Object>& object: group->objects) op(*object);
139 }
140
141 /*!
142 * \~chinese
143 * 对每个物体执行同样的操作,只能读取物体数据。
144 * \param op 要执行的操作,其函数签名必须满足 `ObjectReadOp` 的要求。
145 */
146 template<ObjectReadOp F>
147 void for_each_object(F&& op) const
148 {
149 for (const std::unique_ptr<Group>& group: this->groups)
150 for (const std::unique_ptr<Object>& object: group->objects) op(*object);
151 }
152
153 /*! \~chinese 场景中所有的物体组。 */
154 std::vector<std::unique_ptr<Group>> groups;
155 /*!
156 * \~chinese
157 * \brief 当前被选中的物体。
158 *
159 * 在布局模式和物理模拟模式下,它决定当前被高亮的物体;在建模模式下,仅有这个物体被绘制。
160 */
162 /*!
163 * \~chinese
164 * \brief 当前被选中的元素。
165 *
166 * 根据当前所处的模式,物体、各类几何基本元素、光源都可能被选中,详见 `SelectableType`
167 * 的类型说明。当 `selected_element` 持有 `std::monostate` 类型时,
168 * 当前的选择状态为空(没有任何元素被选中)。
169 */
171 /*! \~chinese 用于预览场景的观察相机(主相机)。 */
173 /*! \~chinese 用于 **离线渲染** 的相机,和用于预览场景的观察相机(主相机)无关。 */
175 /*! \~chinese 用于 **离线渲染** 的光源,和预览时照亮物体的光源无关。 */
176 std::list<Light> lights;
177 /*! \~chinese 用于建模模式的半边网格。 */
178 std::unique_ptr<HalfedgeMesh> halfedge_mesh;
179 /*! \~chinese 用于在物理模拟模式下显示速度向量。 */
181 /*! \~chinese 用于显示地面网格。 */
183 /*! \~chinese 用于显示 x 轴。 */
185 /*! \~chinese 用于显示 y 轴。 */
187 /*! \~chinese 用于显示 z 轴。 */
189 /*! \~chinese 用于显示离线渲染相机。 */
191 /*! \~chinese 被选中元素类型为顶点、边、面片或光源时使用的绘制对象。 */
193 /*! \~chinese 被选中元素类型为半边时使用的绘制对象。 */
195 /*! \~chinese 显示拾取射线用的绘制对象,对应 `DebugOptions::show_picking_ray` 。 */
197 /*! \~chinese 显示光源。这个 Mesh 中只包含一个光源示意图的几何数据,渲染时需要多次绘制。 */
199
200private:
201
202 /*!
203 * \~chinese
204 * 主相机的初始位置。
205 */
206 static Eigen::Vector3f initial_camera_pos;
207 /*!
208 * \~chinese
209 * 主相机的初始观察目标点(看向的位置)。
210 */
211 static Eigen::Vector3f initial_camera_target;
212 /*!
213 * \~chinese
214 * 保存场景元数据的文件名。
215 */
216 static constexpr std::string_view metadata_filename = "metadata.json";
217 /*! \~chinese 状态变量,表示当前是否正在进行物理模拟。 */
219 /*! \~chinese 上一次将模拟状态同步到渲染的时间点。 */
220 std::chrono::time_point<std::chrono::steady_clock> last_update;
221 /*! \~chinese 碰撞检测时记录所有物体,其他情况下无效。 */
222 std::vector<Object*> all_objects;
223 /*! \~chinese 日志记录器。 */
224 std::shared_ptr<spdlog::logger> logger;
225};
226
227#endif // DANDELION_SCENE_SCENE_H
包含相机的类,用来表示场景中的相机。
表示物体的类。
定义 object.h:39
LineSet z_axis
定义 scene.h:188
LineSet picking_ray
定义 scene.h:196
SelectableType selected_element
当前被选中的元素。
定义 scene.h:170
ArrowSet arrows
定义 scene.h:180
LineSet y_axis
定义 scene.h:186
bool during_animation
定义 scene.h:218
ArrowSet highlighted_halfedge
定义 scene.h:194
void reset_simulation()
定义 scene.cpp:276
Mesh highlighted_element
定义 scene.h:192
bool check_during_simulation()
定义 scene.cpp:287
Scene(Scene &other)=delete
std::vector< std::unique_ptr< Group > > groups
定义 scene.h:154
bool load(const std::string_view directory)
从指定目录中加载保存的场景数据。
定义 scene.cpp:190
std::shared_ptr< spdlog::logger > logger
定义 scene.h:224
void stop_simulation()
定义 scene.cpp:271
static Eigen::Vector3f initial_camera_target
定义 scene.h:211
bool import_model(const std::string &file_path)
从指定路径导入模型文件到这个场景中。
定义 scene.cpp:112
void clear()
清除场景中所有元素
定义 scene.cpp:245
std::list< Light > lights
定义 scene.h:176
void for_each_object(F &&op) const
定义 scene.h:147
static Eigen::Vector3f initial_camera_pos
定义 scene.h:206
LineSet ground_grid
定义 scene.h:182
void start_simulation()
定义 scene.cpp:256
Mesh light_indicator
定义 scene.h:198
std::unique_ptr< HalfedgeMesh > halfedge_mesh
定义 scene.h:178
Scene(const Scene &other)=delete
void for_each_object(F &&op)
定义 scene.h:135
Camera main_camera
定义 scene.h:172
LineSet x_axis
定义 scene.h:184
bool save(const std::string_view directory)
保存所有场景数据到指定的目录中。
定义 scene.cpp:128
static constexpr std::string_view metadata_filename
定义 scene.h:216
std::chrono::time_point< std::chrono::steady_clock > last_update
定义 scene.h:220
std::vector< Object * > all_objects
定义 scene.h:222
LineSet camera_wireframe
定义 scene.h:190
Object * selected_object
当前被选中的物体。
定义 scene.h:161
Scene(Scene &&other)=delete
void simulation_update()
计算场景中所有物体下一帧要渲染的运动状态。
定义 scene.cpp:292
Camera camera
定义 scene.h:174
定义 scene.h:30
定义 scene.h:34
包含物体组的类。
std::variant< std::monostate, Object *, const Halfedge *, Vertex *, Edge *, Face *, Light * > SelectableType
场景中可被选择的元素类型。
定义 selection_helper.h:36
半边网格所需各种类型的公共头文件。
包含光源的类,目前只有一个点光源。
用于渲染箭头的特殊线条集。
定义 mesh.hpp:125
表示观察点的相机,既可以用于预览视角,也可以用于渲染视角。
定义 camera.h:24
用于同步线条渲染数据的内存对象。
定义 mesh.hpp:72
用于同步渲染数据的三角形 Mesh 。
定义 mesh.hpp:28