I'm trying to use glDrawElements to draw a model loaded from assimp, geometry displays fine but textures dont show up on the model, i just get a black version of the model i've loaded.
Load Model Function
ModelInfo LoadModel(const std::string& modelPath){
printf( "Loading model: %s\n", modelPath.c_str());
//verify that file exists first
std::ifstream fin(modelPath.c_str());
if(!fin.fail()){
fin.close();
}else{
throw std::runtime_error("could not open file" + modelPath);
}
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile( modelPath,
aiProcessPreset_TargetRealtime_Fast |
//aiProcess_CalcTangentSpace |
aiProcess_Triangulate |
aiProcess_GenSmoothNormals |
aiProcess_FlipUVs
//aiProcess_JoinIdenticalVertices |
//aiProcess_SortByPType);
);
if(!scene){
throw std::runtime_error(importer.GetErrorString());
}
printf("imported %s\n",modelPath.c_str());
fflush(stdout);
std::vector<unsigned int> indices;
std::vector<float> vertices;
std::vector<float> uvs;
std::vector<float> normals;
aiMesh* mesh = scene->mMeshes[0];
int numOfFaces = mesh->mNumFaces;
int numOfIndices = numOfFaces * 3;
indices.resize(numOfIndices);
for (unsigned int i =0; i < mesh->mNumFaces; ++i){
const aiFace &face = mesh->mFaces[i];
assert(face.mNumIndices == 3);
indices[i * 3 + 0] = face.mIndices[0];
indices[i * 3 + 1] = face.mIndices[1];
indices[i * 3 + 2] = face.mIndices[2];
}
int numOfVertices = mesh->mNumVertices;
vertices.resize(numOfVertices * 3);
normals.resize(numOfVertices * 3);
uvs.resize(numOfVertices * 2);
for( unsigned int i = 0; i < mesh->mNumVertices; ++i){
if(mesh->HasPositions()){
vertices[i * 3 + 0] = mesh->mVertices[i].x;
vertices[i * 3 + 1] = mesh->mVertices[i].y;
vertices[i * 3 + 2] = mesh->mVertices[i].z;
//printf("[ %f, %f, %f]\n",vertices[i*3+0],vertices[i*3+1],vertices[i*3+2]);
}
if( mesh->HasNormals()){
normals[i * 3 + 0] = mesh->mNormals[i].x;
normals[i * 3 + 1] = mesh->mNormals[i].x;
normals[i * 3 + 2] = mesh->mNormals[i].x;
}
if(mesh->HasTextureCoords(0)){
uvs[i * 2 + 0] = mesh->mTextureCoords[0][i].x;
uvs[i * 2 + 1] = mesh->mTextureCoords[0][i].y;
printf("[ %f, %f]\n",uvs[i*2+0],uvs[i*2+1]);
}
}
//create voa
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//create element buffer
GLuint elementBuffer;
glGenBuffers(1, &elementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
//create vertex buffer
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(aiVector3D), &vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
printf("vertices.size is %lu\n", vertices.size());
printf("uvs.size is %lu\n", uvs.size());
GLuint uvBuffer;
glGenBuffers(1, &uvBuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(aiVector2D), &uvs[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)0);
GLuint normalBuffer;
glGenBuffers(1, &normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(aiVector3D), &normals[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
ModelInfo retval;
retval.vao = vao;
retval.index = elementBuffer;
retval.vertex = vertexBuffer;
retval.uv = uvBuffer;
retval.normal = normalBuffer;
retval.count = numOfIndices;
return retval;
}
Short overview of Load Model, loads the model with assimp, then loads the data from the first mesh in the assimp scene into vectors, then creates a vao, vbos for geometry, texture coordinates, normals, and indexes. Data is then loaded into the buffers from the vectors and vertex attributes are set. Once all is loaded a struct containing several GLuints is created to return data.
Render Model function
void render_model(ModelInfo info){
cleanup();
//set program
glUseProgram(modelprogram);
//set uniforms
glm::mat4 view = camera.matrix();
glUniformMatrix4fv(modelcamera, 1, GL_FALSE, &view[0][0]);
glm::mat4 model = glm::mat4();
model = glm::rotate(model, degree, glm::vec3(0,1,1));
glUniformMatrix4fv(modelmodel, 1, GL_FALSE, &model[0][0]);
glBindVertexArray(info.vao);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(modeltext, texture);
glDrawElements(GL_TRIANGLES, info.count, GL_UNSIGNED_INT, (void*)0);
}
Brief overview of render model. Set the shader program to handle rendering the model, get matrix for the camera, pass it to the shader, generate a matrix for the model, make it spin, pass it to the shader. Bind the vao of the model to be rendered. Bind a previously loaded text, which is also used on other geometry in the program where it shows up no problem, pass it to the shader. all is set, call glDrawElements starting from the first position in the index buffer of the current vao. Once drawing is complete do clean up to unbind any buffers and arrays
the shaders i'm using for this are very basic vertex shader
#version 140
uniform mat4 camera;
uniform mat4 model;
in vec3 position;
in vec2 uv;
out vec2 fragUV;
void main(){
//pass variables on to fragment shader
fragUV = uv;
//vertex to draw
gl_Position = camera * model * vec4(position,1);
}
fragment shader #version 140
uniform sampler2D modeltext;
in vec2 fragUV;
out vec4 finalColor;
void main(){
finalColor = texture(modeltext, fragUV);
}
All uniforms are loaded correctly with a function that verifies that something was actually loaded, the texture is used and works else where in the program. The model has texture coordinates. The geometry is loading and rendering no problem