Read diffuse textures from 3d models

This commit is contained in:
SeanOMik 2022-09-22 00:11:12 -04:00
parent 5a7e5cd10f
commit 08bcb56a5f
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
9 changed files with 71 additions and 148 deletions

View File

@ -24,6 +24,7 @@
#include <glm/ext/matrix_clip_space.hpp>
#include <glm/fwd.hpp>
#include <assimp/material.h>
#include <memory>
#include <chrono>
@ -80,7 +81,7 @@ int main(int argc, char *argv[]) {
auto light = std::make_shared<se::gfx::Light>(core_shader, glm::vec3(0.f, 1.f, -10.f), glm::vec3(1.f, 1.f, 1.f));
game.add_event(light);
se::gfx::Texture white_texture("examples/dev_testing/resources/white_texture.png");
auto white_texture = se::gfx::Texture::white_texture();
// white_texture.shine_damper = 10;
//white_texture.reflectivity = 1;
/* auto dragon = std::make_shared<se::objects_3d::Mesh>(game.get_window(), core_shader, white_texture, "examples/dev_testing/resources/dragon.obj");
@ -165,11 +166,13 @@ int main(int argc, char *argv[]) {
5, 6, 12, 12, 6, 13
};
se::gfx::Material material(white_texture, 1.f, 0.f, 0.f, 0.f, 0.f);
std::unordered_map<aiTextureType, std::vector<se::gfx::Texture>> textures;
textures.emplace(white_texture.type, std::vector<se::gfx::Texture>{ white_texture });
se::gfx::Material white_material(textures, 1.f, 0.f, 0.f, 0.f, 0.f);
// Create the entity and add the model component to it.
/* auto entity = std::make_shared<simpleengine::Entity>();
entity->add_component<se::MeshComponent>(cube_vertices, cube_indicies, material, true);
entity->add_component<se::MeshComponent>(cube_vertices, cube_indicies, white_material, true);
entity->translate(3.5f, 0.f, 0.f); */
auto entity = std::make_shared<simpleengine::Entity>();

View File

@ -2,12 +2,13 @@
#include "texture.h"
#include <GLFW/glfw3.h>
#include <assimp/material.h>
#include <unordered_map>
namespace simpleengine::gfx {
class Material {
public:
Texture texture;
std::unordered_map<aiTextureType, std::vector<Texture>> textures;
float ambient_scalar;
float diffuse_scalar;
@ -15,8 +16,8 @@ namespace simpleengine::gfx {
float shine;
float reflectivity;
Material(Texture texture, float shine = 1.f, float reflectivity = 0.f, float specular_scalar = 0.f, float ambient_scalar = 0.f, float diffuse_scalar = 0.f) :
texture(texture), ambient_scalar(ambient_scalar), diffuse_scalar(diffuse_scalar), specular_scalar(specular_scalar),
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) :
textures(textures), ambient_scalar(ambient_scalar), diffuse_scalar(diffuse_scalar), specular_scalar(specular_scalar),
shine(shine), reflectivity(reflectivity) {
}

View File

@ -30,8 +30,6 @@ namespace simpleengine::gfx {
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material);
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies = std::vector<GLuint>(), std::optional<Material> material = std::nullopt);
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material, gfx::VBO ebo, gfx::VBO vbo, gfx::VAO vao);
Mesh(Material material, std::string filename);
Mesh(Material material, std::ifstream file_stream);
virtual void destroy() override;
@ -46,10 +44,5 @@ namespace simpleengine::gfx {
*
*/
void calculate_normals();
private:
void process_vertex(const std::vector<std::string>& vertex_data, const std::vector<glm::vec2>& in_textures,
const std::vector<glm::vec3>& in_normals, std::vector<GLuint>& out_indicies,
std::vector<glm::vec2>& out_textures, std::vector<glm::vec3>& out_normals);
};
}

View File

@ -28,6 +28,6 @@ namespace simpleengine::gfx {
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, std::string type_name);
std::vector<Texture> load_material_textures(aiMaterial* material, aiTextureType type);
};
}

View File

