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.