Create a grid in OpenGL - c++

I need to generate a NxN resolution grid in the xy-plane with OpenGL. The final grid needs to be made by triangles (GL_TRIANGLES), so it should seem like the following example:
^
* | ----------
* | |\ |\ |\ |
* | | \| \| \|
* | ----------
* | |\ |\ |\ |
* y | | \| \| \|
* | ----------
* | |\ |\ |\ |
* | | \| \| \|
* | ----------
* |
* |-------------->
* x
Note that I need to store the grid in vertex-index form (given the structures by parameters).
My code at this point:
void generate_grid(
std::uint32_t N,
std::vector<glm::vec3>* vertices,
std::vector<glm::uvec3>* indices)
{
for (int i = 0; i < N; i++) {
glBegin(GL_TRIANGLES);
for (int j = 0; j < N; j++) {
int vertexNum = indices; // Index for vertex j of face i.
double[] vertexCoords = vertices[vertexNum]; // The vertex itself.
glVertex3f(vertexCoords, 0);
}
glEnd();
}
Any advice? Regards.

Since the language is C++ and you are using a std::vector you should change the function signature and pass the parameters by reference instead of by pointer.
void generate_grid(int N, std::vector<glm::vec3> &vertices, std::vector<glm::uvec3> &indices);
First you have to fill the vertex array. Note, for a N*N field you need (N+1)*(N+1) vertices. Second you have to generate the triangle indices, for each field you have to generate 2 triangles:
float f(float x, float y)
{
// use any curve function you want
return sin(x*2.0f*3.141526f) * sin(y*2.0f*3.141526f) * 0.1f;
}
void generate_grid(int N, std::vector<glm::vec3> &vertices, std::vector<glm::uvec3> &indices)
{
for (int j=0; j<=N; ++j)
{
for (int i=0; i<=N; ++i)
{
float x = (float)i/(float)N;
float y = (float)j/(float)N;
float z = f(x, y);
vertices.push_back(glm::vec3(x, y, z));
}
}
for (int j=0; j<N; ++j)
{
for (int i=0; i<N; ++i)
{
int row1 = j * (N+1);
int row2 = (j+1) * (N+1);
// triangle 1
indices.push_back(glm::uvec3(row1+i, row1+i+1, row2+i+1));
// triangle 2
indices.push_back(glm::uvec3(row1+i, row2+i+1, row2+i));
}
}
}
The old school and deprecated way to draw this, would be like this:
void draw_grid(const std::vector<glm::vec3> &vertices, const std::vector<glm::uvec3> &indices)
{
glBegin(GL_TRIANGLES);
for ( auto i : indices )
{
glVertex3fv(glm::value_ptr(vertices[i.x]));
glVertex3fv(glm::value_ptr(vertices[i.y]));
glVertex3fv(glm::value_ptr(vertices[i.z]));
}
glEnd();
}
The common way to draw geometry is to create a Vertex Array Object:
GLuint generate_vao(const std::vector<glm::vec3> &vertices, const std::vector<glm::uvec3> &indices)
{
GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
GLuint vbo;
glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, vertices.size()*sizeof(glm::vec3), glm::value_ptr(vertices[0]), GL_STATIC_DRAW );
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, nullptr );
GLuint ibo;
glGenBuffers( 1, &ibo );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(glm::uvec3), glm::value_ptr(indices[0]), GL_STATIC_DRAW );
glBindVertexArray( 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
return vao;
}
void draw_vao( GLuint vao, GLsizei n )
{
glBindVertexArray( vao );
glDrawElements( GL_TRIANGLES, (GLsizei)n, GL_UNSIGNED_INT, NULL );
glBindVertexArray( 0 );
}
std::vector<glm::vec3> vertices;
std::vector<glm::uvec3> indices;
GLuint vao = generate_vao( vertices, indices );
.....
draw_vao( vao, (GLsizei)indices.size()*3 );

Related

Sphere Calculations

