2

I'm with a problem I can not solve:

attempt to draw a surface formed by a grid of squares (that are two triangles). Everything works fine when I use only the vertex data and drawing with:

//m_totalVertices = m_rows*(m_cols *6)  -> m_rows and m_cols are the quantity of columns and rows that build the surface
glDrawArrays(GL_TRIANGLES, 0, m_totalVertices);

for Example:

//first Quad
Vertex[0] = -15,5;
Vertex[1] = -5,5;
Vertex[2] = -5,-5;
Vertex[3] = -5,-5;
Vertex[4] = -15,-5;
Vertex[5] = -15,5;
//second Quad
Vertex[0] = -5,5;
Vertex[1] = 5,5;
Vertex[2] = 5,-5;
Vertex[3] = 5,-5;
Vertex[4] = -5,-5;
Vertex[5] = -5,5;
//third Quad
Vertex[0] = 5,5;
Vertex[1] = 15,5;
Vertex[2] = 15,-5;
Vertex[3] = 15,-5;
Vertex[4] = 5,-5;
Vertex[5] = 5,5;

RESULT: enter image description here

as a matter of optimization i want to use "indices", to reduce the number of vertex data, but the surface deforms:

to draw it, im using the next function:

//m_totalVertices = m_rows*(m_cols *6)  -> m_rows and m_cols are the quantity of columns and rows that build the surface
glDrawElements(GL_TRIANGLES, m_totalVertices, GL_UNSIGNED_INT, 0);

for Example:

//first Quad
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 2;
indices[4] = 3;
indices[5] = 0;
//second Quad
indices[6] = 1;
indices[7] = 4;
indices[8] = 5;
indices[9] = 5;
indices[10] = 2;
indices[11] = 1;
//third Quad
indices[12] = 4;
indices[13] = 6;
indices[14] = 7;
indices[15] = 7;
indices[16] = 5;
indices[17] = 4;

//first Quad
Vertex[0] = -15,5;
Vertex[1] = -5,5;
Vertex[2] = -5,-5;
Vertex[3] = -15,-5;
//second Quad
Vertex[0] = -5,5;
Vertex[1] = 5,5;
Vertex[2] = 5,-5;
Vertex[3] = -5,-5;
//third Quad
Vertex[0] = 5,5;
Vertex[1] = 15,5;
Vertex[2] = 15,-5;
Vertex[3] = 5,-5;

RESULT: enter image description here

Here's the code of the class that generates the surface only with vertex data (no indices) [WORKS PERFECT]:

 #include "plane.h"
#include "matrix.h"
#include "glslshader.h"
#include "texture.h"

plane::plane(GLuint cols, GLuint rows,GLuint segmentSize, mixedColors color, CTexture* texture, GLshort textureMode) :
m_matrix(0),
m_shader(0),
m_cols(cols),
m_rows(rows),
m_segmentSize(segmentSize),
m_selectedColor(color),
m_texture(texture),
m_textureMode(textureMode),
m_totalVertices(rows*(cols*6))
{
    //matrix handler
    m_matrix = matrix::getInstance();

    //check that variables are > 1
    if(m_cols < 1){m_cols = 1;}
    if(m_rows < 1){m_rows = 1;}

    // generate a VAO 
    glGenVertexArrays(1, &m_uiVAO);

    vbo.createVBO();

}

plane::~plane()
{
    delete m_shader;
    vbo.releaseVBO();

    glDeleteVertexArrays(1, &m_uiVAO);
}


