Followers 0

# OpenGL glDrawElements: Vertices and Normals

## 7 posts in this topic

Hello. I'm fairly new to OpenGL, so up until now I've been doing all my rendering in immediate mode, which I understand to be slow. I've got the code to load and render 3D models from files, but right now I only have immediate-mode render code, and I'm trying to write a version that uses vertex arrays. It looks like the gl*Pointer functions and glDrawElements are the way to go. However, I've run into a problem. My 3D model data is stored as usual with a list of vertices, and then a list of faces (triangles) that each refer to 3 vertices via an index number. There are also 3 normal vectors stored per face. But it appears that glDrawElements uses only one index array to reference both the array of vertices (set by glVertexPointer) and the array of normals (set by glNormalPointer). That means that there can only be one normal per vertex, but there could be more than one described in my 3D model file. How can I use vertex arrays with multiple normals per vertex? Or will I be forced to average all the normals on each vertex so there's only one per vertex? Thanks! EDIT: Sorry about that block of text. Split it into paragraphs for readability. [Edited by - Aikavanak on August 13, 2006 8:19:13 PM]
0

##### Share on other sites
You are correct that OpenGL uses a single index array to index all active vertex arrays (vertex, normal, color, etc.).

You may have to adapt your model data to reflect this. How to do so depends on whether you want smooth or faceted shading. For the latter, you 'detach' the faces so that each has its own copies of the vertex data. For the former, you average the normals associated with each vertex to yield a single normal (as you mentioned).
0

##### Share on other sites
firstly, paragraphs can help make post clearer [smile]

As I see it, you can go about it in one of two ways;

1 - average the normals as you suggested, however this can lead to sharp corners becoming rounded

2 - duplicate the vertex information for each normal as required. This will increase the vertex data size however chances are in a model of any real size this kind of sharing is rare as such the size increase shouldn't be a huge problem..
0

##### Share on other sites
Thanks for the quick replies.

I think I'll go with duplicating the vertex information, because it seems like averaging the normals could distort my 3D modeler's artwork a bit too much for my tastes.

But I have another question about vertex arrays. In my code, I load the model data into my own custom arrays (I use a custom Vector class to help store the data). I obviously can't send my own Vector classes to gl*Pointer functions directly, so I could copy all the data from my Vectors to a new array of floats (float[]) that I can send directly to gl*Pointer. Is this how its generally done? If so, it seems like it could be really bad for performance, since I would basically be copying all my model data every frame. And, it would take more memory.

Should I load the model data directly into float[] arrays that I can pass to gl*Pointer functions? Will this give me a noticeable boost in framerate?

(I would try it both ways myself, but it would require a lot of re-working of code, and I don't feel like doing it right now. Just wondering if any of you have experience with this already.)
0

##### Share on other sites
There are two pretty simple solutions:

First you could make your vector class only store the 2 / 3 / whatever floats and tell the compiler not to add any unused bytes for packing it into a power of two boundry, so your vector class is memory equivalent to the floats it stores. This also means you have to turn down the abillity to use virtual functions and other syntactic sugar, which increases your classes size, but that shouldn't be any problem for any vector class implementation.

The second one, which takes up more memory and is a little less efficient than the first one, but definitely more than copying all the data back and forth, would be to let your vector class hold a pointer to the first of its floats which is actually stored in the vertexarray and the dimension of the vector itself ( can be templated, so that it doesn't need any additional space ).

You should stick with the first solution as long as you don't need any extra variables in your vector class or something that takes up memory, because the second solution adds an additional 4 bytes per vertex which normally is 12 bytes of size ( increase of 33% ) or per normal which is 8 bytes ( 50% ! ) plus the runtime overhead of resolving the pointers ( not that much ^^ ) and the need of initialising all pointers and keeping track of their validity.

t0}{!c
0

##### Share on other sites
while vector classes are good at holding date when it comes to locations, directions and other singlar data I don't see the point in having them when it comes to model information, you won't be perform per-vertex changes on them in any meaningfull way once your load step is completed, as such while you might want to initally load your data into your customs classes once you've done any jiggery pokery you need to it you might as well dump it into a normal array.

Well, a normal array might well be overkill, instead consider a plain struct consisting of the data you'll want per vertex.

struct terraindata {	float x,y,z;	GLubyte r,g,b,a;	// use four bytes so we dont botch the alignment up	float u,v;			// texture U,V coords	float nx,ny,nz;		// normal vector for vertex};

Thats one I've used before now.

You can even make a std::vector of them and render from that, just pass the gl*Pointer() functions the address of the first element as the data location (gl*Pointer(...,static_cast<void*>(&myVec[0]));).

Oh, and interleaving the data as above is a good idea on all hardware and maintaining 4btye alignment on the vertex elements is critical if you don't want to it die on ATI hardware.
0

##### Share on other sites
Actually my first solution behaves exactly the like phantoms. consider

struct TerrainData{vector< float, 3 > Vertex;color< desc_rgba > Color;vector< float, 2 > TexCoord;vector< float, 3 > Normal;};// Now later you can perform stuff likebla->getTerrainData()[234].Normal.normalize();

While this code would behave the same as your code it still allows you to perform all your vector algorithms on the data. You surely wont need them that often but once you will, you'll be glad to not beeing forced to rewrite code or extract the data and then put it in again.
0

##### Share on other sites
Thanks again for the informative replies.

I suppose I should have mentioned that I'm actually using Java and JOGL for my programs, I didn't post this in the Java forum because it's not really a Java-specific topic. But as you all probably know, Java doesn't give the coder as much control over pointers as C++ does, so I'm not sure how to implement your examples with Java.

Technically, JOGL requires NewIO Buffer objects for the gl*Pointer() calls. Any Java masters out there who might have some insight into adapting toxic's first solution to Java and FloatBuffers? (a ByteBuffer could probably also be used.)

From my look through the FloatBuffer API docs, I can't see an easy way to keep my data in a custom class and get it to a gl*Pointer function via Buffers without copying my custom data to a Buffer every frame.

Oh well, maybe I'll just have to do without my vector operations. Like toxic said, they won't be needed often, but it'd be nice to have the ability if the need comes up.

BTW, I've also decided to write two versions of my loader, one that averages the normals and one that duplicates the vertices to preserve normals when needed, just to cover all possibilities.
0

## Create an account

Register a new account

Followers 0

• ### Similar Content

• So it's been a while since I took a break from my whole creating a planet in DX11. Last time around I got stuck on fixing a nice LOD.
A week back or so I got help to find this:
https://github.com/sp4cerat/Planet-LOD
In general this is what I'm trying to recreate in DX11, he that made that planet LOD uses OpenGL but that is a minor issue and something I can solve. But I have a question regarding the code
He gets the position using this row
vec4d pos = b.var.vec4d["position"]; Which is then used further down when he sends the variable "center" into the drawing function:
if (pos.len() < 1) pos.norm(); world::draw(vec3d(pos.x, pos.y, pos.z));
Inside the draw function this happens:
draw_recursive(p3[0], p3[1], p3[2], center); Basically the 3 vertices of the triangle and the center of details that he sent as a parameter earlier: vec3d(pos.x, pos.y, pos.z)
Now onto my real question, he does vec3d edge_center[3] = { (p1 + p2) / 2, (p2 + p3) / 2, (p3 + p1) / 2 }; to get the edge center of each edge, nothing weird there.
But this is used later on with:
vec3d d = center + edge_center[i]; edge_test[i] = d.len() > ratio_size; edge_test is then used to evaluate if there should be a triangle drawn or if it should be split up into 3 new triangles instead. Why is it working for him? shouldn't it be like center - edge_center or something like that? Why adding them togheter? I asume here that the center is the center of details for the LOD. the position of the camera if stood on the ground of the planet and not up int he air like it is now.

Full code can be seen here:
https://github.com/sp4cerat/Planet-LOD/blob/master/src.simple/Main.cpp
If anyone would like to take a look and try to help me understand this code I would love this person. I'm running out of ideas on how to solve this in my own head, most likely twisted it one time to many up in my head
Toastmastern

• I googled around but are unable to find source code or details of implementation.
What keywords should I search for this topic?
Things I would like to know:
A. How to ensure that partially covered pixels are rasterized?
Apparently by expanding each triangle by 1 pixel or so, rasterization problem is almost solved.
But it will result in an unindexable triangle list without tons of overlaps. Will it incur a large performance penalty?
How to ensure proper synchronizations in GLSL?
GLSL seems to only allow int32 atomics on image.
C. Is there some simple ways to estimate coverage on-the-fly?
In case I am to draw 2D shapes onto an exisitng target:
1. A multi-pass whatever-buffer seems overkill.
2. Multisampling could cost a lot memory though all I need is better coverage.
Besides, I have to blit twice, if draw target is not multisampled.

• By mapra99
Hello

I am working on a recent project and I have been learning how to code in C# using OpenGL libraries for some graphics. I have achieved some quite interesting things using TAO Framework writing in Console Applications, creating a GLUT Window. But my problem now is that I need to incorporate the Graphics in a Windows Form so I can relate the objects that I render with some .NET Controls.

To deal with this problem, I have seen in some forums that it's better to use OpenTK instead of TAO Framework, so I can use the glControl that OpenTK libraries offer. However, I haven't found complete articles, tutorials or source codes that help using the glControl or that may insert me into de OpenTK functions. Would somebody please share in this forum some links or files where I can find good documentation about this topic? Or may I use another library different of OpenTK?

Thanks!

• Hello, I have been working on SH Irradiance map rendering, and I have been using a GLSL pixel shader to render SH irradiance to 2D irradiance maps for my static objects. I already have it working with 9 3D textures so far for the first 9 SH functions.
In my GLSL shader, I have to send in 9 SH Coefficient 3D Texures that use RGBA8 as a pixel format. RGB being used for the coefficients for red, green, and blue, and the A for checking if the voxel is in use (for the 3D texture solidification shader to prevent bleeding).
My problem is, I want to knock this number of textures down to something like 4 or 5. Getting even lower would be a godsend. This is because I eventually plan on adding more SH Coefficient 3D Textures for other parts of the game map (such as inside rooms, as opposed to the outside), to circumvent irradiance probe bleeding between rooms separated by walls. I don't want to reach the 32 texture limit too soon. Also, I figure that it would be a LOT faster.
Is there a way I could, say, store 2 sets of SH Coefficients for 2 SH functions inside a texture with RGBA16 pixels? If so, how would I extract them from inside GLSL? Let me know if you have any suggestions ^^.
• By KarimIO
EDIT: I thought this was restricted to Attribute-Created GL contexts, but it isn't, so I rewrote the post.
Hey guys, whenever I call SwapBuffers(hDC), I get a crash, and I get a "Too many posts were made to a semaphore." from Windows as I call SwapBuffers. What could be the cause of this?
Update: No crash occurs if I don't draw, just clear and swap.
static PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be { sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 1, // Version Number PFD_DRAW_TO_WINDOW | // Format Must Support Window PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_DOUBLEBUFFER, // Must Support Double Buffering PFD_TYPE_RGBA, // Request An RGBA Format 32, // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored 0, // No Alpha Buffer 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored 24, // 24Bit Z-Buffer (Depth Buffer) 0, // No Stencil Buffer 0, // No Auxiliary Buffer PFD_MAIN_PLANE, // Main Drawing Layer 0, // Reserved 0, 0, 0 // Layer Masks Ignored }; if (!(hDC = GetDC(windowHandle))) return false; unsigned int PixelFormat; if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) return false; if (!SetPixelFormat(hDC, PixelFormat, &pfd)) return false; hRC = wglCreateContext(hDC); if (!hRC) { std::cout << "wglCreateContext Failed!\n"; return false; } if (wglMakeCurrent(hDC, hRC) == NULL) { std::cout << "Make Context Current Second Failed!\n"; return false; } ... // OGL Buffer Initialization glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glBindVertexArray(vao); glUseProgram(myprogram); glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, (void *)indexStart); SwapBuffers(GetDC(window_handle));

• 11
• 19
• 14
• 23
• 11