-
Notifications
You must be signed in to change notification settings - Fork 2k
/
gltfskinning.h
235 lines (202 loc) · 5.78 KB
/
gltfskinning.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
* Vulkan Example - glTF skinned animation
*
* Copyright (C) 2020-2024 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
/*
* 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
*
* 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/
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define TINYGLTF_NO_STB_IMAGE_WRITE
#ifdef VK_USE_PLATFORM_ANDROID_KHR
# define TINYGLTF_ANDROID_LOAD_FROM_ASSETS
#endif
#include "tiny_gltf.h"
#include "vulkanexamplebase.h"
#include <vulkan/vulkan.h>
// Contains everything required to render a glTF model in Vulkan
// This class is heavily simplified (compared to glTF's feature set) but retains the basic glTF structure
class VulkanglTFModel
{
public:
vks::VulkanDevice *vulkanDevice;
VkQueue copyQueue;
/*
Base glTF structures, see gltfscene sample for details
*/
struct Vertices
{
VkBuffer buffer;
VkDeviceMemory memory;
} vertices;
struct Indices
{
int count;
VkBuffer buffer;
VkDeviceMemory memory;
} indices;
struct Node;
struct Material
{
glm::vec4 baseColorFactor = glm::vec4(1.0f);
uint32_t baseColorTextureIndex;
};
struct Image
{
vks::Texture2D texture;
VkDescriptorSet descriptorSet;
};
struct Texture
{
int32_t imageIndex;
};
struct Primitive
{
uint32_t firstIndex;
uint32_t indexCount;
int32_t materialIndex;
};
struct Mesh
{
std::vector<Primitive> primitives;
};
struct Node
{
Node * parent;
uint32_t index;
std::vector<Node *> children;
Mesh mesh;
glm::vec3 translation{};
glm::vec3 scale{1.0f};
glm::quat rotation{};
int32_t skin = -1;
glm::mat4 matrix;
glm::mat4 getLocalMatrix();
};
struct Vertex
{
glm::vec3 pos;
glm::vec3 normal;
glm::vec2 uv;
glm::vec3 color;
glm::vec4 jointIndices;
glm::vec4 jointWeights;
};
/*
Skin structure
*/
struct Skin
{
std::string name;
Node * skeletonRoot = nullptr;
std::vector<glm::mat4> inverseBindMatrices;
std::vector<Node *> joints;
vks::Buffer ssbo;
VkDescriptorSet descriptorSet;
};
/*
Animation related structures
*/
struct AnimationSampler
{
std::string interpolation;
std::vector<float> inputs;
std::vector<glm::vec4> outputsVec4;
};
struct AnimationChannel
{
std::string path;
Node * node;
uint32_t samplerIndex;
};
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;
};
std::vector<Image> images;
std::vector<Texture> textures;
std::vector<Material> materials;
std::vector<Node *> nodes;
std::vector<Skin> skins;
std::vector<Animation> animations;
uint32_t activeAnimation = 0;
~VulkanglTFModel();
void loadImages(tinygltf::Model &input);
void loadTextures(tinygltf::Model &input);
void loadMaterials(tinygltf::Model &input);
Node * findNode(Node *parent, uint32_t index);
Node * nodeFromIndex(uint32_t index);
void loadSkins(tinygltf::Model &input);
void loadAnimations(tinygltf::Model &input);
void loadNode(const tinygltf::Node &inputNode, const tinygltf::Model &input, VulkanglTFModel::Node *parent, uint32_t nodeIndex, std::vector<uint32_t> &indexBuffer, std::vector<VulkanglTFModel::Vertex> &vertexBuffer);
glm::mat4 getNodeMatrix(VulkanglTFModel::Node *node);
void updateJoints(VulkanglTFModel::Node *node);
void updateAnimation(float deltaTime);
void drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node node);
void draw(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout);
};
class VulkanExample : public VulkanExampleBase
{
public:
bool wireframe = false;
struct ShaderData
{
vks::Buffer buffer;
struct Values
{
glm::mat4 projection;
glm::mat4 model;
glm::vec4 lightPos = glm::vec4(5.0f, 5.0f, 5.0f, 1.0f);
} values;
} shaderData;
VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE };
struct Pipelines
{
VkPipeline solid{ VK_NULL_HANDLE };
VkPipeline wireframe{ VK_NULL_HANDLE };
} pipelines;
struct DescriptorSetLayouts
{
VkDescriptorSetLayout matrices{ VK_NULL_HANDLE };
VkDescriptorSetLayout textures{ VK_NULL_HANDLE };
VkDescriptorSetLayout jointMatrices{ VK_NULL_HANDLE };
} descriptorSetLayouts;
VkDescriptorSet descriptorSet{ VK_NULL_HANDLE };
VulkanglTFModel glTFModel;
VulkanExample();
~VulkanExample();
void loadglTFFile(std::string filename);
virtual void getEnabledFeatures();
void buildCommandBuffers();
void loadAssets();
void setupDescriptors();
void preparePipelines();
void prepareUniformBuffers();
void updateUniformBuffers();
void prepare();
virtual void render();
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay);
};