Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Di Mai 14, 2024 21:53

Foren-Übersicht » English » English Programming Forum
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Autor Nachricht
BeitragVerfasst: So Okt 18, 2009 07:07 
Offline
DGL Member

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:
  1. For i := 0 to CurveSeg_Count do begin
  2.     glBegin(GL_LINE_STRIP);
  3.         glVertex2f(x, y);
  4.         ...
  5.         //Between 5 and 300 vertices per curve segment
  6.         //depending on how cuved it is
  7.         glVertex2f(x, y);
  8.     glEnd
  9. 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?

Dave Blake


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Okt 18, 2009 10:26 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
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:
  1. glEnableClientState(GL_VERTEX_ARRAY);
  2. glVertexPointer(2, GL_FLOAT, 0, pointer);
  3. glDrawArrays(GL_LINE_STRIP, 0, count);
  4. 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:
Code:
  1. uniform vec2 offset;
  2. uniform float scale;
  3.  
  4. void main()
  5. {
  6.     float x = scale * gl_Vertex.x + offset.x;
  7.     float y = evaluateYourCurveFunction(x);
  8.     y = scale * y + offset.y;
  9.     gl_Position = gl_ModelViewProjectionMatrix * vec4(x,y, 0, 1);
  10. }

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! :mrgreen:


Zuletzt geändert von Coolcat am So Okt 18, 2009 10:47, insgesamt 3-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Okt 18, 2009 10:43 
Offline
Guitar Hero
Benutzeravatar

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


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Okt 18, 2009 11:45 
Offline
DGL Member
Benutzeravatar

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.

If you are interested here you can find the paper http://research.microsoft.com/en-us/um/people/cloop/loopblinn05.pdf and this are the ported glsl shader.
Vertexshader:
Code:
  1. #version 130
  2. uniform mat4 ProjectionMatrix;
  3. uniform mat4 ModelviewMatrix;
  4. in vec4 Vertex;
  5. in vec4 Texcoord;
  6. void main(void)
  7. {
  8.   gl_Position=ProjectionMatrix*ModelviewMatrix*Vertex;
  9.   gl_TexCoord[0]=gl_MultiTexCoord0;
  10. }


Fragmentshader:
Code:
  1. #version 130
  2. out vec4 gl_FragColor;
  3. void main(void)
  4. {
  5.    float v=pow(gl_TexCoord[0][0],3.0)-gl_TexCoord[0][1]*gl_TexCoord[0][2];
  6.    float l=length(vec2(dFdx(v),dFdy(v)));
  7.    float f=smoothstep(0.5-l,0.5+l,v);
  8.    if (v<-l*0.5) discard;
  9.    gl_FragColor=vec4(0.0,0.0,1.0,f);
  10. }


NV implemented and optimized the paper on there own site http://http.developer.nvidia.com/GPUGems3/gpugems3_ch25.html

http://karmarama.linuxprofessionals.org/upload/bezier.png
This is the last shot of my implementation but i hadn't enought time to finish it yet.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Okt 18, 2009 13:08 
Offline
DGL Member

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?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Okt 18, 2009 14:20 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
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.
Zitat:
glEnable(GL_POINT_SPRITE);
glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); // generate texcoords automatically


You can do particle systems even completely GPU based (not only rendering, also simulation), but thats another advanced topic.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Okt 18, 2009 15:44 
Offline
DGL Member

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 :oops:
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).

Many thanks for your help.


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Foren-Übersicht » English » English Programming Forum


Wer ist online?

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.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.024s | 17 Queries | GZIP : On ]