bool plane::init()
{
    //load the shaders
    if(m_texture == NULL)
    {
        m_shader = new GLSLProgram("data/shaders/shader-primitives.vert", "data/shaders/shader-primitives.frag");
    }
    else//if primitive use texture...
        {
            m_shader = new GLSLProgram("data/shaders/shader-texture.vert", "data/shaders/shader-texture.frag");
        }

    if (!m_shader->initialize())
    {
        cout << "Los shaders de las primitivas no pudieron ser incializados\n";
        return false;
    }
    m_shader->linkProgram();

    //number of QUAD vertex
    const GLshort QUAD_ELEMENTS = 6;

    GLuint r,c,q,x;

    //bind VBO
    vbo.bindVBO();

    //set the start where you draw the first square of the plane
    // so that everything is centered
    GLfloat initX,initY;
    initX = initY = 0.0f;

    //displacement of each QUAD in X and Y axis.
    const float MODULE = 0.2f;


    //find the init value of X (the start value where you draw the first QUAD)
    if(m_cols > 1)
    {
        initX = (float)((m_cols*MODULE/2.0f))-0.1f;
    }
    //find the init value of y (the start value where you draw the first QUAD)
    if(m_rows > 1)
    {
        initY = (float)((m_rows*MODULE/2.0f))-0.1f;
    }



    //QUAD vertex data
    vector3f quad[QUAD_ELEMENTS];
    quad[0] = vector3f(-0.1f,0.1f,0.0f); quad[1] = vector3f(0.1f,0.1f,0.0f);
    quad[2] = vector3f(0.1f,-0.1f,0.0f); quad[3] = vector3f(0.1f,-0.1f,0.0f);
    quad[4] = vector3f(-0.1f,-0.1f,0.0f); quad[5] = vector3f(-0.1f,0.1f,0.0f);



    x=0;
    //put QUAD vertex in the "init position"
    for(x=0;x<QUAD_ELEMENTS;++x)
    {
        quad[x].x = quad[x].x + (-initX);
        quad[x].y = quad[x].y + initY;
    }


    //store de actual Y value of row (Y axis)
    GLfloat newRow = 0.0f;
    //store de actual X value of column (X axis)
    GLfloat newColumn = 0.0f;


    GLuint colorCounter = 0;


    for(r=0;r<m_rows;++r)
    {
        //reset newColumn variable to 0.0f for each new column
        newColumn = 0.0f;

        //for each column
        for(c=0;c<m_cols;++c)
        {
            //copy QUAD vertex data in new array
            vector3f quadCopy[QUAD_ELEMENTS] = quad;
            //for each column, move 0.1f to right
            for(q=0;q<QUAD_ELEMENTS;++q)
            {
                //move right one MODULE (in x axis)
                quadCopy[q].x = float(quadCopy[q].x + newColumn);
                //move down one MODULE (in Y axis)
                quadCopy[q].y = float(quadCopy[q].y + newRow);
                //add vertex data and color to de vbo
                vector3f resizedVertex = vector3f(quadCopy[q].x*m_segmentSize,quadCopy[q].y*m_segmentSize,quadCopy[q].z);
                vbo.addData(&resizedVertex,sizeof(vector3f));
                //every 4 laps reset colorCounter to 0;

                cout << "Vertex["<< q << "] = "<< resizedVertex.x << "," << resizedVertex.y << ";\n";
                if(colorCounter == 3){colorCounter = 0;}
                vbo.addData(&color4f(m_selectedColor.color[colorCounter].r,m_selectedColor.color[colorCounter].g,m_selectedColor.color[colorCounter].b,m_selectedColor.color[colorCounter].a),sizeof(color4f));


                ++colorCounter;
            }

            //for each column, move right 0.1f
            newColumn += MODULE;

        }

        newRow -= MODULE;
    }


    //bind VAO
    glBindVertexArray(m_uiVAO);
    //bind VBO
    vbo.bindVBO();
    vbo.uploadDataToGPU(GL_STATIC_DRAW);

    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(vector3f)+sizeof(color4f), (void*)sizeof(vector3f));

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vector3f)+sizeof(color4f), 0);

    return true;
}


