mod3d_base/
lib.rs

1//a Documentation
2#![warn(missing_docs)]
3#![warn(rustdoc::missing_doc_code_examples)]
4
5/*!
6# Done
7
8Changed to SInt and UInt in ele type
9
10Added BufferDescriptor
11
12# TODO
13
14Decided not to replace ByteBuffer with T:AsRef<[u8]>; this would
15require clients to still cast Vec<> etc to a something-of-u8
16
17Need to make BufferDataAccessor refer to a BufferDescriptor
18
19Need to add BufferIndexAccessor
20
21Make Vertices have an option<indices> and update renderable vertices clients
22
23# 3D Model library
24
25This library provides structures and functions to support simple and
26complex 3D objects in a reasonably performant system. Its use cases
27include 3D modeling tools, games, and 3D user interfaces.
28
29The object model is derived from the Khronos glTF 3D
30model/scene description (<https://github.com/KhronosGroup/glTF>),
31without explicit support for animation or cameras.
32
33## Overview of the model
34
35The 3D model library is designed to provide for the description of 3D
36objects with simple or sophisticated specifications of their vertices;
37with materials that might be simple colors or complete PRBS
38specifications, and so on.
39
40Once models have been described they can be turned into GL-specific
41instantiable structures. It is quite common for graphics libraries to
42convert some external data form and to allocate internal memory for
43rendering - so that the object description buffers used initially are
44no longer required and their memory can be freed.
45
46When an 'instantiable' object exists it can be rendered many times in
47a single scene, with different transformations and skeleon poses.
48
49Hence this library provides for [Instantiable] object creation that
50first requires memory buffers to be allocated, descriptions of an
51object created; from this [Object] the [Instantiable] is made for a
52particular graphics library context - allowing the freeing of those
53first memory buffers. This [Instantiable] can then be instanced a
54number of times, and these [Instance] each have their own
55[Transformation] and [SkeletonPose].
56
57## Backends
58
59The model of programming and drawing for OpenGL and WebGL is to
60provide buffers to the GPU that separately contain vertex data and
61index data; the shader program is compiled and linked from separate
62sources; the individual vertex attributes used by the shader program
63are named in the program, and need to be mapped to the contents of the
64vertex buffers that need to be drawn. The vertex buffers thus need a
65mapping concept for an object's buffers that need to be drawn; this is
66the Vertex-Attribute-Object (VAO). Different objects can have
67different vertex attribute layouts within their buffers.
68
69Hence OpenGL/WebGL have programs that have program-specified named
70variables of vertex attributes; buffers for different objects can have
71different vertex layouts; VAOs map parts of buffers to the vertex
72attributes.
73
74WebGPU follows a different model; the shader program is a single
75source code (for vertex and fragment), which is compiled into a shader
76module; the shader module can be used in multiple RenderPipelines;
77each RenderPipeline specifies the layouts of the buffers, which maps
78the layout of the vertices in the buffers that are provided to it at
79draw time to the locations that the shader module expects. There is no
80need for a VAO; the eventual draw call uses buffers that are bound
81(prior to the draw; the operation is set pipeline, set buffers, draw).
82
83# Object creation
84
85The first step in using the library is to create the required
86[Object]. This requires some binary data buffer(s) containing float
87vertex data (position, and possible normals, texture coordinates,
88tangents, relevant bones and weights, and so on); also arrays of
89unsigned int vertex indices, that indicate how the vertices form
90strips of triangles, or lines, etc. In some applications this binary
91data might come from a large file, containing the data for many
92objecs; as such, different portions of the binary data contain
93different parts of the object data.
94
95The library requries that a data buffer support the [ByteBuffer]
96trait, and then that data buffer can have [BufferData] views created
97onto it - portions of the data buffer. For particular vertex data a
98subset of [BufferData] is used to create [BufferDataAccessor]s and for
99indices a [BufferIndexAccessor].
100
101A number of [BufferData] are pulled together to produce a [Vertices]
102object - this might describe all the points and drawing indices for a
103complete object. Subsets of the [Vertices] object are combined with a
104[Material] to help describe a set of elements to render - this might
105be a TriangleStrip, for example - this is known as a [Primitive]
106
107A [Component] of an object is a list of [Primitive] and a
108[Transformation] (the list of [Primitive] is a [Mesh])
109
110An [Object] has a hierarchy of [Component], and optionally a
111[Skeleton]; it also must keep references to the data that it uses - so
112it contains arrays of [Vertices] and [Material] references.
113
114Note that the [Vertices] used by one object may be used by others; as
115such one might load a single data file that contains many objects for
116a game, and the objects all refer to the same buffers and even
117[Material] and [Vertices].
118
119## Buffers
120
121Underlying the data model is the [ByteBuffer] trait - any data that is
122used for the models must support this trait, and implementations are
123provided for slice <> and for Vec<>.
124
125### [BufferData]
126
127A type that borrows a sub slice of[u8], using an explicit offset and
128length, and which might have a client reference (e.g. an OpenGL
129GlBuffer handle). It is similar to a Gltf BufferView, without a
130'stride'.
131
132The base concept for model [BufferData] is that it is an immutable
133borrow of a portion of some model data buffer of a type that supports
134the [ByteBuffer] trait; the data internally may be floats, ints, etc,
135or combinations thereof - from which one creates [BufferDataAccessor]s, or
136[BufferIndexAccessor]s when used as model indices. So it can be the complete
137data for a whole set of models.
138
139Each [BufferData] has a related client element (a
140[Renderable::Buffer]) which is created when an [Object] has its
141client structures created; this may be an Rc of an OpenGL buffer, if
142the client is an OpenGL renderer.
143
144Each [BufferData] is use through one or more [BufferDataAccessor] or [BufferIndexAccessor].
145
146### [BufferDataAccessor], [BufferIndexAccessor]
147
148A [BufferDataAccessor] is an immutable reference to a subset of a [BufferData]. A [BufferDataAccessor]
149may, for example, be the vertex positions for one or more models; it may
150be texture coordinates; and so on. The [BufferData] corresponds on the
151OpenGL side to an ARRAY_BUFFER or (for BufferIndexAccessor) an ELEMENT_ARRAY_BUFFER; hence it
152expects to have a VBO associated with it.
153
154The [BufferDataAccessor] and [BufferIndexAccessor] are similar to a glTF Accessor.
155
156Each [BufferDataAccessor] has a related client element (a
157[Renderable::View]) which is created when an [Object] has its
158client structures created; this may be the data indicating the subset
159of the [Renderable::Buffer] that the view refers to, or perhaps a
160client buffer of its own.
161
162A set of [BufferDataAccessor]s are borrowed to describe [Vertices], each
163[BufferDataAccessor] providing one piece of vertex information (position or normal). A single [BufferDataAccessor] may be used by
164more than one [Vertices] object.
165
166A [BufferIndexAccessor] may be borrowed to describe the indices for a [Vertices].
167
168### [Vertices]
169
170The [Vertices] type borrows at least one [BufferAccessor] for a vertex
171indices buffer, and at least one [BufferAccessor] for positions of the
172vertices; in addition it borrows more [BufferAccessor], one for each
173attribute [VertexAttr] that is part of a mesh or set of meshes.
174
175The [Vertices] object should be considered to be a complete descriptor
176of a model or set of models within one or more [ByteBuffer]. In OpenGL
177a Vertices object becomes a set of OpenGL Buffers (and subsets
178thereof) and for a particular shader class it can be bound into a VAO.
179
180A [Vertices] object is a set of related [BufferAccessor]s, with at least a
181view for indices and a view for vertex positions; it may have more
182views for additional attributes. It has a lifetime that is no longer
183than that of the [BufferData] from which the [BufferAccessor]s are made.
184
185A [Renderable::Vertices] can be constructed from a [Vertices]; this
186is a renderer-specific vertices instance that replaces the use of
187[BufferAccessor]s with the underlying client types.
188
189## Skeleton and posing
190
191A [Skeleton] consists of a (possibly multi-rooted) hierarchy of
192[Bone]s. Each bone has a [Transformation], which is the mapping from
193the coordinate space of its parent to the coordinate space of the bone
194itself.
195
196Each [Bone] has a 'matrix_index' which indicates which 'Joints' matrix
197the bone is referred to by any 'joint's attribute entry in a mesh.
198
199An object instance will have a [SkeletonPose] associated with it; this
200allows the object contents to be rendered with adjustments to the
201model, such as to make it appear to walk. A [SkeletonPose] is an array
202of [BonePose] which reflect the associated [Bone]s in the skeleton;
203each has an associated posed [Transformation].
204
205The [SkeletonPose] can be traversed and for each posed bone an
206appropriate mesh-to-model-space matrix can be generated; if a mesh is
207annotated with bone weights that sum to 1 then a mesh vertex
208coordinate can be converted to a posed-model coordinate by summing the
209mesh-to-model-space matrices of the bones times their weights times
210the mesh vertex coordinate.
211
212A [Skeleton] is similar to a `skin` in GLTF.
213
214/// Each bone has a transformation with respect to its parent that is
215/// a translation (its origin relative to its parent origin), scale
216/// (in each direction, although a common scale for each coordinates
217/// is best), and an orientation of its contents provided by a
218/// quaternion (as a rotation).
219///
220/// A point in this bone's space is then translate(rotate(scale(pt)))
221/// in its parent's space. The bone's children start with this
222/// transformation too.
223///
224/// From this the bone has a local bone-to-parent transform matrix
225/// and it has a local parent-to-bone transform matrix
226///
227/// At rest (where a mesh is skinned) there are two rest matrix variants
228/// Hence bone_relative = ptb * parent_relative
229///
230/// The skinned mesh has points that are parent relative, so
231/// animated_parent_relative(t) = btp(t) * ptb * parent_relative(skinned)
232///
233/// For a chain of bones Root -> A -> B -> C:
234///  bone_relative = C.ptb * B.ptb * A.ptb * mesh
235///  root = A.btp * B.btp * C.btp * C_bone_relative
236///  animated(t) = A.btp(t) * B.btp(t) * C.btp(t) * C.ptb * B.ptb * A.ptb * mesh
237
238## Textxures
239
240A texture is a 1D, 2D or 3D object that is indexed by a shader to
241provide one of a scalar, vec2, vec3 or vec4 of byte, short, integer,
242or float.
243
244
245
246## Materials
247
248Materials are types that have the [Material] trait, and which have the
249lifetime of the [BufferData] of the object they belong to; this is
250because they may contain textures. As such they have an associated
251Renderable::Material type, which has a lifetime as defined by the
252Renderable.
253
254[Material] is a trait that must be supported by materials, which thus
255permits different abstract shading models to be used. It has a
256`MaterialClient` parameter, which
257
258Example [Material] instances are:
259
260* [BaseMaterial] -
261
262* [PbrMaterial] -
263
264A [Material] has a make_renderable() method that makes it renderable?
265
266## [Primitive]
267
268A [Primitive] is a small structure that uses a single subset of
269[Vertices] with a [Material] wih a drawing type (such as
270TriangleStrip). It does not contain direct references to the vertices
271or material; rather it uses an index *within* the arrays of [Vertices]
272or [Material] held by an [Object].
273
274A [Primitive] contains:
275
276* a [Material] (from an index within the [Object] to which the primitive mesh belongs)
277
278* a set of [Vertices] - the attributes required by the [Mesh] and a
279  set of indices, a subset of which are used by the [Primitive] (from
280  an index within the [Object] to which the mesh belongs)
281
282* a drawable element type ([PrimitiveType] such as `TriangleStrip`)
283
284* an index offset (within the [Vertices] indices)
285
286* a number of indices
287
288A [Primitive] does *not* contain any transformation information - all
289the [Primitive] that belong to a [Mesh] have the same transformation.
290
291## [Mesh]
292
293A [Mesh] is an array of [Primitive]; this is just a way to combine sets
294of drawn elements, all using the same transformation (other than bone
295poses).
296
297A mesh is part of a [Component] that is part of an [Object].
298
299## [Component] of an Object
300
301A [Component] is part of the hierarchy of an [Object] and has no
302meaning without it; the indices and materials used in the [Component]
303are provided by the [Object]. The [Component] has a [Transformation]
304(relative to its parent) and a [Mesh].
305
306Note that a hierarchy of object [Component]s is implicitly
307`renderable` as it contains only indices, not actual references to
308[BufferAccessor] data structures.
309
310A hierarchy of object [Component]s can be reduced to a
311[RenderRecipe]; this is an array of:
312
313* transformation matrix
314
315* material index (in a [Primitive])
316
317* vertices index (in a [Primitive])
318
319* drawable element type (in a [Primitive])
320
321* index offset (in a [Primitive])
322
323* index count (in a [Primitive])
324
325## [Object]
326
327An Object has an array of [Vertices] and [Materials] references that
328its meshes use; both of these will end up being mapped to arrays of
329graphic library client handles on a one-to-one basis (each [Vertices]
330in the array becomes a graphics library vertices client, for example).
331
332The Object then has a hierarchy of [Component]; this describes everything that it takes to draw the object.
333
334Additionally the Object has an optional [Skeleton].
335
336All of the data from an [Object] can be used to create an
337[Instantiable]; this latter does not refer to any of he data buffers
338(such as the [Vertices]) and so the original byte buffers can be
339dropped once an [Instantiable] exists - all the data will be in the
340graphics library.
341
342## [Instantiable] objects
343
344A 3D model [Object] consists of:
345
346*  a hierarchy of [Component]s
347
348*  a [Skeleton]
349
350*  an array of [Vertices]; each of these is a set
351of indices within a [BufferData] and attribute [BufferAccessor]s.
352
353*  an array of [Material]
354
355Such an object may have a plurality of render views created for it,
356for use with different visualizers (in OpenGL these could be different
357shaders, for example).
358
359An object can be turned in to a renderable object within a
360Renderable::Context using the `into_instantiable` method.  Once created
361(unless the renderable context requires it) the object can be dropped.
362
363The [Instantiable] is created within a specific renderable
364context. For simple graphics libraries this probably means that
365instances of the instantiated object are to be wih a single shader
366program, whose attribute layout an uniforms is known ahead of time. As
367such the renerable context might generate a single VAO for the
368instantiable with appropriate buffer bindings, at the
369into_instantiable invocation. For more complex applications, where an
370object may be rendered with more than one layout of attributes, with
371many different shader program classes, a VAO could be generated per
372shader program class and (e.g.) a 'bind vertex buffers' for the
373*object* can be invoked within a VAO prior to the rendering of a
374number of the instances of the object with the shader program (each
375presumably with its own 'uniform' settings!).
376
377An [Instantiable] can then be drawn by
378(theoretically, and given a particular [SkeletonPose]):
379
380* Generating the [BonePose] mesh-to-model-space matrices for each bone in the [Skeleton]
381
382* Traversing the hierarchy, keeping a current node [Transformation] in hand
383
384* Apply the node's Transformation
385
386* Render the node's [Primitive]s using the [Object]s material at the
387  correct index, with the [Instantiable] associated with the
388  [Vertices] index of the mesh
389
390## Instantiated objects
391
392An instantiated object is created by instantiating an [Instantiable].
393
394The [Instance] has a [Transformation], a [SkeletonPose], and a set of
395[Material] overrides; the [Material] overrides are an array of
396optional materials.
397
398For efficient rendering the object instance includes an array of the
399instance's [SkeletonPose] matrices plus the base instance
400[Transformation] matrix.
401
402## Rendering an instance
403
404A Vertices object is then used by a number of [Primitive]s; each of
405these borrows the Vertices object, and it owns an array of
406Drawables. Each Drawable is an OpenGL element type (such as
407TriangleStrip), a number of indices, and an indication as to which
408index within the Vertices object to use as the first index. Each Primitive has a single Material associated with it.
409
410An array of Primitive objects is owned by a Mesh object, which corresponds to
411the glTF Mesh - hence the Primitive object here corresponds to a glTF
412Primitive within a glTF Mesh. A Mesh might correspond to a table leg or the table top in a model.
413
414A number of Mesh objects are borrowed to form Object Nodes; each Node has its own Transformation that is applied to its Mesh. Hence a table can consist of four Object Nodes that borrow the same table leg Mesh, and a further Object Node that is the table top. A Node may also have a BoneSet associated with it, to provide for *skinned* objects.
415
416An Object Node forms part of an Object's Hierarchy - hence the Object
417Nodes are owned by the Object. An Object, then, can be a complete
418table, for example. It might also be a posable robot; in this case one
419would expect the top level node to have a BoneSet, and there to
420perhaps be Object Nodes for the body, head, arms and legs, perhaps
421sharing the same Mesh for the two arms and anoter Mesh for the two
422legs.
423
424It is worth noting at this point that the lifetime of an Object must
425be no more than the lifetime of the data buffer containing its data;
426even though the Object may be passed in to a GPU memory, the data used
427for building the object then not being required by the CPU (using
428STATIC_DRAW). It is, then, clearly useful to consider the Object as a
429model *construction* type, not necessarily the model *draw* type.
430
431When it comes to rendering an Object, this requires a Shader. The data
432required by a Shader to render an Object depends not just on the
433Object but also on the Shader's capabilities (such as does it utilize
434vertex tangents). However, there is some data that is common for all
435the Shaders that might render a single Object instance - such as the
436bone poses for the object, and the mesh matrices.
437
438Hence an Object must have two type created for it prior to rendering. The first is a drawable::Instantatiable. This is a drawable object that in itself may have instantiations.
439The drawable::Instantiable contains an owned copy of the BoneSet for
440the object, and any transformation data required by the meshes for
441drawing (given each object node has its own transformation). The drawable::Instantiable is created from the object using its create_instantiable method.
442
443The second type required for rendering is a shader::Instantiable. This
444is used by binding the data required for a shader for an object to a
445VAO (Vertex Attribute Object) for the shader; this VAO is used in the
446rendering of any instances of the shader::Instantiable. The
447shader::Instantiable borrows the drawable::Instantiable created for
448the Object; it is created using the Object's bind_shader method.
449
450With STATIC_DRAW the lifetime of the shader::Instantiable can be shorter than that of the Object data - it can have a lifetime of the rendering.
451
452Once an Object has had all of its drawable::Instantiable and shader::Instantiable types created, the Object may be dropped.
453
454A renderable instance of an object then requires a drawable::Instance
455to be created from the drawable::Instantiable; this instance has its
456own transformation and bone poses, and it borrows the
457drawable::Instantiable. The Instance can be rendered with a particular
458shader using that shader::Instantiable's `gl_draw` method, which takes
459a reference to the Instance. This method then has access to all the
460matrices required for the mesh, for the posed bones, and so on.
461
462A Shader is created using standard OpenGL calls. It must have the ShaderClass trait.
463
464An instantiable model consists of abstract mesh data and poses of the
465elements within its skeleton, if required.
466
467Multiple instances of an instantiable model can be created, each with its own set of poses.
468
469The Hierarchy module provides for a hierarchy of owned elements which
470are stored in an array inside the Hierachy structure; the
471rerlationship between nodes in the hierarchy are handled by indices
472into this array. The Hierarchy is designed to be created, and then
473immutably interrogated - although the immutability refers to the
474*hierarchy* and the *node array*, not the contents of the nodes - the
475node content may be updated at will.
476
477# Graphics libraries
478
479In OpenGL we have
480
481VAO = list of binding from VAO attr number to a buffer; it also has an
482'elemeent array buffer' that is the buffer of indices. Note a buffer
483here is an offset/stride of a gl buffer.
484
485The VAO is specific to the shader class, as it uses the attribute locations of the shader
486
487A VAO can have the attribute bbuffers bound iini one go with glBindVertexBuffers (or glVertexArrayVertexBuffers to specify the vao without binding it first),
488
489The index buffer can be bound witth glBindElementBuffer.
490
491In theory a single VAO can work for many objects with one shader class
492as the attribute layour is specific o the shader class. This requires
493all its buffers to be rebound and the element buffer to be rebound. So it keeps some of the VAO.
494
495Uniforms must be set after useProgram
496
497A VBO glBuffer can be a BufferData; an Accessor is the glBuffer with offset and stride.
498
499## OpenGL 4.0
500
501Program has id; attribute list of (AttribLocation, VertexAttr); uniform list of (UniformLocation, UniformId).
502
503UniformId is either ViewMatrix, ModelMatrix, etc, User(x), or Buffer(x)
504
505# Examples
506
507use model3d::{BufferAccessor, MaterialAspect};
508use model3d::example_client::Renderable;
509
510# To do
511
512Optimize primitive to fit within 32 bytes
513
514Make Buffer have a client 'reproduce me' element so that if it comes
515from a file that file could be reloaded if required. This would allow
516the GPU data for an instantiable to be dropped and reloaded, if the
517appropriate client code is written.  The Buffer would require this
518element at creation time so that its create client method could could
519capture it.
520
521Add a String to each component, and extract that for each root component in the hierarchy
522Maybe have an 'extract component by name' from object that creates an Instantiable (requires there to be no skeleton for now)
523
524Make only part of an instantiable be drawn (have a Vec of RenderRecipes, one per component in the root by default)
525
526!*/
527
528mod types;
529pub use types::BufferElementType;
530pub use types::MaterialAspect;
531pub use types::ShortIndex;
532pub use types::{Mat3, Mat4, Quat, Vec3, Vec4};
533pub use types::{PrimitiveType, VertexAttr, VertexDesc};
534
535//a To do
536//
537// Add index size to primitive (it is cache-line sensitive though)
538
539//a Imports and exports
540pub mod hierarchy;
541
542mod transformation;
543pub use transformation::Transformation;
544
545mod bone;
546mod bone_pose;
547pub use bone::Bone;
548pub use bone_pose::BonePose;
549
550mod skeleton;
551mod skeleton_pose;
552pub use skeleton::Skeleton;
553pub use skeleton_pose::SkeletonPose;
554
555mod buffer_data;
556mod buffer_data_accessor;
557mod buffer_descriptor;
558mod buffer_index_accessor;
559mod byte_buffer;
560pub use buffer_data::BufferData;
561pub use buffer_data_accessor::BufferDataAccessor;
562pub use buffer_descriptor::BufferDescriptor;
563pub use buffer_index_accessor::BufferIndexAccessor;
564pub use byte_buffer::ByteBuffer;
565
566mod traits;
567pub use traits::{
568    AccessorClient, BufferClient, DescriptorClient, Material, MaterialClient, Renderable,
569    TextureClient, VerticesClient,
570};
571
572mod texture;
573pub use texture::Texture;
574
575mod material;
576pub use material::BaseData as MaterialBaseData;
577pub use material::{BaseMaterial, PbrMaterial};
578
579mod vertices;
580pub use vertices::Vertices;
581mod mesh;
582mod primitive;
583pub use mesh::Mesh;
584pub use primitive::Primitive;
585
586mod component;
587pub use component::Component;
588mod render_recipe;
589pub use render_recipe::RenderRecipe;
590mod object;
591pub use object::Object;
592
593mod instantiable;
594pub use instantiable::Instantiable;
595mod instance;
596pub use instance::Instance;
597
598pub mod example_objects;
599pub use example_objects::ExampleVertices;
600
601pub mod example_client;