three/
template.rs

1//! Utilites for creating reusable templates for scene objects.
2//!
3//! It is often the case that you will want to have multiple instances of the same model or
4//! hierarchy of objects in your scene. While you could manually construct each instance yourself,
5//! three-rs provides a templating system to allow you to describe your model's hierarchy ahead
6//! of time, and then quickly create instances that three can efficiently batch render.
7//! [`Template`] describes the objects for a single model, and can be instantiated with
8//! [`Factory::instantiate_template`].
9//!
10//! The easiest way to create a template is to load one from a glTF file using
11//! [`Factory::load_gltf`].
12//!
13//! # Object Relations
14//!
15//! Often, one object needs to reference another object in the template, e.g. a bone needs
16//! to specify which skeleton it belongs to, and any object can specify that it belongs to
17//! a group in the template. When doing so, objects reference each other by their index in
18//! their respective arrays in [`Template`]. When such indices are used, the documentation
19//! will specify which array the index refers to.
20//!
21//! # Object Templates
22//!
23//! The [`objects`] field of [`Template`] provides a flattened, type-erased list of all objects
24//! defined in the template. Each type of object provides its type-specific data in that type's
25//! array, and then specifies the index of an [`ObjectTemplate`] in [`objects`]. Every object
26//! in the template must be represented in [`objects`] exactly once.
27//!
28//! The full, flattened list of objects is primarily used by [`AnimationTemplate`] to allow
29//! tracks in the animation to reference the object targeted by the track regardless of the
30//! target object's concrete type.
31//!
32//! # Animations
33//!
34//! Templates can also describe animations that apply to the objects in a template.
35//! When instantiated, the resulting animation clips will be unique to that instance of of the
36//! template. This allows for instances of the template to be animated independently of each
37//! other, without requiring you to manually setup animations for each instance.
38//!
39//! An animation in a template can target any of the objects described in the template. It does
40//! this by specifying the index of the objects in [`objects`]. See
41//! [`AnimationTemplate::tracks`] for more information.
42//!
43//! # Mesh Instancing
44//!
45//! When setting up a mesh in a template, you must first upload your [`Geometry`] to the GPU
46//! using [`Factory::upload_geometry`]. This will give you an [`InstancedGeometry`] object
47//! that acts as a shared handle to the GPU resources for that geometry. By uploading the
48//! data to the GPU ahead of time, we can ensure that all mesh nodes that reference that
49//! geometry, and all [`Mesh`] instances created from the template, will share a single copy
50//! of the data on the GPU. This reduces GPU resource usage and, for any meshes that also share
51//! a material, allows three to render many objects at once.
52//!
53//! [`Factory::instantiate_template`]: ../struct.Factory.html#method.instantiate_template
54//! [`Factory::load_gltf`]: ../struct.Factory.html#method.load_gltf
55//! [`Factory::upload_geometry`]: ../struct.Factory.html#method.upload_geometry
56//! [`Object`]: ../trait.Object.html
57//! [`Group`]: ../struct.Group.html
58//! [`Geometry`]: ../struct.Geometry.html
59//! [`Mesh`]: ../struct.Mesh.html
60//! [`Template`]: ./struct.Template.html
61//! [`ObjectTemplate`]: ./struct.ObjectTemplate.html
62//! [`AnimationTemplate`]: ./struct.AnimationTemplate.html
63//! [`AnimationTemplate::tracks`]: ./struct.AnimationTemplate.html#structfield.tracks
64//! [`nodes`]: ./struct.Template.html#structfield.nodes
65//! [`cameras`]: ./struct.Template.html#structfield.cameras
66//! [`meshes`]: ./struct.Template.html#structfield.meshes
67//! [`roots`]: ./struct.Template.html#structfield.roots
68//! [`objects`]: ./struct.Template.html#structfield.objects
69//! [`InstancedGeometry`]: ./struct.InstancedGeometry.html
70
71use animation::Track;
72use camera::Projection;
73use color::Color;
74use material::Material;
75use node::Transform;
76use render::GpuData;
77use skeleton::InverseBindMatrix;
78
79/// A template representing a hierarchy of objects.
80///
81/// To create an instance of the template that can be added to your scene, use
82/// [`Factory::instantiate_template`]. For more information about the templating system and how
83/// to use it, see the [module documentation].
84///
85/// [`Factory::instantiate_template`]: ../struct.Factory.html#method.instantiate_template
86/// [module documentation]: ./index.html
87#[derive(Debug, Clone, Default)]
88pub struct Template {
89    /// An optional name for the template.
90    pub name: Option<String>,
91
92    /// The base object data for all objects defined in the template.
93    ///
94    /// The index into this array is used to uniquely identify each object in the template. Each
95    /// object, regardless of its concrete type, will be represented in this array exactly once.
96    /// These indices are primarily used in [`AnimationTemplate`] to define the target of each
97    /// track of the animation.
98    ///
99    /// [`AnimationTemplate`]: ./struct.AnimationTemplate.html
100    pub objects: Vec<ObjectTemplate>,
101
102    /// Definitions for all [`Group`] objects in the template, given as indices into [`objects`].
103    ///
104    /// Groups carry no data beyond the common object data, so groups are defined soley by their
105    /// [`ObjectTemplate`].
106    ///
107    /// [`objects`]: #structfield.objects
108    /// [`Group`]: ../struct.Group.html
109    /// [`ObjectTemplate`]: ./struct.ObjectTemplate.html
110    pub groups: Vec<usize>,
111
112    /// Projection data used by cameras defined in the template.
113    pub cameras: Vec<CameraTemplate>,
114
115    /// The meshes defined in this template.
116    pub meshes: Vec<MeshTemplate>,
117
118    /// Data for the lights described by this template.
119    pub lights: Vec<LightTemplate>,
120
121    /// Data for the bones described by this template.
122    pub bones: Vec<BoneTemplate>,
123
124    /// Definitions for all [`Skeleton`] objects in the template, given as indices into
125    /// [`objects`].
126    ///
127    /// Skeletons carry no data beyond the common object data, so groups are defined soley by
128    /// their [`ObjectTemplate`].
129    ///
130    /// [`objects`]: #structfield.objects
131    /// [`Skeleton`]: ../skeleton/struct.Skeleton.html
132    /// [`ObjectTemplate`]: ./struct.ObjectTemplate.html
133    pub skeletons: Vec<usize>,
134
135    /// Templates for animation clips that target objects instantiated from this template.
136    pub animations: Vec<AnimationTemplate>,
137}
138
139impl Template {
140    /// Creates an empty template.
141    ///
142    /// # Examples
143    ///
144    /// Create an empty template and then instantiate it, effectively the most verbose way to
145    /// call [`Factory::group`]:
146    ///
147    /// ```no_run
148    /// use three::template::Template;
149    ///
150    /// # let mut window = three::Window::new("Three-rs");
151    /// let template = Template::new();
152    /// let (group, animations) = window.factory.instantiate_template(&template);
153    /// ```
154    ///
155    /// [`Factory::group`]: ../struct.Factory.html#method.group
156    pub fn new() -> Template { Default::default() }
157}
158
159/// Common data used by all object types.
160///
161/// All objects (i.e. three-rs types that implement the [`Object`] trait) have common data
162/// that the user can set at runtime. `ObjectTemplate` encapsultes these fields, and the
163/// various template types have a way to reference an `ObjectTemplate` to specify the object
164/// data for that template.
165///
166/// See the [module documentation] for more information on how object data is defined in
167/// templates.
168///
169/// [`Object`]: ../trait.Object.html
170/// [module documentation]: ./index.html#object-templates
171#[derive(Debug, Clone, Default)]
172pub struct ObjectTemplate {
173    /// An optional name for the object.
174    pub name: Option<String>,
175
176    /// The parent [`Group`] of the object, given as an index into the [`groups`] array of the
177    /// parent [`Template`].
178    ///
179    /// If `parent` is `None`, then the object is added to the root [`Group`] returned from
180    /// [`Factory::instantiate_template`].
181    ///
182    /// [`Group`]: ../struct.Group.html
183    /// [`Template`]: ./struct.Template.html
184    pub parent: Option<usize>,
185
186    /// The local transform for the object.
187    pub transform: Transform,
188}
189
190impl ObjectTemplate {
191    /// Creates a new `ObjectTemplate` with default values.
192    ///
193    /// The new object template will have no name, no parent (i.e. it will be treated as a root
194    /// object of the template), and a default transform.
195    ///
196    /// # Examples
197    ///
198    /// ```
199    /// use three::template::{ObjectTemplate, Template};
200    ///
201    /// let mut template = Template::new();
202    ///
203    /// let mut object = ObjectTemplate::new();
204    /// object.name = Some("My Node".into());
205    /// object.transform.position = [1.0, 2.0, 3.0].into();
206    ///
207    /// template.objects.push(object);
208    /// ```
209    pub fn new() -> ObjectTemplate {
210        Default::default()
211    }
212}
213
214/// Information for instantiating a [`Mesh`].
215///
216/// See the [module documentation] for more information on mesh instancing and how mesh
217/// data is setup for templates.
218///
219/// [`Mesh`]: ../struct.Mesh.html
220/// [module documentation]: ./index.html#mesh-instancing
221#[derive(Debug, Clone)]
222pub struct MeshTemplate {
223    /// The object data for the mesh, given as an index in the [`objects`] array of the parent
224    /// [`Template`].
225    ///
226    /// [`Template`]: ./struct.Template.html
227    /// [`objects`]: ./struct.Template.html#structfield.objects
228    pub object: usize,
229
230    /// The geometry used in the mesh.
231    pub geometry: InstancedGeometry,
232
233    /// The index of the material for the mesh in the [`meshes`] array of the parent [`Template`].
234    ///
235    /// [`Template`]: ./struct.Template.html
236    /// [`meshes`]: ./struct.Template.html#structfield.meshes
237    pub material: Material,
238
239    /// The skeleton used to render the mesh, if it's a skinned mesh.
240    pub skeleton: Option<usize>,
241}
242
243/// A template for a [`Camera`] object.
244///
245/// [`Camera`]: ../struct.Camera.html
246#[derive(Debug, Clone)]
247pub struct CameraTemplate {
248    /// The object data for the camera, given as an index in the [`objects`] array of the parent
249    /// [`Template`].
250    ///
251    /// [`Template`]: ./struct.Template.html
252    /// [`objects`]: ./struct.Template.html#structfield.objects
253    pub object: usize,
254
255    /// The projection used by the camera.
256    pub projection: Projection,
257}
258
259/// A template for a [`Bone`] object.
260///
261/// For more information about creating a [`Bone`], see [`Factory::bone`].
262///
263/// [`Bone`]: ../skeleton/struct.Bone.html
264/// [`Factory::bone`]: ../struct.Factory.html#method.bone
265#[derive(Debug, Clone)]
266pub struct BoneTemplate {
267    /// The object data for the bone, given as an index in the [`objects`] array of the parent
268    /// [`Template`].
269    ///
270    /// [`Template`]: ./struct.Template.html
271    /// [`objects`]: ./struct.Template.html#structfield.objects
272    pub object: usize,
273
274    /// The index of the bone within its skeleton.
275    pub index: usize,
276
277    /// The inverse bind matrix used to bind vertices of the mesh to the bone.
278    pub inverse_bind_matrix: InverseBindMatrix,
279
280    /// The skeleton that this bone is a part of, given as an index into the [`skeletons`]
281    /// array of the parent [`Template`].
282    ///
283    /// [`Template`]: ./struct.Template.html
284    /// [`skeletons`]: ./struct.Template.html#structfield.skeletons
285    pub skeleton: usize,
286}
287
288/// The definition for an animation targeting objects in a [`Template`].
289///
290/// See the [module documentation] for more information on template animations and how they
291/// are used.
292///
293/// [`Template`]: ./struct.Template.html
294/// [module documentation]: ./index.html#animations
295#[derive(Debug, Clone)]
296pub struct AnimationTemplate {
297    /// An optional name for the animation.
298    pub name: Option<String>,
299
300    /// The tracks making up the animation.
301    ///
302    /// Each track is composed of a [`Track`], containing the data for the track, and the node
303    /// that the track targetes, specified as an index into the [`objects`] array of the
304    /// parent [`Template`].
305    ///
306    /// [`Track`]: ../animation/struct.Track.html
307    /// [`Template`]: ./struct.Template.html
308    /// [`objects`]: ./struct.Template.html#structfield.nodes
309    pub tracks: Vec<(Track, usize)>,
310}
311
312/// Common information for instantiating the various types of lights.
313///
314/// See the [module documentation] for information on how templates are setup and how objects
315/// are added to the template.
316///
317/// [module documentation]: ./index.html
318#[derive(Clone, Copy, Debug)]
319pub struct LightTemplate {
320    /// The object data for the light, given as an index into the [`objects`] array of the parent
321    /// [`Template`].
322    ///
323    /// [`Template`]: ./struct.Template.html
324    /// [`objects`]: ./struct.Template.html#structfield.objects
325    pub object: usize,
326
327    /// The base color of the light.
328    pub color: Color,
329
330    /// The intensity of the light.
331    pub intensity: f32,
332
333    /// The specific type of light represented by the template.
334    pub sub_light: SubLightTemplate,
335}
336
337impl LightTemplate {
338    /// Creates a new template for an ambient light, analogous to [`Factory::ambient_light`].
339    ///
340    /// # Examples
341    ///
342    /// ```
343    /// use three::template::{LightTemplate, ObjectTemplate, Template};
344    ///
345    /// let mut template = Template::new();
346    /// template.objects.push(ObjectTemplate::new());
347    /// let light = LightTemplate::ambient(
348    ///     template.objects.len() - 1,
349    ///     three::color::RED,
350    ///     0.5,
351    /// );
352    /// template.lights.push(light);
353    /// ```
354    ///
355    /// [`Factory::ambient_light`]: ../struct.Factory.html#method.ambient_light
356    pub fn ambient(object: usize, color: Color, intensity: f32) -> LightTemplate {
357        LightTemplate {
358            object,
359
360            color,
361            intensity,
362            sub_light: SubLightTemplate::Ambient,
363        }
364    }
365
366    /// Creates a new template for a directional light, analogous to [`Factory::directional_light`].
367    ///
368    /// # Examples
369    ///
370    /// ```
371    /// use three::template::{LightTemplate, ObjectTemplate, Template};
372    ///
373    /// let mut template = Template::new();
374    /// template.objects.push(ObjectTemplate::new());
375    /// let light = LightTemplate::directional(
376    ///     template.objects.len() - 1,
377    ///     three::color::RED,
378    ///     0.5,
379    /// );
380    /// template.lights.push(light);
381    /// ```
382    ///
383    /// [`Factory::directional_light`]: ../struct.Factory.html#method.directional_light
384    pub fn directional(object: usize, color: Color, intensity: f32) -> LightTemplate {
385        LightTemplate {
386            object,
387
388            color,
389            intensity,
390            sub_light: SubLightTemplate::Directional,
391        }
392    }
393
394    /// Creates a new template for a point light, analogous to [`Factory::point_light`].
395    ///
396    /// # Examples
397    ///
398    /// ```
399    /// use three::template::{LightTemplate, ObjectTemplate, Template};
400    ///
401    /// let mut template = Template::new();
402    /// template.objects.push(ObjectTemplate::new());
403    /// let light = LightTemplate::point(
404    ///     template.objects.len() - 1,
405    ///     three::color::RED,
406    ///     0.5,
407    /// );
408    /// template.lights.push(light);
409    /// ```
410    ///
411    /// [`Factory::point_light`]: ../struct.Factory.html#method.point_light
412    pub fn point(object: usize, color: Color, intensity: f32) -> LightTemplate {
413        LightTemplate {
414            object,
415
416            color,
417            intensity,
418            sub_light: SubLightTemplate::Point,
419        }
420    }
421
422    /// Creates a new template for a hemisphere light, analogous to [`Factory::hemisphere_light`].
423    ///
424    /// # Examples
425    ///
426    /// ```
427    /// use three::template::{LightTemplate, ObjectTemplate, Template};
428    ///
429    /// let mut template = Template::new();
430    /// template.objects.push(ObjectTemplate::new());
431    /// let light = LightTemplate::hemisphere(
432    ///     template.objects.len() - 1,
433    ///     three::color::RED,
434    ///     three::color::BLUE,
435    ///     0.5,
436    /// );
437    /// template.lights.push(light);
438    /// ```
439    ///
440    /// [`Factory::hemisphere_light`]: ../struct.Factory.html#method.hemisphere_light
441    pub fn hemisphere(
442        object: usize,
443        sky_color: Color,
444        ground_color: Color,
445        intensity: f32,
446    ) -> LightTemplate {
447        LightTemplate {
448            object,
449
450            color: sky_color,
451            intensity,
452            sub_light: SubLightTemplate::Hemisphere { ground: ground_color },
453        }
454    }
455}
456
457/// Template information about the different sub-types for light.
458///
459/// See [`LightTemplate`] for more more information on settings up light templates, and
460/// utilities for doing so.
461///
462/// [`LightTemplate`]: ./struct.LightTemplate.html
463#[derive(Clone, Copy, Debug)]
464pub enum SubLightTemplate {
465    /// Represents an ambient light, instantiated as an [`Ambient`].
466    ///
467    /// [`Ambient`]: ../light/struct.Ambient.html
468    Ambient,
469
470    /// Represents a directional light, instantiated as a [`Directional`].
471    ///
472    /// [`Directional`]: ../light/struct.Directional.html
473    Directional,
474
475    /// Represents a hemisphere light, instantiated as a [`Hemisphere`].
476    ///
477    /// [`Hemisphere`]: ../light/struct.Hemisphere.html
478    Hemisphere {
479        /// The ground color for the light.
480        ground: Color,
481    },
482
483    /// Represents a point light, instantiated as a [`Point`].
484    ///
485    /// [`Point`]: ../light/struct.Point.html
486    Point,
487}
488
489/// Geometry data that has been loaded to the GPU.
490///
491/// [`Mesh`] objects instantiated with this data will share GPU resources, allowing for more
492/// efficient instanced rendering. Use [`Factory::upload_geometry`] to upload [`Geometry`]
493/// to the GPU and get an `InstancedGeometry`. You can use an `InstancedGeometry` to create
494/// a [`MeshTemplate`] for use in a [`Template`], or you can use [`Factory::create_instanced_mesh`]
495/// to create a [`Mesh`] directly.
496///
497/// [`Factory::upload_geometry`]: ../struct.Factory.html#method.upload_geometry
498/// [`Factory::create_instanced_mesh`]: ../struct.Factory.html#method.create_instanced_mesh
499/// [`Mesh`]: ../struct.Mesh.html
500/// [`Geometry`]: ../struct.Geometry.html
501/// [`Template`]: ./struct.Template.html
502/// [`MeshTemplate`]: ./struct.MeshTemplate.html
503#[derive(Debug, Clone)]
504pub struct InstancedGeometry {
505    pub(crate) gpu_data: GpuData,
506}