void plane::render()
{
    //bind shader
    m_shader->bindShader();
    //send projection matrix to shader
    m_shader->sendUniform4x4("projectionMatrix", glm::value_ptr(*m_matrix->getProjectionMatrix()));


    //matrix transformations
    m_matrix->loadIdentity();
    m_matrix->scale(vector3f(m_scale,m_scale,m_scale));
    m_matrix->translate(m_pos);
    m_matrix->rotateX(m_orientation.x);
    m_matrix->rotateY(m_orientation.y);
    m_matrix->rotateY(m_orientation.z);

    //sendtransformation matrix  (modelview)
    m_shader->sendUniform4x4("modelViewMatrix", glm::value_ptr(m_matrix->getModelViewMatrix()));

    //bind VAO
    glBindVertexArray(m_uiVAO);

    glDrawArrays(GL_TRIANGLES, 0, m_totalVertices);

}

Here's the code of the class (modified) that generates the surface with vertex data and indices [DONT WORK]:

#include "plane.h"
#include "matrix.h"
#include "glslshader.h"
#include "texture.h"

plane::plane(GLuint cols, GLuint rows,GLuint segmentSize, mixedColors color, CTexture* texture, GLshort textureMode) :
m_matrix(0),
m_shader(0),
m_cols(cols),
m_rows(rows),
m_segmentSize(segmentSize),
m_selectedColor(color),
m_texture(texture),
m_textureMode(textureMode),
m_totalVertices(rows*(cols*6))
{
    //matrix handler
    m_matrix = matrix::getInstance();

    //check that variables are > 1
    if(m_cols < 1){m_cols = 1;}
    if(m_rows < 1){m_rows = 1;}

    // generate a VAO 
    glGenVertexArrays(1, &m_uiVAO);

    vbo.createVBO();
    vboIndices.createVBO();
}

plane::~plane()
{
    delete m_shader;
    vbo.releaseVBO();
    vboIndices.releaseVBO();
    glDeleteVertexArrays(1, &m_uiVAO);
}


bool plane::init()
{
    //load the shaders
    if(m_texture == NULL)
    {
        m_shader = new GLSLProgram("data/shaders/shader-primitives.vert", "data/shaders/shader-primitives.frag");
    }
    else//if primitive use texture...
        {
            m_shader = new GLSLProgram("data/shaders/shader-texture.vert", "data/shaders/shader-texture.frag");
        }

    if (!m_shader->initialize())
    {
        cout << "Los shaders de las primitivas no pudieron ser incializados\n";
        return false;
    }
    m_shader->linkProgram();

    //number of QUAD vertex
    const GLshort QUAD_ELEMENTS = 4;

    GLuint r,c,q,x;

    //---------------------------------------------------------------------------
    //bind VBO
    vboIndices.bindVBO(GL_ELEMENT_ARRAY_BUFFER);
    //base indices that are used to generate dynamic indices to all vertex data

    GLuint  baseIndices[6] = {0,1,2,2,3,0};
    GLshort indicesCounter = 0;



    cout << "indices==========================================\n";



    for(x=0;x<m_totalVertices;++x)
    {

        if(indicesCounter == 6)
        {
            cout << "new pack of indices = " << x << "\n";

            baseIndices[0] = baseIndices[1];
            if(x > 6){baseIndices[1] += 2;}else{if(x == 6){baseIndices[1] += 3;}}
            baseIndices[2] = (baseIndices[1]+1);
            baseIndices[3] = baseIndices[2];
            baseIndices[4] = baseIndices[0]+1;
            baseIndices[5] = baseIndices[0];
            indicesCounter = 0;
        }

        vboIndices.addData(&baseIndices[indicesCounter],sizeof(GLuint ));
        cout << "indices["<<x<<"] = " << baseIndices[indicesCounter] << "\n";

        ++indicesCounter;
    }
    //-------------------------------------------------------------------------------


    //bind VBO
    vbo.bindVBO();

    //set the start where you draw the first square of the plane
    // so that everything is centered
    GLfloat initX,initY;
    initX = initY = 0.0f;

    //displacement of each QUAD in X and Y axis.
    const float MODULE = 0.2f;


    //find the init value of X (the start value where you draw the first QUAD)
    if(m_cols > 1)
    {
        initX = (float)((m_cols*MODULE/2.0f))-0.1f;
    }
    //find the init value of y (the start value where you draw the first QUAD)
    if(m_rows > 1)
    {
        initY = (float)((m_rows*MODULE/2.0f))-0.1f;
    }



    //QUAD vertex data
    vector3f quad[QUAD_ELEMENTS];

    quad[0] = vector3f(-0.1f,0.1f,0.0f); quad[1] = vector3f(0.1f,0.1f,0.0f);
    quad[2] = vector3f(0.1f,-0.1f,0.0f); quad[3] = vector3f(-0.1f,-0.1f,0.0f);


     //put QUAD vertex in the "init position"
    for(x=0;x<QUAD_ELEMENTS;++x)
    {
        quad[x].x = quad[x].x + (-initX);
        quad[x].y = quad[x].y + initY;
    }


    //store de actual Y value of row (Y axis)
    GLfloat newRow = 0.0f;
    //store de actual X value of column (X axis)
    GLfloat newColumn = 0.0f;


    GLuint colorCounter = 0;

    for(r=0;r<m_rows;++r)
    {
        //reset newColumn variable to 0.0f for each new column
        newColumn = 0.0f;

        //for each column
        for(c=0;c<m_cols;++c)
        {
            //copy QUAD vertex data in new array
            vector3f quadCopy[QUAD_ELEMENTS] = quad;
            //for each column, move 0.1f to right
            for(q=0;q<QUAD_ELEMENTS;++q)
            {
                //move right one MODULE (in x axis)
                quadCopy[q].x = float(quadCopy[q].x + newColumn);
                //move down one MODULE (in Y axis)
                quadCopy[q].y = float(quadCopy[q].y + newRow);
                //add vertex data and color to de vbo
                vector3f resizedVertex = vector3f(quadCopy[q].x*m_segmentSize,quadCopy[q].y*m_segmentSize,quadCopy[q].z);
                vbo.addData(&resizedVertex,sizeof(vector3f));
                //every 4 laps reset colorCounter to 0;

                cout << "Vertex["<< q << "] = "<< resizedVertex.x << "," << resizedVertex.y << ";\n";
                if(colorCounter == 3){colorCounter = 0;}
                vbo.addData(&color4f(m_selectedColor.color[colorCounter].r,m_selectedColor.color[colorCounter].g,m_selectedColor.color[colorCounter].b,m_selectedColor.color[colorCounter].a),sizeof(color4f));


                ++colorCounter;
            }

            //for each column, move right 0.1f
            newColumn += MODULE;

        }

        newRow -= MODULE;
    }


    //bind VAO
    glBindVertexArray(m_uiVAO);
    //bind VBO
    vbo.bindVBO();
    vbo.uploadDataToGPU(GL_STATIC_DRAW);

    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(vector3f)+sizeof(color4f), (void*)sizeof(vector3f));

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vector3f)+sizeof(color4f), 0);


    //load indices data in VBO
    vboIndices.bindVBO(GL_ELEMENT_ARRAY_BUFFER);
    vboIndices.uploadDataToGPU(GL_STATIC_DRAW);

    return true;
}


void plane::render()
{
    //bind shader
    m_shader->bindShader();
    //send projection matrix to shader
    m_shader->sendUniform4x4("projectionMatrix", glm::value_ptr(*m_matrix->getProjectionMatrix()));


    //matrix transformations
    m_matrix->loadIdentity();
    m_matrix->scale(vector3f(m_scale,m_scale,m_scale));
    m_matrix->translate(m_pos);
    m_matrix->rotateX(m_orientation.x);
    m_matrix->rotateY(m_orientation.y);
    m_matrix->rotateY(m_orientation.z);

    /sendtransformation matrix  (modelview)
    m_shader->sendUniform4x4("modelViewMatrix", glm::value_ptr(m_matrix->getModelViewMatrix()));

    //bind VAO
    glBindVertexArray(m_uiVAO);

    glDrawElements(GL_TRIANGLES, m_totalVertices, GL_UNSIGNED_INT, 0);
}

Here's the code of class that handle VBO's [this work perfect, only put here for you to understand what do the methods]:

#include "common_header.h"

#include "vertexBufferObject.h"

CVertexBufferObject::CVertexBufferObject()
{
    bDataUploaded = false;
}

/*-----------------------------------------------

Name:       createVBO

Params: a_iSize - initial size of buffer

Result: Creates vertex buffer object.

/*---------------------------------------------*/

void CVertexBufferObject::createVBO(int a_iSize)
{
    //obtiene el ID del VBO
    glGenBuffers(1, &uiBuffer);
    //reserva espacio para los datos que va a alojar
    data.reserve(a_iSize);
    //setea el tamaño
    iSize = a_iSize;
}

/*-----------------------------------------------

Name:       releaseVBO

Params: none

Result: Releases VBO and frees all memory.

/*---------------------------------------------*/

void CVertexBufferObject::releaseVBO()
{
    //elimina el ID obtenido
    glDeleteBuffers(1, &uiBuffer);
    bDataUploaded = false;
    //libera todos los datos almacenados
    data.clear();
}

/*-----------------------------------------------

Name:       mapBufferToMemory

Params: iUsageHint - GL_READ_ONLY, GL_WRITE_ONLY...

Result: Maps whole buffer data to memory and
            returns pointer to data.

/*---------------------------------------------*/

void* CVertexBufferObject::mapBufferToMemory(int iUsageHint)
{
    if(!bDataUploaded)return 0;
    void* ptrRes = glMapBuffer(iBufferType, iUsageHint);
    return ptrRes;
}

/*-----------------------------------------------

Name:       mapSubBufferToMemory

Params: iUsageHint - GL_READ_ONLY, GL_WRITE_ONLY...
            uiOffset - data offset (from where should
                            data be mapped).
            uiLength - length of data

Result: Maps specified part of buffer to memory.

/*---------------------------------------------*/

void* CVertexBufferObject::mapSubBufferToMemory(int iUsageHint, unsigned int uiOffset, unsigned int uiLength)
{
    if(!bDataUploaded)return 0;
    void* ptrRes = glMapBufferRange(iBufferType, uiOffset, uiLength, iUsageHint);
    return ptrRes;
}

/*-----------------------------------------------

Name:       unmapBuffer

Params: none

Result: Unmaps previously mapped buffer.

/*---------------------------------------------*/

void CVertexBufferObject::unmapBuffer()
{
    glUnmapBuffer(iBufferType);
}

/*-----------------------------------------------

Name:       bindVBOiDrawingHint)
{
    glBufferData(iBufferType, data.size(), &data[0], iDrawingHint);
    bDataUploaded = true;


Params: a_iBufferType - buffer type (GL_ARRAY_BUFFER, ...)

Result: Binds this VBO.

/*---------------------------------------------*/

void CVertexBufferObject::bindVBO(int a_iBufferType)
{
    iBufferType = a_iBufferType;
    glBindBuffer(iBufferType, uiBuffer);
}

/*-----------------------------------------------

Name:       uploadDataToGPU

Params: iUsageHint - GL_STATIC_DRAW, GL_DYNAMIC_DRAW...

Result: Sends data to GPU.

/*---------------------------------------------*/

void CVertexBufferObject::uploadDataToGPU(int iDrawingHint)
{
    glBufferData(iBufferType, data.size(), &data[0], iDrawingHint);
    bDataUploaded = true;
    data.clear();
}

