/*! \page UsdSkel_Schemas Schemas In-Depth Data in UsdSkel is stored in modular, reusable, instanceable parts, adhering to the following design principles: - _Skeleton_ "rigs" can be defined and published, to be referenced in wherever needed. Encapsulating skeletons this way is not necessarily a requirement for the interchange of skeletal data, but facilitates scalability and maintainability when deploying directly-rendered, skinned crowds at scale in VFX pipelines. - _Animations_ can be published individually and referenced back into scenes. This not only allows re-use, but also enables sequencing of animations as Value Clips. - Separating the binding of a _skeleton_ and its _animation_ as bound to geometry allows assets to be published with a bound _skeleton_, inside of a \ref Usd_ScenegraphInstancing_Overview "instance primitive", which can still be driven by a separate animation. - All posing and animation data is vectorized. This encoding is concise and ideal for scalability and speed of data consumption in the USD APIs. Although vectorization may seem unnecessary to the client attempting to interchange individual models only, it is an important consideration for achieving a scalable encoding of crowds in VFX pipelines. Following these principles, UsdSkel defines skeletal data using the following schema types: - \ref UsdSkel_SkelRoot "Skel Root": Identifies where in a scene graph skeletal processing takes place, in addition to providing bounds for skinned models. - \ref UsdSkel_Skeleton "Skeleton": Defines the \ref UsdSkel_Term_SkeletonTopology "topology" of the skeleton, as well as storing a _bind pose_. Skeletons are animated by attaching a SkelAnimation. - \ref UsdSkel_SkelAnimation "Skel Animation": Stores joint and blend shape animations, which may be applied to any _Skeleton_. - \ref UsdSkel_BlendShape "Blend Shape": Stores an individual blend shape, and optional in-betweens, for a geometric primitive. - \ref UsdSkel_BindingAPI "Binding API": API schema used to describe which skeletons affect which primitives, as well as basic skinning properties like joint influences. The BindingAPI is also used to attach a _SkelAnimation_ to a _Skeleton_. \section UsdSkel_JointOrder Joint Order Joint data in UsdSkel is stored in vectorized arrays. Throughout UsdSkel, these arrays may be ordered in slightly different ways. For instance, a _skeleton_ has its own explicit joint ordering, but an _animation_ may have another order, representing either a different ordering of joints, or a sparse subset of joints. These data orderings are referred to as a primitive's **joint order**, and are defined using token arrays. The tokens in a joint array are given as Sdf-style paths, where parent-child relationships in the given paths establish a \ref UsdSkel_JointHierarchy "joint hierarchy." Note that these paths do not need to refer to actual primitives in the scene. They are used as a way to name and order joints in vectorized data. For example: \code def SkelAnimation "Anim" { uniform token[] = ["A", "A/B"] } def Skeleton "Skel" { uniform token[] = ["A/B", "A"] } \endcode Note that in both example primitives above, the given paths do not reference any real primitives. Also note that each primitive has its own joint ordering, and that those orders need not be identical. The purpose of encoding orderings in this manner is to allow for the creation of **self-contained** assets. For example, it is possible to construct a \ref UsdSkel_SkelAnimation "skel animation" primitive independently from any skeleton definitions, which will remain valid even if a _skeleton_ that the animation is mapped to has a slightly different ordering. Part of the motivation for this is to allow for more robust, composed assets. When orderings are required to remain fixed, maintenance difficulties may arise. For example, if animation assets are produced through a process independent from the process that produces a shared definition of a _skeleton asset_, data can easily get out of sync. On top of allowing for more robust assets, these flexible joint orderings allow for additional features like sparse authoring of animation data. Data can be remapped from one joint ordering to another using a UsdSkelAnimMapper, and is done so by matching joint names. \sa UsdSkelAnimQuery::GetJointOrder, UsdSkelSkeletonQuery::GetJointOrder, UsdSkelSkinningQuery::GetJointOrder \section UsdSkel_SkelRoot Skeleton Root Schema The UsdSkelRoot schema is used to **encapsulate** primitives with skeletal skinning behaviors, and is required when authoring skeletal data. A SkelRoot is a boundable primitive, and provides a place to encode the extents of all skinned primitives beneath it. It is neither expected nor required the descendent primitives that are being skinned will encode their own skinned extents. These extents are made available to renders to enable operations like out-of-camera culling, without requiring that skinned geometry be computed first. A SkelRoot additionally gives DCC apps a way of identifying which parts of a scene graph require skeletal processing, so that they can take different code paths, as is often required to consume skeletal data. It is possible to override a primitive's composed type in USD, in order to either enable or disable skeletal processing. For example: \code{.cpp} // Enable skeletal processing by setting the type to UsdSkelRoot. UsdSkel.Root.Define(prim.GetStage(), prim.GetPath()); // Disable skeletal processing by changing the type to a normal transform. UsdGeomTransform.Define(prim.GetStage(), prim.GetPath()); \endcode \section UsdSkel_Skeleton Skeleton Schema The UsdSkelSkeleton schema describes a skeleton. This schema is responsible both for establishing the _topology_ of a skeleton, as well as for identifying a _bind pose_. A skeleton itself provides only structure. Meshes are posed with a skeleton by way of \ref UsdSkel_BindingAPI "skeletal bindings" inside of the "geometry hierarchy" of primitives. \subsection UsdSkel_JointHierarchy Skeleton Schema: Joint Hierarchy The joints of a Skeleton are defined by the _joints_ attribute. This attribute encodes joint paths -- each of which is a valid SdfPath strings. The parent-child relationships that these paths describe are used to define the parent-child relationships of the joints themselves. For example: \code def Skeleton "Skel" { uniform token[] joints = ["A", "A/B", "C", "C/D/E"] } \endcode In the above example, there are four joints: - `A`: A root joint (no parent) - `A/B`: A joint parented beneath joint `A` - `C`: Another root joint (no parent). There can be any number of root joints. - `C/D/E`: A joint which, since `C/D` has not been defined, will be parented beneath joint `C`. In addition to providing parent-child relationships, this token array also establishes the \ref UsdSkel_JointOrder "joint order" of the skeleton. The targets of the _joints_ attribute are required to be authored such that all parent joints come before any of their children in the array. This is a requirement because it simplifies some computations without necessitating the creation of additional data structures. This ordering can most easily be achieved by simply sorting the array. It's possible to test whether or not an array of joint paths defines a valid topology as follows: - C++: \code{.cpp} std::string whyNot; bool isValid = UsdSkelTopology(paths).Validate(&whyNot); \endcode - Python: \code{.py} (isValid,whyNot) = UsdSkel.Topology(paths).Validate() \endcode \section UsdSkel_SkelAnimation Skel Animation Schema Schema describing skeletal animation, within which joint animations and blend shapes are stored in a vecorized form. A SkelAnimation encodes the animation of a Skeleton as a separate primitive to facilitate instancing workflows. Both as a storage optimization and to allow for value interpolation that preserves transform orthogonality, joint transforms are encoded as separate translate, rotate and scale components, given in _joint local_ space. Transforms are constructed from components using an order of scale-rotate-translate. Client code may make use of the \ref UsdSkel_TransformCompositionUtils "transform composition utilities" for converting transforms to and from this component form. Joint data is stored in arrays, using the \ref UsdSkel_JointOrder "joint order" specified by the _joints_ attribute. This ordering may be different from the Skeletons that the animation maps to, and may also only identify a sparse subset of the joints in a skeleton. When an animation provides sparse data, fallback values are taken from the rest pose on the UsdSkelSkeleton primitive to which they apply. An animation source is only valid if its _translation_, _rotation_, and _scale_ components are all authored, storing arrays size to the same size as the authored _joints_ array. The effect of a skel animation prim may also be directly nullified by either deactivating the primitive, or by blocking the component attributes. In addition to providing joint animations, a SkelAnimation may also provide blend shape weight animations. Blend shape weights are specified in a vectorized form using the _blendShapeWeights_ attribute. The _blendShapes_ attribute holds a token array which, for every element authored in _blendShapeWeights_, identifies which blend shape each weight value applies to. The point of this encoding is to decouple the blendshape weight animation from the description of how that animation maps to different skinnable shapes. Refer to the \ref UsdSkel_BindingAPI_BlendShapes 'BindingAPI: Blend Shapes' documentation for information on how these weights are mapped to skinnable primitives. \section UsdSkel_SkelAnimation_Binding Skel Animation Schema: Binding to Skeletons A _SkelAnimation_ is made to affect a _Skeleton_ by *binding* the animation to the skeleton, using the _skel:animationSource_ property of UsdSkelBindingAPI schema. For example: \code def SkelAnimation "Anim" {} def "Model" { rel skel:animationSource = def Skeleton "Skel" {} } \endcode When a _skel:animationSource_ property is defined, it is "inherited" down namespace, onto any _Skeleton_ primitive beneath it. So in the above example, `` will be affected by the SkelAnimation at ``. There are a couple reasons why data is separated in this manner: - Encoding animation separately means that different schemes can be developed for describing the animation of a Skeleton. For example, it is possible to define a "blender" animation type that encodes the blending of animation. - It is possible to apply different animations to _instanced assets_. \sa \ref UsdSkel_Instancing \section UsdSkel_BlendShape Blend Shape Schema Schema describing a single blend shape. Blend shapes specify a target shape, in terms of point offsets, for a point-based primitive. The offsets may hold a direct correspondance with the points of the point-based primitive to which they are meant to apply, or the points may specify a shape using a sparse subset of points. The mapping in the latter case is described using the *pointIndices* attribute. If a blend shape defines any \ref UsdSkel_BlendShape_Inbetweens "in-between shapes", the same *pointIndices* mapping additionaly applies to all in-between shapes. When a mesh is skinned in UsdSkel, blend shape application precedes the effect of skinning using joint transformations. If no in-between shapes are defined, a set of blend shapes is applied against an input point as follows: \image html ../images/blendshapes.svg \htmlonly \endhtmlonly In other words, the position offsets are multiplied against the corresponding weight value, and added against the input positions. Note that the above equation only describes application of blend shapes in the absence of in-between shapes. \subsection UsdSkel_BlendShape_Inbetweens Blend Shape: In-betweens Each blend shape prim may define in-between shapes, which specify explicit corrective shape to apply when the blend shape is resolved at different weights. For example, suppose that a blend shape defines a 'smile' shape. At a weight of 1, we apply the full effect of the shape. At in-between weight values, we linearly interpolate the shape back towards a neutral pose to derive an in-between shape. Using in-betweens, we can instead specify those in-between shapes explicitly. So instead of linearly interpolating to derive a 'half-smile' pose, we might provide an explicit shape corresponding to a weight of 0.5. Scene description for the scenario described above is as follows: \code def BlendShape "Smile" { uniform vector3f[] inbetweens:halfSmile = [...] (weight = 0.5) } \endcode While an equivalent animation could be defined without in-betweens by animating the weights of two blend shapes separately, using in-betweens provides a more convenient encoding that allows us to decouple the specification of in-betweens from the primary weight animation. In-between shapes can be created via UsdSkelBlend::CreateInbetween(), and are manipulated and introspected using UsdSkelInbetweenShape objects. The in-between shapes themselves are encoded as attributes in the 'inbetweens:' namespace, using the 'weight' metadata field to indicate the weight value at which they apply. The in-between shapes corresponding to `weight = 0` and `weight = 1` are **implicitly** defined on a blend shape. The former defines the null shape, for which all shape offset are zero, while the latter is the shape given by the _offsets_ property of the UsdSkelBlendShape primitive. Because the existence of those in-betweens is implied, it is considered an authoring error for any in-betweens to specify a weight of 0 or 1. We must also consider the behavior when multiple in-betweens have matching weight values. Although it would be possible to adopt an interpretation that allows all shapes to have meaning -- such as averaging across all shapes -- this introduces some ambiguity for interchange: If the in-betweens are averaged together, it's unclear what the _name_ should be given to the resulting shape. To avoid this ambiguous interpretation, in addition to treating in-betweens with a weight value of 0 or 1 as an authoring error, it is also considered an error for any two in-betweens of a blend shape to have the same weight value. Typical run-time behavior for these malformed in-betweens is to produce an error, but continue to process the blend shape while ignoring the malformed in-betweens. If we consider only the set of valid in-betweens, a set of blend shapes containing in-betweens are applied to a point as follows: \image html ../images/blendshapesWithInbetweens.svg \htmlonly \endhtmlonly For example, given in-between weights of `[0.25, 0.5]`, if a blendshape weight is greater than 0.5, we interpolate between the shape at 0.5 and the implicit primary shape (`weight = 1`), adding the result to the base shape. If the weight is in the `[0.25,0.5]` interval, we interpolate between the shapes at 0.25 and 0.5, adding the result to the base shape. Finally, if the weight is less than 0.25, we interpolate between the implicit null shape (`weight = 0`) and the shape at 0.25. Note also that this interpolation is _unbounded_, so if the input weight is, say, -0.25, then we have: \image html ../images/unboundedInterpolationExample.svg \htmlonly \endhtmlonly So at a weight value of -0.25, the shape at 0.25 is applied with a weight of -1. \section UsdSkel_BindingAPI Binding API Schema The UsdSkelBindingAPI schema provides a means of binding a _Skeleton_ into a geometry hierarchy. This schema is also responsible for defining joint influences, as well as an optional _geomBindTransform_ property to define the space for skinning. Since a UsdSkelRoot primitive provides encapsulation of skeletal data, bindings defined on any primitives that do not have a UsdSkelRoot primitive as one of their ancestors have no meaning, and should be ignored. \subsection UsdSkel_BindingAPI_Skeletons BindingAPI: Binding Skeletons Meshes are skinned based on \ref UsdSkel_Term_SkinningTransform "skinning transforms", computed from a UsdSkelSkeletonQuery, which is bound hierarchically using the _skel:skeleton_ relationship. The transforms for a bound skeleton are driven from an animation source, such as a \ref UsdSkel_SkelAnimation "skel animation", which is also bound hierarchically, via the _skel:animationSource_ binding relationship. By defining bindings hierarchically, it is possible to define models that each have unique skeletal animations, while also being \ref Usd_ScenegraphInstancing_Overview "instanced". For example: \code def "Character" { rel skel:skeleton = def Skeleton "Skel" {} } def SkelAnimation "Anim" {} over "Instance" ( prepend references = instanceable=true ) { rel skel:animationSource = } \endcode Each _skel:skeleton_ binding may be thought of as identifying a \ref UsdSkel_Term_SkeletonInstance "Skeleton Instance", animated according to whichever inherited _skel:animationSource_ is defined at the location at which the _skel:skeleton_ is bound. Although _skel:animationSource_ bindings are inherited, they only apply when a _skel:skeleton_ is resolved. For example: \code over "A" { rel skel:animationSource = over "B" { rel skel:skeleton = } over "C" { rel skel:skeleton = } } \endcode The above example includes two separate _skeleton instances_, with the same animation being applied to each instance. Contrast that with the following case: \code over "A" { rel skel:skeleton = over "B" { rel skel:animationSource = } over "C" { rel skel:animationSource = } } \endcode In the above example, there is only a single _skeleton instance_ (at ``), which has no animation, because a _skel:animationSource_ binding is not considered to have any effect until the next _skel:skeleton_ binding at or beneath the binding location in namespace. One final example may clarify behavior: \code over "A" { rel skel:skeleton = rel skel:animationSource = over "B" { rel skel:animationSource = } over "C" { rel skel:animationSource = rel skel:skeleton = } } \endcode In this case, there are two _skeleton instances_: One at ``, referencing the animation at ``, and one at ``, referencing the animation at ``. The _skel:animationSource_ relationship at `` has no effect. \subsection UsdSkel_BindingAPI_JointInfluences BindingAPI: Joint Influences Joint influences for skinning points are defined by setting the _primvars:skel:jointIndices_ and _primvars:skel:jointWeights_ primvars, using the UsdSkelBindingAPI. The _jointIndices_ primvar provides an array giving the joint index of an influence, while the _jointWeights_ primvar provides a weight value corresponding to each of those indices. Above, since `` does not specify a _skel:joints_ ordering of its own, the joint indices refer to the ordering of the bound Skeleton, and so the joint indices refer to joints `A/B` and `A`, respectively. However, `` specifies a `skel:joints` property that gives an alternate joint ordering. Using that, the indices of `` refer to joints `A/B/C` and `A/B`, in that order. In the common case, the joint influence primvars are configured with _vertex_ interpolation, and define a fixed number of contiguous influences per point. The primvar's _elementSize_ defines the fixed number of influences for each point. _elementSize_ of the primvar. I.e., \image html ../images/influencesPrimvarLayout.svg \htmlonly \endhtmlonly If a point has fewer influences than are needed for other points, the unused array elements of that point should be filled with 0, both for joint indices and for weights. See \ref UsdGeomPrimvar for more information on the meaning of primvar interpolation and elementSize. No restrictions are placed on the _elementSize_ when defining joint influences. Because such a limit may vary among different DCC applications, we feel that it is inappropriate to hard-code any such restrictions at the file storage level. Instead, for clients that require a strict limit on the number of influences per point, UsdSkel provides helper method, \ref UsdSkelResizeInfluences, that can be used to enforce such limits within each client, as necessary. See the \ref UsdSkel_CE_Skinning "skinning coding examples" for an example of how resolved joint influences may be read. The interpolation, element size and the size of the stored arrays must be consistent across both the _joindIndices_ and _jointWeights_ primvars. Aside from _vertex_ interpolation, the only other valid primvar interpolation for joint influences is _constant_ interpolation, which is used in defining rigid deformations. It is considered an error to apply any other type of interpolation. \subsection UsdSkel_BindingAPI_RigidDeformations BindingAPI: Rigid Deformations In addition to defining influences that vary per point, joint influences may also be defined with _constant_ interpolation. In this form, the _jointIndices_ and _jointWeights_ arrays define a set of influences that apply the same way to all points. Constant joint influences are supported both as a form of storage optimization, as well as for the sake of encoding _rigid deformations_. By identifying rigid deformations, some clients may be able to retain instancing properties that would otherwise be lost by skinning, by affecting only the transform of an instance rather than the deforming points of that instance. For example: \code def "MeshA" { int[] primvars:skel:jointIndices = [0] (interpolation = "constant") float[] primvars:skel:jointWeights = [1] (interpolation = "constant") } def "MeshB" { int[] primvars:skel:jointIndices = [0,1] (interpolation = "constant") float[] primvars:skel:jointWeights = [0.5,0.5] (interpolation = "constant") } \endcode In the example above, `` can be seen as being ridigly constrained to infuence 0. `` is rigidly deformed, but it's also important to note that even though it is rigidly deformed, it is still influenced by more than one joint. It is not expected that all applications know how to deal with rigid deformations. For applications that don't understand them, UsdSkel provides the helper methods UsdSkelSkinningQuery::ComputeVaryingJointInfluences and \ref UsdSkelExpandConstantInfluencesToVarying, which both provide a means of querying rigid deformations as if they had been encoded with per-point influences. \subsection UsdSkel_BindingAPI_StoringInfluences BindingAPI: Storing Influences To ensure correct skinning, joint influences should be normalized when they are written using the UsdSkelBindingAPI. UsdSkel does *not* automatically normalize weights when reading data. Clients should instead use the \ref UsdSkelNormalizeWeights helper method to normalize weights prior to storing them. Additionally, as part of our \ref UsdSkel_BestPractices "best practices", we suggest that joint influences be sorted from largest weight value to smallest. The \ref UsdSkelSortInfluences utility can be used to do so. UsdSkel does not currently *require* sorted joint influences, but may later add such restrictions, since they enable some skinning optimizations, such as allowing a skinning kernel to exit from a point-deformation loop early. \subsection UsdSkel_BindingAPI_GeomBindTransform BindingAPI: GeomBindTransform For skinning to apply correctly, the constant _primvars:skel:geomBindTransform_ primvar should be authored on each skinnable primitive, using the UsdSkelBindingAPI. This primvar stores the world space transform of a skinned primitive at bind time. When skinning is applied, points of each skinnable primitive are trasnformed by their _geomBindTransform_ into bind space, after which joint transforms are applied, placing the result in either _skeleton space_ or _world space_. When a primitive is skinned, any transform on the prim authored by way of the typical UsdGeomXformable schema has **no effect** on the rendered results. Skinned geometry primitives are rendered in _skeleton space_, rather than being transformed back into local gprim space. This avoids double-transform problems that can otherwise occur, for example, if an ancestor of both a skinnable primitive and its driving Skeleton is moved. \subsection UsdSkel_BindingAPI_BlendShapes BindingAPI: Binding Blend Shapes UsdSkel decouples the encoding of blend shape animations from the description of how those animations map to skinnable primitives. This has numerous advantages, such as allowing the set of primitives skinned by a particular \ref UsdSkel_Term_SkeletonInstance "Skeleton Instance" to be swapped out -- via variants or other composition features -- with a different set of skinnable primitives, holding different blend shapes. This decoupling also means that an existing blend shape animation is not necessarily invalidated by asset changes that alter the set of shapes defined for a character. Given a skinnable primitive, the _skel:blendShapes_ and _skel:blendShapeTargets_ properties of the UsdSkelBindingAPI specify a mapping from the animation of the bound \ref UsdSkel_Term_SkeletonInstance "Skeleton Instance" to different skinnable primitives. Note that because blend shapes are usually tightly coupled with individual geometric primitives, whereas other properties of UsdSkelBindingAPI are hierarchically inherited, these blendshape-related properties are *not* inherited from ancestor primitives in namespace, and are relevant only when specified directly on primitives. To bind blend shapes, the _skel:blendShapeTargets_ rel should be created, and set to target UsdSkelBlendShape primitives, which define each shape. Additionally, the _skel:blendShapes_ array should also be defined, providing a unique token per bound blend shape. For example: \code def Skeleton "Skel" {} def SkelAnimation "Anim" { uniform token[] blendShapes = ["A","B","C","D"] float[] blendShapeWeights = [1,0.75,0,0] } def Mesh "Mesh { def BlendShape "Foo" {} def BlendShape "Bar" {} uniform token[] skel:blendShapes = ["B", "A"] rel skel:blendShapeTargets = [, ] rel skel:skeleton = rel skel:animationSource = } \endcode In the above example, note that the `` primitive specifies more blend shapes than are actually used on ``. This is because an animation source is providing animation data for a **complete model** (I.e., multiple geometric primitives). The _skel:blendShape_ attribute, as defined on ``, provides a mapping between the _blendShapeWeights_ animation data on ` -- which holds weight animation for multiple geometric primitives. The set of blend shape targets specified by the _skel:blendShapeTargets_ rel identifies, for each mapped blend shape token in _skel:blendShapes_, the target UsdSkelBlendShape primitive to which animation data should apply. From the example above, shape `` is using shapes `['B', 'A']` (in that order). First we map the _blendShapeWeights_ from the ordering specified by `` to the ordering on ``, which gives local weight values of [0.75,1.0]. For each token in ``, the `` rel identifies which UsdSkelBlendShape primitive that token maps to. So `B = ` and `A = `. From this, we find that we our final blend shapes and weights, as pairs, are `[(, 0.75), (, 1.0)`. */