为啥纹理(GL_TEXTURE_2D)不能与(VertexArray)VAO一起使用

Posted

技术标签:

【中文标题】为啥纹理(GL_TEXTURE_2D)不能与(VertexArray)VAO一起使用【英文标题】:Why texture (GL_TEXTURE_2D) cannot work with (VertexArray) VAO为什么纹理(GL_TEXTURE_2D)不能与(VertexArray)VAO一起使用 【发布时间】:2014-10-29 13:40:58 【问题描述】:

我正在开发一个带有 openGL 部分的项目。场景图部分基于核心OpenGL1.0,仍然使用glBegin和glEnd。 现在我在上面添加新东西并且必须使用 VAO。我是初学者并使用 QOpenGLFunctions_3_0 因为我无法从 openGL 注册表中找到 gl3.h 现在的问题是我使用GL_TEXTURE_2DglBegin(GL_QUADS),它可以工作, 我画了一个glDrawElements( GL_QUADS, 4, GL_UNSIGNED_BYTE, 0); 它也可以。 但是当我使用 GL_TEXTURE_2DglDrawElements( GL_QUADS... 时,无法正确生成纹理。请告诉我正确的使用方法。 这是代码

/** draws Texture */

class TextureNode
    : public Node


public:

TextureNode( const cv::Mat& mat )

    m_mat = mat;

TextureNode( const std::string& id, const cv::Mat& mat )
    : Node( id )

    m_mat = mat;


~TextureNode()

    //glDeleteTextures( 1, &m_texture[0] );


void init( TraversalContext& context )

    initializeOpenGLFunctions();


    struct Vertex 
      GLfloat position[3];
      GLfloat texcoord[2];
      GLfloat normal[3];
    ;
    const int NUM_VERTS = 4;
    const int NUM_INDICES = 4;
    Vertex vertexdata[NUM_VERTS] = 
        0,    0,  0,         0,0,  0,0,1,
        0,    100,    0,     0,1,  0,0,1,
        100,  100,    0,     1,1,  0,0,1,
        100,  0,  0,         1,0,  0,0,1,
    ;
    GLubyte indexdata[NUM_INDICES] =  0, 1, 2, 3 ;

            // Create and bind a VAO
    glGenVertexArrays(1, &m_quadVAO);
    glBindVertexArray(m_quadVAO);

    glGenBuffers(1, &m_quadPositionVBO);
    glBindBuffer(GL_ARRAY_BUFFER, m_quadPositionVBO);

    // copy data into the buffer object
    glBufferData(GL_ARRAY_BUFFER, NUM_VERTS * sizeof(Vertex), vertexdata, GL_STATIC_DRAW);


    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoord));
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));

    glGenBuffers(1, &m_quadIndexVBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_quadIndexVBO);

    // copy data into the buffer object
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, NUM_INDICES * sizeof(GLubyte), indexdata, GL_STATIC_DRAW);


    // Create and bind a texture

    glGenTextures(1, &m_texture);                 // Create The Texture
    glBindTexture(GL_TEXTURE_2D, m_texture); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_mat.cols, m_mat.rows, 0, GL_BGR, GL_UNSIGNED_BYTE,  m_mat.data);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);

    //////// At this point the VAO is set up with two vertex attributes
    //////// referencing the same buffer object, and another buffer object
    //////// as source for index data. We can now unbind the VAO, go do
    //////// something else, and bind it again later when we want to render
    //////// with it.

    glBindTexture(GL_TEXTURE_2D, 0); 
    glBindVertexArray(NULL);    

    //////glBindBuffer(GL_ARRAY_BUFFER, NULL);  
    //glBindTexture( GL_TEXTURE_2D, NULL );
    //////glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL); 




/** apply transformation */
void doWork( TraversalContext& context )


//QTime time;
//time.start();
    initializeOpenGLFunctions();
    glDisable( GL_LIGHTING );

    glEnable(GL_TEXTURE_2D);
    glBindVertexArray( m_quadVAO );



    //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);



    glActiveTexture(GL_TEXTURE0 + m_texture - 1 );
    glBindTexture(GL_TEXTURE_2D, m_texture);
    glDrawElements( GL_QUADS, 4, GL_UNSIGNED_BYTE, 0);

    //glBegin(GL_QUADS);
    //  glColor3d( 0,0,0 );
    //  glTexCoord2f(1.0f, 0.0f); glVertex2d( 0, 0 );
    //  glTexCoord2f(1.0f, 1.0f); glVertex2d( 0, m_mat.rows );
    //  glTexCoord2f(0.0f, 1.0f); glVertex2d( m_mat.cols, m_mat.rows );
    //  glTexCoord2f(0.0f, 0.0f); glVertex2d( m_mat.cols, 0 );
    //glEnd();

    glBindTexture(GL_TEXTURE_2D, 0);
    glDisable(GL_TEXTURE_2D);


    glBindVertexArray(0);
    glEnable( GL_LIGHTING );

void destroy( TraversalContext& context )


    glDeleteVertexArrays( 1, &m_quadVAO );
    glDeleteTextures(1,&m_texture);
    glDeleteBuffers(1, &m_quadPositionVBO);
    glDeleteBuffers(1, &m_quadTexcoordVBO);
    glDeleteBuffers(1, &m_quadIndexVBO);



protected:

GLuint m_quadVAO;
GLuint m_quadPositionVBO;
GLuint m_quadTexcoordVBO;
GLuint m_quadIndexVBO;
GLuint m_texture;
///** list of vertices */
GLfloat m_vertices[4][2];
cv::Mat m_mat;
;

【问题讨论】:

没有gl3.h 这样的东西,至少在原版OpenGL 中没有。您必须手动或使用 GLEW 之类的方式加载扩展功能。 @ColonelThirtyTwo 这仅在 Windows 上是正确的。在其他平台上,您只需包含 OpenGL 头文件,然后调用函数。 在许多使用 GLX 的平台(例如 Linux)上也是如此。 OS X 确实是 OpenGL 实现中的怪人,因为无论安装什么硬件驱动程序,您在构建时链接到的库都包含所有符号。在任何情况下,OpenGL/gl3.h 是一种 Apple 构造。如果你想要 OpenGL 注册表中的等价物,它将是 GL/glcorearb.h 【参考方案1】:
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoord));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));

这是使用通用顶点属性,但这仅在使用共享器时才有意义,并且 afaik 不适用于固定功能管道。要么创建一个着色器来使用它们,要么改用glVertexPointerglTexCoordPointer 和/或glNormalPointer

glActiveTexture(GL_TEXTURE0 + m_texture - 1 );

这是不正确的。 glActiveTexture 选择绑定到哪个纹理单元;它根本不使用纹理名称。由于您没有使用着色器,因此应该是 glActiveTexture(GL_TEXTURE0)

旁注:您不需要使用索引缓冲区来绘制单个四边形;你可以改用glDrawArrays

【讨论】:

我试过 glActiveTexture(GL_TEXTURE0),结果是一样的。而且,我还尝试了 glDrawArrays(GL_QUADS, 0, 4 );还是一样,只有一种颜色,没有质感 最后一个参数是要绘制多少个顶点你应该使用glDrawArrays(GL_QUADS, 0, 4 ); 现在我使用 glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, position)); glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoord)); glNormalPointer(GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal)); 和 dann glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_texture); glDrawArrays(GL_QUADS, 0, 4);那我根本看不到方格 看来glVertexPointer不起作用,如果我使用glVertexAttribPointer,至少我有一个四边形,虽然没有显示纹理,但是如果我使用glVertexPointer,我什么都没有。 @langbeibei:如果你要使用glVertexPointer和朋友,你需要启用GL_VERTEX_ARRAY等客户端状态,而不是使用glEnableVertexAttribArray (...)。在 modern(基于 GLSL)OpenGL 中,通用属性数组不应该别名为客户端数组,但在较旧的 GL 实现中,可以理解通用属性 0 别名为 @例如 987654334@;通过不混合和匹配这两种东西来避免这种情况并编写符合标准的代码。

以上是关于为啥纹理(GL_TEXTURE_2D)不能与(VertexArray)VAO一起使用的主要内容,如果未能解决你的问题,请参考以下文章

立方体侧面的纹理与opengl

在具有目标 GL_TEXTURE_2D 的纹理上渲染相机预览

GL_TEXTURE_3D 是啥意思?

Android Opengl OES 纹理渲染到 GL_TEXTURE_2D

Android Opengl OES 纹理渲染到 GL_TEXTURE_2D

OpenGL 与 C++ - 纹理