Функция загрузчик с анимациями
This commit is contained in:
parent
a0a19fee55
commit
6811650249
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "Model.h"
|
||||
#include "Camera.h"
|
||||
#include "Animation.h"
|
||||
|
||||
#include <GLM/gtc/type_ptr.hpp>
|
||||
#include <GLM/gtc/quaternion.hpp>
|
||||
|
@ -33,7 +34,9 @@ class Scene
|
|||
std::list<Node> nodes; // Список пустых узлов
|
||||
std::list<Model> models; // Список моделей для рендера
|
||||
std::list<Camera> cameras; // Список камер
|
||||
|
||||
|
||||
std::vector<Animation> animations; // Список анимаций
|
||||
std::map<std::string, size_t> animation_names; // Имя анимации - индекс
|
||||
protected:
|
||||
void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
|
||||
template <class T>
|
||||
|
|
169
src/Scene.cpp
169
src/Scene.cpp
|
@ -20,7 +20,7 @@ Scene& Scene::operator=(const Scene& other)
|
|||
nodes = other.nodes;
|
||||
models = other.models;
|
||||
cameras = other.cameras;
|
||||
|
||||
|
||||
rebuld_tree(other);
|
||||
|
||||
return *this;
|
||||
|
@ -29,7 +29,7 @@ Scene& Scene::operator=(const Scene& other)
|
|||
// Рендер сцены
|
||||
void Scene::render(ShaderProgram &shaderProgram, UBO &material_buffer)
|
||||
{
|
||||
for (auto & model : models)
|
||||
for (auto & model : models)
|
||||
model.render(shaderProgram, material_buffer);
|
||||
}
|
||||
|
||||
|
@ -277,6 +277,55 @@ void collectGLTFnodes(int node_id, std::vector<int> &nodes, tinygltf::Model &in_
|
|||
collectGLTFnodes(child, nodes, in_model);
|
||||
}
|
||||
|
||||
float getFloatChannelOutput(int type, const void* array, int index)
|
||||
{
|
||||
float result;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
{
|
||||
const char* bvalues = reinterpret_cast<const char*> (array);
|
||||
result = bvalues[index] / 127.0;
|
||||
if (result < -1.0)
|
||||
result = -1.0;
|
||||
|
||||
break;
|
||||
}
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
{
|
||||
const unsigned char* ubvalues = reinterpret_cast<const unsigned char*> (array);
|
||||
result = ubvalues[index] / 255.0;
|
||||
|
||||
break;
|
||||
}
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
{
|
||||
const short* svalues = reinterpret_cast<const short*> (array);
|
||||
result = svalues[index] / 32767.0;
|
||||
if (result < -1.0)
|
||||
result = -1.0;
|
||||
|
||||
break;
|
||||
}
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
{
|
||||
const unsigned short* usvalues = reinterpret_cast<const unsigned short*>(array);
|
||||
result = usvalues[index] / 65535.0;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
const float* fvalues = reinterpret_cast<const float*> (array);
|
||||
result = fvalues[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Scene loadGLTFtoScene(std::string filename)
|
||||
{
|
||||
Scene result;
|
||||
|
@ -302,7 +351,7 @@ Scene loadGLTFtoScene(std::string filename)
|
|||
auto &buffer = in_model.buffers[bufferView.buffer];
|
||||
BOs.push_back(BO((BUFFER_TYPE)bufferView.target, buffer.data.data() + bufferView.byteOffset, bufferView.byteLength));
|
||||
}
|
||||
|
||||
|
||||
// Адрес директории для относительных путей изображений
|
||||
std::string dir = filename.substr(0, filename.find_last_of("/\\") + 1);
|
||||
// Загрузим используемые текстуры
|
||||
|
@ -343,7 +392,7 @@ Scene loadGLTFtoScene(std::string filename)
|
|||
std::vector<Node *> pNodes(in_model.nodes.size(), NULL);
|
||||
// Индексы родителей (-1 - корневой узел сцены)
|
||||
std::vector<int> parents_id(in_model.nodes.size(), -1);
|
||||
|
||||
|
||||
// Цикл по сценам
|
||||
for (auto &scene : in_model.scenes)
|
||||
{
|
||||
|
@ -488,7 +537,7 @@ Scene loadGLTFtoScene(std::string filename)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
result.models.push_back(model); // Добавляем к сцене
|
||||
// Если ещё не сохранили
|
||||
if (!pNodes[node_id])
|
||||
|
@ -526,6 +575,116 @@ Scene loadGLTFtoScene(std::string filename)
|
|||
}
|
||||
}
|
||||
|
||||
// Цикл по анимациям
|
||||
for (auto &in_animation : in_model.animations)
|
||||
{
|
||||
Animation animation;
|
||||
|
||||
for (auto &in_channel : in_animation.channels)
|
||||
{
|
||||
Channel channel;
|
||||
|
||||
channel.target = pNodes[in_channel.target_node]; // Анимируемый узел
|
||||
// Анимируемый параметр
|
||||
if (in_channel.target_path == "translation")
|
||||
channel.path = POSITION;
|
||||
else
|
||||
if (in_channel.target_path == "rotation")
|
||||
channel.path = ROTATION;
|
||||
else
|
||||
if (in_channel.target_path == "scale")
|
||||
channel.path = SCALE;
|
||||
else
|
||||
throw std::runtime_error("Неподдерживаемый параметр анимации");
|
||||
|
||||
|
||||
// Получение сэмплера для канала
|
||||
const auto& sampler = in_animation.samplers[in_channel.sampler];
|
||||
|
||||
// Тип интерполяции
|
||||
if (sampler.interpolation == "LINEAR")
|
||||
channel.interpolation = LINEAR;
|
||||
else
|
||||
if (sampler.interpolation == "STEP")
|
||||
channel.interpolation = STEP;
|
||||
else
|
||||
if (sampler.interpolation == "CUBICSPLINE")
|
||||
channel.interpolation = CUBICSPLINE;
|
||||
else
|
||||
throw std::runtime_error("Неподдерживаемый тип интерполяции");
|
||||
|
||||
// Получение временных меток ключевых кадров (Input Accessor)
|
||||
const auto& inputAccessor = in_model.accessors[sampler.input];
|
||||
const auto& inputBufferView = in_model.bufferViews[inputAccessor.bufferView];
|
||||
const auto& inputBuffer = in_model.buffers[inputBufferView.buffer];
|
||||
const float* keyframeTimes = reinterpret_cast<const float*>(&inputBuffer.data[inputBufferView.byteOffset + inputAccessor.byteOffset]);
|
||||
// Скопируем через метод insert
|
||||
channel.timestamps.insert(channel.timestamps.end(), keyframeTimes, keyframeTimes + inputAccessor.count);
|
||||
|
||||
// Получение данных ключевых кадров (Output Accessor)
|
||||
const auto& outputAccessor = in_model.accessors[sampler.output];
|
||||
const auto& outputBufferView = in_model.bufferViews[outputAccessor.bufferView];
|
||||
const auto& outputBuffer = in_model.buffers[outputBufferView.buffer];
|
||||
|
||||
// Зарезервируем место
|
||||
channel.values.resize(inputAccessor.count);
|
||||
if (channel.interpolation == CUBICSPLINE)
|
||||
channel.tangents.resize(inputAccessor.count);
|
||||
|
||||
// Проверим формат и запишем данные с учетом преобразования
|
||||
if (( (channel.path == POSITION || channel.path == SCALE)
|
||||
&& outputAccessor.type == TINYGLTF_TYPE_VEC3) // == 3
|
||||
|| ( channel.path == ROTATION
|
||||
&& outputAccessor.type == TINYGLTF_TYPE_VEC4) // == 4
|
||||
)
|
||||
{
|
||||
// Цикл по ключевым кадрам
|
||||
for (int keyframe = 0; keyframe < inputAccessor.count; keyframe++)
|
||||
// Цикл по компонентам
|
||||
for (int component = 0; component < outputAccessor.type; component++)
|
||||
{
|
||||
// Для CUBICSPLINE интерполяции требуется дополнительно списать касательные
|
||||
if (channel.interpolation == CUBICSPLINE)
|
||||
{
|
||||
if (channel.path == ROTATION)
|
||||
{
|
||||
channel.tangents[keyframe].in. quat[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3 + component);
|
||||
channel.values [keyframe]. quat[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3 + outputAccessor.type + component);
|
||||
channel.tangents[keyframe].out.quat[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3 + outputAccessor.type*2 + component);
|
||||
}
|
||||
else
|
||||
{
|
||||
channel.tangents[keyframe].in. vec3[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3 + component);
|
||||
channel.values [keyframe]. vec3[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3 + outputAccessor.type + component);
|
||||
channel.tangents[keyframe].out.vec3[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3 + outputAccessor.type*2 + component);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (channel.path == ROTATION)
|
||||
channel.values [keyframe]. quat[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type + component);
|
||||
else
|
||||
channel.values [keyframe]. vec3[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type + component);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Неподдерживаемые данные анимации");
|
||||
|
||||
animation.channels.push_back(channel);
|
||||
}
|
||||
|
||||
// Имя анимации
|
||||
// Если имени нет - сгенерируем
|
||||
if (in_animation.name.empty())
|
||||
{
|
||||
std::string name = filename + std::to_string(result.animations.size());
|
||||
result.animation_names[name] = result.animations.size();
|
||||
}
|
||||
else
|
||||
result.animation_names[in_animation.name] = result.animations.size();
|
||||
|
||||
result.animations.push_back(animation);
|
||||
}
|
||||
|
||||
// Зададим трансформацию и родителей для узлов
|
||||
// Цикл по всем индексам узлов
|
||||
for (int node_id = 0; node_id < in_model.nodes.size(); node_id++)
|
||||
|
|
Loading…
Reference in New Issue