Функция-загрузчик

This commit is contained in:
parent f9971fce0a
commit 1b58e6b89b
4 changed files with 261 additions and 6 deletions

View File

@ -6,11 +6,16 @@
#include "Shader.h" #include "Shader.h"
#include <GLM/glm.hpp> #include <GLM/glm.hpp>
#include <GLM/gtc/type_ptr.hpp>
#include <GLM/gtc/quaternion.hpp>
#include <GLM/gtx/quaternion.hpp>
#include <GLM/gtx/euler_angles.hpp>
#include <vector> #include <vector>
#define DEFAULT_MTL_DIR "./" #define DEFAULT_MTL_DIR "./"
class GrouptedModel loadOBJtoGroupted(const char* filename, const char* mtl_directory = DEFAULT_MTL_DIR, const char* texture_directory = DEFAULT_MTL_DIR); class GrouptedModel loadOBJtoGroupted(const char* filename, const char* mtl_directory = DEFAULT_MTL_DIR, const char* texture_directory = DEFAULT_MTL_DIR);
class GrouptedModel loadGLTFtoGroupted(std::string filename);
void calc_tb(const GLuint* indices, const int indices_count, const glm::vec3* verteces, const glm::vec2* texCords, glm::vec3* tangent, glm::vec3* bitangent); void calc_tb(const GLuint* indices, const int indices_count, const glm::vec3* verteces, const glm::vec2* texCords, glm::vec3* tangent, glm::vec3* bitangent);
struct Material struct Material

View File

@ -104,10 +104,19 @@ void main()
// Сохранение базового цвета // Сохранение базового цвета
gBaseColor.rgb = base_color.r<0?texture(tex_albedo, new_texCoord).rgb:base_color; gBaseColor.rgb = base_color.r<0?texture(tex_albedo, new_texCoord).rgb:base_color;
// Сохранение шероховатости // Если используется двухканальная текстура
gRMS.r = roughness<0?texture(tex_roughness, new_texCoord).r:roughness; if (roughness < -1)
// Сохранение металличности {
gRMS.g = metallic<0?texture(tex_metallic, new_texCoord).r:metallic; // Сохранение шероховатости и металличности
gRMS.rg = texture(tex_metallic, new_texCoord).bg;
}
else
{
// Сохранение шероховатости
gRMS.r = roughness<0?texture(tex_roughness, new_texCoord).r:roughness;
// Сохранение металличности
gRMS.g = metallic<0?texture(tex_metallic, new_texCoord).r:metallic;
}
// Сохранение интенсивности блика диэлектриков // Сохранение интенсивности блика диэлектриков
gRMS.b = specular<0?texture(tex_specular, new_texCoord).r:specular; gRMS.b = specular<0?texture(tex_specular, new_texCoord).r:specular;
// Сохранение идентификатора объекта // Сохранение идентификатора объекта

View File

