Skip to main content

he3d_core/
scene.rs

1use crate::{
2   Arena, DirectionalLight, Material, Mesh, MeshId, ObjectId, Texture, TextureId, Transform,
3};
4
5/// A renderable instance: a mesh, optional texture, transform, and material.
6/// 一个可渲染实例:一个网格、可选纹理、变换和材质。
7#[derive(Clone, Debug)]
8pub struct RenderObject {
9   /// The mesh to draw.
10   /// 要绘制的网格。
11   pub mesh: MeshId,
12   /// Optional texture applied on top of the material tint.
13   /// 叠加在材质色调上的可选纹理。
14   pub texture: Option<TextureId>,
15   /// Placement in world space.
16   /// 世界空间中的放置。
17   pub transform: Transform,
18   /// Surface shading parameters.
19   /// 表面着色参数。
20   pub material: Material,
21   /// Whether the object participates in rendering.
22   /// 对象是否参与渲染。
23   pub visible: bool,
24}
25
26/// Owns meshes, textures, render objects, and the scene light.
27/// 拥有网格、纹理、渲染对象和场景光。
28///
29/// Resources live in [`Arena`]s; the scene exposes the arenas directly so callers can insert assets and get stable handles back.
30/// 资源存放在 [`Arena`] 中;场景直接暴露这些 arena,以便调用方可以插入资源并获得稳定的句柄。
31pub struct Scene {
32   /// Mesh storage.
33   /// 网格存储。
34   pub meshes: Arena<Mesh>,
35   /// Texture storage.
36   /// 纹理存储。
37   pub textures: Arena<Texture>,
38   /// Render-object storage.
39   /// 渲染对象存储。
40   pub objects: Arena<RenderObject>,
41   /// The single directional light of the scene.
42   /// 场景中唯一的方向光。
43   pub light: DirectionalLight,
44}
45
46impl Scene {
47   /// Create an empty scene.
48   /// 创建一个空场景。
49   ///
50   /// # Examples
51   /// 示例
52   /// ```
53   /// use he3d_core::{Material, Mesh, RenderObject, Rgb, Scene, Transform};
54   ///
55   /// let mut scene = Scene::new();
56   /// let mesh = scene.meshes.insert(Mesh::triangle(1.0, 1.0)?);
57   /// let object = scene.spawn(RenderObject {
58   ///    mesh,
59   ///    texture: None,
60   ///    transform: Transform::default(),
61   ///    material: Material::new(Rgb::WHITE),
62   ///    visible: true,
63   /// });
64   /// assert!(scene.objects.contains(object));
65   /// # Ok::<(), he3d_core::Error>(())
66   /// ```
67   #[must_use]
68   pub fn new() -> Self {
69      Self {
70         meshes: Arena::new(),
71         textures: Arena::new(),
72         objects: Arena::new(),
73         light: DirectionalLight::default(),
74      }
75   }
76
77   /// Insert a render object and return its handle.
78   /// 插入一个渲染对象并返回其句柄。
79   pub fn spawn(&mut self, object: RenderObject) -> ObjectId {
80      self.objects.insert(object)
81   }
82}
83
84impl Default for Scene {
85   fn default() -> Self {
86      Self::new()
87   }
88}
89
90#[cfg(test)]
91mod tests {
92   use super::*;
93   use crate::{Material, Rgb, Transform};
94
95   #[test]
96   fn spawn_returns_reachable_object() {
97      let mut scene = Scene::new();
98      let mesh = scene.meshes.insert(Mesh::triangle(1.0, 1.0).unwrap());
99      let object = scene.spawn(RenderObject {
100         mesh,
101         texture: None,
102         transform: Transform::default(),
103         material: Material::new(Rgb::new(1.0, 0.5, 0.25)),
104         visible: true,
105      });
106      let fetched = scene.objects.get(object).unwrap();
107      assert_eq!(fetched.mesh, mesh);
108      assert!(fetched.visible);
109      assert_eq!(fetched.material.tint, Rgb::new(1.0, 0.5, 0.25));
110   }
111
112   #[test]
113   fn removed_object_does_not_leak_into_scene() {
114      let mut scene = Scene::new();
115      let mesh = scene.meshes.insert(Mesh::plane(1.0, 1.0).unwrap());
116      let object = scene.spawn(RenderObject {
117         mesh,
118         texture: None,
119         transform: Transform::default(),
120         material: Material::default(),
121         visible: true,
122      });
123      assert_eq!(scene.objects.len(), 1);
124      let _ = scene.objects.remove(object);
125      assert!(scene.objects.is_empty());
126   }
127}