@ -8,7 +8,7 @@
#include <gl/gl.h>
#endif
#include <GLFW/glfw3.h>
#include <assimp/material.h>
#include <glm/glm.hpp>
@ -26,19 +26,10 @@ namespace simpleengine::gfx {
Texture() = default;
public:
/**
* @brief The type of the texture
*
*/
enum Type {
TexT_DIFFUSE,
TexT_SPECULAR
};
int height;
int width;
int channels;
Type type;
aiTextureType type;
/**
* @brief Construct a new Texture object from a path.
@ -47,7 +38,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, Type type = Type::TexT_DIFFUSE, bool img_2d = true, bool mipmap = true);
Texture(const char* path, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true);
/**
* @brief Construct a new Texture object from the loaded file buffer.
@ -57,7 +48,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, Type type = Type::TexT_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 mipmap = true);
/**
* @brief Construct a new Texture object from the loaded file buffer.
@ -66,7 +57,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, Type type = Type::TexT_DIFFUSE, bool img_2d = true, bool mipmap = true);
Texture(std::vector<unsigned char> buffer, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true);
static Texture white_texture();

View File

@ -21,10 +21,6 @@ namespace simpleengine::gfx {
}
Mesh::Mesh(Material material, std::string filename) :
Mesh(material, std::ifstream(filename, std::ios::in | std::ios::binary)) {
}
std::vector<std::string> split_string(std::string str, const char delim) {
std::istringstream ss(str);
@ -41,90 +37,6 @@ namespace simpleengine::gfx {
return tokens;
}
Mesh::Mesh(Material material, std::ifstream file_stream) :
vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)),
vao(gfx::VAO::init()), material(material) {
if (!file_stream.is_open()) {
std::cerr << "File stream that was given to ObjModel::ObjModel is not open!" << std::endl;
throw std::runtime_error("Failed to open ObjModel model file");
}
// The vertices, texture coords, and normals that were read from the obj file
// these are not in a particular order.
std::vector<glm::vec3> obj_vertices;
std::vector<glm::vec2> obj_textures;
std::vector<glm::vec3> obj_normals;
// The texture coords and normals that have been sorted.
std::vector<glm::vec2> textures;
std::vector<glm::vec3> normals;
// Read the vertices, texture coords, and normals. Break when run into indices
std::string line;
while (std::getline(file_stream, line)) {
std::vector<std::string> line_tokens = split_string(line, ' ');
if (line_tokens.front() == "v") {
//glm::vec3 vertex(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3]));
obj_vertices.emplace_back(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3]));
} else if (line_tokens.front() == "vt") {
obj_textures.emplace_back(stof(line_tokens[1]), stof(line_tokens[2]));
} else if (line_tokens.front() == "vn") {
obj_normals.emplace_back(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3]));
} else if (line_tokens.front() == "f") {
auto size = obj_vertices.size();
textures.resize(size);
normals.resize(size);
break;
}
}
// Process the indicies. This will sort everything for storing inside of the Vertex list.
do {
if (!line.starts_with("f")) {
continue;
}
std::vector<std::string> line_tokens = split_string(line, ' ');
std::vector<std::string> vertex1 = split_string(line_tokens[1], '/');
std::vector<std::string> vertex2 = split_string(line_tokens[2], '/');
std::vector<std::string> vertex3 = split_string(line_tokens[3], '/');
process_vertex(vertex1, obj_textures, obj_normals, indicies, textures, normals);
process_vertex(vertex2, obj_textures, obj_normals, indicies, textures, normals);
process_vertex(vertex3, obj_textures, obj_normals, indicies, textures, normals);
} while (std::getline(file_stream, line));
file_stream.close();
const int texture_id = 0;
std::cout << "Texture ID: " << texture_id << std::endl;
// Insert everything into lit_vertices.
for (int i = 0; i < obj_vertices.size(); i++) {
vertices.emplace_back(simpleengine::Vectorf(obj_vertices.at(i)), glm::vec3(1.f), textures.at(i), normals.at(i), texture_id);
}
}
void Mesh::process_vertex(const std::vector<std::string>& vertex_data, const std::vector<glm::vec2>& in_textures,
const std::vector<glm::vec3>& in_normals, std::vector<GLuint>& out_indicies,
std::vector<glm::vec2>& out_textures, std::vector<glm::vec3>& out_normals) {
// Get the index the current vertex and put it in indicies
int currentVertexIndex = stoi(vertex_data[0]) - 1;
out_indicies.push_back(currentVertexIndex);
// Read texture coords
glm::vec2 current_tex = in_textures.at(stoi(vertex_data[1]) - 1);
current_tex.y = 1 - current_tex.y;
out_textures.at(currentVertexIndex) = current_tex;
// Read normals
glm::vec3 current_norm = in_normals.at(stoi(vertex_data[2]) - 1);
out_normals.at(currentVertexIndex) = current_norm;
}
void Mesh::destroy() {
this->ebo.destroy();
this->vbo.destroy();

View File

@ -7,7 +7,11 @@
#include <assimp/material.h>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <optional>
#include <sstream>
#include <unordered_map>
#include <vector>
namespace simpleengine::gfx {
Model::Model(std::string file_path) {
@ -77,38 +81,48 @@ namespace simpleengine::gfx {
}
}
std::optional<gfx::Material> op_mat;
// 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 });
gfx::Material mat(default_textures, 1.f, 0.f, 0.f, 0.f, 0.f);
// TODO: Process material
if(mesh->mMaterialIndex >= 0) {
std::cout << "TODO: Process model materials!" << std::endl;
/* aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
std::vector<Texture> diffuseMaps = load_material_textures(material,
aiTextureType_DIFFUSE, "texture_diffuse");
std::unordered_map<aiTextureType, std::vector<Texture>> textures;
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
std::vector<Texture> specularMaps = load_material_textures(material,
aiTextureType_SPECULAR, "texture_specular");
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end()); */
// Load Diffuse texture maps
std::vector<Texture> diffuse_maps = load_material_textures(material, aiTextureType_DIFFUSE);
if (!diffuse_maps.empty()) textures.emplace(aiTextureType_DIFFUSE, diffuse_maps);
// TODO Handle other types of texture maps
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);
}
}
// TODO: After we start processing materials, this can be put in the else statement as a fallback.
auto white_texture = gfx::Texture::white_texture();
//gfx::Material mat(white_texture);
//gfx::Texture white_texture("examples/dev_testing/resources/white_texture.png");
gfx::Material mat(white_texture, 1.f, 0.f, 0.f, 0.f, 0.f);
op_mat = std::optional<gfx::Material>(mat);
//return Mesh(vertices, indices, textures);
return Mesh(vertices, indices, op_mat);
return Mesh(vertices, indices, mat);
}
std::vector<Texture> Model::load_material_textures(aiMaterial* material, aiTextureType* type, std::string type_name) {
std::vector<Texture> Model::load_material_textures(aiMaterial* material, aiTextureType type) {
std::vector<Texture> textures;
for(int i = 0; i < material->GetTextureCount(type); i++) {
aiString texture_path;
material->GetTexture(type, i, &texture_path);
std::stringstream ss;
ss << model_directory << "/" << texture_path.C_Str();
std::string full_path = ss.str();
Texture texture(full_path.c_str(), type);
textures.emplace_back(texture);
}
return textures;
}
} // namespace simpleengine::gfx

