0

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();
Keastmin
  • 85
  • 6
  • 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. – Rabbid76 Jun 04 '22 at 12:15
  • Then should I call that function from the glutIdleFunc function instead of the glutDisplayFunc function of the main function? – Keastmin Jun 04 '22 at 13:41
  • You should separate loading a drawing. When drawing, the mesh is quite enough to bind the VAO and the texture. – Rabbid76 Jun 04 '22 at 14:36
  • Since I am not an English speaker, I am reading while using a translator, and I do not understand well because it is my first time studying. Can you explain it a little more easily? – Keastmin Jun 04 '22 at 15:35
  • I can't help you as I don't know what happened in the `Mesh` constructor and what actually happens in the `drawSolid` method. I recommend reading https://learnopengl.com/ – Rabbid76 Jun 04 '22 at 15:41
  • I added some content, but there are so many classes that I can't explain them all. And I will read the link you sent me. Thank you! – Keastmin Jun 04 '22 at 16:35

1 Answers1

1

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

    // [...]
}
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • As you advised, I divided the mesh class object into ```_mesh1``` and ```_mesh2```. And I wrote it in the main function. Then, ```_drawSolid``` was written in the ```RenderScene``` function. The obj worked well, but the texture was not applied. I think it's not a problem with the main cpp from here, but the class in charge of the texture I made. It's hard to find because there are no documents related to OpenGl in South Korea. I should have studied English. lol But I will study OpenGl even if it's slow. – Keastmin Jun 04 '22 at 16:56
  • @Keastmin You have to call bind the texture in the `drawSolid` method before drawing the mesh. Just call `glBIndTexture(GL_TXEXTURE_2D, _textureIndex)` at the begin of the method. – Rabbid76 Jun 04 '22 at 16:57
  • Additional questions have been created. Am I right to understand? – Keastmin Jun 04 '22 at 17:15