如何绘制一个所有面都有不同纹理的立方体



我正在尝试将我的代码移动到现代Opengl,但遇到了麻烦。现在我的代码将绘制一个立方体,它会放置一个纹理,但它只会将第一个纹理附加到我所有的脸上。我还使用 SOIL 将我的纹理加载到我的程序中。我做错了什么?

这是我的代码:

class Rectangle
{
public:
    Rectangle();
    Rectangle(float x, float y, float z, float width, float height, float depth, string frontFace, string backFace, string leftFace, 
            string RightFace, string topFace, string bottomFace);
    void Draw();
private:
   GLuint m_Textures[6];
   string m_TextureNames[6];

   GLfloat m_Vertices[72];   // v0,v1,v2,v3 (front)
    // normal array
    GLfloat m_Normals[72];   // v0,v1,v2,v3 (front)
    // color array
    GLfloat m_Colours[72];   // v0,v1,v2,v3 (front)
    // index array of vertex array for glDrawElements() & glDrawRangeElement()
    GLubyte m_Indices[36];     // front
    GLfloat m_Texcoords[48];
};
Rectangle::Rectangle(float x, float y, float z, float width, float height, float depth, string topFace, string bottomFace, string frontFace, 
            string backFace, string leftFace, string rightFace)
{
    m_CenterX = x;
    m_CenterY = y;
    m_CenterZ = z; 
    m_Width = width;
    m_Height = height;
    m_Depth = depth; 
    m_TextureNames[0] = topFace;
    m_TextureNames[1] = bottomFace;
    m_TextureNames[2] = frontFace;
    m_TextureNames[3] = backFace;
    m_TextureNames[4] = leftFace;
    m_TextureNames[5] = rightFace;
    m_ObjectType = Textured;
    GLfloat tempVert[] = {  // front
    -1.0, -1.0,  1.0,
     1.0, -1.0,  1.0,
     1.0,  1.0,  1.0,
    -1.0,  1.0,  1.0,
    // top
    -1.0,  1.0,  1.0,
     1.0,  1.0,  1.0,
     1.0,  1.0, -1.0,
    -1.0,  1.0, -1.0,
    // back
     1.0, -1.0, -1.0,
    -1.0, -1.0, -1.0,
    -1.0,  1.0, -1.0,
     1.0,  1.0, -1.0,
    // bottom
    -1.0, -1.0, -1.0,
     1.0, -1.0, -1.0,
     1.0, -1.0,  1.0,
    -1.0, -1.0,  1.0,
    // left
    -1.0, -1.0, -1.0,
    -1.0, -1.0,  1.0,
    -1.0,  1.0,  1.0,
    -1.0,  1.0, -1.0,
    // right
     1.0, -1.0,  1.0,
     1.0, -1.0, -1.0,
     1.0,  1.0, -1.0,
     1.0,  1.0,  1.0,
     };
    // normal array
    GLfloat tempNormals[]  = { 0, 0, 1,   0, 0, 1,   0, 0, 1,   0, 0, 1,   // v0,v1,v2,v3 (front)
                            1, 0, 0,   1, 0, 0,   1, 0, 0,   1, 0, 0,   // v0,v3,v4,v5 (right)
                            0, 1, 0,   0, 1, 0,   0, 1, 0,   0, 1, 0,   // v0,v5,v6,v1 (top)
                           -1, 0, 0,  -1, 0, 0,  -1, 0, 0,  -1, 0, 0,   // v1,v6,v7,v2 (left)
                            0,-1, 0,   0,-1, 0,   0,-1, 0,   0,-1, 0,   // v7,v4,v3,v2 (bottom)
                            0, 0,-1,   0, 0,-1,   0, 0,-1,   0, 0,-1 }; // v4,v7,v6,v5 (back)
    // color array
    GLfloat tempColors[]   = { 1, 1, 1,   1, 1, 0,   1, 0, 0,   1, 0, 1,   // v0,v1,v2,v3 (front)
                            1, 1, 1,   1, 0, 1,   0, 0, 1,   0, 1, 1,   // v0,v3,v4,v5 (right)
                            1, 1, 1,   0, 1, 1,   0, 1, 0,   1, 1, 0,   // v0,v5,v6,v1 (top)
                            1, 1, 0,   0, 1, 0,   0, 0, 0,   1, 0, 0,   // v1,v6,v7,v2 (left)
                            0, 0, 0,   0, 0, 1,   1, 0, 1,   1, 0, 0,   // v7,v4,v3,v2 (bottom)
                            0, 0, 1,   0, 0, 0,   0, 1, 0,   0, 1, 1 }; // v4,v7,v6,v5 (back)
    // index array of vertex array for glDrawElements() & glDrawRangeElement()
    GLubyte tempIndices[]  = { 0, 1, 2,   2, 3, 0,      // front
                           4, 5, 6,   6, 7, 4,      // right
                           8, 9,10,  10,11, 8,      // top
                          12,13,14,  14,15,12,      // left
                          16,17,18,  18,19,16,      // bottom
                          20,21,22,  22,23,20 };    // back
    GLfloat tempTexcoords[2*4*6] = {
    // front
    0.0, 0.0,
    1.0, 0.0,
    1.0, 1.0,
    0.0, 1.0,
  };
  for (int i = 1; i < 6; i++)
    memcpy(&tempTexcoords[i*4*2], &tempTexcoords[0], 2*4*sizeof(GLfloat));

    copy(tempVert, tempVert + 72, m_Vertices);
    copy(tempNormals, tempNormals + 72, m_Normals);
    copy(tempColors, tempColors + 72, m_Colours);
    copy(tempIndices, tempIndices + 36, m_Indices);
    std::copy(tempTexcoords, tempTexcoords + 48, m_Texcoords);
    LoadTexture(m_TextureNames);
}
void Rectangle::LoadTexture(string TextureName[6])          
{
    // Create texture index array.
    glGenTextures(6, m_Textures); 

    for(int i = 0 ; i < 1 ; i++)
    {
        glBindTexture(GL_TEXTURE_2D, m_Textures[i]);
        // Set our texture parameters
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        // Set texture filtering
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);  // NOTE the GL_NEAREST Here! 
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);  // NOTE the GL_NEAREST Here! 
        std::string fileType;
        fileType.append(m_TextureNames[i], m_TextureNames[i].size()-3,3);
        if(fileType == "jpg")
        {
            m_Textures[i] = SOIL_load_OGL_texture // load an image file directly as a new OpenGL texture
            (
                m_TextureNames[i].c_str(),
                SOIL_LOAD_AUTO,
                SOIL_CREATE_NEW_ID,
                SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
            );
            // allocate a texture name
        }
        else
        {
            m_Textures[i] = SOIL_load_OGL_texture // load an image file directly as a new OpenGL texture
            (
                m_TextureNames[i].c_str(),
                SOIL_LOAD_AUTO,
                SOIL_CREATE_NEW_ID,
                SOIL_FLAG_MIPMAPS | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
            );
            // allocate a texture name
        }
    }
}
// Function to draw Sphere.
void Rectangle::Draw()
{
        // enable and specify pointers to vertex arrays
        glEnableClientState(GL_NORMAL_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glEnableClientState(GL_COLOR_ARRAY);
        glEnableClientState(GL_VERTEX_ARRAY);
        glNormalPointer(GL_FLOAT, 0, m_Normals);
        glTexCoordPointer(2, GL_FLOAT, 0, m_Texcoords);
        glColorPointer(3, GL_FLOAT, 0, m_Colours);
        glVertexPointer(3, GL_FLOAT, 0, m_Vertices);
        for (int i=0;i<6;i++)
        {
        glPushMatrix();
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, m_Textures[i]);
            glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, m_Indices);
        glPopMatrix();
        }
        glDisableClientState(GL_VERTEX_ARRAY);  // disable vertex arrays
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        glDisableClientState(GL_COLOR_ARRAY);
        glDisableClientState(GL_NORMAL_ARRAY);
}

Rectangle testRect;
// Drawing routine.
void drawScene(void)
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glLoadIdentity();
   testRect.Draw();
   glutSwapBuffers();
}
// Initialization routine.
void setup(void) 
{
   glClearColor(0.0, 0.0, 0.0, 0.0); 
   testRect = Rectangle(2, 0.0, 0.0, 1, 2, 1, "grass.bmp","grass.bmp", "grass.bmp", "launch.png", "launch.png", "launch.png");
   // Turn on OpenGL texturing.
   glEnable(GL_TEXTURE_2D);
   glShadeModel (GL_SMOOTH);
}

发布的代码有几个问题:

  • 它只加载一个纹理:

    glGenTextures(6, m_Textures); 
    for(int i = 0 ; i < 1 ; i++)
    {
        glBindTexture(GL_TEXTURE_2D, m_Textures[i]);
        ...
    

    如果你想加载 6 个纹理,就像代码的其余部分建议的那样,你必须使用 6 作为循环的结束值:

    for(int i = 0 ; i < 6 ; i++)
    
  • 它创建纹理 ID 两次,并使用错误的纹理绑定设置参数。在LoadTexture()开始时,它会生成 6 个纹理 ID:

    glGenTextures(6, m_Textures); 
    

    然后绑定它们,并glTexParameteri()在它们上设置各种参数。但随后它会用一个标志调用SOIL_load_ogl_texture(),要求它再次创建一个新 id,然后将该 id 存储起来:

    m_Textures[i] = SOIL_load_OGL_texture(
        m_TextureNames[i].c_str(),
        SOIL_LOAD_AUTO,
        SOIL_CREATE_NEW_ID,
        SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
        );
    

    若要解决此问题,可以省略gGenTextures()调用,并在SOIL_load_ogl_texture()调用后移动代码以绑定纹理和调用glTexParameteri()。此外,这使用标志来生成 mipmap,但将纹理过滤器设置为不使用 mipmap。

  • 在绘制函数中,它循环遍历 6 个面,但每次都绘制整个立方体:

    for (int i=0;i<6;i++)
    {
    glPushMatrix();
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, m_Textures[i]);
        glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, m_Indices);
    glPopMatrix();
    }
    

    glDrawElements()的第二个参数指定要呈现的顶点数。值为 36 时,将使用所有顶点(立方体的 6 条边,每条边有 2 个三角形,每个边有 3 个顶点。

    此外,glPushMatrix()/glPopMatrix()绝对没有任何用途。绘制循环应如下所示:

    glActiveTexture(GL_TEXTURE0);
    for (int i=0;i<6;i++)
    {
        glBindTexture(GL_TEXTURE_2D, m_Textures[i]);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, m_Indices + i * 6);
    }
    
  • 我没有看到任何地方启用深度测试。将此添加到setup()

    glEnable(GL_DEPTH_TEST); 
    

