Compare commits
No commits in common. "master" and "v0.2" have entirely different histories.
|
@ -6,14 +6,8 @@
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
#include "Camera.h"
|
#include "Camera.h"
|
||||||
|
|
||||||
#include <GLM/gtc/type_ptr.hpp>
|
|
||||||
#include <GLM/gtc/quaternion.hpp>
|
|
||||||
#include <GLM/gtx/quaternion.hpp>
|
|
||||||
#include <GLM/gtx/euler_angles.hpp>
|
|
||||||
|
|
||||||
#define DEFAULT_MTL_DIR "./"
|
#define DEFAULT_MTL_DIR "./"
|
||||||
class Scene loadOBJtoScene(const char* filename, const char* mtl_directory = DEFAULT_MTL_DIR, const char* texture_directory = DEFAULT_MTL_DIR);
|
class Scene loadOBJtoScene(const char* filename, const char* mtl_directory = DEFAULT_MTL_DIR, const char* texture_directory = DEFAULT_MTL_DIR);
|
||||||
class Scene loadGLTFtoScene(std::string filename);
|
|
||||||
|
|
||||||
// Класс сцены
|
// Класс сцены
|
||||||
class Scene
|
class Scene
|
||||||
|
|
|
@ -104,19 +104,10 @@ 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;
|
||||||
// Если используется двухканальная текстура
|
|
||||||
if (roughness < -1)
|
|
||||||
{
|
|
||||||
// Сохранение шероховатости и металличности
|
|
||||||
gRMS.rg = texture(tex_metallic, new_texCoord).bg;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Сохранение шероховатости
|
// Сохранение шероховатости
|
||||||
gRMS.r = roughness<0?texture(tex_roughness, new_texCoord).r:roughness;
|
gRMS.r = roughness<0?texture(tex_roughness, new_texCoord).r:roughness;
|
||||||
// Сохранение металличности
|
// Сохранение металличности
|
||||||
gRMS.g = metallic<0?texture(tex_metallic, new_texCoord).r:metallic;
|
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;
|
||||||
// Сохранение идентификатора объекта
|
// Сохранение идентификатора объекта
|
||||||
|
|
302
src/Scene.cpp
302
src/Scene.cpp
|
@ -263,305 +263,3 @@ void Scene::set_group_id(GLuint64 id, GLuint etc)
|
||||||
model.id.etc = etc;
|
model.id.etc = etc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TINYGLTF_IMPLEMENTATION
|
|
||||||
#define TINYGLTF_NO_STB_IMAGE_WRITE
|
|
||||||
#define TINYGLTF_NOEXCEPTION
|
|
||||||
#define JSON_NOEXCEPTION
|
|
||||||
#include "tiny_gltf.h"
|
|
||||||
|
|
||||||
void collectGLTFnodes(int node_id, std::vector<int> &nodes, tinygltf::Model &in_model)
|
|
||||||
{
|
|
||||||
nodes.push_back(node_id);
|
|
||||||
for (auto& child : in_model.nodes[node_id].children)
|
|
||||||
collectGLTFnodes(child, nodes, in_model);
|
|
||||||
}
|
|
||||||
|
|
||||||
Scene loadGLTFtoScene(std::string filename)
|
|
||||||
{
|
|
||||||
Scene 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<Node *> pNodes(in_model.nodes.size(), NULL);
|
|
||||||
// Индексы родителей (-1 - корневой узел сцены)
|
|
||||||
std::vector<int> parents_id(in_model.nodes.size(), -1);
|
|
||||||
|
|
||||||
// Цикл по сценам
|
|
||||||
for (auto &scene : in_model.scenes)
|
|
||||||
{
|
|
||||||
// Так как у нас есть информация о потомках корневого узла сцены - пройдем рекурсивно и соберем все узлы из этой сцены:
|
|
||||||
std::vector<int> scene_nodes;
|
|
||||||
// Цикл по узлам рассматриваемой сцены с рекурсивным проходом потомков
|
|
||||||
for (auto &node_id : scene.nodes)
|
|
||||||
collectGLTFnodes(node_id, scene_nodes, in_model);
|
|
||||||
|
|
||||||
// Цикл по всем узлам рассматриваемой сцены
|
|
||||||
for (auto &node_id : scene_nodes)
|
|
||||||
{
|
|
||||||
auto &node = in_model.nodes[node_id];
|
|
||||||
|
|
||||||
Node *tmpParent = &result.root; // Указатель на родителя, используется если узел сложный (несколько мешей или камера-меш)
|
|
||||||
|
|
||||||
// Запишем текущий узел как родительский для потомков
|
|
||||||
for (auto& child : node.children)
|
|
||||||
parents_id[child] = node_id;
|
|
||||||
|
|
||||||
// Проверим наличие сложной сетки
|
|
||||||
bool complex_mesh = false;
|
|
||||||
// Если у узла есть полигональная сетка
|
|
||||||
if (node.mesh > -1)
|
|
||||||
if (in_model.meshes[node.mesh].primitives.size() > 1)
|
|
||||||
complex_mesh = true;
|
|
||||||
|
|
||||||
// Если узел составной: имеет и камеру, и полигональную сетку
|
|
||||||
// или узел пустой
|
|
||||||
// или имеет сложную полигональную сетку (примитивов больше одного)
|
|
||||||
if (node.camera > -1 && node.mesh > -1
|
|
||||||
|| node.camera == -1 && node.mesh == -1
|
|
||||||
|| complex_mesh)
|
|
||||||
{
|
|
||||||
// Создадим вспомогательный родительский узел для трансформаций
|
|
||||||
result.nodes.push_back(Node(&result.root));
|
|
||||||
pNodes[node_id] = tmpParent = &result.nodes.back(); // Сохраним в массив узлов и как родителя
|
|
||||||
// В противном случае дополнительный узел не требуется
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обработаем полигональную сетку
|
|
||||||
if (node.mesh > -1)
|
|
||||||
{
|
|
||||||
auto &mesh = in_model.meshes[node.mesh];
|
|
||||||
|
|
||||||
// Для каждого примитива связанного с полигональной сеткой
|
|
||||||
for (auto &primitive : mesh.primitives)
|
|
||||||
{
|
|
||||||
Model model(tmpParent); // Тут используется либо корневой узел сцены, либо вспомогательный узел
|
|
||||||
|
|
||||||
// Цикл по атрибутам примитива
|
|
||||||
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);
|
|
||||||
// Определим спецификацию атрибута
|
|
||||||
glVertexAttribPointer( attribute_index // индекс атрибута, должен совпадать с Layout шейдера
|
|
||||||
, tinygltf::GetNumComponentsInType(accessor.type) // количество компонент одного элемента
|
|
||||||
, accessor.componentType // тип
|
|
||||||
, accessor.normalized ? GL_TRUE : GL_FALSE // нормализованность значений
|
|
||||||
, accessor.ByteStride(bufferView) // шаг
|
|
||||||
, ((char *)NULL + accessor.byteOffset) // отступ с начала массива
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Если есть индексы
|
|
||||||
if (primitive.indices > -1)
|
|
||||||
{
|
|
||||||
// Средство доступа для индексов
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Если есть материал
|
|
||||||
if (primitive.material > -1)
|
|
||||||
{
|
|
||||||
// Параметры материалов
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.models.push_back(model); // Добавляем к сцене
|
|
||||||
// Если ещё не сохранили
|
|
||||||
if (!pNodes[node_id])
|
|
||||||
pNodes[node_id] = &result.models.back(); // Сохраним адрес созданного узла
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обработаем камеру
|
|
||||||
if (in_model.nodes[node_id].camera > -1)
|
|
||||||
{
|
|
||||||
auto &in_camera = in_model.cameras[in_model.nodes[node_id].camera];
|
|
||||||
// Если камера использует проекцию перспективы
|
|
||||||
if (in_camera.type == "perspective")
|
|
||||||
{
|
|
||||||
Camera camera(in_camera.perspective.aspectRatio, glm::vec3(0.0f), CAMERA_DEFAULT_ROTATION, in_camera.perspective.yfov, in_camera.perspective.znear, in_camera.perspective.zfar);
|
|
||||||
result.cameras.push_back(camera);
|
|
||||||
}
|
|
||||||
// Иначе ортографическую проекцию
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Camera camera(in_camera.orthographic.xmag, in_camera.orthographic.ymag, glm::vec3(0.0f), CAMERA_DEFAULT_ROTATION, in_camera.orthographic.znear, in_camera.orthographic.zfar);
|
|
||||||
result.cameras.push_back(camera);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Если у узла есть полигональная сетка - сделаем камеру потомком модели, адрес которой записан в вектор
|
|
||||||
if (in_model.nodes[node_id].mesh > -1)
|
|
||||||
result.cameras.back().setParent(pNodes[node_id]);
|
|
||||||
// Иначе узел является камерой сам по себе
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.cameras.back().setParent(&result.root);
|
|
||||||
pNodes[node_id] = &result.cameras.back(); // Сохраним адрес созданного узла
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Зададим трансформацию и родителей для узлов
|
|
||||||
// Цикл по всем индексам узлов
|
|
||||||
for (int node_id = 0; node_id < in_model.nodes.size(); node_id++)
|
|
||||||
{
|
|
||||||
// Проверка на нулевой указатель
|
|
||||||
if (pNodes[node_id])
|
|
||||||
{
|
|
||||||
// Если есть матрица трансформации - разберем её на составляющие
|
|
||||||
if (in_model.nodes[node_id].matrix.size() == 16)
|
|
||||||
{
|
|
||||||
glm::mat4 transform = glm::make_mat4(in_model.nodes[node_id].matrix.data());
|
|
||||||
pNodes[node_id]->e_position() = glm::vec3(transform[3][0], transform[3][1], transform[3][2]);
|
|
||||||
pNodes[node_id]->e_scale() = {glm::length(glm::vec3(transform[0][0], transform[1][0], transform[2][0])), glm::length(glm::vec3(transform[0][1], transform[1][1], transform[2][1])), glm::length(glm::vec3(transform[0][2], transform[1][2], transform[2][2]))};
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
transform[i] = glm::normalize(transform[i]);
|
|
||||||
pNodes[node_id]->e_rotation() = glm::quat_cast(transform);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Если есть параметры трансформации
|
|
||||||
if (in_model.nodes[node_id].translation.size() == 3)
|
|
||||||
pNodes[node_id]->e_position() = glm::vec3(in_model.nodes[node_id].translation[0], in_model.nodes[node_id].translation[1], in_model.nodes[node_id].translation[2]);
|
|
||||||
if (in_model.nodes[node_id].rotation.size() == 4)
|
|
||||||
pNodes[node_id]->e_rotation() = glm::quat(in_model.nodes[node_id].rotation[3], glm::vec3(in_model.nodes[node_id].rotation[0], in_model.nodes[node_id].rotation[1], in_model.nodes[node_id].rotation[2]));
|
|
||||||
if (in_model.nodes[node_id].scale.size() == 3)
|
|
||||||
pNodes[node_id]->e_scale() = glm::vec3(in_model.nodes[node_id].scale[0], in_model.nodes[node_id].scale[1], in_model.nodes[node_id].scale[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Если индекс родителя > -1, то родитель создан и это не корневой узел сцены
|
|
||||||
if (parents_id[node_id] > -1)
|
|
||||||
pNodes[node_id]->setParent(pNodes[parents_id[node_id]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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/blob.gltf");
|
Scene scene = loadOBJtoScene("../resources/models/blob.obj", "../resources/models/", "../resources/textures/");
|
||||||
scene.root.e_scale() = glm::vec3(0.01);
|
scene.root.e_scale() = glm::vec3(0.01);
|
||||||
scene.root.e_position().z = 1;
|
scene.root.e_position().z = 1;
|
||||||
scene.set_group_id((GLuint64) &scene.root);
|
scene.set_group_id((GLuint64) &scene.root);
|
||||||
|
|
Loading…
Reference in New Issue