Advantage of GL_TRIANGLE_STRIP?

Member
Posts: 95
Joined: 2009.09
Post: #1
Hey,

I'm using
Code:
    glDrawElements(GL_TRIANGLES, _edgeCount, GL_UNSIGNED_SHORT, _Indices);

to draw my Scene. Right now I'm drawing around 30k triangles per frame in a midsized map.
I wondered if using "GL_TRIANGLE_STRIP" would improve performance(fps), how is your experience here?

And if so, is there some library/program that may transform saved Geometries vom GL_TRIANGLES into GL_TRIANGLE_STRIP, that you know of?
Right now I use my own program to parse obj-Files I exported from blender into c-header files I can import in my project.
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #2
Triangle strips tend to be more efficient because you don't have duplicated vertexes to copy and there are probably optimizations where it only has to transform each shared vertex once.

However, each triangle strip must be drawn as a separate draw call, and you can't use a single strip to draw more than one object. I'm not sure if there are simple algorithms for taking a set of triangles and turning that into an optimized set of triangle strips either. I suspect not.

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Moderator
Posts: 3,571
Joined: 2003.06
Post: #3
(Jul 13, 2010 10:38 AM)Skorche Wrote:  I'm not sure if there are simple algorithms for taking a set of triangles and turning that into an optimized set of triangle strips either. I suspect not.

There was something mentioned in the PowerVR docs that triangle strip "ordering" improves cache performance and so they recommend it. I've tried it but can't claim to have seen improvement, although my testing wasn't extensive. You can find a really good triangle stripper (IMHO) in the oolong engine codebase. There are other triangle strip algorithms I've tried out but for some reason that one seems to do the best. You can easily use the output from it to generate actual triangles strips instead of just triangle strip ordering.
Quote this message in a reply
Member
Posts: 95
Joined: 2009.09
Post: #4
(Jul 13, 2010 10:38 AM)Skorche Wrote:  [..]
However, each triangle strip must be drawn as a separate draw call, [...]

Well I could always add 3 vertices with alpha = 1 to the end of each individual geometry that I add into my one big array.

Then I would only have to change the saved default header-files of my 3D modells.

Still this might be a little work-overkill, I have many other things to do then writing a stripping algorithm.

The problem is , that with Multisampling I lost half of my fps so I thought I could regain some of them by using GL_TRIANGLE_STRIP.

On a more basic OpenGL note:
I don't refill my single big interleaved Array for each frame, I only change it once the actual geometry changed (e.g. when the player built a unit).
But I still call
Code:
    glVertexPointer(3, GL_FLOAT, sizeof(iVertex3D), &_interleavedVerts[0].v);
    glTexCoordPointer(2, GL_FLOAT, sizeof(iVertex3D), &_interleavedVerts[0].uv);
    glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(iVertex3D), &_interleavedVerts[0].color);
    glNormalPointer(GL_FLOAT, sizeof(iVertex3D), &_interleavedVerts[0].n);
    glDrawElements(GL_TRIANGLES, _edgeCount, GL_UNSIGNED_SHORT, _Indices);
each time I render.

Does this mean I'm sending the Data to the GPU for each frame?
In normal Gameplay the matrix doesn't change (only the viewing angles and scales, i.e. the viewing Matrices) so may there be some advanced OpenGL ways of telling the GPU to only change the model-projections of the already stored Vertex-Array?
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #5
Yes, you are still submitting vertex data to driver memory every time you call glDraw*() if you don't have a VBO set up. Using VBOs are faster on the 3GS devices, but not on the older devices for whatever reason. (iirc)

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Member
Posts: 95
Joined: 2009.09
Post: #6
(Jul 13, 2010 01:12 PM)Skorche Wrote:  Yes, you are still submitting vertex data to driver memory every time you call glDraw*() if you don't have a VBO set up. Using VBOs are faster on the 3GS devices, but not on the older devices for whatever reason. (iirc)

Hmm, well I could always turn of antialiasing on older devices and use the VBO's to increase the performance I lost with antialiasing on the newer iPod 3G, 3GS and iPhone 4.
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2010.03
Post: #7
Drawing strips is faster in my experience if only because you store/move less data. You'll need one strip per material you want to render, you can stitch together disparate strips with degenerate triangles as long as the whole strip doesn't go over 65535 indices.

I wrote a short blog post about using NvTriStrip with blender, including a download of a version that compiles on OSX here. I've only really used NvTriStrip but I've used it for the last 10 years or so.

You sometimes get artefacts with degenerate triangles but I don't seem to see them on any iOS devices.

Hope that helps, good luck.
Quote this message in a reply
Member
Posts: 95
Joined: 2009.09
Post: #8
(Jul 14, 2010 01:17 PM)dazza Wrote:  Hope that helps, good luck.

Thanks, I'll try it once I find the time. Sadly I have over 20 models, each consisting of several objects that would all needed to be parsed. As I see it all the degenerate vertices I need to stitch them together would increase my vertex count and therefore I'd have to modify the code that fills the interleaved array.
I appreciate you providing is with your sample code Smile
Quote this message in a reply
Member
Posts: 95
Joined: 2009.09
Post: #9
Again, I didn't wanna open a new thread.

