Сцена и функция-загрузчик
This commit is contained in:
parent
7af8fbb143
commit
004c255013
|
@ -19,32 +19,36 @@ class Scene loadGLTFtoScene(std::string filename);
|
||||||
// Класс сцены
|
// Класс сцены
|
||||||
class Scene
|
class Scene
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Scene(); // Конструктор пустой сцены
|
Scene(); // Конструктор пустой сцены
|
||||||
Scene(const Scene ©); // Конструктор копирования
|
Scene(const Scene ©); // Конструктор копирования
|
||||||
Scene& operator=(const Scene& other); // Оператор присваивания
|
Scene& operator=(const Scene& other); // Оператор присваивания
|
||||||
|
|
||||||
void render(ShaderProgram &shaderProgram, UBO &material_buffer, bool recalc_animations = false); // Рендер сцены
|
void render(ShaderProgram &shaderProgram, UBO &material_buffer, UBO *bones_buffer = NULL, bool recalc_animations = false); // Рендер сцены
|
||||||
|
|
||||||
void set_group_id(GLuint64 id, GLuint etc = 0); // Изменение флага записи идентификатора для всех моделей
|
void set_group_id(GLuint64 id, GLuint etc = 0); // Изменение флага записи идентификатора для всех моделей
|
||||||
|
|
||||||
Node root; // Корневой узел
|
Node root; // Корневой узел
|
||||||
|
|
||||||
// Списки объектов, выступающих узлами
|
// Списки объектов, выступающих узлами
|
||||||
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::list<Bone> bones; // Узлы, выступающие в роли костей
|
||||||
std::map<std::string, size_t> animation_names; // Имя анимации - индекс
|
std::list<Skeleton> skeletons; // Скелеты
|
||||||
protected:
|
|
||||||
void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
|
std::vector<Animation> animations; // Список анимаций
|
||||||
template <class T>
|
std::map<std::string, size_t> animation_names; // Имя анимации - индекс
|
||||||
void rebuild_Nodes_list(T& nodes, const Scene& from); // Перестройка узлов выбранного списка
|
protected:
|
||||||
template <class T>
|
void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
|
||||||
void move_parent(Node& for_node, const std::list<T>& from_nodes, std::list<T>& this_nodes); // Сдвигает родителя узла между двумя списками при условии его принадлежности к оригинальному
|
template <class T>
|
||||||
template <class T>
|
void rebuild_Nodes_list(T& nodes, const Scene& from); // Перестройка узлов выбранного списка
|
||||||
void move_animation_target(Node*& target, const std::list<T>& from_nodes, std::list<T>& this_nodes); // Перестройка узлов анимации
|
template <class T>
|
||||||
|
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); // Перестройка узлов анимации
|
||||||
|
void rebuld_bones(const Scene &from); // Перестройка указателей на кости и узлы, которые выступают в роли костей
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SCENE_H
|
#endif // SCENE_H
|
||||||
|
|
144
src/Scene.cpp
144
src/Scene.cpp
|
@ -9,7 +9,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)
|
animations(copy.animations), animation_names(copy.animation_names),
|
||||||
|
bones(copy.bones) // скелеты (skeletons) перестраиваются в методе Scene::rebuild_bones
|
||||||
{
|
{
|
||||||
rebuld_tree(copy);
|
rebuld_tree(copy);
|
||||||
}
|
}
|
||||||
|
@ -24,13 +25,15 @@ Scene& Scene::operator=(const Scene& other)
|
||||||
animations = other.animations;
|
animations = other.animations;
|
||||||
animation_names = other.animation_names;
|
animation_names = other.animation_names;
|
||||||
|
|
||||||
|
bones = other.bones; // скелеты (skeletons) перестраиваются в методе Scene::rebuild_bones
|
||||||
|
|
||||||
rebuld_tree(other);
|
rebuld_tree(other);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Рендер сцены
|
// Рендер сцены
|
||||||
void Scene::render(ShaderProgram &shaderProgram, UBO &material_buffer, bool recalc_animations)
|
void Scene::render(ShaderProgram &shaderProgram, UBO &material_buffer, UBO *bones_buffer, bool recalc_animations)
|
||||||
{
|
{
|
||||||
// Если требуется пересчитаем анимации
|
// Если требуется пересчитаем анимации
|
||||||
if (recalc_animations)
|
if (recalc_animations)
|
||||||
|
@ -40,7 +43,7 @@ void Scene::render(ShaderProgram &shaderProgram, UBO &material_buffer, bool reca
|
||||||
|
|
||||||
// Рендер моделей
|
// Рендер моделей
|
||||||
for (auto & model : models)
|
for (auto & model : models)
|
||||||
model.render(shaderProgram, material_buffer);
|
model.render(shaderProgram, material_buffer, bones_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Перестройка узлов выбранного списка
|
// Перестройка узлов выбранного списка
|
||||||
|
@ -101,6 +104,71 @@ void Scene::move_animation_target(Node*& target, const std::list<T>& from_nodes,
|
||||||
target = &(*it_this);
|
target = &(*it_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Перестройка указателей на кости и узлы, которые выступают в роли костей
|
||||||
|
void Scene::rebuld_bones(const Scene &from)
|
||||||
|
{
|
||||||
|
// Цикл по костям
|
||||||
|
for (auto bone = bones.begin(); bone != bones.end(); ++bone)
|
||||||
|
{
|
||||||
|
// Если целевой узел - оригинальный корневой узел, то меняем на собственный корневой узел
|
||||||
|
if (bone->node == &from.root)
|
||||||
|
{
|
||||||
|
bone->node = &root;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если можно привести к модели, то ищем родителя среди моделей
|
||||||
|
if (dynamic_cast<Model*>(bone->node))
|
||||||
|
move_animation_target(bone->node, from.models, this->models);
|
||||||
|
else
|
||||||
|
// Иначе проверяем на принадлежность к камерам
|
||||||
|
if (dynamic_cast<Camera*>(bone->node))
|
||||||
|
move_animation_target(bone->node, from.cameras, this->cameras);
|
||||||
|
// Иначе это пустой узел
|
||||||
|
else
|
||||||
|
move_animation_target(bone->node, from.nodes, this->nodes);
|
||||||
|
|
||||||
|
// Не нашли узел - значит он не часть этой сцены
|
||||||
|
// и изменений по каналу не требуется
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Построим скелеты с нуля
|
||||||
|
// Цикл по скелетам оригинала
|
||||||
|
for (auto & f_skeleton : from.skeletons)
|
||||||
|
{
|
||||||
|
Skeleton tmp;
|
||||||
|
|
||||||
|
// Цикл по костям в конкретном скелете оригинала
|
||||||
|
for (Bone* fs_bones : f_skeleton.bones)
|
||||||
|
{
|
||||||
|
auto it_bone = this->bones.begin();
|
||||||
|
// Цикл по общему списку костей оригинала
|
||||||
|
for (auto f_bone = from.bones.begin(); f_bone != from.bones.end(); ++f_bone, ++it_bone)
|
||||||
|
// Если адрес объекта, на который указывает итератор, равен кости в скелете
|
||||||
|
if (&(*f_bone) == fs_bones)
|
||||||
|
tmp.bones.push_back(&(*it_bone));
|
||||||
|
}
|
||||||
|
|
||||||
|
skeletons.push_back(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обновим указатели в моделях для скелета
|
||||||
|
for (auto & model : models)
|
||||||
|
{
|
||||||
|
// Если есть скелет
|
||||||
|
if (model.skeleton)
|
||||||
|
{
|
||||||
|
auto it_skeleton = this->skeletons.begin();
|
||||||
|
// Цикл по скелетам оригинала
|
||||||
|
for (auto f_skeleton = from.skeletons.begin(); f_skeleton != from.skeletons.end(); ++f_skeleton, ++it_skeleton)
|
||||||
|
// Если адрес оригинального скелета, на который указывает итератор, равен используемому в модели
|
||||||
|
if (&(*f_skeleton) == model.skeleton)
|
||||||
|
model.skeleton = &(*it_skeleton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Перестройка дерева после копирования или присваивания
|
// Перестройка дерева после копирования или присваивания
|
||||||
void Scene::rebuld_tree(const Scene& from)
|
void Scene::rebuld_tree(const Scene& from)
|
||||||
{
|
{
|
||||||
|
@ -134,6 +202,9 @@ void Scene::rebuld_tree(const Scene& from)
|
||||||
// Не нашли узел - значит он не часть этой сцены
|
// Не нашли узел - значит он не часть этой сцены
|
||||||
// и изменений по каналу не требуется
|
// и изменений по каналу не требуется
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Восстановим указатели на кости и перестроим скелеты
|
||||||
|
rebuld_bones(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TINYOBJLOADER_IMPLEMENTATION
|
#define TINYOBJLOADER_IMPLEMENTATION
|
||||||
|
@ -441,6 +512,9 @@ Scene loadGLTFtoScene(std::string filename)
|
||||||
// Индексы родителей (-1 - корневой узел сцены)
|
// Индексы родителей (-1 - корневой узел сцены)
|
||||||
std::vector<int> parents_id(in_model.nodes.size(), -1);
|
std::vector<int> parents_id(in_model.nodes.size(), -1);
|
||||||
|
|
||||||
|
// Зарезервируем место под скелеты
|
||||||
|
result.skeletons.resize(in_model.skins.size());
|
||||||
|
|
||||||
// Цикл по сценам
|
// Цикл по сценам
|
||||||
for (auto &scene : in_model.scenes)
|
for (auto &scene : in_model.scenes)
|
||||||
{
|
{
|
||||||
|
@ -491,6 +565,10 @@ Scene loadGLTFtoScene(std::string filename)
|
||||||
{
|
{
|
||||||
Model model(tmpParent); // Тут используется либо корневой узел сцены, либо вспомогательный узел
|
Model model(tmpParent); // Тут используется либо корневой узел сцены, либо вспомогательный узел
|
||||||
|
|
||||||
|
// Скелеты записываются только для моделей (не для узлов), если есть
|
||||||
|
if (node.skin > -1)
|
||||||
|
model.skeleton = &(*std::next(result.skeletons.begin(), node.skin));
|
||||||
|
|
||||||
// Цикл по атрибутам примитива
|
// Цикл по атрибутам примитива
|
||||||
for (auto &attribute : primitive.attributes)
|
for (auto &attribute : primitive.attributes)
|
||||||
{
|
{
|
||||||
|
@ -507,6 +585,10 @@ Scene loadGLTFtoScene(std::string filename)
|
||||||
attribute_index = 1;
|
attribute_index = 1;
|
||||||
else if (attribute.first.compare("NORMAL") == 0)
|
else if (attribute.first.compare("NORMAL") == 0)
|
||||||
attribute_index = 2;
|
attribute_index = 2;
|
||||||
|
else if (attribute.first.compare("JOINTS_0") == 0)
|
||||||
|
attribute_index = 5;
|
||||||
|
else if (attribute.first.compare("WEIGHTS_0") == 0)
|
||||||
|
attribute_index = 6;
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -516,13 +598,23 @@ Scene loadGLTFtoScene(std::string filename)
|
||||||
|
|
||||||
glEnableVertexAttribArray(attribute_index);
|
glEnableVertexAttribArray(attribute_index);
|
||||||
// Определим спецификацию атрибута
|
// Определим спецификацию атрибута
|
||||||
glVertexAttribPointer( attribute_index // индекс атрибута, должен совпадать с Layout шейдера
|
// Если это индексы костей - привяжем как int
|
||||||
, tinygltf::GetNumComponentsInType(accessor.type) // количество компонент одного элемента
|
if (attribute_index == 5)
|
||||||
, accessor.componentType // тип
|
glVertexAttribIPointer( attribute_index // индекс атрибута, должен совпадать с Layout шейдера
|
||||||
, accessor.normalized ? GL_TRUE : GL_FALSE // нормализованность значений
|
, tinygltf::GetNumComponentsInType(accessor.type) // количество компонент одного элемента
|
||||||
, accessor.ByteStride(bufferView) // шаг
|
, accessor.componentType // тип
|
||||||
, ((char *)NULL + accessor.byteOffset) // отступ с начала массива
|
, accessor.ByteStride(bufferView) // шаг
|
||||||
);
|
, ((char *)NULL + accessor.byteOffset) // отступ с начала массива
|
||||||
|
);
|
||||||
|
// Иначе как float
|
||||||
|
else
|
||||||
|
glVertexAttribPointer ( attribute_index // индекс атрибута, должен совпадать с Layout шейдера
|
||||||
|
, tinygltf::GetNumComponentsInType(accessor.type) // количество компонент одного элемента
|
||||||
|
, accessor.componentType // тип
|
||||||
|
, accessor.normalized ? GL_TRUE : GL_FALSE // нормализованность значений
|
||||||
|
, accessor.ByteStride(bufferView) // шаг
|
||||||
|
, ((char *)NULL + accessor.byteOffset) // отступ с начала массива
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если есть индексы
|
// Если есть индексы
|
||||||
|
@ -733,6 +825,38 @@ Scene loadGLTFtoScene(std::string filename)
|
||||||
result.animations.push_back(animation);
|
result.animations.push_back(animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto result_skeleton = result.skeletons.begin(); // Итератор по скелетам в нашей сцене
|
||||||
|
// Цикл по скелетам (зарезервированы в начале)
|
||||||
|
for (auto &in_skin : in_model.skins)
|
||||||
|
{
|
||||||
|
// Цикл по костям скелета
|
||||||
|
for (int i = 0; i < in_skin.joints.size(); i++)
|
||||||
|
{
|
||||||
|
Bone bone;
|
||||||
|
// Если есть матрица обратного преобразования связывания
|
||||||
|
if (in_skin.inverseBindMatrices > 0)
|
||||||
|
{
|
||||||
|
// Получение матриц обратного преобразования связывания
|
||||||
|
const auto& accessor = in_model.accessors[in_skin.inverseBindMatrices];
|
||||||
|
const auto& bufferView = in_model.bufferViews[accessor.bufferView];
|
||||||
|
const auto& buffer = in_model.buffers[bufferView.buffer];
|
||||||
|
const glm::mat4* matrix = reinterpret_cast<const glm::mat4*>(&(buffer.data[bufferView.byteOffset + accessor.byteOffset]));
|
||||||
|
|
||||||
|
bone.inverseBindMatrix = matrix[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Узел, выступающий в роли кости
|
||||||
|
bone.node = pNodes[in_skin.joints[i]];
|
||||||
|
|
||||||
|
// Добавим в список костей сцены
|
||||||
|
result.bones.push_back(bone);
|
||||||
|
|
||||||
|
// Добавим кость к скелету
|
||||||
|
result_skeleton->bones.push_back(&(result.bones.back()));
|
||||||
|
}
|
||||||
|
++result_skeleton; // Двигаем итератор
|
||||||
|
}
|
||||||
|
|
||||||
// Зададим трансформацию и родителей для узлов
|
// Зададим трансформацию и родителей для узлов
|
||||||
// Цикл по всем индексам узлов
|
// Цикл по всем индексам узлов
|
||||||
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,7 +153,7 @@ 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/rotating-cube_cubic-spline.gltf");
|
Scene scene = loadGLTFtoScene("../resources/models/LowpolyHuman_Hi.gltf");
|
||||||
scene.root.e_position().y = -1;
|
scene.root.e_position().y = -1;
|
||||||
scene.root.e_position().z = 3;
|
scene.root.e_position().z = 3;
|
||||||
scene.set_group_id((GLuint64) &scene.root);
|
scene.set_group_id((GLuint64) &scene.root);
|
||||||
|
@ -458,6 +458,9 @@ int main(void)
|
||||||
TextureCube reflections_texture(skybox_texture);
|
TextureCube reflections_texture(skybox_texture);
|
||||||
reflections_texture.setType(9);
|
reflections_texture.setType(9);
|
||||||
|
|
||||||
|
// Буфер для костей
|
||||||
|
UBO bones_matrices_data(NULL, sizeof(glm::mat4)*MAX_BONES, 5);
|
||||||
|
|
||||||
// Пока не произойдет событие запроса закрытия окна
|
// Пока не произойдет событие запроса закрытия окна
|
||||||
while(!glfwWindowShouldClose(window))
|
while(!glfwWindowShouldClose(window))
|
||||||
{
|
{
|
||||||
|
@ -476,7 +479,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, true);
|
scene.render(gShader, material_data, &bones_matrices_data, true);
|
||||||
rectangle.render(gShader, material_data);
|
rectangle.render(gShader, material_data);
|
||||||
|
|
||||||
// Отрисовка отладочных лампочек со специальным шейдером
|
// Отрисовка отладочных лампочек со специальным шейдером
|
||||||
|
@ -530,7 +533,7 @@ int main(void)
|
||||||
// Очистка буфера глубины
|
// Очистка буфера глубины
|
||||||
glClear(GL_DEPTH_BUFFER_BIT);
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
// Рендерим геометрию в буфер глубины
|
// Рендерим геометрию в буфер глубины
|
||||||
scene.render(sunShadowShader, material_data);
|
scene.render(sunShadowShader, material_data, &bones_matrices_data);
|
||||||
rectangle.render(sunShadowShader, material_data);
|
rectangle.render(sunShadowShader, material_data);
|
||||||
|
|
||||||
// Изменим размер вывода для стороны кубической карты точечного источника
|
// Изменим размер вывода для стороны кубической карты точечного источника
|
||||||
|
@ -546,7 +549,7 @@ int main(void)
|
||||||
{
|
{
|
||||||
glUniform1i(pointShadowShader.getUniformLoc("light_i"), i);
|
glUniform1i(pointShadowShader.getUniformLoc("light_i"), i);
|
||||||
// Рендерим геометрию в буфер глубины
|
// Рендерим геометрию в буфер глубины
|
||||||
scene.render(pointShadowShader, material_data);
|
scene.render(pointShadowShader, material_data, &bones_matrices_data);
|
||||||
rectangle.render(pointShadowShader, material_data);
|
rectangle.render(pointShadowShader, material_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue