PDA

View Full Version : How to use glDrawElements to draw a building?



anime.igala.net
10-03-2008, 08:14 AM
Hello all,

I'm working in a 3D project. But I'm not very well in OpenGL.
Some one give me a structure of a building, and I have to draw it in 3D.

A building includes a footprint, a height and latitude. So a building looks like a box 3D, some things likes this (please view the image). A building can have more than 4 vertex:

http://img237.imageshack.us/img237/1434/boxjp2.jpg

He gives me a building class looks like this (I have removed some data) and he said that I should use the glDrawElements function. This is the building class code (please read the cpp file):

http://video.igala.net/building.cpp.html

I have used the glDrawElements function like this :

[CODE]
glEnableClientState ( GL_VERTEX_ARRAY );
int nbVertices = pbuilding->getData()->GetWallVerticesCount();
GLfloat *vertices = pbuilding->getData()->GLWallVertices();

glVertexPointer( 3, GL_FLOAT, 0, vertices );
int n = pbuilding->getData()->getNbRings();
unsigned int* pn = pbuilding->getData()->GetWallIndicesCount();
unsigned int** indices = pbuilding->getData()->GLWallIndices();
for (int i=0; i<n; ++i){
if (n == 0)
glDrawElements(GL_TRIANGLES, pn[i], GL_UNSIGNED_SHORT, (GLvoid*)indices[i]);
}

glDisableClientState(GL_VERTEX_ARRAY);

[/B][/QUOTE]

But it does not run, the programme was crashed when it start to draw.

Does any one can tell how to can I draw this building?

Thanks so much,

trinitrotoluene
10-03-2008, 09:14 AM
First: In your source file, your indices array (unsigned int** m_WallIndices;) is of type unsigned int and when you use glDrawElements you use GL_UNSIGNED_SHORT. It should be GL_UNSIGNED_INT.

Second: In your for loop glDrawElements will never be called. If n == 0 the for loop will terminate immediately because of i < n. If n > 0 the for loop will iterate n times but n != 0, so the loop do nothing at all. This tell me that your program don't crash when drawing.

Third: In your source file I see


// wall vertices:
// 4 points per wall
// 8 value per point: 2 texture coordinates + (x,y,z) coordinates, + normal coordinates computed later
m_WallVertices = new float [m_nbWallVertices * 8 * 4];

Your m_WallVertices array is interleaved with other data so
glVertexPointer( 3, GL_FLOAT, 0, vertices ); should be something like glVertexPointer( 3, GL_FLOAT, 8*sizeof(GL_FLOAT), &vertices[2] );

Look at the references pages (http://www.opengl.org/sdk/docs/man/) for glVertexPointer and glDrawElements documentation.

anime.igala.net
10-06-2008, 01:07 AM
Thanks for your time to help me.

First: I have changed as you said.
Second: n == 0 is only for testing :), I have removed.
Third: Could you please explain more detail? I need to starting at 0, so why we need to change to glVertexPointer( 3, GL_FLOAT, 8*sizeof(GL_FLOAT), &vertices[2] ) ?

trinitrotoluene
10-06-2008, 10:15 AM
For glVertexPointer, I noticed in your building.cpp file that the m_WallVertices array contain for each vertex a 2 dimensions texture coordinate + a normal. I have supposed that pbuilding->getData()->GLWallVertices() function call return the m_WallVertices array. So in memory the array will look like this:

m_WallVertices[0] = texture coordinate u for vertex 0
m_WallVertices[1] = texture coordinate v for vertex 0
m_WallVertices[2] = vertex position x for vertex 0
m_WallVertices[3] = vertex position y for vertex 0
m_WallVertices[4] = vertex position z for vertex 0
m_WallVertices[5] = vertex normal x for vertex 0
m_WallVertices[6] = vertex normal y for vertex 0
m_WallVertices[7] = vertex normal z for vertex 0

m_WallVertices[8] = texture coordinate u for vertex 1
...
m_WallVertices[10] = vertex position x for vertex 1
...
m_WallVertices[13] = vertex normal x for vertex 1
...

So with this array layout you have to tell OpenGL that your vertex position data begin at address &vertices[2] and you have to jump 8*sizeof(GL_FLOAT) bytes to get the next vertex position data.If you use texturing, to tell OpenGL where the texture coordinate data is you need to call glTexCoorPointer(2,GL_FLOAT,8*sizeof(GL_FLOAT),&vertices[0]).If you use OpenGL lighting you need to call glNormalPointer(GL_FLOAT,8*sizeof(GL_FLOAT),&vertices[5]).

trinitrotoluene
10-06-2008, 01:57 PM
After checking the code again it seems that the comment is misleading about the order of data for vertex position and normal. So glVertexPointer(3, GL_FLOAT, 8*sizeof(GL_FLOAT),&vertices[5]) <=> glNormalPointer(GL_FLOAT,8*sizeof(GL_FLOAT),&vertices[2]).

He gives me a building class
Ask your project coordinator for the exact layout of data for m_WallVertices array if you cannot find it yourself.

anime.igala.net
10-08-2008, 09:46 AM
It works well now, just replace sizeof(GL_FLOAT) by sizeof(float).

OMG.

Thanks all,

_NK47
10-09-2008, 02:06 AM
how does that help???

anime.igala.net
10-09-2008, 02:23 AM
The new code now is:



int nbVertices = pbuilding->getData()->GetWallVerticesCount();
glEnableClientState ( GL_VERTEX_ARRAY );
GLfloat *vertices = pbuilding->getData()->GLWallVertices();

glVertexPointer( 3, GL_FLOAT, 8*sizeof(float), vertices+5 );
int n = pbuilding->getData()->getNbRings();
unsigned int* pn = pbuilding->getData()->GetWallIndicesCount();
unsigned short** indices = pbuilding->getData()->GLWallIndices();

for (int i=0; i<n; ++i){
glDrawElements(GL_TRIANGLE_FAN, pn[i], GL_UNSIGNED_SHORT, indices[i]);
}

glDisableClientState(GL_VERTEX_ARRAY);



You can see this line: glVertexPointer( 3, GL_FLOAT, 8*sizeof(float), vertices+5 );

_NK47
10-09-2008, 03:15 AM
can you check the following:
int size1 = sizeof(GL_FLOAT);
int size2 = sizeof(float);

and post it back here.

trinitrotoluene
10-09-2008, 07:17 AM
Of course replace GL_FLOAT with GLfloat. GL_FLOAT is a enum I think.

_NK47
10-09-2008, 08:42 AM
Damn! right! for some reasons i thought of GL_FLOAT as GLfloat.