So I have created all of the correct sphere vertices using this algorithm:
GLint total = 100;
GLfloat radius = 200;
GLfloat sphereVertices[30000];
for (int i = 0; i < total; i++)
{
float lon = map(i, 0, total, -M_PI, M_PI);
for (int j = 0; j < total; j++)
{
float lat = map(j, 0, total, -M_PI/2, M_PI/2);
sphereVertices[(i * 300) + (j * 3)] = radius * sin(lon) * cos(lat);
sphereVertices[(i * 300) + (j * 3) + 1] = radius * sin(lon) * sin(lat);
sphereVertices[(i * 300) + (j * 3) + 2] = radius * cos(lon);
}
}
But when I draw it using either GL_TRIANGLES and GL_TRIANGLE_STRIP, I'm produced with this result:
As you can see the only triangles which are being rendered are slicing through the center of the sphere. Is my math wrong? Or am I not plotting my data into my array the correct way for my glVertexAttribPointer function to read the data correctly?
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0);
EDIT 1:
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glDrawArrays(GL_TRIANGLES, 0, 10000);
You cant't draw the inices directly by glDrawArrays. You have to bring them in a proper order.
Create a triangle index list and use glDrawElements
See also How to map texture to sphere that rendered by parametric equation using points primitive
Further note, that your loop should run from i = 0 to i <= total, because you want to create vertex coordinates on both poles of the sphere.
GLint layers = 100;
GLint circumferenceTiles = 100;
std::vector<GLfloat> sphereVertices;
va.reserve( (layers+1)*(circumferenceTiles+1)*3 ); // 3 floats: x, y, z
for ( int i = 0; i <= layers; ++ i )
{
GLfloat lon = map(i, 0, layers, -M_PI, M_PI);
GLfloat lon_sin = std::sin( lon );
GLfloat lon_cos = std::cos( lon );
for ( int j = 0; j <= circumferenceTiles; j ++ )
{
GLfloat lat = map(j, 0, circumferenceTiles, -M_PI/2, M_PI/2);
GLfloat lat_sin = std::sin( lat);
GLfloat lat_cos = std::cos( lat);
va.push_back( lon_cos * lat_cos ); // x
va.push_back( lon_cos * lat_sin ); // y
va.push_back( lon_sin ); // z
}
}
You can create triangles by stacking up discs:
// create the face indices
std::vector<GLuint> ia;
ia.reserve( layers*circumferenceTiles*6 );
for ( GLuint il = 0; il < layers; ++ il )
{
for ( GLuint ic = 0; ic < circumferenceTiles; ic ++ )
{
GLuint i0 = il * (circumferenceTiles+1) + ic;
GLuint i1 = i0 + 1;
GLuint i3 = i0 + circumferenceTiles+1;
GLuint i2 = i3 + 1;
int faces[]{ i0, i1, i2, i0, i2, i3 };
ia.insert(ia.end(), faces+(il==0?3:0), faces+(il==layers-1?3:6));
}
}
Specify the vertex array object:
GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
GLuint vbo;
glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, sphereVertices.size()*sizeof(GLfloat), sphereVertices.data(),
GL_STATIC_DRAW );
GLuint ibo;
glGenBuffers( 1, &ibo );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, ia.size()*sizeof(GLuint), ia.data(), GL_STATIC_DRAW );
GLuint v_attr_inx = 0;
glVertexAttribPointer( v_attr_inx , 3, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray( v_attr_inx );
glBindVertexArray( 0 );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
Draw the sphere:
glBindVertexArray( vao );
glDrawElements( GL_TRIANGLES, (GLsizei)ia.size(), GL_UNSIGNED_INT, 0 );
glBindVertexArray( 0 );

my sprites are switching between textures opengl

I'm drawing sprites that are all in a buffer using glDrawElements.
To tell sprites what texture to be in the fragment shader I have uniform sampler2D textures[32]; each vertex has an index, which is passed to the fragment shader from the vertex shader:
color = texture(textures[index], fs_in.uv);
when I try draw my sprites with more than 1 texture active it gets the wrong textures in the top right corner
http://puu.sh/lyr5j/d8c2cf6c8f.png
I have no clue why this is happening have tried texture parameters
I cant seem to find anyone who has had a similar problem.
This is my renderer's init function (I am purposly passing the texid as float since I have heard ints don't work well (also tried))
glGenBuffers(1, &m_VDBO);
glGenVertexArrays(1, &m_VAO);
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VDBO);
glBufferData(GL_ARRAY_BUFFER, RENDERER_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(SHADER_VERTEX_INDEX);
glEnableVertexAttribArray(SHADER_UV_INDEX);
glEnableVertexAttribArray(SHADER_COLOR_INDEX);
glEnableVertexAttribArray(SHADER_TEXID_INDEX);
glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::vertex));
glVertexAttribPointer(SHADER_UV_INDEX, 2, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::uv));
glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_UNSIGNED_BYTE, GL_TRUE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::color));
glVertexAttribPointer(SHADER_TEXID_INDEX, 1, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *)offsetof(VertexData, VertexData::texID));
glBindBuffer(GL_ARRAY_BUFFER, 0);
const GLushort modelindices[] = { 0, 1, 2, 2, 3, 0 };
GLuint indices[RENDERER_INDICES_SIZE];
for (int i = 0; i < RENDERER_INDICES_SIZE; i += 6)
{
for (int o = 0; o < 6; o++)
{
indices[i + o] = modelindices[o] + (i / 6 * 4);
}
}
glGenBuffers(1, &m_IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, RENDERER_INDICES_SIZE * sizeof(GLuint), indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
the flush function
glBindVertexArray(m_VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
for (int i = 0; i < m_TextureSlots.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, m_TextureSlots[i]);
}
glDrawElements(GL_TRIANGLES, m_IndexCount, GL_UNSIGNED_INT, 0);
m_TextureSlots.clear();
m_IndexCount = 0;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
It is hard for me to see where your problem is coming from, the only thing I can suggest is taking a look at an Image2d class object constructor that I have. Now, my source depends on outside classes such as a ShaderManager class that relies heavily on template types and a Batch class and a BatchManager class to send over the vertices to the video card. Also this Image2d is an inherited object. However, this may serve as some help to you in tracking down your own problem. There are two different constructors for different versions of the implementation depending on which version of OpenGL and GLSL is being used. If I remember correctly version 2 uses the BatchManager to send the vertices to the video card where version 1 doesn't which can be seen within the render() method.
Image2d v1.0
// ----------------------------------------------------------------------------
// Image2d()
Image2d::Image2d( float fWidth, float fHeight, TextureInfo::FilterQuality filterQuality, bool generateMipMap, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( glm::uvec2(), strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
if ( fWidth <= 0 || fHeight <= 0 ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Invalid image size (" << fWidth << "," << fHeight << ") must be more then 0 in each dimension.";
throw ExceptionHandler( strStream );
}
// Save TextureId
TextureFileReader textureFileReader( strTextureFilename );
m_textureInfo = textureFileReader.getOrCreateTextureInfo( filterQuality, generateMipMap, false );
// Define Texture Co-Ordinates
std::vector<float> vTextureCoordinates;
vTextureCoordinates.push_back( 0.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 0 );
vTextureCoordinates.push_back( 0 );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 0 );
// Define Vertex Positions (x,y,z)
std::vector<float> vVertexPositions;
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( fHeight );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( fWidth );
vVertexPositions.push_back( fHeight );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( fWidth );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
// Define 2 Triangle Faces
std::vector<unsigned char> vIndices;
vIndices.push_back( 0 );
vIndices.push_back( 1 );
vIndices.push_back( 2 );
vIndices.push_back( 3 );
// Create Vertex Array Object
glGenVertexArrays( 1, &m_vao );
glBindVertexArray( m_vao ); // Start Array
m_pShaderManager->setAttribute( A_COLOR, COLOR_WHITE );
// Create Position Buffer And Store On Video Card
glGenBuffers( 1, & m_vboPosition );
glBindBuffer( GL_ARRAY_BUFFER, m_vboPosition );
glBufferData( GL_ARRAY_BUFFER, vVertexPositions.size() * sizeof( vVertexPositions[0] ), &vVertexPositions[0], GL_STATIC_DRAW );
m_pShaderManager->enableAttribute( A_POSITION );
// Create Texture Coordinate Buffer
glGenBuffers( 1, &m_vboTexture );
glBindBuffer( GL_ARRAY_BUFFER, m_vboTexture );
glBufferData( GL_ARRAY_BUFFER, vTextureCoordinates.size() * sizeof( vTextureCoordinates[0] ), &vTextureCoordinates[0], GL_STATIC_DRAW );
m_pShaderManager->enableAttribute( A_TEXTURE_COORD0 );
// Create Index Buffer
glGenBuffers( 1, &m_vboIndices );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_vboIndices );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, vIndices.size() * sizeof( vIndices[0] ), &vIndices[0], GL_STATIC_DRAW );
glBindVertexArray( 0 ); // Stop Array
// Disable Attribute Pointers
m_pShaderManager->disableAttribute( A_POSITION );
m_pShaderManager->disableAttribute( A_TEXTURE_COORD0 );
// THIS MUST BE AFTER Vertex Array Buffer Is Unbound!
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); // Stop Buffer Index
glBindBuffer( GL_ARRAY_BUFFER, 0 ); // Stop Buffer
// We have a Valid Image2d Save Filename
m_strFilename = strTextureFilename;
} // Image2D - v1.0
Image2D - v2.0
// ----------------------------------------------------------------------------
// Image2d()
Image2d::Image2d( const glm::uvec2& origin, const glm::uvec2& size, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( size, strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
m_version = 2;
TextureFileReader textureFileReader( strTextureFilename );
m_textureInfo = textureFileReader.getOrCreateTextureInfo( TextureInfo::FILTER_NONE, false, false );
m_config.uTextureId = m_textureInfo.uTextureId;
if ( 0 == m_textureInfo.size.x || 0 == m_textureInfo.size.y ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << "size of " << strTextureFilename << " is invalid " << m_textureInfo.size;
throw ExceptionHandler( strStream );
}
// Verify Image Fits Inside Texture
if ( m_textureInfo.size.x < size.x + origin.x || m_textureInfo.size.y < size.y + origin.y ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " " << strTextureFilename << " size is " << m_textureInfo.size
<< " which is too small for an image that is " << size
<< " pixels in size, with an origin point set at " << origin ;
throw ExceptionHandler( strStream );
}
glm::vec2 textureCoordScaleFactor( 1.0f / static_cast<float>( m_textureInfo.size.x ),
1.0f / static_cast<float>( m_textureInfo.size.y ) );
glm::vec2 textureCoordBottomLeft = glm::vec2( textureCoordScaleFactor.x * origin.x,
textureCoordScaleFactor.y * ( m_textureInfo.size.y - origin.y - size.y ) );
glm::vec2 textureCoordTopRight = glm::vec2( textureCoordScaleFactor.x * ( origin.x + size.x ),
textureCoordScaleFactor.y * ( m_textureInfo.size.y - origin.y ) );
// Set Colors And Texture Coordinates (Position Will Be Updated In Render Function)
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordBottomLeft.x, textureCoordTopRight.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordBottomLeft.x, textureCoordBottomLeft.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordTopRight.x, textureCoordTopRight.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordTopRight.x, textureCoordBottomLeft.y ) ) );
} // Image2d - v2.0
and here is my render() method
// ----------------------------------------------------------------------------
// render()
void Image2d::render() {
if ( 1 == m_version ) {
m_pShaderManager->setTexture( 0, U_TEXTURE0_SAMPLER_2D, m_textureInfo.uTextureId );
glBindVertexArray( m_vao );
glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, nullptr );
glBindVertexArray( 0 );
} else {
// Version 2.0
// Update Vertices
if ( m_transformMatrix.updateTranslation || m_transformMatrix.updateScale || m_transformMatrix.updateRotation ) {
m_transformMatrix.updateTranslation = m_transformMatrix.updateScale = m_transformMatrix.updateRotation = false;
// Order Of Operations Matter Here!
glm::mat4 matrix; // Identity
if ( m_transformMatrix.hasTranslation ) {
matrix[3][0] = m_transformMatrix.translation.x;
matrix[3][1] = m_transformMatrix.translation.y;
}
if ( m_transformMatrix.hasRotation ) {
matrix = glm::rotate( matrix, m_transformMatrix.fRotationAngleRadians, glm::vec3( 0.0f, 0.0f, -1.0f ) );
}
if ( m_transformMatrix.hasScale ) {
matrix = matrix * glm::mat4( m_transformMatrix.scale.x, 0.0f, 0.0f, 0.0f,
0.0f, m_transformMatrix.scale.y, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f );
}
// Center Offset
if ( m_offsetPosition.x != 0 || m_offsetPosition.y != 0 ) {
matrix = glm::translate( matrix, glm::vec3( -m_offsetPosition.x, -m_offsetPosition.y, 0.0f ) );
}
// Apply Transformation To All 4 Vertices
m_vVertices[0].position = glm::vec2( matrix * glm::vec4( 0, 0, 0, 1.0f ) );
m_vVertices[1].position = glm::vec2( matrix * glm::vec4( 0, m_size.y, 0, 1.0f ) );
m_vVertices[2].position = glm::vec2( matrix * glm::vec4( m_size.x, 0, 0, 1.0f ) );
m_vVertices[3].position = glm::vec2( matrix * glm::vec4( m_size.x, m_size.y, 0, 1.0f ) );
}
renderBatch();
}
} // render
Make sure that the sizes you are specifying in your glBufferData(GL_ARRAY_BUFFER, RENDERER_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW);
is accurate. Also make sure that you are stopping your your VertexArray at the appropriate time as well as disabling your Attribute Pointers. Everything that you bound must be unbound, and for some types Order does matter!

OpenGL - SegFault on glBufferData() while loading vertex data

Problem: Segmentation fault on glBufferData.
About libs & input data:
3ds file contains a few models.
GLEW - 1.11.0
GLFW - 3.0.4
GLM - 0.9.5.4
ASSIMP - 3.1.1
OS - Windows 7 x64 lastest PS
GPU: nvidia 770
Output:
Wersja OpenGL: 4.4.0
Kompilacja shadera...
Compiling shader : vert.vs
- Success
Compiling shader : frag.fs
- Success
Ustawianie Model - Widok - Projekcja...
Wczytywanie wczeťniej wygenerowanych obiektˇw...
Ladowanie Mesha nr.0...
Rozmiary - 2 | 108 | 108
a
b
c
Here is code:
Mesh_Loader.cpp
GLfloat **vertexData, **normalData, **colorsData_buffer;
GLushort** indexData;
/** Bufory */
GLuint* vertexBuffer, *colorBuffer, *indexBuffer;
int mesh_size = 0;
unsigned int* count_of_vertex; //Licznik ile vertex-ów na danym meshie jest
int* count_of_index; //Licznik indeksów
unsigned int suma_vertexow = 0; //Suma wszystkich vertexow... normalnie się powinno to inaczej obejść. Ale kij.
const struct aiFace* tmp_face;
int tmp_index = 0;
//[...]
bool mesh_load(const std::string& Filename)
{
Assimp::Importer Importer;
const aiScene* pScene = Importer.ReadFile(Filename.c_str(), aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs);
/** Sprawdzenie czy wczytał scene */
if (pScene) {
init_from_scene(pScene);
return true;
}
else
{
std::cout << "Wystąpił błąd podczas wczytywania: " << Importer.GetErrorString() << std::endl;
return false;
}
}
void pre_reserve_memory(const aiMesh* paiMesh, int cur_poz)
{
count_of_index[cur_poz] = 0;
for (unsigned int i = 0; i < paiMesh->mNumFaces; i++) {
tmp_face = &paiMesh->mFaces[i];
count_of_index[cur_poz] += tmp_face->mNumIndices;
}
indexData[cur_poz] = new GLushort[count_of_index[cur_poz]];
}
void init_from_scene(const aiScene* pScene)
{
mesh_size = pScene->mNumMeshes;
//Pre Rezerwacja miejsca
vertexData = new GLfloat*[mesh_size];
colorsData_buffer = new GLfloat*[mesh_size];
normalData = new GLfloat*[mesh_size];
indexData = new GLushort*[mesh_size];
//Buffory
vertexBuffer = new GLuint[mesh_size];
colorBuffer = new GLuint[mesh_size];
indexBuffer = new GLuint[mesh_size];
count_of_vertex = new unsigned int[mesh_size];
count_of_index = new int[mesh_size];
for (unsigned int i = 0; i < pScene->mNumMeshes; i++)
{
pre_reserve_memory(pScene->mMeshes[i], i);
// [...]
przepare_mesh(pScene->mMeshes[i], vertexData[i], colorsData_buffer[i], normalData[i], indexData[i], &count_of_vertex[i]);
}
}
void przepare_mesh(const aiMesh* paiMesh, GLfloat* vertexData, GLfloat* colorsData_buffer, GLfloat* normalData, GLushort* indexData, unsigned int* count_of_vertex)
{
int counter;
vertexData = (GLfloat *)&paiMesh->mVertices;
colorsData_buffer = (GLfloat *)&paiMesh->mColors;
normalData = (GLfloat *)&paiMesh->mNormals;
*count_of_vertex = paiMesh->mNumVertices;
for (unsigned int i = 0; i < paiMesh->mNumFaces; i++) {
tmp_face = &paiMesh->mFaces[i];
for (unsigned int j = 0; j < tmp_face->mNumIndices; j++)
{
counter = i + j;
indexData[counter] = tmp_face->mIndices[j];
}
}
}
/** TODO: RE-LIGHTING, MOUSE */
void render_scene()
{
glLinkProgram(program); // jak skompilowalem kod to moge go polaczyc z bibliotekami - linkowanie
glUseProgram(program); // od tego momentu wszystko co zrobie bedzie uzywac tego programu (tej kombinacji shaderow)
glClearColor(0.0f, 0.0f, 0.4f, 0.0f); // ustala kolor wyczyszczonego okna
glEnable(GL_CULL_FACE); // wewnetrzne flagi opengl
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/** Model - View - Projection */
glm::mat4 Model = glm::mat4(1.0f); // tworzenie macierzy obiektu
glm::mat4 View = glm::lookAt(glm::vec3(0.0f, 2.0f, -5.0f), glm::vec3(), glm::vec3(0.0f, 1.0f, 0.0f)); // widoku
glm::mat4 Projection = glm::perspective(60.0f, 16.0f / 9.0f, 0.1f, 1000.0f); // projekcji
glm::mat4 MVP; // zmienna na pozniej
GLuint MVPUniformLoc = glGetUniformLocation(program, "MVP"); // daje wskaznik gdzie MVP znajduje sie w pamieci
/** Addresy Pamięci */
GLuint positionAttribLoc = glGetAttribLocation(program, "position"); // wytlumaczenie cpu jak sie dostac do adresu pamieci gpu
GLuint colorAttribLoc = glGetAttribLocation(program, "color");
/** tworzenie tablicy przechowujacej vertexy */
GLuint vertexArrayObject;
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
for (int i = 0; i < mesh_size; i++)
{
suma_vertexow += count_of_vertex[i];
glGenBuffers(1, &vertexBuffer[i]);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[i]);
glBufferData(GL_ARRAY_BUFFER, (sizeof(GLfloat)* count_of_vertex[i]), vertexData[i], GL_STATIC_DRAW); //Problem Area
if (colorsData_buffer[i] != NULL)
{
glGenBuffers(1, &colorBuffer[i]);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer[i]);
glBufferData(GL_ARRAY_BUFFER, (sizeof(GLfloat) * count_of_vertex[i]), colorsData_buffer[i], GL_DYNAMIC_DRAW);
}
glGenBuffers(1, &indexBuffer[i]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (sizeof(GLushort)* count_of_index[i]), indexData[i], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);
glEnableVertexAttribArray(positionAttribLoc); // atrybuty wskazinikow (bufory)
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[i]);
glVertexAttribPointer(
positionAttribLoc, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
NORMALIZED, // normalized?
0, // stride - wierzcholki oznaczajace pozycje sa w tym buforze jeden za drugim (odstep miedzy kolejnymi wierzcholkami)
(GLvoid*)0 // array buffer offset - w ktorym miejscu bufora zaczyna sie inf o wierzcholkach
);
glBindBuffer(GL_ARRAY_BUFFER, NULL);
if (colorsData_buffer[i] != NULL)
{
glEnableVertexAttribArray(colorAttribLoc);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer[i]);
glVertexAttribPointer(
colorAttribLoc, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
NORMALIZED, // normalized?
0, // stride
(GLvoid*)0 // array buffer offset
);
}
glBindBuffer(GL_ARRAY_BUFFER, NULL);
}
//[...]
}
Mesh_Loader -> load via assimp.importer data from 3DS file
and extract data about index, Colors, Vertex, Normals for each mesh
function render -> load data about: data about index, Colors, Vertex, Normals
but It causes some problem when it loading data into buffer "glBufferData"
SegFault
Additioanl_func.cpp
Extra functions for load shader & mouse callback
Where is there problem?
I don't think this is an OpenGL problem. The code is simply using uninitialized pointers. This would likely cause a crash if they are used for anything. It just happens to be the case that they are passed to glBufferData().
Walking through the usage of vertexData, it's declared as a pointer to pointer to GLfloat:
GLfloat **vertexData;
Then it gets allocated:
vertexData = new GLfloat*[mesh_size];
vertexData now points to mesh_size pointers to GLfloat. Note that these pointers are uninitialized.
These pointers are then passed as arguments to a function:
przepare_mesh(..., vertexData[i], ...);
Inside the function, a value is then assigned to the function argument (I'm renaming the argument from the original code to avoid name confusion in my explanation):
void przepare_mesh(..., GLfloat* vertices, ...)
{
...
vertices = (GLfloat *)&paiMesh->mVertices;
Since the pointer was passed to the function by value, this assignment only changes the local value of the argument, and does not set a value for the pointer that was originally passed in. So vertexData[i] will still be uninitialized when this function returns.
Later, vertexData[i] is used as an argument for glBufferData(), and causes a crash because it's uninitialized.
The easiest way to fix this would be to change the declaration of the function argument to a reference:
void przepare_mesh(..., GLfloat*& vertices, ...)
Once the argument is a reference, assigning a value to it inside the function will change the value of the pointer passed in by the caller.
There are other cases of the same problem in the code, I just used the first one to illustrate the problem.

OpenGL: Terrain not drawing (heightmap)

EDIT: I'm thinking the problem might be when I'm loading the vertices and indices. Maybe focus on that section :)
I'm trying to load a heightmap from a bmp file and displaying it in OpenGL. As with most things I try, everything compiles and runs without errors but nothing is drawn on the screen. I can't seem to isolate the issue that much, since all the code works on its own, but when combined to draw terrain, nothing works.
Terrain class
I have a terrain class. It has 2 VBOs, 1 IBO and 1 VAO. It also stores the vertices, indices, colours of the vertices and the heights. It is loaded from a bmp file.
Loading terrain:
Terrain* Terrain::loadTerrain(const std::string& filename, float height)
{
BitMap* bmp = BitMap::load(filename);
Terrain* t = new Terrain(bmp->width, bmp->length);
for(unsigned y = 0; y < bmp->length; y++)
{
for(unsigned x = 0; x < bmp->width; x++)
{
unsigned char color =
(unsigned char)bmp->pixels[3 * (y * bmp->width + x)];
float h = height * ((color / 255.0f) - 0.5f);
t->setHeight(x, y, h);
}
}
delete bmp;
t->initGL();
return t;
}
Initializing the buffers:
void Terrain::initGL()
{
// load vertices from heights data
vertices = new Vector4f[w * l];
int vertIndex = 0;
for(unsigned y = 0; y < l; y++)
{
for(unsigned x = 0; x < w; x++)
{
vertices[vertIndex++] = Vector4f((float)x, (float)y, heights[y][x], 1.0f);
}
}
// generate indices for indexed drawing
indices = new GLshort[(w - 1) * (l - 1) * 6]; // patch count * 6 (2 triangles per terrain patch)
int indicesIndex = 0;
for(unsigned y = 0; y < (l - 1); ++y)
{
for(unsigned x = 0; x < (w - 1); ++x)
{
int start = y * w + x;
indices[indicesIndex++] = (GLshort)start;
indices[indicesIndex++] = (GLshort)(start + 1);
indices[indicesIndex++] = (GLshort)(start + w);
indices[indicesIndex++] = (GLshort)(start + 1);
indices[indicesIndex++] = (GLshort)(start + 1 + w);
indices[indicesIndex++] = (GLshort)(start + w);
}
}
// generate colours for the vertices
colours = new Vector4f[w * l];
for(unsigned i = 0; i < w * l; i++)
{
colours[i] = Vector4f(0.0f, 1.0f, 0.0f, 1.0f); // let's make the entire terrain green
}
// THIS CODE WORKS FOR CUBES (BEGIN)
// vertex buffer object
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// index buffer object
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// colours vertex buffer object
glGenBuffers(1, &colour_vbo);
glBindBuffer(GL_ARRAY_BUFFER, colour_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(colours), colours, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// create vertex array object
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, colour_vbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBindVertexArray(0);
// THIS CODE WORKS FOR CUBES (END)
}
The part where I create the VBOs, IBO and VAO works fine for cubes, they are drawn nicely.
Rendering terrain:
void Terrain::render()
{
glUseProgram(shaderProgram);
glBindVertexArray(vao);
int indices_length = (w - 1) * (l - 1) * 6;
glDrawElements(GL_TRIANGLES, indices_length, GL_UNSIGNED_SHORT, 0);
}
Shaders
These are the vertex and fragment shaders.
Vertex:
#version 330
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 vertexColour;
out vec4 fragmentColour;
uniform vec3 offset;
uniform mat4 perspectiveMatrix;
void main()
{
vec4 cameraPos = position + vec4(offset.x, offset.y, offset.z, 0.0);
gl_Position = perspectiveMatrix * cameraPos;
fragmentColour = vertexColour;
}
Fragment:
#version 330
in vec4 fragmentColour;
out vec4 outputColour;
void main()
{
outputColour = fragmentColour;
}
Perspective matrix
Here are the settings for the "camera":
struct CameraSettings
{
static const float FRUSTUM_SCALE = 1.0f;
static const float Z_NEAR = 0.5f;
static const float Z_FAR = 3.0f;
static float perspective_matrix[16];
};
float CameraSettings::perspective_matrix[16] = {
FRUSTUM_SCALE,
0, 0, 0, 0,
FRUSTUM_SCALE,
0, 0, 0, 0,
(Z_FAR + Z_NEAR) / (Z_NEAR - Z_FAR),
-1.0f,
0, 0,
(2 * Z_FAR * Z_NEAR) / (Z_NEAR - Z_FAR),
0
};
The uniforms get filled in after initGL() is called:
// get offset uniform
offsetUniform = ShaderManager::getUniformLocation(shaderProgram, "offset");
perspectiveMatrixUniform = ShaderManager::getUniformLocation(shaderProgram, "perspectiveMatrix");
// set standard uniform data
glUseProgram(shaderProgram);
glUniform3f(offsetUniform, xOffset, yOffset, zOffset);
glUniformMatrix4fv(perspectiveMatrixUniform, 1, GL_FALSE, CameraSettings::perspective_matrix);
glUseProgram(0);
Could someone check out my code and give suggestions?
I'm pretty sure that when you say :
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
you actually want to say :
glBufferData(GL_ARRAY_BUFFER, sizeof (Vector4f) * w * l, vertices, GL_STATIC_DRAW);
(same to color buffer, etc)

Using glDrawElements does not draw my .obj file

I am trying to correctly import an .OBJ file from 3ds Max. I got this working using glBegin() & glEnd() from a previous question on here, but had really poor performance obviously, so I am trying to use glDrawElements now.
I am importing a chessboard, its game pieces, etc. The board, each game piece, and each square on the board is stored in a struct GroupObject. The way I store the data is like this:
struct Vertex
{
float position[3];
float texCoord[2];
float normal[3];
float tangent[4];
float bitangent[3];
};
struct Material
{
float ambient[4];
float diffuse[4];
float specular[4];
float shininess; // [0 = min shininess, 1 = max shininess]
float alpha; // [0 = fully transparent, 1 = fully opaque]
std::string name;
std::string colorMapFilename;
std::string bumpMapFilename;
std::vector<int> indices;
int id;
};
//A chess piece or square
struct GroupObject
{
std::vector<Material *> materials;
std::string objectName;
std::string groupName;
int index;
};
All vertices are triangles, so there are always 3 points. When I am looping through the faces f section in the obj file, I store the v0, v1, & v2 in the Material->indices. (I am doing v[0-2] - 1 to account for obj files being 1-based and my vectors being 0-based.
So when I get to the render method, I am trying to loop through every object, which loops through every material attached to that object. I set the material information and try and use glDrawElements. However, the screen is black. I was able to draw the model just fine when I looped through each distinct material with all the indices associated with that material, and it drew the model fine. This time around, so I can use the stencil buffer for selecting GroupObjects, I changed up the loop, but the screen is black.
UPDATE
Replaced original render loop with current one and screenshot of it's result
Here is my render loop. The only thing I changed was the for loop(s) so they go through each object, and each material in the object in turn.
void GLEngine::drawModel()
{
ModelTextures::const_iterator iter;
GLuint texture = 0;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Vertex arrays setup
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer(3, GL_FLOAT, model.getVertexSize(), model.getVertexBuffer()->position);
glEnableClientState( GL_NORMAL_ARRAY );
glNormalPointer(GL_FLOAT, model.getVertexSize(), model.getVertexBuffer()->normal);
glClientActiveTexture( GL_TEXTURE0 );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glTexCoordPointer(2, GL_FLOAT, model.getVertexSize(), model.getVertexBuffer()->texCoord);
glUseProgram(blinnPhongShader);
objects = model.getObjects();
// Loop through objects...
for( int i=0 ; i < objects.size(); ++i )
{
ModelOBJ::GroupObject *object = objects[i];
// Loop through materials used by object...
for( int j=0 ; j<object->materials.size() ; ++j )
{
ModelOBJ::Material *pMaterial = object->materials[j];
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, pMaterial->ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pMaterial->diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, pMaterial->specular);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, pMaterial->shininess * 128.0f);
if (pMaterial->bumpMapFilename.empty())
{
//Bind the color map texture.
texture = nullTexture;
if (enableTextures)
{
iter = modelTextures.find(pMaterial->colorMapFilename);
if (iter != modelTextures.end())
texture = iter->second;
}
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
//Update shader parameters.
glUniform1i(glGetUniformLocation(
blinnPhongShader, "colorMap"), 0);
glUniform1f(glGetUniformLocation(
blinnPhongShader, "materialAlpha"), pMaterial->alpha);
}
//glDrawElements( GL_TRIANGLES, pMaterial->triangleCount * 3, GL_UNSIGNED_INT, &pMaterial->indices.front() );
glDrawElements( GL_TRIANGLES, pMaterial->triangleCount * 3, GL_UNSIGNED_INT, model.getIndexBuffer() + pMaterial->startIndex );
}
}
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
glDisable(GL_BLEND);
}
Here is what the above method draws:
http://img844.imageshack.us/img844/3793/chess4.png
I don't know what I am missing that's important. If it's also helpful, here is where I read a 'f' face line and store the info in the obj importer in the pMaterial->indices.
else if (sscanf(buffer, "%d/%d/%d", &v[0], &vt[0], &vn[0]) == 3) // v/vt/vn
{
fscanf(pFile, "%d/%d/%d", &v[1], &vt[1], &vn[1]);
fscanf(pFile, "%d/%d/%d", &v[2], &vt[2], &vn[2]);
v[0] = (v[0] < 0) ? v[0] + numVertices - 1 : v[0] - 1;
v[1] = (v[1] < 0) ? v[1] + numVertices - 1 : v[1] - 1;
v[2] = (v[2] < 0) ? v[2] + numVertices - 1 : v[2] - 1;
currentMaterial->indices.push_back(v[0]);
currentMaterial->indices.push_back(v[1]);
currentMaterial->indices.push_back(v[2]);
UPDATE 2
Current output: http://img337.imageshack.us/img337/860/chess4s.png
I was able to fix the model with the following code
glDrawElements( GL_TRIANGLES, pMaterial->triangleCount * 3, GL_UNSIGNED_INT, model.getIndexBuffer() + pMaterial->startIndex );
When I was done importing the model, I went through running a triangleCount & set the startIndex like so. This was my solution:
for (int i = 0; i < static_cast<int>(m_attributeBuffer.size()); i++)
{
if (m_attributeBuffer[i] != materialId)
{
materialId = m_attributeBuffer[i];
++numMaterials;
}
}
// Allocate memory for the materials and reset counters.
m_numberOfObjectMaterials = numMaterials;
m_materials.resize(m_numberOfObjectMaterials);
numMaterials = 0;
materialId = -1;
// Build the meshes. One mesh for each unique material.
for (int i = 0; i < static_cast<int>(m_attributeBuffer.size()); i++)
{
if (m_attributeBuffer[i] != materialId)
{
materialId = m_attributeBuffer[i];
m = m_ObjectMaterials[materialId];
m->startIndex = i * 3;
m->triangleCount = 0;
++m->triangleCount;
}
else
{
++m->triangleCount;
}
}