obj 在 OpenGl 中无法正确移动的问题

Problems with obj not moving properly in OpenGl

这样,每个输出一个obj文件效果很好

但是如果我试图表示同时围绕中心太阳旋转的这两个 obj,则会出现错误。

一开始看起来还不错,后来纹理就消失了。结果window被强制关机

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

这段代码是一个输出和移动obj的函数。那边的_mesh有一个class对象让我加载obj文件。 DrawSolid是一种平滑方法的表达。我认为 glPushMatrixglPopMatrix 在该代码中的用法是错误的,但我不知道如何修复它。为什么会这样?

附加说明

此代码为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);
};

创建 Mesh class 对象时,它会读取 obj 文件和纹理文件。

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

这段代码是Mesh的Open函数class。此代码从 obj 文件中读取顶点值、纹素值和面值。然后将其传递给每个 class 对象并存储在 class 向量列表中并进行归一化。

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

在这里,我平滑了归一化值。 在此代码中,_texelPos 是每个面的纹素值数组。

其他问题

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

这是负责设置纹理的代码。

这里,glGenTextures(1, &texture_index);如果我这样写代码,是否可以在main cppRenderScene函数中写glBindTexture(GL_TEXTURE_2D, _textureIndex);?喜欢下面的代码吗?

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

您是否在每一帧中创建网格并加载纹理?可能您没有释放资源和 运行 内存不足。一次加载网格和纹理,但每帧绘制它们

在渲染循环之前创建一次网格:

_mesh1 = new Mesh("obj\Earth_2K.obj", "obj\Diffuse_2K_Earth.png");
_mesh2 = new Mesh("obj\Moon 2K.obj", "obj\Diffuse_2K_Moon.png");

但是在RenderScene中绘制网格:

void RenderScene(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // [...]

    _mesh1->drawSolid(_smoothing);

    // [...]

    _mesh2->drawSolid(_smoothing);

    // [...]
}