In this way, outputting one obj file each works well.
But if I try to represent these two objs revolving around the center sun at the same time, I get an error.
It looks like it's working well at first, and then the texture disappears. And the result window is forced to shut down.
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// World Transfrom
glPushMatrix();
glLoadIdentity();
//glTranslatef (0.0f, 0.0f, -300.0f);
///////////////////Drawing//////////////////////////////////////////////////////
// Figure0 Draw
glPushMatrix();
glLoadIdentity();
glColor3f(1.0f, 0.0f, 0.0f);
glutSolidSphere(10, 15, 15);
glPopMatrix();
// Figure1 Draw
glPushMatrix();
glLoadIdentity();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glRotatef(0.0f, 0.0f, 1.0f, 0.0f);
glRotatef(Sphere1_degree, 0.0f, 1.0f, 0.0f);
glTranslatef(70.0f, 0.0f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
_mesh = new Mesh("obj\\Earth_2K.obj", "obj\\Diffuse_2K_Earth.png");
_mesh->drawSolid(_smoothing);
glPopMatrix();
// Figure2 Draw
glPushMatrix();
glLoadIdentity();
glRotatef(-45.0f, 0.0f, 0.0f, 1.0f);
glRotatef(Sphere2_degree, 0.0f, 1.0f, 0.0f);
glTranslatef(60.0f, 0.0f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
_mesh = new Mesh("obj\\Moon 2K.obj", "obj\\Diffuse_2K_Moon.png");
_mesh->drawSolid(_smoothing);
glPopMatrix();
////////////////////////////////////////////////////////////////////////////////
glPopMatrix();
glutSwapBuffers();
}
This code is a function that outputs and moves obj. The _mesh
over there is a class object for me to load the obj file. DrawSolid
is an expression of a smoothing method. I think the usage of glPushMatrix
and glPopMatrix
is wrong in that code, but I don't know how to fix it. Why is that happening?
Additional Description
This code is Mesh class
class Mesh
{
public:
vector<Face*> _faces;
vector<Vertex*> _vertices;
Vec3<double> _minBound;
Vec3<double> _maxBound;
vector<Texture*> _textureCoords;
GLuint _textureIndex;
public:
Mesh();
Mesh(char* obj, char* texture) {
open(obj);
loadTexture(texture, _textureIndex);
}
Mesh(char* obj) {
open(obj);
}
~Mesh();
public:
void makeList(void);
void open(char* file);
void loadTexture(char* file, GLuint& texture_index);
void computeNormal(void);
void moveToCenter(double scale = 1.0);
public:
void drawWire(void);
void drawPoint(void);
void drawSolid(bool smoothing);
};
When a Mesh class object is created, it reads the obj file and the texture file.
void Mesh::open(char* file)
{
FILE* fp;
char buffer[100] = { 0 };
Vec3<double> pos;
int index[4], tex[4], empty[4];
int id = 0;
_minBound.Set(1000000.0);
_maxBound.Set(-1000000.0);
fopen_s(&fp, file, "r");
while (fscanf(fp, "%s %lf %lf %lf", buffer, &pos[0], &pos[1], &pos[2]) != EOF)
{
// v 0.2 0.3 0.1
// vt
if (buffer[0] == 'v' && buffer[1] == NULL) {
for (int i = 0; i < 3; i++) {
if (_minBound[i] > pos[i]) _minBound[i] = pos[i];
if (_maxBound[i] < pos[i]) _maxBound[i] = pos[i];
}
_vertices.push_back(new Vertex(id, pos));
}
}
// read texture coordinate of vertics
id = 0;
fseek(fp, 0, SEEK_SET);
while (fscanf(fp, "%s %lf %lf", &buffer, &pos[0], &pos[1]) != EOF) {
if (!strcmp(buffer, "vt")) {
_textureCoords.push_back(new Texture(pos[0], 1.0 - pos[1], 0.0));
}
}
// read faces
id = 0;
fseek(fp, 0, SEEK_SET);
while (fscanf(fp, "%s %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d", &buffer, &index[0], &tex[0], &empty[0], &index[1], &tex[1], &empty[1], &index[2], &tex[2], &empty[2], &index[3], &tex[3], &empty[3]) != EOF) {
if (buffer[0] == 'f' && buffer[1] == NULL) {
auto v0 = _vertices[index[0] - 1];
auto v1 = _vertices[index[1] - 1];
auto v2 = _vertices[index[2] - 1];
_faces.push_back(new Face(id++, v0, v1, v2, _vertices[index[3] - 1], tex[0] - 1, tex[1] - 1, tex[2] - 1, tex[3] - 1));
//_faces.push_back(new Face(index++, _vertices[v_index[0] - 1], _vertices[v_index[1] - 1], _vertices[v_index[2] - 1]);
}
}
fclose(fp);
moveToCenter(10.0);
makeList();
computeNormal();
}
This code is the Open function of the Mesh class. This code reads the vertex value, the texel value, and the face value from the obj file. It is then passed over to each class object and stored in the list of class vectors and normalized.
void Mesh::drawSolid(bool smoothing) {
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, _textureIndex);
glEnable(GL_LIGHTING);
glEnable(GL_SMOOTH)
for (auto f : _faces) {
// get texture coord
glBegin(GL_POLYGON);
if(!smoothing)
glNormal3f(f->_normal.x(), f->_normal.y(), f->_normal.z());
_textureCoords[f->_texelPos[0]];
for (int i = 0; i < 4; i++) {
auto t = _textureCoords[f->_texelPos[i]];
auto v = f->_vertices[i];
glTexCoord2f((GLfloat)t->x(), (GLfloat)t->y());
glNormal3f(v->_normal.x(), v->_normal.y(), v->_normal.z());
}
glEnd();
}
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
And here, I smoothed the normalized values. In this code, _texelPos is an array of texel values at each face.
Additional Questions
void Mesh::loadTexture(char* file, GLuint& texture_index) {
glGenTextures(1, &texture_index);
FILE* fp;
fopen_s(&fp, file, "rb");
if (!fp) {
printf("ERROR : No %s.\n fail to bind %d\n", file, texture_index);
}
int width, height, channel;
unsigned char *image = stbi_load_from_file(fp, &width, &height, &channel, 4);
fclose(fp);
glBindTexture(GL_TEXTURE_2D, texture_index);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GL_MODULATE);
}
This is the code that is responsible for setting the textures.
Here, glGenTextures(1, &texture_index);
If I write the code like this, can I write the glBindTexture(GL_TEXTURE_2D, _textureIndex);
in the RenderScene
function of main cpp
? Like that code down there?
// Figure1 Draw
glPushMatrix();
glLoadIdentity();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glRotatef(0.0f, 0.0f, 1.0f, 0.0f);
glRotatef(Sphere1_degree, 0.0f, 1.0f, 0.0f);
glTranslatef(70.0f, 0.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, 1);
_mesh1->drawSolid(_smoothing);
glPopMatrix();
Do you create the mesh and load the texture in every frame? Likely you do not free the resources and run out of memory. Load the mesh and texture once, but draw them every frame
Create the meshes once before the render loop:
_mesh1 = new Mesh("obj\\Earth_2K.obj", "obj\\Diffuse_2K_Earth.png");
_mesh2 = new Mesh("obj\\Moon 2K.obj", "obj\\Diffuse_2K_Moon.png");
But draw the meshes in the RenderScene
:
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// [...]
_mesh1->drawSolid(_smoothing);
// [...]
_mesh2->drawSolid(_smoothing);
// [...]
}