Registriert: Do Sep 04, 2008 11:30 Beiträge: 7 Wohnort: England
I am converting some 2D GDI based graphics to use OpenGL. Even my first rough attempts are twice as fast as GDI, and I get nice anti-aliasing, dotted lines etc. with more pretty possibilities. However I would like some advice on using OpenGL efficiently.
I am drawing parameterised curves, working from a list of the start and end parameter values where a segment of the curve enters and exits the viewport. For each pair I then draw the curve segment as a number of straight lines, recursively adapting how many segments are needed depending on curvature. This is a flexible approach and produces good looking curvy curves and almost straight lines without excess processing. I have replaced what was a sequence of moveto and lineto commands GDI with GL_LINE_STRIP and glVertex2f(x, y) in OpenGL. Stripped of al my calculations the resulting sequence of OpenGL calls would look like
Code:
For i := 0 to CurveSeg_Count do begin
glBegin(GL_LINE_STRIP);
glVertex2f(x, y);
...
//Between 5 and 300 vertices per curve segment
//depending on how cuved it is
glVertex2f(x, y);
glEnd
end;
With between 3 and 70 curve segments to draw.
Is there a more efficient way to do this in OpenGL? Would it be better to use vertex arrays and glDrawArrays somehow? Not really sure that this is viable, can I put all the vertices in one array and somehow tell OpenGL how many relate to each connected strip of lines? Or do VBOs have something to offer - they are a bit of a mystery to me.
Then again maybe I should be happy with what I've got! Any suggestions?
Is there a more efficient way to do this in OpenGL?
Yes
First the simple way, VertexArrays: Using glDrawArrays you can draw directly from an Array. You can use simply an pointer to an memory area containing an array of floats (= Single in Delphi)
The memory area needs to look like this: x0, y0, x1, y1, x2, y2, x3, y3, .... pointer is the memory area, count the number of vertices (= xy-Pairs).
Code:
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, pointer);
glDrawArrays(GL_LINE_STRIP, 0, count);
glDisableClientState(GL_VERTEX_ARRAY);
VertexArrays are faster than glBegin/glEnd-Stuff because you save a lot of function calls.
Now, VertexBufferObjects (VBO): When using VertexArrays or this glBegin/glEnd-Stuff you need to upload all data each time you render to the graphics card. But in many cases this data does not change. Using VBOs you can permanently store your vertices in graphics memory. Rendering an VBO is basicly the same as rendering an VertexArray. But you use glBindBuffer to bind your VBO and set the pointer to zero instead. There should be many VBO tutorials out there.
Zitat:
working from a list of the start and end parameter values where a segment of the curve enters and exits the viewport.
I assume you want to zoom into your curve so an static VBO does not make sense here because the number of vertices is infinite? However, for rendering a line consisting of 70 vertices VertexArrays should be fast enough when not doing anything else.
An more advanced way would be using shaders. You just render an straight line consisting of N segments, say N = 100. You X coordinate is simply the real X coordinate, Y coordinate can be zero. (because a Vertex needs at least two coordinates, you need Y...) Then use an simple Vertexshader which calculates Y for you:
Because you can zoom and pan using the uniforms offset and scale, your line segments don't need to change. You can use an static VBO for them.
However, shaders are a complex topic, so think about: Do you really need maximum performance?
_________________ Yeah!
Zuletzt geändert von Coolcat am So Okt 18, 2009 10:47, insgesamt 3-mal geändert.
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7804 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
OpenGL also Provides a way to draw curves. It is not so often used by us (because it is not standard in private game development ) but may you have a look at NURBS. Our Tutorials and Wiki is in german so not a help for you. But I guess with the Buzzword NURBS you will find also English tutorials.
But your method is also valid. In our wiki, one of your mathematic affine members had described a way to render 3D curved objects. See Geometrie_durch_Kurven. (Article is in german but code and example are usable anyway.)
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2621 Wohnort: Berlin
Programmiersprache: Go, C/C++
You wouldn't like to hear it but the fastes possible way is really complex.
The solution render 1 or 2 triangle per curve and use 2 different shader which calculate the distance to the cubic/quadratic bezier curve and if it below Linewidth the texel will draw else it will skiped.
But you need precalculated texturecoords and have to validate that the curve is valid.
Registriert: Do Sep 04, 2008 11:30 Beiträge: 7 Wohnort: England
Many thanks Flash, Coolcat and Tak2004 for such speedy replies.
I will have a longer look at NURBS it is always good to learn something new. But at an initial glance it may be over kill for my use (I have the clipped line segments I need to draw, all I want to do is draw them efficiently).
The shader approach also sounds just a bit too complex for a OpenGL nubie like myself.
VertexBufferObjects (VBO):
Zitat:
I assume you want to zoom into your curve so an static VBO does not make sense here because the number of vertices is infinite? However, for rendering a line consisting of 70 vertices VertexArrays should be fast enough when not doing anything else.
Actually, as well as zooming, the shape of the curve despite being parameterised could change every frame, so it seems that VBOs are not the way to go.
This leaves Vertex Arrays. I have my data as integers (pixels), is there any advantage/disadvantage in a GL_INT memory area? I guess it would take more space 32-byte integer verses 8-byte single. I could fill a single memory area with all the vertices, for all the curve segments but presumably I would need a glDrawArrays call for every line strip? I am a bit vague on this. With GL_QUADS glDrawArrays knows that every 4 vertices go together, so can do lots of quads in one go. But GL_LINE_STRIP can have any number of vertices, and my curves have a varied number each.
I am a bit hesitant to dive in and try this approach, as I have just tried using vertex arrays to render a number of "particles" (well in GDI they were small circles but in OpenGl I used a texture and glDrawArrays(GL_QUADS...). The result was only marginally faster than a glBegin/glEnd approach, and I failed to get the output to look the same. Still trying to see what that is about, and wondering if all the extra memory usage (especially the texture array with the same 4 values repeated over and over) is worth it. Or have I made so major error?
is there any advantage/disadvantage in a GL_INT memory area? I guess it would take more space 32-byte integer verses 8-byte single.
Integer and Single are both 32bit = 4 Byte.
Zitat:
But GL_LINE_STRIP can have any number of vertices, and my curves have a varied number each.
When using an LineStrip you can render just one of these per call of glDrawArrays. However this single LineStrip can have arbitrary length. Same goes by the way for TriangleStrips. However, when using TriangleStrips you can concatenate two strips by using some invalid triangles (dirty hack...), which is not possible for lines.
However, it is possible to have multiple linestrips in the same VBO. Just store one after the other. Then use second (offset) and third parameter (primitive count) of glDrawArrays to render each strip individually.
Zitat:
Still trying to see what that is about, and wondering if all the extra memory usage (especially the texture array with the same 4 values repeated over and over) is worth it. Or have I made so major error?
You might want to use PointSprites. It's just a point and a size per particle. The graphics hardware can generate the quad including texture coordinates on the fly.
Registriert: Do Sep 04, 2008 11:30 Beiträge: 7 Wohnort: England
I did get my bits and bytes in a mess, don't know what I was thinking
Zitat:
When using an LineStrip you can render just one of these per call of glDrawArrays.
Thank you for confirming that. Thanks for the PointSprites suggestion too - so many new things that I need to fnd out about.
I got my first attempt at vertex arrays working - I wasn't setting all the colour data. So far it is only maginally faster than a many glbegin/glend approach, but it likely that my timings are being dominated by something else (probably the calculation burden of the rest of the app).
Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.