我的做法有点不同,所以也许问题在于不同。

我会将每个纹理绑定到不同的GL_Texture(GL_Texture0,GL_Texture1...),以便每个纹理都有自己的数据。 我不知道 SOIL 是如何工作的,但在我的情况下,第一个纹理之后:

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);

我会包括一个电话:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture1Width, texture1Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmapData);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Textures[0]);

我会对 6 种纹理中的每一种重复此过程。

然后我会画每张脸:

// First face
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Textures[0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, m_Indices);
// Second face
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_Textures[1]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, m_Indices);

每张脸都以此类推。

编辑:

我对 SOIL 进行了一些检查,在我看来(使用 SOIL)你会:

GLuint m_Textures[6];  
int img_width, img_height;
glGenTextures(6, m_Textures);
// For each texture
unsigned char* img = SOIL_load_image(m_TextureNames[0].c_str(), &img_width, &img_height, NULL, 0); // or m_TextureNames[1].c_str() ...
glBindTexture(GL_TEXTURE_2D, m_Textures[0]); // or m_textures[1]...
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture filtering
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);  // NOTE the GL_NEAREST Here! 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);  // NOTE the GL_NEAREST Here! 
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img_width, img_height, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
glActiveTexture(GL_TEXTURE0); // or GL_TEXTURE1....
glBindTexture(GL_TEXTURE_2D, m_Textures[0]); // or m_Textures[1]...

相关内容

  • 没有找到相关文章