Started working on small glTF skinning example tutorial/readme

This commit is contained in:
Sascha Willems 2020-05-26 08:13:47 +02:00
parent 5fcb480187
commit ec023cf581
5 changed files with 130 additions and 26 deletions

View file

@ -0,0 +1,118 @@
# glTF vertex skinning
<img src="../../screenshots/gltf_skinning.jpg" height="256px">
## Synopsis
Renders an animated glTF model with vertex skinning. The sample is based on the [glTF scene](../gltfscene) sample, and adds data structures, functions and shaders required to apply vertex skinning to a mesh.
## Description
This example demonstrates how to load and use the data structures required for animating a mesh with vertex skinning.
Vertex skinning is a technique that uses per-vertex weights based on the current pose of a skeleton made up of bones.
Animations then are applied to those bones instead and during rendering the matrices of those bones along with the vertex weights are used to calculate the final vertex positions.
A good glTF skinning tutorial can be found [here](https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_020_Skins.md), so this readme only gives a coarse overview.
## Points of interest
### Data structures
Several new data structures are required for doing animations with vertex skinning. The [official glTF spec](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skinned-mesh-attributes) has the details on those.
#### Node additions
```cpp
struct Node {
...
// Matrix components are stored separately as they are affected by animations
glm::vec3 translation{};
glm::vec3 scale{ 1.0f };
glm::quat rotation{};
// Index of the skin for this node
int32_t skin = -1;
// Gets the current local matrix based on translation, rotation and scale, which can all be affected by animations
glm::mat4 getLocalMatrix();
};
```
The node now also stores the matrix components (```translation```, ```rotation``` ,```scale```) as they can be independently influenced.
The ```skin``` member is the index of the skin (see below) that is applied to this node.
A new function called ```getLocalMatrix``` is introduced that calculates the local matrix from the initial one and the current components.
#### Vertex additions
```cpp
struct Vertex {
...
glm::vec4 jointIndices;
glm::vec4 jointWeights;
};
```
To calculate the final matrix to be applied to the vertex we now pass the indices of the joints (see below) and the weights of those, which determines how strongly this vertex is influenced by the joint. glTF support at max. four indices and weights per joint, so we pass them as four-component vectors.
@todo: Show loading of data? separate chapter?
#### Skin
[glTF spec chapter on skins](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins)
```cpp
struct Skin {
std::string name;
Node* skeletonRoot = nullptr;
std::vector<glm::mat4> inverseBindMatrices;
std::vector<Node*> joints;
// The join matrices for this skin are stored in an shader storage buffer
std::vector<glm::mat4> jointMatrices;
vks::Buffer ssbo;
VkDescriptorSet descriptorSet;
};
```
@todo: text
#### Animations
[glTF spec chapter on animations](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations)
##### Animation sampler
```cpp
struct AnimationSampler {
std::string interpolation;
std::vector<float> inputs;
std::vector<glm::vec4> outputsVec4;
};
```
The animation sampler contains the key frame data read from a buffer using an accessor (@todo: document loading) and the way the key frame is interpolated. This can be ```LINEAR```, which is just a simple linear interpolation over time, ```STEP```, which remains constant until the next key frame is reached, and ```CUBICSPLINE``` which uses a cubic spline with tangents for calculating the interpolated key frames. This is a bit more complex and separately documented in this [glTF spec chapter](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#appendix-c-spline-interpolation).
##### Animation channel
```cpp
struct AnimationChannel {
std::string path;
Node* node;
uint32_t samplerIndex;
};
```
The animation channel connects the node with a key frame specified by an animation sampler with the ```path``` member specifying the node property to animate, which is either ```translation```, ```rotation```, ```scale``` or ```weights```. The latter one refers to morph targets and not vertex weights (for skinning) and is not used in this sample.
##### Animation
```cpp
struct Animation {
std::string name;
std::vector<AnimationSampler> samplers;
std::vector<AnimationChannel> channels;
float start = std::numeric_limits<float>::max();
float end = std::numeric_limits<float>::min();
float currentTime = 0.0f;
};
```
@todo: text

View file

@ -7,18 +7,14 @@
*/ */
/* /*
* Shows how to load and display a simple scene from a glTF file * Shows how to load and display an animated scene from a glTF file using vertex skinning
* Note that this isn't a complete glTF loader and only basic functions are shown here * See the accompanying README.md for a short tutorial on the data structures and functions required for vertex skinning
* This means no complex materials, no animations, no skins, etc.
* For details on how glTF 2.0 works, see the official spec at https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
* *
* Other samples will load models using a dedicated model loader with more features (see base/VulkanglTFModel.hpp) * For details on how glTF 2.0 works, see the official spec at https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
* *
* If you are looking for a complete glTF implementation, check out https://github.com/SaschaWillems/Vulkan-glTF-PBR/ * If you are looking for a complete glTF implementation, check out https://github.com/SaschaWillems/Vulkan-glTF-PBR/
*/ */
// @todo: add link to https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_020_Skins.md
#include "gltfskinning.h" #include "gltfskinning.h"
/* /*
@ -460,7 +456,6 @@ void VulkanglTFModel::updateJoints(VulkanglTFModel::Node* node) {
glm::mat4 inverseTransform = glm::inverse(m); glm::mat4 inverseTransform = glm::inverse(m);
Skin skin = skins[node->skin]; Skin skin = skins[node->skin];
size_t numJoints = (uint32_t)skin.joints.size(); size_t numJoints = (uint32_t)skin.joints.size();
// @todo: linkt to skin spec gltf https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_020_Skins.md#the-joint-matrices
std::vector<glm::mat4> jointMatrices(numJoints); std::vector<glm::mat4> jointMatrices(numJoints);
// @todo: bail out if model has more joints than shader can handle // @todo: bail out if model has more joints than shader can handle
for (size_t i = 0; i < numJoints; i++) { for (size_t i = 0; i < numJoints; i++) {

View file

@ -7,21 +7,14 @@
*/ */
/* /*
* This is based on the glTF scene example and only the parts that show added functionality are commented * Shows how to load and display an animated scene from a glTF file using vertex skinning
* See the accompanying README.md for a short tutorial on the data structures and functions required for vertex skinning
* @todo: Rework comments
* Shows how to load and display a simple scene from a glTF file
* Note that this isn't a complete glTF loader and only basic functions are shown here
* This means no complex materials, no animations, no skins, etc.
* For details on how glTF 2.0 works, see the official spec at https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
* *
* Other samples will load models using a dedicated model loader with more features (see base/VulkanglTFModel.hpp) * For details on how glTF 2.0 works, see the official spec at https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
* *
* If you are looking for a complete glTF implementation, check out https://github.com/SaschaWillems/Vulkan-glTF-PBR/ * If you are looking for a complete glTF implementation, check out https://github.com/SaschaWillems/Vulkan-glTF-PBR/
*/ */
// @todo: add link to https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_020_Skins.md
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -126,7 +119,6 @@ public:
/* /*
Skin structure Skin structure
Spec: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins
*/ */
struct Skin { struct Skin {
@ -143,21 +135,20 @@ public:
/* /*
Animation related structures Animation related structures
Spec: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations
*/ */
struct AnimationChannel {
std::string path;
Node* node;
uint32_t samplerIndex;
};
struct AnimationSampler { struct AnimationSampler {
std::string interpolation; std::string interpolation;
std::vector<float> inputs; std::vector<float> inputs;
std::vector<glm::vec4> outputsVec4; std::vector<glm::vec4> outputsVec4;
}; };
struct AnimationChannel {
std::string path;
Node* node;
uint32_t samplerIndex;
};
struct Animation { struct Animation {
std::string name; std::string name;
std::vector<AnimationSampler> samplers; std::vector<AnimationSampler> samplers;

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB