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, using in BufferDataAccessor
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 use a *reference* to 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 slices 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.
136
137A portion of a [BufferData] can be intepreted by a [BufferDescriptor],
138which effectively describes an array of structures within that portion
139of the [BufferData].
140
141A [BufferDataAccessor] can then use a [BufferDescriptor] to provide
142access to a array of values for *single* field in a data structure
143held in the underlying [BufferData].
144
145A portion of a [BufferData] can also be intepreted by directly a [BufferIndexAccessor],
146which effectively describes an array of indices used to access arrays of [BufferDataAccessor] within a render pipeline.
147
148Each [BufferData] has a related client element (a
149[Renderable::Buffer]) which is created when an [Object] has its
150client structures created; this may be an Rc of an OpenGL buffer, if
151the client is an OpenGL renderer.
152
153Each [BufferData] is use through one or more [BufferDataAccessor] or [BufferIndexAccessor].
154
155### [BufferDataAccessor], [BufferIndexAccessor]
156
157A [BufferDataAccessor] is an immutable reference to a subset of a [BufferData]. A [BufferDataAccessor]
158may, for example, be the vertex positions for one or more models; it may
159be texture coordinates; and so on. The [BufferData] corresponds on the
160OpenGL side to an ARRAY_BUFFER or (for BufferIndexAccessor) an ELEMENT_ARRAY_BUFFER; hence it
161expects to have a VBO associated with it.
162
163The [BufferDataAccessor] and [BufferIndexAccessor] are similar to a glTF Accessor.
164
165Each [BufferDataAccessor] has a related client element (a
166[Renderable::View]) which is created when an [Object] has its
167client structures created; this may be the data indicating the subset
168of the [Renderable::Buffer] that the view refers to, or perhaps a
169client buffer of its own.
170
171A set of [BufferDataAccessor]s are borrowed to describe [Vertices], each
172[BufferDataAccessor] providing one piece of vertex information (position or normal). A single [BufferDataAccessor] may be used by
173more than one [Vertices] object.
174
175A [BufferIndexAccessor] may be borrowed to describe the indices for a [Vertices].
176
177### [Vertices]
178
179The [Vertices] type borrows at least one [BufferAccessor] for a vertex
180indices buffer, and at least one [BufferAccessor] for positions of the
181vertices; in addition it borrows more [BufferAccessor], one for each
182attribute [VertexAttr] that is part of a mesh or set of meshes.
183
184The [Vertices] object should be considered to be a complete descriptor
185of a model or set of models within one or more [ByteBuffer]. In OpenGL
186a Vertices object becomes a set of OpenGL Buffers (and subsets
187thereof) and for a particular shader class it can be bound into a VAO.
188
189A [Vertices] object is a set of related [BufferAccessor]s, with at least a
190view for indices and a view for vertex positions; it may have more
191views for additional attributes. It has a lifetime that is no longer
192than that of the [BufferData] from which the [BufferAccessor]s are made.
193
194A [Renderable::Vertices] can be constructed from a [Vertices]; this
195is a renderer-specific vertices instance that replaces the use of
196[BufferAccessor]s with the underlying client types.
197
198## Skeleton and posing
199
200A [Skeleton] consists of a (possibly multi-rooted) hierarchy of
201[Bone]s. Each bone has a [Transformation], which is the mapping from
202the coordinate space of its parent to the coordinate space of the bone
203itself.
204
205Each [Bone] has a 'matrix_index' which indicates which 'Joints' matrix
206the bone is referred to by any 'joint's attribute entry in a mesh.
207
208An object instance will have a [SkeletonPose] associated with it; this
209allows the object contents to be rendered with adjustments to the
210model, such as to make it appear to walk. A [SkeletonPose] is an array
211of [BonePose] which reflect the associated [Bone]s in the skeleton;
212each has an associated posed [Transformation].
213
214The [SkeletonPose] can be traversed and for each posed bone an
215appropriate mesh-to-model-space matrix can be generated; if a mesh is
216annotated with bone weights that sum to 1 then a mesh vertex
217coordinate can be converted to a posed-model coordinate by summing the
218mesh-to-model-space matrices of the bones times their weights times
219the mesh vertex coordinate.
220
221A [Skeleton] is similar to a `skin` in GLTF.
222
223/// Each bone has a transformation with respect to its parent that is
224/// a translation (its origin relative to its parent origin), scale
225/// (in each direction, although a common scale for each coordinates
226/// is best), and an orientation of its contents provided by a
227/// quaternion (as a rotation).
228///
229/// A point in this bone's space is then translate(rotate(scale(pt)))
230/// in its parent's space. The bone's children start with this
231/// transformation too.
232///
233/// From this the bone has a local bone-to-parent transform matrix
234/// and it has a local parent-to-bone transform matrix
235///
236/// At rest (where a mesh is skinned) there are two rest matrix variants
237/// Hence bone_relative = ptb * parent_relative
238///
239/// The skinned mesh has points that are parent relative, so
240/// animated_parent_relative(t) = btp(t) * ptb * parent_relative(skinned)
241///
242/// For a chain of bones Root -> A -> B -> C:
243/// bone_relative = C.ptb * B.ptb * A.ptb * mesh
244/// root = A.btp * B.btp * C.btp * C_bone_relative
245/// animated(t) = A.btp(t) * B.btp(t) * C.btp(t) * C.ptb * B.ptb * A.ptb * mesh
246
247## Textxures
248
249A texture is a 1D, 2D or 3D object that is indexed by a shader to
250provide one of a scalar, vec2, vec3 or vec4 of byte, short, integer,
251or float.
252
253
254
255## Materials
256
257Materials are types that have the [Material] trait, and which have the
258lifetime of the [BufferData] of the object they belong to; this is
259because they may contain textures. As such they have an associated
260Renderable::Material type, which has a lifetime as defined by the
261Renderable.
262
263[Material] is a trait that must be supported by materials, which thus
264permits different abstract shading models to be used. It has a
265`MaterialClient` parameter, which
266
267Example [Material] instances are:
268
269* [BaseMaterial] -
270
271* [PbrMaterial] -
272
273A [Material] has a make_renderable() method that makes it renderable?
274
275## [Primitive]
276
277A [Primitive] is a small structure that uses a single subset of
278[Vertices] with a [Material] wih a drawing type (such as
279TriangleStrip). It does not contain direct references to the vertices
280or material; rather it uses an index *within* the arrays of [Vertices]
281or [Material] held by an [Object].
282
283A [Primitive] contains:
284
285* a [Material] (from an index within the [Object] to which the primitive mesh belongs)
286
287* a set of [Vertices] - the attributes required by the [Mesh] and a
288 set of indices, a subset of which are used by the [Primitive] (from
289 an index within the [Object] to which the mesh belongs)
290
291* a drawable element type ([PrimitiveType] such as `TriangleStrip`)
292
293* an index offset (within the [Vertices] indices)
294
295* a number of indices
296
297A [Primitive] does *not* contain any transformation information - all
298the [Primitive] that belong to a [Mesh] have the same transformation.
299
300## [Mesh]
301
302A [Mesh] is an array of [Primitive]; this is just a way to combine sets
303of drawn elements, all using the same transformation (other than bone
304poses).
305
306A mesh is part of a [Component] that is part of an [Object].
307
308## [Component] of an Object
309
310A [Component] is part of the hierarchy of an [Object] and has no
311meaning without it; the indices and materials used in the [Component]
312are provided by the [Object]. The [Component] has a [Transformation]
313(relative to its parent) and a [Mesh].
314
315Note that a hierarchy of object [Component]s is implicitly
316`renderable` as it contains only indices, not actual references to
317[BufferAccessor] data structures.
318
319A hierarchy of object [Component]s can be reduced to a
320[RenderRecipe]; this is an array of:
321
322* transformation matrix
323
324* material index (in a [Primitive])
325
326* vertices index (in a [Primitive])
327
328* drawable element type (in a [Primitive])
329
330* index offset (in a [Primitive])
331
332* index count (in a [Primitive])
333
334## [Object]
335
336An Object has an array of [Vertices] and [Materials] references that
337its meshes use; both of these will end up being mapped to arrays of
338graphic library client handles on a one-to-one basis (each [Vertices]
339in the array becomes a graphics library vertices client, for example).
340
341The Object then has a hierarchy of [Component]; this describes everything that it takes to draw the object.
342
343Additionally the Object has an optional [Skeleton].
344
345All of the data from an [Object] can be used to create an
346[Instantiable]; this latter does not refer to any of he data buffers
347(such as the [Vertices]) and so the original byte buffers can be
348dropped once an [Instantiable] exists - all the data will be in the
349graphics library.
350
351## [Instantiable] objects
352
353A 3D model [Object] consists of:
354
355* a hierarchy of [Component]s
356
357* a [Skeleton]
358
359* an array of [Vertices]; each of these is a set
360 of indices within a [BufferData] and attribute [BufferAccessor]s.
361
362* an array of [Material]
363
364Such an object may have a plurality of render views created for it,
365for use with different visualizers (in OpenGL these could be different
366shaders, for example).
367
368An object can be turned in to a renderable object within a
369Renderable::Context using the `into_instantiable` method. Once created
370(unless the renderable context requires it) the object can be dropped.
371
372The [Instantiable] is created within a specific renderable
373context. For simple graphics libraries this probably means that
374instances of the instantiated object are to be wih a single shader
375program, whose attribute layout an uniforms is known ahead of time. As
376such the renerable context might generate a single VAO for the
377instantiable with appropriate buffer bindings, at the
378into_instantiable invocation. For more complex applications, where an
379object may be rendered with more than one layout of attributes, with
380many different shader program classes, a VAO could be generated per
381shader program class and (e.g.) a 'bind vertex buffers' for the
382*object* can be invoked within a VAO prior to the rendering of a
383number of the instances of the object with the shader program (each
384presumably with its own 'uniform' settings!).
385
386An [Instantiable] can then be drawn by
387(theoretically, and given a particular [SkeletonPose]):
388
389* Generating the [BonePose] mesh-to-model-space matrices for each bone in the [Skeleton]
390
391* Traversing the hierarchy, keeping a current node [Transformation] in hand
392
393* Apply the node's Transformation
394
395* Render the node's [Primitive]s using the [Object]s material at the
396 correct index, with the [Instantiable] associated with the
397 [Vertices] index of the mesh
398
399## Instantiated objects
400
401An instantiated object is created by instantiating an [Instantiable].
402
403The [Instance] has a [Transformation], a [SkeletonPose], and a set of
404[Material] overrides; the [Material] overrides are an array of
405optional materials.
406
407For efficient rendering the object instance includes an array of the
408instance's [SkeletonPose] matrices plus the base instance
409[Transformation] matrix.
410
411## Rendering an instance
412
413A Vertices object is then used by a number of [Primitive]s; each of
414these borrows the Vertices object, and it owns an array of
415Drawables. Each Drawable is an OpenGL element type (such as
416TriangleStrip), a number of indices, and an indication as to which
417index within the Vertices object to use as the first index. Each Primitive has a single Material associated with it.
418
419An array of Primitive objects is owned by a Mesh object, which corresponds to
420the glTF Mesh - hence the Primitive object here corresponds to a glTF
421Primitive within a glTF Mesh. A Mesh might correspond to a table leg or the table top in a model.
422
423A 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.
424
425An Object Node forms part of an Object's Hierarchy - hence the Object
426Nodes are owned by the Object. An Object, then, can be a complete
427table, for example. It might also be a posable robot; in this case one
428would expect the top level node to have a BoneSet, and there to
429perhaps be Object Nodes for the body, head, arms and legs, perhaps
430sharing the same Mesh for the two arms and anoter Mesh for the two
431legs.
432
433It is worth noting at this point that the lifetime of an Object must
434be no more than the lifetime of the data buffer containing its data;
435even though the Object may be passed in to a GPU memory, the data used
436for building the object then not being required by the CPU (using
437STATIC_DRAW). It is, then, clearly useful to consider the Object as a
438model *construction* type, not necessarily the model *draw* type.
439
440When it comes to rendering an Object, this requires a Shader. The data
441required by a Shader to render an Object depends not just on the
442Object but also on the Shader's capabilities (such as does it utilize
443vertex tangents). However, there is some data that is common for all
444the Shaders that might render a single Object instance - such as the
445bone poses for the object, and the mesh matrices.
446
447Hence 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.
448The drawable::Instantiable contains an owned copy of the BoneSet for
449the object, and any transformation data required by the meshes for
450drawing (given each object node has its own transformation). The drawable::Instantiable is created from the object using its create_instantiable method.
451
452The second type required for rendering is a shader::Instantiable. This
453is used by binding the data required for a shader for an object to a
454VAO (Vertex Attribute Object) for the shader; this VAO is used in the
455rendering of any instances of the shader::Instantiable. The
456shader::Instantiable borrows the drawable::Instantiable created for
457the Object; it is created using the Object's bind_shader method.
458
459With 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.
460
461Once an Object has had all of its drawable::Instantiable and shader::Instantiable types created, the Object may be dropped.
462
463A renderable instance of an object then requires a drawable::Instance
464to be created from the drawable::Instantiable; this instance has its
465own transformation and bone poses, and it borrows the
466drawable::Instantiable. The Instance can be rendered with a particular
467shader using that shader::Instantiable's `gl_draw` method, which takes
468a reference to the Instance. This method then has access to all the
469matrices required for the mesh, for the posed bones, and so on.
470
471A Shader is created using standard OpenGL calls. It must have the ShaderClass trait.
472
473An instantiable model consists of abstract mesh data and poses of the
474elements within its skeleton, if required.
475
476Multiple instances of an instantiable model can be created, each with its own set of poses.
477
478The Hierarchy module provides for a hierarchy of owned elements which
479are stored in an array inside the Hierachy structure; the
480rerlationship between nodes in the hierarchy are handled by indices
481into this array. The Hierarchy is designed to be created, and then
482immutably interrogated - although the immutability refers to the
483*hierarchy* and the *node array*, not the contents of the nodes - the
484node content may be updated at will.
485
486# Graphics libraries
487
488In OpenGL we have
489
490VAO = list of binding from VAO attr number to a buffer; it also has an
491'elemeent array buffer' that is the buffer of indices. Note a buffer
492here is an offset/stride of a gl buffer.
493
494The VAO is specific to the shader class, as it uses the attribute locations of the shader
495
496A VAO can have the attribute bbuffers bound iini one go with glBindVertexBuffers (or glVertexArrayVertexBuffers to specify the vao without binding it first),
497
498The index buffer can be bound witth glBindElementBuffer.
499
500In theory a single VAO can work for many objects with one shader class
501as the attribute layour is specific o the shader class. This requires
502all its buffers to be rebound and the element buffer to be rebound. So it keeps some of the VAO.
503
504Uniforms must be set after useProgram
505
506A VBO glBuffer can be a BufferData; an Accessor is the glBuffer with offset and stride.
507
508## OpenGL 4.0
509
510Program has id; attribute list of (AttribLocation, VertexAttr); uniform list of (UniformLocation, UniformId).
511
512UniformId is either ViewMatrix, ModelMatrix, etc, User(x), or Buffer(x)
513
514# Examples
515
516use model3d::{BufferAccessor, MaterialAspect};
517use model3d::example_client::Renderable;
518
519# To do
520
521Optimize primitive to fit within 32 bytes
522
523Make Buffer have a client 'reproduce me' element so that if it comes
524from a file that file could be reloaded if required. This would allow
525the GPU data for an instantiable to be dropped and reloaded, if the
526appropriate client code is written. The Buffer would require this
527element at creation time so that its create client method could could
528capture it.
529
530Add a String to each component, and extract that for each root component in the hierarchy
531Maybe have an 'extract component by name' from object that creates an Instantiable (requires there to be no skeleton for now)
532
533Make only part of an instantiable be drawn (have a Vec of RenderRecipes, one per component in the root by default)
534
535!*/
536
537mod types;
538pub use types::BufferElementType;
539pub use types::MaterialAspect;
540pub use types::ShortIndex;
541pub use types::{Mat3, Mat4, Quat, Vec3, Vec4};
542pub use types::{PrimitiveType, VertexAttr, VertexDesc};
543
544//a To do
545//
546// Add index size to primitive (it is cache-line sensitive though)
547
548//a Imports and exports
549pub mod hierarchy;
550
551mod transformation;
552pub use transformation::Transformation;
553
554mod bone;
555mod bone_pose;
556pub use bone::Bone;
557pub use bone_pose::BonePose;
558
559mod skeleton;
560mod skeleton_pose;
561pub use skeleton::Skeleton;
562pub use skeleton_pose::SkeletonPose;
563
564mod buffer_data;
565mod buffer_data_accessor;
566mod buffer_descriptor;
567mod buffer_index_accessor;
568mod byte_buffer;
569pub use buffer_data::BufferData;
570pub use buffer_data_accessor::BufferDataAccessor;
571pub use buffer_descriptor::BufferDescriptor;
572pub use buffer_index_accessor::BufferIndexAccessor;
573pub use byte_buffer::ByteBuffer;
574
575mod traits;
576pub use traits::{
577 AccessorClient, BufferClient, DescriptorClient, Material, MaterialClient, Renderable,
578 TextureClient, VerticesClient,
579};
580
581mod texture;
582pub use texture::Texture;
583
584mod material;
585pub use material::BaseData as MaterialBaseData;
586pub use material::{BaseMaterial, PbrMaterial};
587
588mod vertices;
589pub use vertices::Vertices;
590mod mesh;
591mod primitive;
592pub use mesh::Mesh;
593pub use primitive::Primitive;
594
595mod component;
596pub use component::Component;
597mod render_recipe;
598pub use render_recipe::RenderRecipe;
599mod object;
600pub use object::Object;
601
602mod instantiable;
603pub use instantiable::Instantiable;
604mod instance;
605pub use instance::Instance;
606
607pub mod example_objects;
608pub use example_objects::ExampleVertices;
609
610pub mod example_client;