简体   繁体   中英

creating indexes and GL_TRIANGLES surface (only works with vertices data)

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: 在此处输入图片说明

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: 在此处输入图片说明

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM