Сцена и функция-загрузчик
This commit is contained in:
		
							parent
							
								
									7af8fbb143
								
							
						
					
					
						commit
						004c255013
					
				@ -19,32 +19,36 @@ class Scene loadGLTFtoScene(std::string filename);
 | 
			
		||||
// Класс сцены
 | 
			
		||||
class Scene
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        Scene(); // Конструктор пустой сцены
 | 
			
		||||
        Scene(const Scene ©); // Конструктор копирования
 | 
			
		||||
        Scene& operator=(const Scene& other); // Оператор присваивания
 | 
			
		||||
public:
 | 
			
		||||
    Scene(); // Конструктор пустой сцены
 | 
			
		||||
    Scene(const Scene ©); // Конструктор копирования
 | 
			
		||||
    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<Model> models; // Список моделей для рендера
 | 
			
		||||
        std::list<Camera> cameras; // Список камер
 | 
			
		||||
    // Списки объектов, выступающих узлами
 | 
			
		||||
    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>
 | 
			
		||||
        void rebuild_Nodes_list(T& nodes, const Scene& from); // Перестройка узлов выбранного списка
 | 
			
		||||
        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); // Перестройка узлов анимации
 | 
			
		||||
    std::list<Bone> bones; // Узлы, выступающие в роли костей
 | 
			
		||||
    std::list<Skeleton> skeletons; // Скелеты
 | 
			
		||||
 | 
			
		||||
    std::vector<Animation> animations; // Список анимаций
 | 
			
		||||
    std::map<std::string, size_t> animation_names; // Имя анимации - индекс
 | 
			
		||||
protected:
 | 
			
		||||
    void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
 | 
			
		||||
    template <class T>
 | 
			
		||||
    void rebuild_Nodes_list(T& nodes, const Scene& from); // Перестройка узлов выбранного списка
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										144
									
								
								src/Scene.cpp
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								src/Scene.cpp
									
									
									
									
									
								
							@ -9,7 +9,8 @@ Scene::Scene()
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
Scene::Scene(const Scene ©): root(copy.root), 
 | 
			
		||||
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);
 | 
			
		||||
} 
 | 
			
		||||
@ -24,13 +25,15 @@ Scene& Scene::operator=(const Scene& other)
 | 
			
		||||
    animations = other.animations;
 | 
			
		||||
    animation_names = other.animation_names;
 | 
			
		||||
 | 
			
		||||
    bones = other.bones; // скелеты (skeletons) перестраиваются в методе Scene::rebuild_bones
 | 
			
		||||
 | 
			
		||||
    rebuld_tree(other);
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
@ -40,7 +43,7 @@ void Scene::render(ShaderProgram &shaderProgram, UBO &material_buffer, bool reca
 | 
			
		||||
 | 
			
		||||
    // Рендер моделей
 | 
			
		||||
    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Перестройка указателей на кости и узлы, которые выступают в роли костей
 | 
			
		||||
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)
 | 
			
		||||
{    
 | 
			
		||||
@ -134,6 +202,9 @@ void Scene::rebuld_tree(const Scene& from)
 | 
			
		||||
            // Не нашли узел - значит он не часть этой сцены 
 | 
			
		||||
            // и изменений по каналу не требуется
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    // Восстановим указатели на кости и перестроим скелеты
 | 
			
		||||
    rebuld_bones(from);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define TINYOBJLOADER_IMPLEMENTATION
 | 
			
		||||
@ -440,6 +511,9 @@ 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);
 | 
			
		||||
 | 
			
		||||
        // Зарезервируем место под скелеты
 | 
			
		||||
        result.skeletons.resize(in_model.skins.size());
 | 
			
		||||
        
 | 
			
		||||
        // Цикл по сценам
 | 
			
		||||
        for (auto &scene : in_model.scenes)
 | 
			
		||||
