c++openglglutwavefront

Problems with obj not moving properly in OpenGl


In this way, outputting one obj file each works well.

enter image description here

enter image description here

But if I try to represent these two objs revolving around the center sun at the same time, I get an error.

enter image description here

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();

Solution

  • 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);
    
        // [...]
    }