I am loading textures using reference in .mtl file coming with .obj of my model. I am using Assimp library for this purpose.
The problem is, as stated in the title, texture doesn't show up on the model or (in what I can't believe) it's black.
Here is the code for loading the texture:
std::vector<texture> model::loadMaterialTextures(aiMaterial * mat, aiTextureType type, std::string typeName)
{
std::vector<texture> textures;
for (GLuint i = 0; i < mat->GetTextureCount(type); i++)
{
aiString str;
mat->GetTexture(type, i, &str);
GLboolean skip = false;
for (GLuint j = 0; j < textures_loaded.size(); j++)
{
if (textures_loaded[j].path == str)
{
skip = true;
break;
}
}
if (!skip)
{
texture tex;
tex.id = textureFromFile(str.C_Str(), this->directory);
tex.type = typeName;
tex.path = str;
textures.push_back(tex);
this->textures_loaded.push_back(tex);
}
}
return textures;
}
GLint model::textureFromFile(const char* path, std::string directory)
{
//Generate texture ID and load texture data
std::string filename = std::string(path);
filename = directory + '\\' + filename;
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
int width, height;
unsigned char* image = SOIL_load_image(filename.c_str(), &width, &height, 0, SOIL_LOAD_RGB);
std::cout << SOIL_last_result() << std::endl;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
//auto e = glGetError();
// Parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image);
return textureID;
}
Okay, these two functions read .mtl for texture names and load them from the same directory. I have stepped through the code with debugger, and width and height are set correctly and image pointer points to the character array. Which makes me think this part is good.
Further returned texture struct goes into a constructor of my mesh object:
mesh::mesh(std::vector<vertex> vertices, std::vector<GLuint> indices, std::vector<texture> textures)
: vertices(vertices), textures(textures), indices(indices)
{
this->setupMesh();
}
In setupMesh I perform basic attributes setup, bindings to the buffers etc.. During the rendering loop I call mesh->draw() method that looks like this:
void mesh::draw(shader* shader)
{
GLuint tex_diffNumber = 1;
GLuint tex_specNumber = 1;
for (GLuint i = 0; i < this->textures.size() ; i++)
{
//load target texture
glActiveTexture(GL_TEXTURE0 + 1);
std::stringstream sstream;
std::string number;
std::string name = this->textures[i].type;
if (name == TEX_DIFF_NAME)
sstream << tex_diffNumber++;
else if (name == TEX_SPEC_NAME)
sstream << tex_specNumber++;
number = sstream.str();
glBindTexture(GL_TEXTURE_2D, this->textures[i].id);
glUniform1i(glGetUniformLocation(shader->shaderProgID, (name + number).c_str()), i);
}
//set shininess
//glUniform1f(glGetUniformLocation(shader->shaderProgID, "material.shininess"), 16.0f);
//draw
glBindVertexArray(this->vao);
glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
//release
for (GLuint i = 0; i < this->textures.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
The important bit (imho) here is the call to uniform update:
glUniform1i(glGetUniformLocation(shader->shaderProgID, (name + number).c_str()), i);
And again, no problem here, had I misstype, shader would't compile, here is the shader:
#version 330 core
in vec2 TexCoords;
in vec4 customColor;
uniform sampler2D tex_diff1;
void main()
{
gl_FragColor = vec4(texture(tex_diff1, TexCoords));
}
Name "tex_diff1" is the exact member name that is used during the draw() call. Additionally I tested if the texture coordinates were good, I output color in fragment shader based on the values from texCoords. As the result I got colorful model, which meant it was all good.
So the question is, what is missing?
Any ideas where to dig and what to shake?
PS.
In the for loop, you are setting the active texture constantly to GL_TEXTURE0 + 1
, but you are telling the shader to use texture unit i.
Most probably you wanted something like:
for (GLuint i = 0; i < this->textures.size() ; i++)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, this->textures[i].id);
glUniform1i(glGetUniformLocation(shader->shaderProgID, (name + number).c_str()), i);
}