@ -491,6 +565,10 @@ Scene loadGLTFtoScene(std::string filename)
 | 
			
		||||
                    {
 | 
			
		||||
                        Model model(tmpParent); // Тут используется либо корневой узел сцены, либо вспомогательный узел
 | 
			
		||||
 | 
			
		||||
                        // Скелеты записываются только для моделей (не для узлов), если есть 
 | 
			
		||||
                        if (node.skin > -1)
 | 
			
		||||
                            model.skeleton = &(*std::next(result.skeletons.begin(), node.skin));
 | 
			
		||||
 | 
			
		||||
                        // Цикл по атрибутам примитива
 | 
			
		||||
                        for (auto &attribute : primitive.attributes)
 | 
			
		||||
                        {
 | 
			
		||||
@ -507,6 +585,10 @@ Scene loadGLTFtoScene(std::string filename)
 | 
			
		||||
                                attribute_index = 1;
 | 
			
		||||
                            else if (attribute.first.compare("NORMAL") == 0)
 | 
			
		||||
                                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
 | 
			
		||||
                                continue;
 | 
			
		||||
                        
 | 
			
		||||
@ -516,13 +598,23 @@ Scene loadGLTFtoScene(std::string filename)
 | 
			
		||||
 | 
			
		||||
                            glEnableVertexAttribArray(attribute_index);
 | 
			
		||||
                            // Определим спецификацию атрибута
 | 
			
		||||
                            glVertexAttribPointer( attribute_index // индекс атрибута, должен совпадать с Layout шейдера
 | 
			
		||||
                                                , tinygltf::GetNumComponentsInType(accessor.type) // количество компонент одного элемента
 | 
			
		||||
                                                , accessor.componentType // тип
 | 
			
		||||
                                                , accessor.normalized ? GL_TRUE : GL_FALSE // нормализованность значений
 | 
			
		||||
                                                , accessor.ByteStride(bufferView) // шаг
 | 
			
		||||
                                                , ((char *)NULL + accessor.byteOffset) // отступ с начала массива
 | 
			
		||||
                                                );
 | 
			
		||||
                            // Если это индексы костей - привяжем как int
 | 
			
		||||
                            if (attribute_index == 5)
 | 
			
		||||
                                glVertexAttribIPointer( attribute_index // индекс атрибута, должен совпадать с Layout шейдера
 | 
			
		||||
                                                      , tinygltf::GetNumComponentsInType(accessor.type) // количество компонент одного элемента
 | 
			
		||||
                                                      , accessor.componentType // тип
 | 
			
		||||
                                                      , 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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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++)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/main.cpp
									
									
									
									
									
								
							@ -153,14 +153,14 @@ int main(void)
 | 
			
		||||
    gShader.bindTextures(textures_base_shader_names, sizeof(textures_base_shader_names)/sizeof(const char*));
 | 
			
		||||
 | 
			
		||||
    // Загрузка сцены из 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().z = 3;
 | 
			
		||||
    scene.set_group_id((GLuint64) &scene.root);
 | 
			
		||||
    // Включим первую анимацию, если есть
 | 
			
		||||
    if (scene.animations.size())
 | 
			
		||||
        scene.animations[0].begin();
 | 
			
		||||
    
 | 
			
		||||
     
 | 
			
		||||
    // Установка цвета очистки буфера цвета
 | 
			
		||||
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
 | 
			
		||||
 | 
			
		||||
@ -458,6 +458,9 @@ int main(void)
 | 
			
		||||
    TextureCube reflections_texture(skybox_texture);
 | 
			
		||||
    reflections_texture.setType(9);
 | 
			
		||||
 | 
			
		||||
    // Буфер для костей
 | 
			
		||||
    UBO bones_matrices_data(NULL, sizeof(glm::mat4)*MAX_BONES, 5);
 | 
			
		||||
    
 | 
			
		||||
    // Пока не произойдет событие запроса закрытия окна
 | 
			
		||||
    while(!glfwWindowShouldClose(window))
 | 
			
		||||
    {
 | 
			
		||||
@ -476,7 +479,7 @@ int main(void)
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
        // Отрисовка отладочных лампочек со специальным шейдером
 | 
			
		||||
@ -530,7 +533,7 @@ int main(void)
 | 
			
		||||
        // Очистка буфера глубины
 | 
			
		||||
        glClear(GL_DEPTH_BUFFER_BIT);
 | 
			
		||||
        // Рендерим геометрию в буфер глубины
 | 
			
		||||
        scene.render(sunShadowShader, material_data);
 | 
			
		||||
        scene.render(sunShadowShader, material_data, &bones_matrices_data);
 | 
			
		||||
        rectangle.render(sunShadowShader, material_data);
 | 
			
		||||
 | 
			
		||||
        // Изменим размер вывода для стороны кубической карты точечного источника
 | 
			
		||||
@ -546,7 +549,7 @@ int main(void)
 | 
			
		||||
        {
 | 
			
		||||
            glUniform1i(pointShadowShader.getUniformLoc("light_i"), i);
 | 
			
		||||
            // Рендерим геометрию в буфер глубины
 | 
			
		||||
            scene.render(pointShadowShader, material_data);  
 | 
			
		||||
            scene.render(pointShadowShader, material_data, &bones_matrices_data);  
 | 
			
		||||
            rectangle.render(pointShadowShader, material_data);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user