View File

@ -9,6 +9,7 @@
#include "ecs/component/model_component.h"
#include <algorithm>
#include <assimp/material.h>
namespace simpleengine::gfx {
void create_mesh_buffers(std::shared_ptr<simpleengine::Component> comp, simpleengine::gfx::Mesh& mesh);
@ -99,9 +100,17 @@ namespace simpleengine::gfx {
shader.set_uniform_float("u_texture_shine", material->shine, false);
shader.set_uniform_float("u_texture_reflectivity", material->reflectivity, false);
glActiveTexture(GL_TEXTURE0);
glBindTextureUnit(0, material->texture.get_texture_id());
material->texture.bind();
int texture_count = 0;
auto diffuse_maps = material->textures.find(aiTextureType_DIFFUSE);
for (const auto& texture : diffuse_maps->second) {
// We can only bind to 16 textures at a time (indexes are 0-15)
if (texture_count >= 16) break;
glActiveTexture(GL_TEXTURE0 + texture_count);
glBindTextureUnit(texture_count, texture.get_texture_id());
texture_count++;
}
}
model.vao.bind();

View File

@ -4,7 +4,7 @@
#include <stb_image.h>
namespace simpleengine::gfx {
Texture::Texture(const char* path, Type type, bool img_2d, bool mipmap): type(type) {
Texture::Texture(const char* path, aiTextureType type, bool img_2d, bool mipmap): type(type) {
image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D;
glGenTextures(1, &texture_id);
@ -12,7 +12,7 @@ namespace simpleengine::gfx {
int linear_param = mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
glTexParameteri(image_type_gl, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(image_type_gl, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(image_type_gl, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param);
glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param);
@ -35,7 +35,7 @@ namespace simpleengine::gfx {
unbind();
}
Texture::Texture(const unsigned char *const buffer, int buffer_length, Type type, bool img_2d, bool mipmap): type(type) {
Texture::Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type, bool img_2d, bool mipmap): type(type) {
image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D;
glGenTextures(1, &texture_id);
@ -66,7 +66,7 @@ namespace simpleengine::gfx {
unbind();
}
Texture::Texture(std::vector<unsigned char> buffer, Type type, bool img_2d, bool mipmap) :
Texture::Texture(std::vector<unsigned char> buffer, aiTextureType type, bool img_2d, bool mipmap) :
Texture(buffer.data(), buffer.size(), type, img_2d, mipmap) {
}
@ -86,7 +86,7 @@ namespace simpleengine::gfx {
texture.width = width;
texture.height = height;
texture.channels = 4;
texture.type = Texture::Type::TexT_DIFFUSE;
texture.type = aiTextureType::aiTextureType_DIFFUSE;
texture.img_data = data;
glGenTextures(1, &texture.texture_id);