It's just a tried VBO's but I'm still doing something the wrong way, I just can't figure it out.
I'm calling the two functions:
Code:
void CreateVertexBuffers(GLuint vertexBuffer, GLuint indexBuffer)
{
    glGenBuffers(1, &vertexBuffer);    
    glGenBuffers(1, &indexBuffer);
    
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(_interleavedVerts), _interleavedVerts, GL_DYNAMIC_DRAW);
    
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(_interleavedEdges), _interleavedEdges, GL_DYNAMIC_DRAW);
}

void DrawVBOs(GLuint vertexBuffer, GLuint indexBuffer)
{
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexPointer(3, GL_FLOAT, sizeof(iVertex3D), (void*)offsetof(iVertex3D,v));
    glTexCoordPointer(2, GL_FLOAT, sizeof(iVertex3D), (void*)offsetof(iVertex3D,uv));
    glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(iVertex3D), (void*)offsetof(iVertex3D,color));
    glNormalPointer(GL_FLOAT, sizeof(iVertex3D), (void*)offsetof(iVertex3D,n));

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glDrawElements(GL_TRIANGLES, _edgeCount, GL_UNSIGNED_SHORT, (void*)0);
}

But I always get a EXC_BAD_ACCESS in:
Code:
#0    0x0d0f132a in gleRunVertexSubmitImmediate
#1    0x0d0f0eb3 in gleLLVMArrayFunc
#2    0x0d0f0e5b in gleSetVertexArrayFunc
#3    0x0d0e7938 in gleDrawArraysOrElements_ExecCore
#4    0x0d0cbfe1 in glDrawElements_Exec
#5    0x02aa0a91 in glDrawElements
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2010.03
Post: #10
Code:
void CreateVertexBuffers(GLuint vertexBuffer, GLuint indexBuffer)

Here you are passing in two GLuint by value and then calling

Code:
glGenBuffers(1, &vertexBuffer);    
glGenBuffers(1, &indexBuffer);

setting your function parameters values to the buffer id's. These values are thrown away when the CreateVertBuffers function returns (but the GL buffers are leaked).

I think you need something like
Code:
void CreateVertexBuffers(GLuint *vertexBuffer, GLuint *indexBuffer){
   glGenBuffers(1, vertexBuffer);    
   glGenBuffers(1, indexBuffer);
...
}

calling it thus:

Code:
GLuint vBuffer, iBuffer;
CreateVertexBuffers(&vBuffer, &iBuffer);

does that make sense?
Quote this message in a reply
Member
Posts: 95
Joined: 2009.09
Post: #11
@Dazza
Of course you are right!
(Its mainly because I learned programming in Fortran and sometimes I still forget its call by value now)

Still it doesn't seem to add normals and colors, do I have to Enable Normal_Array and Color-Array everytime I bind the vbo's?
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #12
Binding the VBO just changes what chunk of memory your pointers are referencing relative to. With the '0' VBO being main memory and not driver managed VBO memory. It does not change which pointers are bound or what value they are bound to.

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Member
Posts: 95
Joined: 2009.09
Post: #13
(Jul 20, 2010 07:11 AM)Skorche Wrote:  Binding the VBO just changes what chunk of memory your pointers are referencing relative to. With the '0' VBO being main memory and not driver managed VBO memory. It does not change which pointers are bound or what value they are bound to.
Maybe its too warm here (32° currently) but I'm sorry I don't get you....

You mean if I only move pointers to the data around, the state of glEnable(GL_NORMAL_ARRAY) should not change?
The problem was that I can draw with VBO's now, but there are neither textures on my geometry nor is there any light except ambient (because of no normals).
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #14
I mean that VBOs do not remember which pointers you enabled or where they are pointing to. So when you switch VBOs you have to do all your enables and pointer rebinding again unless they are the same between different VBOs.

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Member
Posts: 95
Joined: 2009.09
Post: #15
(Jul 20, 2010 08:33 AM)Skorche Wrote:  I mean that VBOs do not remember which pointers you enabled or where they are pointing to. So when you switch VBOs you have to do all your enables and pointer rebinding again unless they are the same between different VBOs.

Well to save redundant state calls, I only enable Colors, Vector_Array, Texture_Coord and Normal_Array in my init and disable them when the user leaves the view.
That's why I didn't see any problems here, still the VBO's don't seem to show Textures or normals. Whats more interesting is that they do show the color correctly, so colors are switched on.

I mean I basically left the whole program the way it was, in the place that I formerly called " flush()" I just now call "drawVBO's".
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Normals and GL_TRIANGLE_STRIP Mars_999 12 9,860 Jul 30, 2003 10:00 PM
Last Post: Mars_999
  How to take advantage of HW T&L? morgant 14 5,730 Jun 20, 2003 04:08 PM
Last Post: OneSadCookie