/*-----------------------------------------------

Name:       addData

Params: ptrData - pointer to arbitrary data
            uiDataSize - data size in chars

Result: Adds arbitrary data to VBO.

/*---------------------------------------------*/

void CVertexBufferObject::addData(void* ptrData, unsigned int uiDataSize)
{
    data.insert(data.end(), (char*)ptrData, (char*)ptrData+uiDataSize);
}

/*-----------------------------------------------

Name:       getDataPointer

Params: none

Result: Returns data pointer (only before uplading).

/*---------------------------------------------*/

void* CVertexBufferObject::getDataPointer()
{
    if(bDataUploaded)return 0;
    return (void*)data[0];
}

/*-----------------------------------------------

Name:       getBuffer

Params: none

Result: Returns VBO ID.

/*---------------------------------------------*/

unsigned int CVertexBufferObject::getBuffer()
{
    return uiBuffer;
}
Fabian Orue
  • 193
  • 2
  • 14
  • Your index code is quite large and quite hard to read. Could you eleborate on how you fill your baseIndices variable? It looks like the problem is there. It all seems overcomplicated to me, plus I (and possibly many other people here) can't read spanish that well. – Full Frontal Nudity Oct 15 '13 at 20:00
  • thank you! I translated all the comments so they can be better understood. Anyway, to avoid having to read all the code, I put the output of the code, Please, check what I´ve mentioned in the text above "section" -> "for example" this is the output and image is the result. – Fabian Orue Oct 16 '13 at 02:56
  • any idea guys? im lost .. i dont know why the indices dont draw the surface correctly.. – Fabian Orue Oct 17 '13 at 21:57
  • I think i've figured it out. Your indices are indeed wrong, you need to fill in different numbers. Also, when calling "glDrawElements(GL_TRIANGLES, m_totalVertices, GL_UNSIGNED_INT, 0);" you should always use the amount of indices instead of the amount of vertices. Stand by for answer – Full Frontal Nudity Oct 19 '13 at 10:08

1 Answers1

1

I can't be 100% sure without having more information, but anyway:

The correct array of indices should be like this: 0,1,2,2,3,0 , 4,5,6,6,7,4 , 8,9,10,10,11,8.

This is because you use your indices as if you do NOT have duplicate vertices, but according to the output, you DO :). Alternatively, if you want to use even less space, consider using GL_QUADS instead of GL_TRIANGLES, this way you will only have to specify 4 indices per quad.

If you want to fix your vertices instead, submit only vertices 0,1,2,3, 5,6, 9,10 to your floatbuffer and don't modify your indices.

  • Thank you! you are right! :D the indices should be: 0,1,2,2,3,0 , 4,5,6,6,7,4 , 8,9,10,10,11,8 generating them that way, everything works fine :) thanks for the tips and thanks to all for the help. – Fabian Orue Oct 19 '13 at 18:22
  • I have a new doubt, I created two VBO one for the vertices, including textures and another for indices. The fact is that the textures, although they are mapped correctly, not shown, or it does so erroneous. for each quad, i apply the following texture: texcoords [0] = texCoord (0.0,1.0); texcoords [1] = texCoord (1.0,1.0); texcoords [2] = texCoord (1.0,0.0); texcoords [3] = texCoord (0.0,0.0); – Fabian Orue Oct 19 '13 at 20:12
  • considering that the "indices VBO" contains 6 points to represent the four vertex of the QUAD, in the "vertex VBO" only add four vertex and for each vertex, one texture coordinate. – Fabian Orue Oct 19 '13 at 20:22
  • forget the last thing, this is solved, the problem was as generating texture coordinates, now works! thanks to all. The issue is solved, if someone tells me how to put it in the "solved" state, I will do it :) good luck! – Fabian Orue Oct 19 '13 at 20:50
  • No problem! You have flagged my answer as accepted, so it's "solved" now :), you don't need to do anything else. – Full Frontal Nudity Oct 20 '13 at 09:35