0
\$\begingroup\$

I want to display a simple textured Monkey mesh using VAO. Here's the code in the render part first without VAO to see what is the result I'm looking for.

Texture *pTexture = meshList[idx]->GetSubMaterial()->getTexture();
VertexBuffer *pVBO = meshList[idx]->GetVertexBuffer();

pVBO->Lock();

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, OFFSET_BUFFER(0));

if (pTexture)
{
    glEnableVertexAttribArray(1);
    glActiveTexture(GL_TEXTURE0);
    pTexture->Lock();
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, OFFSET_BUFFER(pVBO->GetVerticesByteSize(VERTEX_POSITION)));
}
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, OFFSET_BUFFER(
    (pVBO->GetVerticesByteSize(VERTEX_POSITION) +
         pVBO->GetVerticesByteSize(VERTEX_TEXTURE))));

pVBO->Unlock();

glDrawArrays(GL_TRIANGLES, 0, meshList[idx]->GetVertexBuffer()->GetBufferSize());

And here's the output :

enter image description here

As you can see, the texture mapping is correct.

Now I want to implement the code above into a VAO. So I displace it before the main loop (so out of my rendering system) and copy it in the initialization of my Mesh class (the model class).

Here's the header of the Mesh class (it's just to see the composition of this class, the attributes, etc.) :

class Mesh : public Resource
    {
        public:
            Mesh(void);
            Mesh(std::string const &other);
            Mesh(Mesh const &mesh);
            virtual ~Mesh(void);

        public:
            Mesh &operator=(Mesh const &other);
            void Create(std::string const &filename);
            void Create(OBJVertexImage *pVertexImg, OBJFaceImage *pFaceImg);
            void AttachVertexBuffer(VertexBuffer *pVertexBuffer);
            void AttachSubMaterial(SubMaterial *pSubMaterial);
            std::string const &GetUseMtlName(void) const;
            virtual std::string const &GetName(void) const;
            VertexBuffer *GetVertexBuffer(void);
            SubMaterial *GetSubMaterial(void) const;
            VertexArray *GetVertexArray(void) const;
            void prepareMeshRendering(void); //The VAO initialization is here !!!
            virtual void Release(void);

        private:
            VertexArray *m_pVertexArray;
            VertexBuffer *m_pVertexBuffer;
            SubMaterial *m_pMaterial;
            std::string m_UseMtlName;
            std::string m_Name;
    };

The VAO initialization is written in 'prepareMeshRendering' method. Of course I call this method when my mesh is already loaded (texture and vertex buffer loaded). The vertex buffer respect the following pattern:

[[all_position_vertices][all_texture_vertices][all_normal_vertices]].

Here's the content of this function :

this->m_pVertexArray->Lock();
    {
        this->m_pVertexBuffer->Lock();
        {
            glEnableVertexAttribArray(0);
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, OFFSET_BUFFER(0));

            if (this->m_pMaterial->getTexture())
            {
                glEnableVertexAttribArray(1);
                glActiveTexture(GL_TEXTURE0);
                this->m_pMaterial->getTexture()->Lock();
                glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0,
                    OFFSET_BUFFER(this->m_pVertexBuffer->GetVerticesByteSize(VERTEX_POSITION)));
            }
            glEnableVertexAttribArray(2);
            glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, OFFSET_BUFFER(
                this->m_pVertexBuffer->GetVerticesByteSize(VERTEX_POSITION) +
                    this->m_pVertexBuffer->GetVerticesByteSize(VERTEX_TEXTURE)));
        }
        this->m_pVertexBuffer->Unlock();
    }
    this->m_pVertexArray->Unlock();

The texture binding code is encapsulated in the Texture class as follow :

void Texture::Lock(void) const
{
    glBindTexture(GL_TEXTURE_2D, &this->m_Handle);
}

This is the same concept for the binding of the VAO but this time in the VertexArray class.

The rendering part (more simple now than before):

VertexArray *pVertexArray = meshList[idx]->GetVertexArray();

pVertexArray->Lock();

glDrawArrays(GL_TRIANGLES, 0, meshList[idx]->GetVertexBuffer()->GetBufferSize());

pVertexArray->Unlock();

And the output :

enter image description here

I checked. In those 2 versions :

  • The byte size of the 3 buffers (position, texture and normal) is the same (so the offsets are corrects).

  • The texture handle is the same (here aqual to 1)

So I don't know what's happening. This kind of display usually appears when the texture is not bound or the channel is not correct. But here, in those 2 cases I precise the channel and the texture handle is the same. I'm going to be crazy! I think I forget something but can't find the error.

Does anyone can help me, please ?

Thanks a lot in advance for your help !

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I don't see any glActiveTexture or glBindTexture calls in your drawing code. As far as I know, VAOs handle vertex attributes only. You have to make sure the right texture unit is active and your texture is bound in your drawing routine.

\$\endgroup\$
6
  • \$\begingroup\$ The glActiveTexture is in the VAO section code. So it's defined only at the initialization so before the drawing code. The glBindTexture code is encapsulated in the Texture class in the 'Lock' method. I will updated my question to be more precise. \$\endgroup\$ Feb 12, 2014 at 11:14
  • \$\begingroup\$ VAO works for position vertex attributes, texture vertex attributes and normal vertex attributes. I check. The display is correct if I disable the texture mapping (the monkey is display correctly with the light effects). But if I want to uv-map the monkey I have the black display above. \$\endgroup\$ Feb 12, 2014 at 12:27
  • 1
    \$\begingroup\$ OK. My point is which texture unit is active and what texture is bound to which target is not saved in your VAO. Hence, if make any call to glActiveTexture or glBindTexture after creating your VAO, binding it will not restore the correct texture settings. Can you just try putting glActiveTexture(GL_TEXTURE0); and binding your texture right before calling glDrawArrays? \$\endgroup\$
    – jcorbier
    Feb 12, 2014 at 13:14
  • \$\begingroup\$ Ok I'll try this when I'll be back home :). But the VAO should save the current active channel and the current texture id during the VAO initialization and restore them at each vertex array binding. Plus, the default active channel is GL_TEXTURE0. \$\endgroup\$ Feb 12, 2014 at 13:37
  • 1
    \$\begingroup\$ "the VAO should save the current active channel and the current texture id during the VAO initialization and restore them at each vertex array binding" ==> This is precisely what I am challenging. The VAO spec explicitely states that the client active texture is not saved (search for the CLIENT_ACTIVE_TEXTURE string in the linked doc). If for some reason, you change the current active texture between your VAO creation and the moment you bind it for drawing, the one you chose at creation time won't be restored. \$\endgroup\$
    – jcorbier
    Feb 12, 2014 at 14:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .