So i made a obj loader in c++.I used blender to export my files.
I tried to draw 2 squares(one perpendicular to the other) and when im looking at them from above some weird black triangles apear, although i have glEnable(DL_DEPTH_TEST)
I uploaded a video so you can see the problem https://www.youtube.com/watch?v=1NStm1mFkX0&feature=youtu.be
Vertex shader:
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoord;
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
TexCoord=texCoord;
}
Fragment Shader
#version 330 core
in vec2 TexCoord;
out vec4 color;
uniform sampler2D Texture;
void main()
{
color = texture(Texture, TexCoord);
}
Here is my class
#ifndef MESH_H
#define MESH_H
#include "Includes.h"
#include "Shader.h"
struct Vertex
{
glm::vec3 position;
glm::vec3 normal;
glm::vec2 texCoord;
Vertex(){};
Vertex(glm::vec3 p,glm::vec3 n,glm::vec2 t)
{
position=p;
normal=n;
texCoord=t;
}
};
struct Material{
char name[100];
float ns,alpha,illum;
float amb[3],dif[3],spec[3];
unsigned int ID;
string path;
sf::Image image;
};
class Mesh
{
public:
void draw(Shader &shader);
void loadMesh(const char* fileName);
private:
GLuint VAO,VBO,EBO;
vector<Material>material;
vector<Vertex> vertex;
vector<GLuint> indices;
void loadMaterial(Material &M,string imgPath);
void setupMesh();
};
#endif // MESH_H
And the cpp:
void Mesh::loadMaterial(Material &M,string imgPath)
{
M.path=imgPath;
M.image.loadFromFile(imgPath);
M.image.flipVertically();
glGenTextures(1,&M.ID);
glBindTexture(GL_TEXTURE_2D,M.ID);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, M.image.getSize().x, M.image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, M.image.getPixelsPtr());
}
void Mesh::loadMesh(const char* fileName)
{
int i,j,number1,number2,number3,indNormal1,indNormal2,indNormal3,indTC1,indTC2,indTC3,nrFace=0,nrInd=-1;
char text[256],matName[256],path[256];
vector<string>tmp;
vector<string>line;
vector<glm::vec3>position;
vector<glm::vec3>normal;
vector<glm::vec2>texCoord;
vector<glm::vec3>vertexNormal;
vector<glm::vec2>texCoordCopy;
ifstream fin;
string imageName;
glm::vec3 v;
glm::vec2 t;
fin.open(fileName);
while(!fin.eof())
{
fin.getline(text,256);
line.push_back(text);
}
fin.close();
string matFileName;
matFileName=fileName;
matFileName.resize(matFileName.size()-3);
matFileName+="mtl";
fin.open(matFileName.c_str());
while(!fin.eof())
{
fin.getline(text,200);
tmp.push_back(text);
}
fin.close();
for(i=0;i<tmp.size();i++)///READ MATERIALS
{
Material M;
if(tmp[i][0]=='\n')
continue;
if(tmp[i][0]=='n'&&tmp[i][1]=='e'&&tmp[i][2]=='w')
{
sscanf(tmp[i++].c_str(),"newmtl %s",&M.name);
if(tmp[i][0]=='N'&&tmp[i][1]=='s')
sscanf(tmp[i++].c_str(),"Ns %f",&M.ns);
if(tmp[i][0]=='K'&&tmp[i][1]=='a')
sscanf(tmp[i++].c_str(),"Ka %f %f %f",&M.amb[0],&M.amb[1],&M.amb[2]);
if(tmp[i][0]=='K'&&tmp[i][1]=='d')
sscanf(tmp[i++].c_str(),"Kd %f %f %f",&M.dif[0],&M.dif[1],&M.dif[2]);
if(tmp[i][0]=='K'&&tmp[i][1]=='s')
sscanf(tmp[i++].c_str(),"Ks %f %f %f",&M.spec[0],&M.spec[1],&M.spec[2]);
if(tmp[i][0]=='K'&&tmp[i][1]=='e')
i++;
if(tmp[i][0]=='N'&&tmp[i][1]=='i')
i++;
if(tmp[i][0]=='d'&&tmp[i][1]==' ')
sscanf(tmp[i++].c_str(),"d %f",&M.alpha);
if(tmp[i][0]=='i'&&tmp[i][1]=='l')
sscanf(tmp[i++].c_str(),"illum %f",&M.illum);
if(tmp[i][0]=='m'&&tmp[i][1]=='a')
{
tmp[i].erase(tmp[i].begin(),tmp[i].begin()+7);
i++;
}
imageName=fileName;
for(j=imageName.size()-1;j>=0;j--)
if(imageName[j]=='/')
break;
imageName.erase(imageName.begin()+j+1,imageName.end());
imageName+=tmp[i-1];
loadMaterial(M,imageName);
material.push_back(M);
}
}
//vector<int>face;
for(i=3;i<line.size();i++)///READ THE MESHES
{
if(line[i][0]=='v'&&line[i][1]==' ')
{
sscanf(line[i].c_str(),"v %f %f %f",&v.x,&v.y,&v.z);
position.push_back(v);
}
else if(line[i][0]=='v'&&line[i][1]=='t')
{
sscanf(line[i].c_str(),"vt %f %f",&t.x,&t.y);
texCoord.push_back(t);
}
else if(line[i][0]=='v'&&line[i][1]=='n')
{
sscanf(line[i].c_str(),"vn %f %f %f",&v.x,&v.y,&v.z);
normal.push_back(v);
}
else if(line[i][0]=='s'&&line[i][1]==' ')
continue;
else if(line[i][0]=='u'&&line[i][1]=='s'&&line[i][2]=='e')
{
sscanf(line[i].c_str(),"usemtl %s",&matName);
//face.push_back(nrFace);
}
else if(line[i][0]=='f'&&line[i][1]==' ')
{
nrFace++;
sscanf(line[i].c_str(),"f %d/%d/%d %d/%d/%d %d/%d/%d",&number1,&indTC1,&indNormal1,
&number2,&indTC2,&indNormal2,
&number3,&indTC3,&indNormal3);
indices.push_back(number1-1);
indices.push_back(number3-1);
indices.push_back(number2-1);
if(position.size()>vertexNormal.size())
vertexNormal.resize(position.size());
if(position.size()>texCoordCopy.size())
texCoordCopy.resize(position.size());
vertexNormal[number1-1]=normal[indNormal1-1];
vertexNormal[number2-1]=normal[indNormal2-1];
vertexNormal[number3-1]=normal[indNormal3-1];
texCoordCopy[number1-1]=texCoord[indTC1-1];
texCoordCopy[number2-1]=texCoord[indTC2-1];
texCoordCopy[number3-1]=texCoord[indTC3-1];
}
}
//face.push_back(nrFace+1);
for(i=0;i<position.size();i++)
vertex.push_back(Vertex(position[i],vertexNormal[i],texCoordCopy[i]));
setupMesh();
fin.close();
}
void Mesh::setupMesh()
{
int i;
glGenVertexArrays(1, & VAO);
glGenBuffers(1, & VBO);
glGenBuffers(1, & EBO);
glBindVertexArray( VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertex.size() * sizeof(Vertex),
& vertex[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint),
& indices[0], GL_STATIC_DRAW);
// Vertex Positions
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
(GLvoid*)0);
// Vertex Normals
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
(GLvoid*)offsetof(Vertex, normal));
// Vertex Texture Coords
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
(GLvoid*)offsetof(Vertex, texCoord));
glBindVertexArray(0);
}
void Mesh::draw(Shader &shader)
{
int i,j,ind;
//glEnable(GL_DEPTH_TEST);
shader.Use();
glBindTexture(GL_TEXTURE_2D, material[0].ID);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
The loadMesh()
fuction gets a fileName(the exemple.obj file) and reads the content from it.Also it reads the exemple.mtl file content.Then it starts building the data from that file.The first file is the mtl file.It reads all the parameters and saves them into the vectormaterial .Then the function builds data from the obj file.
Then the setupMesh function uses the opengl functions. I know that my code is incomplete since my program doesnt know which texture to bind for each face,it just binds the first one.But i have a model which has only one texture so i figured it should work.