Optimize model texture loading, test assimp with complicated model
This commit is contained in:
parent
ab3f6c98ff
commit
475bb08f0e
|
@ -1,5 +1,2 @@
|
|||
*.blend
|
||||
*.obj
|
||||
*.png
|
||||
*.bin
|
||||
*.gltf
|
||||
*
|
||||
!shaders
|
|
@ -1,4 +1,3 @@
|
|||
#include "entt/entity/fwd.hpp"
|
||||
#include "simpleengine/camera.h"
|
||||
#include "simpleengine/ecs/component/mesh_component.h"
|
||||
#include <simpleengine/ecs/component/model_component.h>
|
||||
|
@ -12,7 +11,6 @@
|
|||
#include "simpleengine/gfx/renderer.h"
|
||||
#include "simpleengine/gfx/texture.h"
|
||||
#include "simpleengine/vector.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <simpleengine/gfx/shader.h>
|
||||
#include <simpleengine/renderable.h>
|
||||
#include <simpleengine/event/event.h>
|
||||
|
@ -21,11 +19,8 @@
|
|||
#include <simpleengine/vertex.h>
|
||||
#include <simpleengine/gfx/shaders/core_3d_shader.h>
|
||||
#include <simpleengine/gfx/model.h>
|
||||
|
||||
#include <simpleengine/scene.h>
|
||||
|
||||
//#include <simpleengine/scene.h>
|
||||
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/fwd.hpp>
|
||||
#include <assimp/material.h>
|
||||
|
@ -170,8 +165,8 @@ int main(int argc, char *argv[]) {
|
|||
5, 6, 12, 12, 6, 13
|
||||
};
|
||||
|
||||
std::unordered_map<aiTextureType, std::vector<se::gfx::Texture>> textures;
|
||||
textures.emplace(white_texture.type, std::vector<se::gfx::Texture>{ white_texture });
|
||||
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<se::gfx::Texture>>> textures;
|
||||
textures.emplace(white_texture.type, std::vector<std::shared_ptr<se::gfx::Texture>>{ std::make_shared<se::gfx::Texture>(white_texture) });
|
||||
se::gfx::Material white_material(textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
// Create a renderer
|
||||
|
@ -184,10 +179,17 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
// Create an Entity in the Scene and add components to it.
|
||||
se::ecs::Entity entity = scene->create_entity();
|
||||
entity.add_component<se::ModelComponent>("examples/dev_testing/resources/dragon.obj");
|
||||
entity.add_component<se::RotatingComponent>();
|
||||
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/dragon.obj");
|
||||
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/stall.obj");
|
||||
entity.add_component<se::ModelComponent>("examples/dev_testing/resources/backpack/backpack.obj");
|
||||
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/scientist/scientist.fbx");
|
||||
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/paradigm/paradigm.fbx");
|
||||
//entity.add_component<se::RotatingComponent>();
|
||||
auto& transform_comp = entity.add_component<se::TransformComponent>();
|
||||
transform_comp.translate(12.f, -4.f, 0.f);
|
||||
transform_comp.translate(15.f, -8.f, 0.f);
|
||||
/* transform_comp.scale(0.1f);
|
||||
transform_comp.rotate_z(-90.f);*/
|
||||
transform_comp.rotate_x(-90.f);
|
||||
|
||||
|
||||
// Create the entity and add the model component to it.
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
#include "texture.h"
|
||||
|
||||
#include <assimp/material.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
namespace simpleengine::gfx {
|
||||
class Material {
|
||||
public:
|
||||
std::unordered_map<aiTextureType, std::vector<Texture>> textures;
|
||||
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures;
|
||||
|
||||
float ambient_scalar;
|
||||
float diffuse_scalar;
|
||||
|
@ -16,7 +18,7 @@ namespace simpleengine::gfx {
|
|||
float shine;
|
||||
float reflectivity;
|
||||
|
||||
Material(std::unordered_map<aiTextureType, std::vector<Texture>> textures, float shine = 1.f, float reflectivity = 0.f, float specular_scalar = 0.f, float ambient_scalar = 0.f, float diffuse_scalar = 0.f) :
|
||||
Material(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures, float shine = 1.f, float reflectivity = 0.f, float specular_scalar = 0.f, float ambient_scalar = 0.f, float diffuse_scalar = 0.f) :
|
||||
textures(textures), ambient_scalar(ambient_scalar), diffuse_scalar(diffuse_scalar), specular_scalar(specular_scalar),
|
||||
shine(shine), reflectivity(reflectivity) {
|
||||
|
||||
|
|
|
@ -26,8 +26,10 @@ namespace simpleengine::gfx {
|
|||
Model(std::string file_path);
|
||||
|
||||
void load_model(std::string path);
|
||||
void process_node(aiNode* node, const aiScene* scene);
|
||||
gfx::Mesh process_mesh(aiMesh* mesh, const aiScene* scene);
|
||||
std::vector<Texture> load_material_textures(aiMaterial* material, aiTextureType type);
|
||||
void process_node(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiNode* node, const aiScene* scene);
|
||||
gfx::Mesh process_mesh(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMesh* mesh, const aiScene* scene);
|
||||
|
||||
std::unordered_map<aiTextureType, std::vector<Texture>> load_all_textures(aiMaterial* material);
|
||||
std::vector<std::shared_ptr<Texture>> load_material_texture(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMaterial* material, aiTextureType type);
|
||||
};
|
||||
}
|
|
@ -30,6 +30,7 @@ namespace simpleengine::gfx {
|
|||
int width;
|
||||
int channels;
|
||||
aiTextureType type;
|
||||
std::string path;
|
||||
|
||||
/**
|
||||
* @brief Construct a new Texture object from a path.
|
||||
|
@ -38,7 +39,7 @@ namespace simpleengine::gfx {
|
|||
* @param img_2d Whether or not the texture is 2D.
|
||||
* @param mipmap Whether or not to generate mipmaps for this texture.
|
||||
*/
|
||||
Texture(const char* path, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true);
|
||||
Texture(const char* path, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool flip_vertically = false, bool mipmap = true);
|
||||
|
||||
/**
|
||||
* @brief Construct a new Texture object from the loaded file buffer.
|
||||
|
@ -48,7 +49,7 @@ namespace simpleengine::gfx {
|
|||
* @param img_2d Whether or not the texture is 2D.
|
||||
* @param mipmap Whether or not to generate mipmaps for this texture.
|
||||
*/
|
||||
Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true);
|
||||
Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool flip_vertically = false, bool mipmap = true);
|
||||
|
||||
/**
|
||||
* @brief Construct a new Texture object from the loaded file buffer.
|
||||
|
@ -57,7 +58,7 @@ namespace simpleengine::gfx {
|
|||
* @param img_2d Whether or not the texture is 2D.
|
||||
* @param mipmap Whether or not to generate mipmaps for this texture.
|
||||
*/
|
||||
Texture(std::vector<unsigned char> buffer, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true);
|
||||
Texture(std::vector<unsigned char> buffer, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool flip_vertically = false, bool mipmap = true);
|
||||
|
||||
static Texture white_texture();
|
||||
|
||||
|
|
|
@ -12,6 +12,5 @@ pkgs.mkShell {
|
|||
glfw
|
||||
glm
|
||||
assimp
|
||||
(callPackage ./soil2.nix { })
|
||||
];
|
||||
}
|
37
soil2.nix
37
soil2.nix
|
@ -1,37 +0,0 @@
|
|||
{ lib
|
||||
, stdenv
|
||||
, fetchFromGitHub
|
||||
, cmake
|
||||
, libGL
|
||||
, libX11
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
version = "39028e64921c03cabbc53b937da4a85aba264e00";
|
||||
pname = "soil2";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "SpartanJ";
|
||||
repo = pname;
|
||||
rev = version;
|
||||
sha256 = "sha256-zQQ8lwOkMCxdlf6zfnIOYVUTGVqnJuHL/LL8fbzxwHY=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ cmake libGL libX11 ];
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
cmake --build . --target install --config Release
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "SOIL2 is a tiny C library used primarily for uploading textures into OpenGL.";
|
||||
homepage = "https://github.com/SpartanJ/SOIL2";
|
||||
license = licenses.mit0;
|
||||
platforms = platforms.unix;
|
||||
maintainers = with maintainers; [ seanomik ];
|
||||
};
|
||||
}
|
|
@ -31,28 +31,28 @@ namespace simpleengine::gfx {
|
|||
|
||||
model_directory = path.substr(0, path.find_last_of('/'));
|
||||
|
||||
process_node(scene->mRootNode, scene);
|
||||
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> processed_textures;
|
||||
process_node(processed_textures, scene->mRootNode, scene);
|
||||
}
|
||||
|
||||
void Model::process_node(aiNode* node, const aiScene* scene) {
|
||||
void Model::process_node(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiNode* node, const aiScene* scene) {
|
||||
// process all the node's meshes (if any)
|
||||
for (int i = 0; i < node->mNumMeshes; i++) {
|
||||
aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
|
||||
meshes.push_back(process_mesh(mesh, scene));
|
||||
meshes.push_back(process_mesh(processed_textures, mesh, scene));
|
||||
}
|
||||
|
||||
// then do the same for each of its children
|
||||
for (int i = 0; i < node->mNumChildren; i++) {
|
||||
process_node(node->mChildren[i], scene);
|
||||
process_node(processed_textures, node->mChildren[i], scene);
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Mesh Model::process_mesh(aiMesh* mesh, const aiScene* scene) {
|
||||
gfx::Mesh Model::process_mesh(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMesh* mesh, const aiScene* scene) {
|
||||
std::vector<LitVertex> vertices;
|
||||
std::vector<unsigned int> indices;
|
||||
std::vector<Texture> textures;
|
||||
|
||||
for(unsigned int i = 0; i < mesh->mNumVertices; i++) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
|
||||
LitVertex vertex;
|
||||
vertex.color = glm::vec3(1.f);
|
||||
vertex.texture_id = 0;
|
||||
|
@ -63,7 +63,7 @@ namespace simpleengine::gfx {
|
|||
glm::vec3 normal(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z);
|
||||
vertex.normal = normal;
|
||||
|
||||
if(mesh->mTextureCoords[0]) {
|
||||
if (mesh->mTextureCoords[0]) {
|
||||
glm::vec2 tex_coord(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y);
|
||||
|
||||
vertex.tex_coord = tex_coord;
|
||||
|
@ -83,18 +83,18 @@ namespace simpleengine::gfx {
|
|||
|
||||
// Create a default material and white texture.
|
||||
auto white_texture = gfx::Texture::white_texture();
|
||||
std::unordered_map<aiTextureType, std::vector<Texture>> default_textures;
|
||||
default_textures.emplace(white_texture.type, std::vector<Texture>{ white_texture });
|
||||
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> default_textures;
|
||||
default_textures.emplace(white_texture.type, std::vector<std::shared_ptr<Texture>>{ std::make_shared<Texture>(white_texture) });
|
||||
gfx::Material mat(default_textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
if(mesh->mMaterialIndex >= 0) {
|
||||
if (mesh->mMaterialIndex >= 0) {
|
||||
std::cout << "TODO: Process model materials!" << std::endl;
|
||||
|
||||
std::unordered_map<aiTextureType, std::vector<Texture>> textures;
|
||||
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures;
|
||||
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
|
||||
|
||||
// Load Diffuse texture maps
|
||||
std::vector<Texture> diffuse_maps = load_material_textures(material, aiTextureType_DIFFUSE);
|
||||
std::vector<std::shared_ptr<Texture>> diffuse_maps = load_material_texture(processed_textures, material, aiTextureType_DIFFUSE);
|
||||
if (!diffuse_maps.empty()) textures.emplace(aiTextureType_DIFFUSE, diffuse_maps);
|
||||
|
||||
// TODO Handle other types of texture maps
|
||||
|
@ -102,25 +102,73 @@ namespace simpleengine::gfx {
|
|||
if (!textures.empty()) {
|
||||
// TODO: Find a way to let the user set the scalars.
|
||||
mat = Material(textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
// Add `textures` into the `processed_textures` list.
|
||||
for (const auto& pair : textures) {
|
||||
for (const auto& texture : pair.second) {
|
||||
bool contains = false;
|
||||
|
||||
auto found = processed_textures.find(pair.first);
|
||||
if (found != processed_textures.end()) {
|
||||
for (const auto& processed_text : found->second) {
|
||||
if (processed_text->path == texture->path) {
|
||||
contains = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!contains) {
|
||||
//found->second
|
||||
found->second.emplace_back(texture);
|
||||
}
|
||||
} else {
|
||||
processed_textures.emplace(pair.first, std::vector<std::shared_ptr<Texture>>{ pair.second });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Mesh(vertices, indices, mat);
|
||||
}
|
||||
|
||||
std::vector<Texture> Model::load_material_textures(aiMaterial* material, aiTextureType type) {
|
||||
std::vector<Texture> textures;
|
||||
std::unordered_map<aiTextureType, std::vector<Texture>> load_all_textures(aiMaterial* material) {
|
||||
// Load Diffuse texture maps
|
||||
return {};
|
||||
}
|
||||
|
||||
for(int i = 0; i < material->GetTextureCount(type); i++) {
|
||||
aiString texture_path;
|
||||
material->GetTexture(type, i, &texture_path);
|
||||
std::vector<std::shared_ptr<Texture>> Model::load_material_texture(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMaterial* material, aiTextureType type) {
|
||||
std::vector<std::shared_ptr<Texture>> textures;
|
||||
|
||||
for (int i = 0; i < material->GetTextureCount(type); i++) {
|
||||
aiString texture_path_ai;
|
||||
material->GetTexture(type, i, &texture_path_ai);
|
||||
std::string texture_path = texture_path_ai.C_Str();
|
||||
|
||||
// If the texture has been read, we should skip it.
|
||||
bool skip = false;
|
||||
for (const auto& pair : processed_textures) {
|
||||
if (pair.first == type) {
|
||||
for (const auto& texture : pair.second) {
|
||||
if (texture->path == texture_path) {
|
||||
textures.emplace_back(texture); // Push a copy of the texture for this Mesh.
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (skip) continue;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << model_directory << "/" << texture_path.C_Str();
|
||||
ss << model_directory << "/" << texture_path;
|
||||
std::string full_path = ss.str();
|
||||
|
||||
Texture texture(full_path.c_str(), type);
|
||||
textures.emplace_back(texture);
|
||||
Texture texture(full_path.c_str(), type, true, true);
|
||||
texture.path = texture_path;
|
||||
textures.emplace_back(std::make_shared<Texture>(texture));
|
||||
|
||||
std::cout << "Texture full path: " << full_path << ", texture_path: " << texture_path << std::endl;
|
||||
}
|
||||
|
||||
return textures;
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace simpleengine::gfx {
|
|||
if (texture_count >= 16) break;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + texture_count);
|
||||
glBindTextureUnit(texture_count, texture.get_texture_id());
|
||||
glBindTextureUnit(texture_count, texture->get_texture_id());
|
||||
|
||||
texture_count++;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <stb_image.h>
|
||||
|
||||
namespace simpleengine::gfx {
|
||||
Texture::Texture(const char* path, aiTextureType type, bool img_2d, bool mipmap): type(type) {
|
||||
Texture::Texture(const char* path, aiTextureType type, bool img_2d, bool flip_vertically, bool mipmap): type(type) {
|
||||
image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D;
|
||||
|
||||
glGenTextures(1, &texture_id);
|
||||
|
@ -17,6 +17,8 @@ namespace simpleengine::gfx {
|
|||
glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param);
|
||||
glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param);
|
||||
|
||||
stbi_set_flip_vertically_on_load(flip_vertically);
|
||||
|
||||
// Read 4 channels (RGBA)
|
||||
img_data = stbi_load(path, &width, &height, &channels, 4);
|
||||
if(!img_data) {
|
||||
|
@ -32,10 +34,12 @@ namespace simpleengine::gfx {
|
|||
glGenerateMipmap(image_type_gl);
|
||||
}
|
||||
|
||||
stbi_set_flip_vertically_on_load(false);
|
||||
|
||||
unbind();
|
||||
}
|
||||
|
||||
Texture::Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type, bool img_2d, bool mipmap): type(type) {
|
||||
Texture::Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type, bool img_2d, bool flip_vertically, bool mipmap): type(type) {
|
||||
image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D;
|
||||
|
||||
glGenTextures(1, &texture_id);
|
||||
|
@ -48,6 +52,8 @@ namespace simpleengine::gfx {
|
|||
glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param);
|
||||
glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param);
|
||||
|
||||
stbi_set_flip_vertically_on_load(flip_vertically);
|
||||
|
||||
// Read 4 channels (RGBA)
|
||||
img_data = stbi_load_from_memory(buffer, buffer_length, &width, &height, &channels, 4);
|
||||
if(!img_data) {
|
||||
|
@ -63,10 +69,12 @@ namespace simpleengine::gfx {
|
|||
glGenerateMipmap(image_type_gl);
|
||||
}
|
||||
|
||||
stbi_set_flip_vertically_on_load(false);
|
||||
|
||||
unbind();
|
||||
}
|
||||
|
||||
Texture::Texture(std::vector<unsigned char> buffer, aiTextureType type, bool img_2d, bool mipmap) :
|
||||
Texture::Texture(std::vector<unsigned char> buffer, aiTextureType type, bool img_2d, bool flip_vertically, bool mipmap) :
|
||||
Texture(buffer.data(), buffer.size(), type, img_2d, mipmap) {
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue