-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGltfModel.h
More file actions
448 lines (378 loc) · 11.3 KB
/
GltfModel.h
File metadata and controls
448 lines (378 loc) · 11.3 KB
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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
#pragma once
#define GLM_ENABLE_EXPERIMENTAL
#include<iostream>
#include<vector>
#include<array>
#include<map>
#include<glm/glm.hpp>
#include <glm/gtx/hash.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include"Material.h"
#include"StructList.h"
#include"GpuBufferFactory.h"
#include"DescriptorSetFactory.h"
struct Vertex;
struct Primitive;
struct Mesh;
struct Skin;
struct GltfNode;
struct Animation;
struct BoundingBox;
//AABB用の構造体
struct BoundingBox
{
glm::vec3 min;
glm::vec3 max;
bool valid = false;
BoundingBox() {};
BoundingBox(glm::vec3 min, glm::vec3 max) : min(min), max(max) {
};
BoundingBox getAABB(glm::mat4 m) {
glm::vec3 min = glm::vec3(m[3]);
glm::vec3 max = min;
glm::vec3 v0, v1;
glm::vec3 right = glm::vec3(m[0]);
v0 = right * this->min.x;
v1 = right * this->max.x;
min += glm::min(v0, v1);
max += glm::max(v0, v1);
glm::vec3 up = glm::vec3(m[1]);
v0 = up * this->min.y;
v1 = up * this->max.y;
min += glm::min(v0, v1);
max += glm::max(v0, v1);
glm::vec3 back = glm::vec3(m[2]);
v0 = back * this->min.z;
v1 = back * this->max.z;
min += glm::min(v0, v1);
max += glm::max(v0, v1);
return BoundingBox(min, max);
}
};
//頂点をまとめる用のプリミティブ
//プリミティブ単位でマテリアルを指定される
struct Primitive
{
int primitiveIndex;//番号
int firstIndex;//インデックスバッファ内のこのプリミティブのインデックスの開始位置
int indexCount;//プリミティブのインデックスの数
int vertexCount;//頂点の数
int materialIndex;//このプリミティブが持つマテリアルの番号
bool hasIndices;
BoundingBox bb;//aabb
Primitive(int primitiveIndex,int firstIndex, int indexCount, int vertexCount,int materialIndex)
: primitiveIndex(primitiveIndex),firstIndex(firstIndex), indexCount(indexCount), vertexCount(vertexCount), materialIndex(materialIndex) {
hasIndices = indexCount > 0;
}
void setBoundingBox(glm::vec3 min, glm::vec3 max)
{
bb.min = min;
bb.max = max;
bb.valid = true;
}
};
//スケルトンの構造体
struct Skin
{
std::string name;
//スキンのルートノードの配列上の位置
int skinRootNodeOffset;
std::vector<glm::mat4> inverseBindMatrices;
std::vector<int> jointNodeOffset;
};
//プリミティブをひとまとめにしたもの
struct Mesh
{
//Meshの持つ頂点をバッファから参照するためのindex
uint32_t meshIndex;
std::vector<Vertex> vertices;//頂点配列
std::vector<uint32_t> indices;//インデックス配列
std::vector<Primitive> primitives;
glm::vec3 min;
glm::vec3 max;
};
//ノードごとのトランスフォームを記録
struct NodeTransform
{
std::vector<glm::vec3> translation;
std::vector<glm::quat> rotation;
std::vector<glm::vec3> scale;
std::vector<glm::mat4> matrix;
std::vector<glm::mat4> nodeTransform;
void init()
{
translation.clear();
rotation.clear();
scale.clear();
matrix.clear();
nodeTransform.clear();
}
void setNodeCount(size_t nodeCount)
{
translation.resize(nodeCount);
rotation.resize(nodeCount);
scale.resize(nodeCount);
matrix.resize(nodeCount);
nodeTransform.resize(nodeCount);
}
void resetMat()
{
std::fill(translation.begin(), translation.end(), glm::vec3(0.0f));
std::fill(rotation.begin(), rotation.end(), glm::quat());
std::fill(scale.begin(), scale.end(), glm::vec3(1.0f));
std::fill(matrix.begin(), matrix.end(), glm::mat4(1.0f));
std::fill(nodeTransform.begin(), nodeTransform.end(), glm::mat4(-1000.0f));
}
};
struct GltfNode
{
//このノードが配置されている配列上の位置
size_t offset;
//このindexはtinygltf上の番号
uint32_t index;
//parentIndex実際の配列上の親ノードの位置
int parentIndex;
glm::mat4 matrix;//ローカル空間へ変換用行列
std::string name;
Mesh mesh;
Skin skin;
int skinIndex = -1;
int globalHasSkinNodeIndex = 0;
int firstIndex;
int indexCount;
DescriptorInfo descriptorInfo;
BoundingBox bvh;
GltfNode()
{
offset = 0;
matrix = glm::mat4(1.0f);
index = 0;
parentIndex = -1;
}
~GltfNode()
{
}
void setLocalMatrix(NodeTransform& nodeTransform)
{
//このノード個別の行列
glm::mat4 localMatrix = glm::translate(glm::mat4(1.0f), nodeTransform.translation[offset]) *
glm::mat4(nodeTransform.rotation[offset]) * glm::scale(glm::mat4(1.0f), nodeTransform.scale[offset]) * matrix;
glm::mat4 parentMatrix = glm::mat4(1.0f);
if (parentIndex > -1)
{
parentMatrix = nodeTransform.nodeTransform[parentIndex];
}
nodeTransform.nodeTransform[offset] = parentMatrix * localMatrix;
nodeTransform.matrix[offset] = matrix;
}
//このノードが所属するスケルトンのアニメーション行列を計算する
void update(NodeTransform& nodeTransform, std::array<glm::mat4, 128>& jointMatrices, size_t& updatedIndex)
{
glm::mat4 m = nodeTransform.nodeTransform[offset];
//ボーンの行列の更新
glm::mat4 inverseTransform = glm::inverse(m);
size_t numJoints = std::min((uint32_t)skin.jointNodeOffset.size(), 128u);
if (numJoints <= updatedIndex)
{
return;
}
for (size_t i = 0; i < numJoints; i++)
{
glm::mat4 jointMat = nodeTransform.nodeTransform[skin.jointNodeOffset[i]] * skin.inverseBindMatrices[i];
jointMat = inverseTransform * jointMat;
jointMatrices[i] = jointMat;
}
//計算し終えたジョイントを記録して、メモ化を行い、同じジョイントの行列を計算しない
updatedIndex = numJoints;
}
int getJointCount() const
{
if (skin.name.size() == 0)
{
return 0;
}
return std::min((uint32_t)skin.jointNodeOffset.size(), 128u);
}
};
//アニメーションのキーの持つ行列が移動、回転、拡大のどれに関するか示す
struct AnimationChannel {
enum PathType { TRANSLATION, ROTATION, SCALE };
PathType path;
size_t nodeOffset;
uint32_t samplerIndex;
};
//アニメーションの保管に関する構造体
struct AnimationSampler {
enum InterpolationType { LINEAR, STEP, CUBICSPLINE };
InterpolationType interpolation;
std::vector<float> inputs;
std::vector<glm::vec4> outputsVec4;
std::vector<float> outputs;
glm::vec4 cubicSplineInterpolation(size_t index, double time, uint32_t stride)
{
float delta = inputs[index + 1] - inputs[index];
float t = static_cast<float>((time - inputs[index]) / delta);
const size_t current = index * stride * 3;
const size_t next = (index + 1) * stride * 3;
const size_t A = 0;
const size_t V = stride * 1;
const size_t B = stride * 2;
float t2 = powf(t, 2);
float t3 = powf(t, 3);
glm::vec4 pt{ 0.0f };
for (uint32_t i = 0; i < stride; i++) {
float p0 = outputs[current + i + V]; // starting point at t = 0
float m0 = delta * outputs[current + i + A]; // scaled starting tangent at t = 0
float p1 = outputs[next + i + V]; // ending point at t = 1
float m1 = delta * outputs[next + i + B]; // scaled ending tangent at t = 1
pt[i] = ((2.f * t3 - 3.f * t2 + 1.f) * p0) + ((t3 - 2.f * t2 + t) * m0) + ((-2.f * t3 + 3.f * t2) * p1) + ((t3 - t2) * m0);
}
return pt;
}
//平行移動の補間
glm::vec3 translate(size_t index, double time)
{
switch (interpolation) {
case AnimationSampler::InterpolationType::LINEAR: {
float u = static_cast<float>(std::max(0.0, time - inputs[index]) / (inputs[index + 1] - inputs[index]));
return glm::mix(outputsVec4[index], outputsVec4[index + 1], u);
}
case AnimationSampler::InterpolationType::STEP: {
return outputsVec4[index];
}
case AnimationSampler::InterpolationType::CUBICSPLINE: {
return cubicSplineInterpolation(index, time, 3);
}
}
return glm::vec3(0.0f);
}
//拡大の補間
glm::vec3 scale(size_t index, double time)
{
switch (interpolation) {
case AnimationSampler::InterpolationType::LINEAR: {
float u = static_cast<float>(std::max(0.0, time - inputs[index]) / (inputs[index + 1] - inputs[index]));
return glm::mix(outputsVec4[index], outputsVec4[index + 1], u);
}
case AnimationSampler::InterpolationType::STEP: {
return outputsVec4[index];
}
case AnimationSampler::InterpolationType::CUBICSPLINE: {
return cubicSplineInterpolation(index, time, 3);
}
}
return glm::vec3(1.0f);
}
//回転の補間
glm::quat rotate(size_t index, double time)
{
switch (interpolation) {
case AnimationSampler::InterpolationType::LINEAR: {
float u = static_cast<float>(std::max(0.0, time - inputs[index]) / (inputs[index + 1] - inputs[index]));
glm::quat q1;
q1.x = outputsVec4[index].x;
q1.y = outputsVec4[index].y;
q1.z = outputsVec4[index].z;
q1.w = outputsVec4[index].w;
glm::quat q2;
q2.x = outputsVec4[index + 1].x;
q2.y = outputsVec4[index + 1].y;
q2.z = outputsVec4[index + 1].z;
q2.w = outputsVec4[index + 1].w;
return glm::normalize(glm::slerp(q1, q2, u));
}
case AnimationSampler::InterpolationType::STEP: {
glm::quat q1;
q1.x = outputsVec4[index].x;
q1.y = outputsVec4[index].y;
q1.z = outputsVec4[index].z;
q1.w = outputsVec4[index].w;
return q1;
}
case AnimationSampler::InterpolationType::CUBICSPLINE: {
glm::vec4 rot = cubicSplineInterpolation(index, time, 4);
glm::quat q;
q.x = rot.x;
q.y = rot.y;
q.z = rot.z;
q.w = rot.w;
return glm::normalize(q);
}
}
return glm::quat();
}
};
//アニメーション全体の構造体
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();//終了時間
};
//読み込んだgltfモデル全体のクラス
class GltfModel
{
private:
//gltfモデルの頂点関連用のバッファ
std::vector<std::shared_ptr<GpuBuffer>> vertBuffer;
std::vector<std::shared_ptr<GpuBuffer>> indeBuffer;
//ディスクリプタセット
std::vector<std::shared_ptr<DescriptorSet>> descriptorSet;
std::shared_ptr<GpuBufferFactory> bufferFactory;
std::shared_ptr<DescriptorSetLayoutFactory> layoutFactory;
std::shared_ptr<DescriptorSetFactory> descriptorSetFactory;
public:
GltfModel(std::shared_ptr<GpuBufferFactory> bf
,std::shared_ptr<DescriptorSetLayoutFactory> layout
,std::shared_ptr<DescriptorSetFactory> desc)
{
this->meshCount = 0;
this->primitiveCount = 0;
this->setup = false;
this->jointNum = 0;
bufferFactory = bf;
layoutFactory = layout;
descriptorSetFactory = desc;
}
~GltfModel();
std::vector<GltfNode> nodes;
void setPointBufferNum();
bool setup;
//メッシュの数、プリミティブの数、ジョイントの数、Modelクラスに設定した際の、バッファの作成時に利用
int meshCount;
int primitiveCount;
int jointNum;
int vertexNum;
int indexNum;
//ノードの個数
int nodeCount;
//アニメーションの名前をキーとして、アニメーションを記録
std::unordered_map<std::string,Animation> animations;
//スケルトン 通常は一つ
std::vector<Skin> skins;
//同じくマテリアルデータ Primitive構造体のmaterialIndexから指定される
std::vector<std::shared_ptr<Material>> materials;
BoundingBox boundingBox;
glm::vec3 initPoseMin, initPoseMax;
int nodeFromIndex(const int& index);
int findNode(const int& index);
void createBuffer();
void createDescriptorSet(std::vector<std::shared_ptr<DescriptorSet>>& descriptorSet);
std::shared_ptr<GpuBuffer> getVertBuffer(int index)
{
return vertBuffer[index];
}
std::shared_ptr<GpuBuffer> getIndeBuffer(int index)
{
return indeBuffer[index];
}
//アニメーションの各ノードの更新処理
void updateAllNodes(NodeTransform& nodeTransform
, std::vector<std::array<glm::mat4, 128>>& jointMatrices, size_t& updatedIndex);
//アニメーションの長さを取得
float animationDuration(std::string animationName);
//指定したアニメーションの行列を取得
void updateAnimation(double animationTime, std::string animationName, NodeTransform& nodeTransform
, std::vector<std::array<glm::mat4, 128>>& jointMatrices);
};