186 lines
9.7 KiB
C++
186 lines
9.7 KiB
C++
//----------------------------------------------------------------------------//
|
|
// //
|
|
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
|
// and distributed under the MIT License (MIT). //
|
|
// //
|
|
// Copyright (c) Guillaume Blanc //
|
|
// //
|
|
// Permission is hereby granted, free of charge, to any person obtaining a //
|
|
// copy of this software and associated documentation files (the "Software"), //
|
|
// to deal in the Software without restriction, including without limitation //
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
|
// and/or sell copies of the Software, and to permit persons to whom the //
|
|
// Software is furnished to do so, subject to the following conditions: //
|
|
// //
|
|
// The above copyright notice and this permission notice shall be included in //
|
|
// all copies or substantial portions of the Software. //
|
|
// //
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
|
// DEALINGS IN THE SOFTWARE. //
|
|
// //
|
|
//----------------------------------------------------------------------------//
|
|
|
|
#ifndef OZZ_OZZ_GEOMETRY_RUNTIME_SKINNING_JOB_H_
|
|
#define OZZ_OZZ_GEOMETRY_RUNTIME_SKINNING_JOB_H_
|
|
|
|
#include "ozz/base/platform.h"
|
|
#include "ozz/base/span.h"
|
|
#include "ozz/geometry/runtime/export.h"
|
|
|
|
namespace ozz {
|
|
namespace math {
|
|
struct Float4x4;
|
|
}
|
|
namespace geometry {
|
|
|
|
// Provides per-vertex matrix palette skinning job implementation.
|
|
// Skinning is the process of creating the association of skeleton joints with
|
|
// some vertices of a mesh. Portions of the mesh's skin can normally be
|
|
// associated with multiple joints, each one having a weight. The sum of the
|
|
// weights for a vertex is equal to 1. To calculate the final position of the
|
|
// vertex, each joint transformation is applied to the vertex position, scaled
|
|
// by its corresponding weight. This algorithm is called matrix palette skinning
|
|
// because of the set of joint transformations (stored as transform matrices)
|
|
// form a palette for the skin vertex to choose from.
|
|
//
|
|
// This job iterates and transforms vertices (points and vectors) provided as
|
|
// input using the matrix palette skinning algorithm. The implementation
|
|
// supports any number of joints influences per vertex, and can transform one
|
|
// point (vertex position) and two vectors (vertex normal and tangent) per loop
|
|
// (aka vertex). It assumes bi-normals aren't needed as they can be rebuilt
|
|
// from the normal and tangent with a lower cost than skinning (a single cross
|
|
// product).
|
|
// Input and output buffers must be provided with a stride value (aka the
|
|
// number of bytes from a vertex to the next). This allows the job to support
|
|
// vertices packed as array-of-structs (array of vertices with positions,
|
|
// normals...) or struct-of-arrays (buffers of points, buffer of normals...).
|
|
// The skinning job optimizes every code path at maximum. The loop is indeed not
|
|
// the same depending on the number of joints influencing a vertex (or if there
|
|
// are normals to transform). To maximize performances, application should
|
|
// partition its vertices based on their number of joints influences, and call
|
|
// a different job for every vertices set.
|
|
// Joint matrices are accessed using the per-vertex joints indices provided as
|
|
// input. These matrices must be pre-multiplied with the inverse of the skeleton
|
|
// bind-pose matrices. This allows to transform vertices to joints local space.
|
|
// In case of non-uniform-scale matrices, the job proposes to transform vectors
|
|
// using an optional set of matrices, whose are usually inverse transpose of
|
|
// joints matrices (see http://www.glprogramming.com/red/appendixf.html). This
|
|
// code path is less efficient than the one without this matrices set, and
|
|
// should only be used when input matrices have non uniform scaling or shearing.
|
|
// The job does not owned the buffers (in/output) and will thus not delete them
|
|
// during job's destruction.
|
|
struct OZZ_GEOMETRY_DLL SkinningJob {
|
|
// Default constructor, initializes default values.
|
|
SkinningJob();
|
|
|
|
// Validates job parameters.
|
|
// Returns true for a valid job, false otherwise:
|
|
// - if any range is invalid. See each range description.
|
|
// - if normals are provided but positions aren't.
|
|
// - if tangents are provided but normals aren't.
|
|
// - if no output is provided while an input is. For example, if input normals
|
|
// are provided, then output normals must also.
|
|
bool Validate() const;
|
|
|
|
// Runs job's skinning task.
|
|
// The job is validated before any operation is performed, see Validate() for
|
|
// more details.
|
|
// Returns false if *this job is not valid.
|
|
bool Run() const;
|
|
|
|
// Number of vertices to transform. All input and output arrays must store at
|
|
// least this number of vertices.
|
|
int vertex_count;
|
|
|
|
// Maximum number of joints influencing each vertex. Must be greater than 0.
|
|
// The number of influences drives how joint_indices and joint_weights are
|
|
// sampled:
|
|
// - influences_count joint indices are red from joint_indices for each
|
|
// vertex.
|
|
// - influences_count - 1 joint weights are red from joint_weightrs for each
|
|
// vertex. The weight of the last joint is restored (weights are normalized).
|
|
int influences_count;
|
|
|
|
// Array of matrices for each joint. Joint are indexed through indices array.
|
|
span<const math::Float4x4> joint_matrices;
|
|
|
|
// Optional array of inverse transposed matrices for each joint. If provided,
|
|
// this array is used to transform vectors (normals and tangents), otherwise
|
|
// joint_matrices array is used.
|
|
// As explained here (http://www.glprogramming.com/red/appendixf.html) in the,
|
|
// red book, transforming normals requires a special attention when the
|
|
// transformation matrix has scaling or shearing. In this case the right
|
|
// transformation is done by the inverse transpose of the transformation that
|
|
// transforms points. Any rotation matrix is good though.
|
|
// These matrices are optional as they might by costly to compute, and also
|
|
// fall into a more costly code path in the skinning algorithm.
|
|
span<const math::Float4x4> joint_inverse_transpose_matrices;
|
|
|
|
// Array of joints indices. This array is used to indexes matrices in joints
|
|
// array.
|
|
// Each vertex has influences_max number of indices, meaning that the size of
|
|
// this array must be at least influences_max * vertex_count.
|
|
span<const uint16_t> joint_indices;
|
|
size_t joint_indices_stride;
|
|
|
|
// Array of joints weights. This array is used to associate a weight to every
|
|
// joint that influences a vertex. The number of weights required per vertex
|
|
// is "influences_max - 1". The weight for the last joint (for each vertex) is
|
|
// restored at runtime thanks to the fact that the sum of the weights for each
|
|
// vertex is 1.
|
|
// Each vertex has (influences_max - 1) number of weights, meaning that the
|
|
// size of this array must be at least (influences_max - 1)* vertex_count.
|
|
span<const float> joint_weights;
|
|
size_t joint_weights_stride;
|
|
|
|
// Input vertex positions array (3 float values per vertex) and stride (number
|
|
// of bytes between each position).
|
|
// Array length must be at least vertex_count * in_positions_stride.
|
|
span<const float> in_positions;
|
|
size_t in_positions_stride;
|
|
|
|
// Input vertex normals (3 float values per vertex) array and stride (number
|
|
// of bytes between each normal).
|
|
// Array length must be at least vertex_count * in_normals_stride.
|
|
span<const float> in_normals;
|
|
size_t in_normals_stride;
|
|
|
|
// Input vertex tangents (3 float values per vertex) array and stride (number
|
|
// of bytes between each tangent).
|
|
// Array length must be at least vertex_count * in_tangents_stride.
|
|
span<const float> in_tangents;
|
|
size_t in_tangents_stride;
|
|
|
|
// Output vertex positions (3 float values per vertex) array and stride
|
|
// (number of bytes between each position).
|
|
// Array length must be at least vertex_count * out_positions_stride.
|
|
span<float> out_positions;
|
|
size_t out_positions_stride;
|
|
|
|
// Output vertex normals (3 float values per vertex) array and stride (number
|
|
// of bytes between each normal).
|
|
// Note that output normals are not normalized by the skinning job. This task
|
|
// should be handled by the application, who knows if transform matrices have
|
|
// uniform scale, and if normals are re-normalized later in the rendering
|
|
// pipeline (shader vertex transformation stage).
|
|
// Array length must be at least vertex_count * out_normals_stride.
|
|
span<float> out_normals;
|
|
size_t out_normals_stride;
|
|
|
|
// Output vertex positions (3 float values per vertex) array and stride
|
|
// (number of bytes between each tangent).
|
|
// Like normals, Note that output tangents are not normalized by the skinning
|
|
// job.
|
|
// Array length must be at least vertex_count * out_tangents_stride.
|
|
span<float> out_tangents;
|
|
size_t out_tangents_stride;
|
|
};
|
|
} // namespace geometry
|
|
} // namespace ozz
|
|
#endif // OZZ_OZZ_GEOMETRY_RUNTIME_SKINNING_JOB_H_
|