Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
Ковалев Роман Евгеньевич | 7e94400f55 | |
Ковалев Роман Евгеньевич | 0f3f3e4c59 | |
Ковалев Роман Евгеньевич | 0511c6ca1e | |
Ковалев Роман Евгеньевич | b5572c5de0 | |
Ковалев Роман Евгеньевич | 6811650249 |
|
@ -13,8 +13,7 @@
|
||||||
],
|
],
|
||||||
"compilerPath": "C:/MinGW/bin/g++.exe",
|
"compilerPath": "C:/MinGW/bin/g++.exe",
|
||||||
"cStandard": "c11",
|
"cStandard": "c11",
|
||||||
"cppStandard": "c++11",
|
"cppStandard": "c++11"
|
||||||
"intelliSenseMode": "gcc-x86"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version": 4
|
"version": 4
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
#include "Camera.h"
|
#include "Camera.h"
|
||||||
|
#include "Animation.h"
|
||||||
|
|
||||||
#include <GLM/gtc/type_ptr.hpp>
|
#include <GLM/gtc/type_ptr.hpp>
|
||||||
#include <GLM/gtc/quaternion.hpp>
|
#include <GLM/gtc/quaternion.hpp>
|
||||||
|
@ -23,7 +24,7 @@ class Scene
|
||||||
Scene(const Scene ©); // Конструктор копирования
|
Scene(const Scene ©); // Конструктор копирования
|
||||||
Scene& operator=(const Scene& other); // Оператор присваивания
|
Scene& operator=(const Scene& other); // Оператор присваивания
|
||||||
|
|
||||||
void render(ShaderProgram &shaderProgram, UBO &material_buffer); // Рендер сцены
|
void render(ShaderProgram &shaderProgram, UBO &material_buffer, bool recalc_animations = false); // Рендер сцены
|
||||||
|
|
||||||
void set_group_id(GLuint64 id, GLuint etc = 0); // Изменение флага записи идентификатора для всех моделей
|
void set_group_id(GLuint64 id, GLuint etc = 0); // Изменение флага записи идентификатора для всех моделей
|
||||||
|
|
||||||
|
@ -33,13 +34,17 @@ class Scene
|
||||||
std::list<Node> nodes; // Список пустых узлов
|
std::list<Node> nodes; // Список пустых узлов
|
||||||
std::list<Model> models; // Список моделей для рендера
|
std::list<Model> models; // Список моделей для рендера
|
||||||
std::list<Camera> cameras; // Список камер
|
std::list<Camera> cameras; // Список камер
|
||||||
|
|
||||||
|
std::vector<Animation> animations; // Список анимаций
|
||||||
|
std::map<std::string, size_t> animation_names; // Имя анимации - индекс
|
||||||
protected:
|
protected:
|
||||||
void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
|
void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
|
||||||
template <class T>
|
template <class T>
|
||||||
void rebuild_Nodes_list(T& nodes, const Scene& from); // Перестройка узлов выбранного списка
|
void rebuild_Nodes_list(T& nodes, const Scene& from); // Перестройка узлов выбранного списка
|
||||||
template <class T>
|
template <class T>
|
||||||
void move_parent(Node& for_node, const std::list<T>& from_nodes, std::list<T>& this_nodes); // Сдвигает родителя узла между двумя списками при условии его принадлежности к оригинальному
|
void move_parent(Node& for_node, const std::list<T>& from_nodes, std::list<T>& this_nodes); // Сдвигает родителя узла между двумя списками при условии его принадлежности к оригинальному
|
||||||
|
template <class T>
|
||||||
|
void move_animation_target(Node*& target, const std::list<T>& from_nodes, std::list<T>& this_nodes); // Перестройка узлов анимации
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SCENE_H
|
#endif // SCENE_H
|
||||||
|
|
217
src/Scene.cpp
217
src/Scene.cpp
|
@ -8,7 +8,8 @@ Scene::Scene()
|
||||||
|
|
||||||
// Конструктор копирования
|
// Конструктор копирования
|
||||||
Scene::Scene(const Scene ©): root(copy.root),
|
Scene::Scene(const Scene ©): root(copy.root),
|
||||||
nodes(copy.nodes), models(copy.models), cameras(copy.cameras)
|
nodes(copy.nodes), models(copy.models), cameras(copy.cameras),
|
||||||
|
animations(copy.animations), animation_names(copy.animation_names)
|
||||||
{
|
{
|
||||||
rebuld_tree(copy);
|
rebuld_tree(copy);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +21,8 @@ Scene& Scene::operator=(const Scene& other)
|
||||||
nodes = other.nodes;
|
nodes = other.nodes;
|
||||||
models = other.models;
|
models = other.models;
|
||||||
cameras = other.cameras;
|
cameras = other.cameras;
|
||||||
|
animations = other.animations;
|
||||||
|
animation_names = other.animation_names;
|
||||||
|
|
||||||
rebuld_tree(other);
|
rebuld_tree(other);
|
||||||
|
|
||||||
|
@ -27,8 +30,15 @@ Scene& Scene::operator=(const Scene& other)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Рендер сцены
|
// Рендер сцены
|
||||||
void Scene::render(ShaderProgram &shaderProgram, UBO &material_buffer)
|
void Scene::render(ShaderProgram &shaderProgram, UBO &material_buffer, bool recalc_animations)
|
||||||
{
|
{
|
||||||
|
// Если требуется пересчитаем анимации
|
||||||
|
if (recalc_animations)
|
||||||
|
for (auto & animation : animations)
|
||||||
|
if (animation.isEnabled())
|
||||||
|
animation.process();
|
||||||
|
|
||||||
|
// Рендер моделей
|
||||||
for (auto & model : models)
|
for (auto & model : models)
|
||||||
model.render(shaderProgram, material_buffer);
|
model.render(shaderProgram, material_buffer);
|
||||||
}
|
}
|
||||||
|
@ -79,6 +89,18 @@ void Scene::move_parent(Node& for_node, const std::list<T>& from_nodes, std::lis
|
||||||
for_node.setParent(&(*it_this));
|
for_node.setParent(&(*it_this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Перестройка узлов анимации
|
||||||
|
template <class T>
|
||||||
|
void Scene::move_animation_target(Node*& target, const std::list<T>& from_nodes, std::list<T>& this_nodes)
|
||||||
|
{
|
||||||
|
// Цикл по элементам списков для перемещения родителя
|
||||||
|
// Списки в процессе копирования идеинтичные, вторая проверка не требуется
|
||||||
|
for (auto it_from = from_nodes.begin(), it_this = this_nodes.begin(); it_from != from_nodes.end(); ++it_from, ++it_this)
|
||||||
|
// Если адрес объекта, на который указывает итератор, совпадает с родителем - меняем родителя по второму итератору (it_this)
|
||||||
|
if (&(*it_from) == target)
|
||||||
|
target = &(*it_this);
|
||||||
|
}
|
||||||
|
|
||||||
// Перестройка дерева после копирования или присваивания
|
// Перестройка дерева после копирования или присваивания
|
||||||
void Scene::rebuld_tree(const Scene& from)
|
void Scene::rebuld_tree(const Scene& from)
|
||||||
{
|
{
|
||||||
|
@ -86,6 +108,32 @@ void Scene::rebuld_tree(const Scene& from)
|
||||||
rebuild_Nodes_list(nodes, from);
|
rebuild_Nodes_list(nodes, from);
|
||||||
rebuild_Nodes_list(models, from);
|
rebuild_Nodes_list(models, from);
|
||||||
rebuild_Nodes_list(cameras, from);
|
rebuild_Nodes_list(cameras, from);
|
||||||
|
|
||||||
|
// Восстановим указатели на узлы для каналов анимаций
|
||||||
|
for (auto & animation : animations)
|
||||||
|
for (auto & channel : animation.channels)
|
||||||
|
{
|
||||||
|
// Если целевой узел - оригинальный корневой узел, то меняем на собственный корневой узел
|
||||||
|
if (channel.target == &from.root)
|
||||||
|
{
|
||||||
|
channel.target = &root;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если можно привести к модели, то ищем родителя среди моделей
|
||||||
|
if (dynamic_cast<Model*>(channel.target))
|
||||||
|
move_animation_target(channel.target, from.models, this->models);
|
||||||
|
else
|
||||||
|
// Иначе проверяем на принадлежность к камерам
|
||||||
|
if (dynamic_cast<Camera*>(channel.target))
|
||||||
|
move_animation_target(channel.target, from.cameras, this->cameras);
|
||||||
|
// Иначе это пустой узел
|
||||||
|
else
|
||||||
|
move_animation_target(channel.target, from.nodes, this->nodes);
|
||||||
|
|
||||||
|
// Не нашли узел - значит он не часть этой сцены
|
||||||
|
// и изменений по каналу не требуется
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TINYOBJLOADER_IMPLEMENTATION
|
#define TINYOBJLOADER_IMPLEMENTATION
|
||||||
|
@ -277,6 +325,55 @@ void collectGLTFnodes(int node_id, std::vector<int> &nodes, tinygltf::Model &in_
|
||||||
collectGLTFnodes(child, nodes, in_model);
|
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 loadGLTFtoScene(std::string filename)
|
||||||
{
|
{
|
||||||
Scene result;
|
Scene result;
|
||||||
|
@ -302,7 +399,7 @@ Scene loadGLTFtoScene(std::string filename)
|
||||||
auto &buffer = in_model.buffers[bufferView.buffer];
|
auto &buffer = in_model.buffers[bufferView.buffer];
|
||||||
BOs.push_back(BO((BUFFER_TYPE)bufferView.target, buffer.data.data() + bufferView.byteOffset, bufferView.byteLength));
|
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);
|
std::string dir = filename.substr(0, filename.find_last_of("/\\") + 1);
|
||||||
// Загрузим используемые текстуры
|
// Загрузим используемые текстуры
|
||||||
|
@ -343,7 +440,7 @@ Scene loadGLTFtoScene(std::string filename)
|
||||||
std::vector<Node *> pNodes(in_model.nodes.size(), NULL);
|
std::vector<Node *> pNodes(in_model.nodes.size(), NULL);
|
||||||
// Индексы родителей (-1 - корневой узел сцены)
|
// Индексы родителей (-1 - корневой узел сцены)
|
||||||
std::vector<int> parents_id(in_model.nodes.size(), -1);
|
std::vector<int> parents_id(in_model.nodes.size(), -1);
|
||||||
|
|
||||||
// Цикл по сценам
|
// Цикл по сценам
|
||||||
for (auto &scene : in_model.scenes)
|
for (auto &scene : in_model.scenes)
|
||||||
{
|
{
|
||||||
|
@ -488,7 +585,7 @@ Scene loadGLTFtoScene(std::string filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.models.push_back(model); // Добавляем к сцене
|
result.models.push_back(model); // Добавляем к сцене
|
||||||
// Если ещё не сохранили
|
// Если ещё не сохранили
|
||||||
if (!pNodes[node_id])
|
if (!pNodes[node_id])
|
||||||
|
@ -526,6 +623,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++)
|
for (int node_id = 0; node_id < in_model.nodes.size(); node_id++)
|
||||||
|
|
11
src/main.cpp
11
src/main.cpp
|
@ -153,10 +153,13 @@ int main(void)
|
||||||
gShader.bindTextures(textures_base_shader_names, sizeof(textures_base_shader_names)/sizeof(const char*));
|
gShader.bindTextures(textures_base_shader_names, sizeof(textures_base_shader_names)/sizeof(const char*));
|
||||||
|
|
||||||
// Загрузка сцены из obj файла
|
// Загрузка сцены из obj файла
|
||||||
Scene scene = loadGLTFtoScene("../resources/models/blob.gltf");
|
Scene scene = loadGLTFtoScene("../resources/models/rotating-cube_cubic-spline.gltf");
|
||||||
scene.root.e_scale() = glm::vec3(0.01);
|
scene.root.e_position().y = -1;
|
||||||
scene.root.e_position().z = 1;
|
scene.root.e_position().z = 3;
|
||||||
scene.set_group_id((GLuint64) &scene.root);
|
scene.set_group_id((GLuint64) &scene.root);
|
||||||
|
// Включим первую анимацию, если есть
|
||||||
|
if (scene.animations.size())
|
||||||
|
scene.animations[0].begin();
|
||||||
|
|
||||||
// Установка цвета очистки буфера цвета
|
// Установка цвета очистки буфера цвета
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
@ -473,7 +476,7 @@ int main(void)
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
// Тут производится рендер
|
// Тут производится рендер
|
||||||
scene.render(gShader, material_data);
|
scene.render(gShader, material_data, true);
|
||||||
rectangle.render(gShader, material_data);
|
rectangle.render(gShader, material_data);
|
||||||
|
|
||||||
// Отрисовка отладочных лампочек со специальным шейдером
|
// Отрисовка отладочных лампочек со специальным шейдером
|
||||||
|
|
Loading…
Reference in New Issue