@ -532,6 +532,247 @@ void Model::setIndicesBO(BO & data)
index_vbo = data; index_vbo = data;
} }
#define TINYGLTF_IMPLEMENTATION
#define TINYGLTF_NO_STB_IMAGE_WRITE
#define TINYGLTF_NOEXCEPTION
#define JSON_NOEXCEPTION
#include "tiny_gltf.h"
// Проход вложенных узлов для расчета дочерних трансформаций
void node_process(int current, int parrent, tinygltf::Model & model, std::vector<glm::mat4> & transforms)
{
// Если текущий индекс отрицательный - выходим из вершины
if (current < 0)
return;
// Получаем узел
tinygltf::Node & node = model.nodes[current];
// Текущая матрица
glm::mat4 cur(1); // Изначально единичная
if (node.matrix.size() == 16) // Если задана - заменяем
cur = glm::make_mat4(node.matrix.data());
// Если текущий индекс не равен родительскому - родительский будет левой матрицей в произведении
if (current != parrent)
transforms[current] = transforms[parrent];
transforms[current] *= cur; // Домножаем на правую - матрицу текущего узла
// Проходим рекурсивно по вложенным узлам
for (auto & child : node.children)
{
node_process(child, current, model, transforms);
}
}
GrouptedModel loadGLTFtoGroupted(std::string filename)
{
GrouptedModel result; // Результат возвращаемый функцией
tinygltf::TinyGLTF loader; // Объект загрузчика
tinygltf::Model in_model; // Модель в формате загрузчика
std::string err; // Строка под ошибки
std::string warn; // Строка под предупреждения
bool success = loader.LoadASCIIFromFile(&in_model, &err, &warn, filename); // Загрузка из файла
// Если есть ошибки или предупреждения - выдадим исключение
if (!err.empty() || !warn.empty())
throw std::runtime_error(err + '\n' + warn);
// Если все успешно считано - продолжаем загрузку
if (success)
{
// Загрузим данные в вершинные и индексные буферы
std::vector<BO> BOs;
for (auto & bufferView : in_model.bufferViews)
{
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);
// Загрузим используемые текстуры
std::vector<Texture> textures;
for (auto & image : in_model.images)
{
// Если длинна файла больше 0, то текстура в отдельном файле
if (image.uri.size() > 0)
{
Texture tmp(TEX_AVAILABLE_COUNT,(dir + image.uri).c_str());
textures.push_back(tmp);
}
else // иначе она является частью буфера
{
GLuint format = GL_RGBA;
GLenum type = GL_UNSIGNED_BYTE;
// Формат пикселя
if (image.component == 1)
format = GL_RED;
else if (image.component == 2)
format = GL_RG;
else if (image.component == 3)
format = GL_RGB;
// Тип данных
if (image.bits == 16)
type = GL_UNSIGNED_SHORT;
else if (image.bits == 32)
type = GL_UNSIGNED_INT;
Texture tmp( image.width, image.height
, image.image.data()
, 0, format, format
, type
);
textures.push_back(tmp);
}
}
// Трансформации вложенных узлов
std::vector<glm::mat4> transforms(in_model.nodes.size(), glm::mat4(1));
for (auto & scene : in_model.scenes)
for (auto & node_id : scene.nodes)
node_process(node_id, node_id, in_model, transforms);
// Цикл по всем индексам узлов
for (int node_id = 0; node_id < in_model.nodes.size(); node_id++)
{
// Узел по индексу
auto & node = in_model.nodes[node_id];
// Если нет полигонов - это групповой узел
if (node.mesh < 0)
continue; // Пропускаем
// Полигональная сетка по индексу из узла
auto & mesh = in_model.meshes[node.mesh];
// Для каждого примитива связанного с полигональной сеткой
for (auto & primitive : mesh.primitives)
{
Model model;
// Цикл по атрибутам примитива
for (auto & attribute : primitive.attributes)
{
// Средство доступа
auto & accessor = in_model.accessors[attribute.second];
// Границы буфера
auto & bufferView = in_model.bufferViews[accessor.bufferView];
// Индекс привязки на шейдере
int attribute_index;
if (attribute.first.compare("POSITION") == 0)
attribute_index = 0;
else
if (attribute.first.compare("TEXCOORD_0") == 0)
attribute_index = 1;
else
if (attribute.first.compare("NORMAL") == 0)
attribute_index = 2;
else
continue;
// Подключаем вершинный буфер
model.setBO(attribute_index, BOs[accessor.bufferView]);
BOs[accessor.bufferView].use();
glEnableVertexAttribArray(attribute_index);
// Устанавливаем связь между VAO и привязанным VBO
glVertexAttribPointer( attribute_index // индекс атрибута, должен совпадать с Layout шейдера
, tinygltf::GetNumComponentsInType(accessor.type) // количество компонент одного элемента
, accessor.componentType // тип
, accessor.normalized ? GL_TRUE : GL_FALSE // нормализованность значений
, accessor.ByteStride(bufferView) // шаг
, ((char *)NULL + accessor.byteOffset) // отступ с начала массива
);
}
// Средство доступа для индексов
auto & accessor = in_model.accessors[primitive.indices];
// Границы индексного буфера
auto & bufferView = in_model.bufferViews[accessor.bufferView];
model.setIndicesBO(BOs[accessor.bufferView]);
model.set_index_range(accessor.byteOffset, accessor.count, accessor.componentType);
// Трансформация относительно родительских узлов
model.position = glm::vec3(transforms[node_id][3][0], transforms[node_id][3][1], transforms[node_id][3][2]);
model.scale = { glm::length(glm::vec3(transforms[node_id][0][0],transforms[node_id][1][0],transforms[node_id][2][0]))
, glm::length(glm::vec3(transforms[node_id][0][1],transforms[node_id][1][1],transforms[node_id][2][1]))
, glm::length(glm::vec3(transforms[node_id][0][2],transforms[node_id][1][2],transforms[node_id][2][2]))
};
glm::extractEulerAngleXYZ(transforms[node_id], model.rotation.x, model.rotation.y, model.rotation.z);
// Если есть параметры трансформации
if (node.translation.size() == 3)
model.position += glm::vec3(node.translation[0], node.translation[1], node.translation[2]);
if (node.rotation.size() == 4)
model.rotation += glm::eulerAngles(glm::quat(node.rotation[3], glm::vec3(node.rotation[0], node.rotation[1], node.rotation[2])));
if (node.scale.size() == 3)
model.scale *= glm::vec3(node.scale[0], node.scale[1], node.scale[2]);
model.rotation *= 180.0f / 3.14159f; // угол в градусы
// Параметры материалов
auto& material = in_model.materials[primitive.material];
model.material.base_color = { material.pbrMetallicRoughness.baseColorFactor[0]
, material.pbrMetallicRoughness.baseColorFactor[1]
, material.pbrMetallicRoughness.baseColorFactor[2] };
model.material.metallic = material.pbrMetallicRoughness.metallicFactor;
model.material.roughness = material.pbrMetallicRoughness.roughnessFactor;
model.material.emitted = { material.emissiveFactor[0]
, material.emissiveFactor[1]
, material.emissiveFactor[2] };
if (material.pbrMetallicRoughness.baseColorTexture.index > -1)
{
textures[material.pbrMetallicRoughness.baseColorTexture.index].setType(TEX_ALBEDO);
model.set_texture(textures[material.pbrMetallicRoughness.baseColorTexture.index]);
}
if (material.pbrMetallicRoughness.metallicRoughnessTexture.index > -1)
{
textures[material.pbrMetallicRoughness.metallicRoughnessTexture.index].setType(TEX_METALLIC);
model.set_texture(textures[material.pbrMetallicRoughness.metallicRoughnessTexture.index]);
model.material.roughness = -2;
}
if (material.emissiveTexture.index > -1)
{
textures[material.emissiveTexture.index].setType(TEX_EMITTED);
model.set_texture(textures[material.emissiveTexture.index]);
}
auto specular_ext = material.extensions.find("KHR_materials_specular");
if (specular_ext != material.extensions.end())
{
if (specular_ext->second.Has("specularColorFactor"))
{
auto& specular_color = specular_ext->second.Get("specularColorFactor");
model.material.specular = (specular_color.Get(0).GetNumberAsDouble() + specular_color.Get(1).GetNumberAsDouble() + specular_color.Get(2).GetNumberAsDouble()) / 3;
}
if (specular_ext->second.Has("specularColorTexture"))
{
auto& specular_texture = specular_ext->second.Get("specularColorTexture");
int index = specular_texture.Get("index").GetNumberAsInt();
if (index > -1)
{
textures[index].setType(TEX_SPECULAR);
model.set_texture(textures[index]);
}
}
}
// Добавляем в GrouptedModel
result.parts.push_back(model);
}
}
}
return result;
}
// Вызов отрисовки групповой модели // Вызов отрисовки групповой модели
void GrouptedModel::render(ShaderProgram &shaderProgram, UBO &material_buffer) void GrouptedModel::render(ShaderProgram &shaderProgram, UBO &material_buffer)
{ {

View File

@ -115,8 +115,8 @@ 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 файла // Загрузка сцены из glTF файла
GrouptedModel scene = loadOBJtoGroupted("../resources/models/blob.obj", "../resources/models/", "../resources/textures/"); GrouptedModel scene = loadGLTFtoGroupted("../resources/models/blob.gltf");
scene.scale = glm::vec3(0.01); scene.scale = glm::vec3(0.01);
scene.position.z = 1; scene.position.z = 1;
scene.set_group_id((GLuint64) &scene); scene.set_group_id((GLuint64) &scene);