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

Aktuelle Zeit: Do Mai 23, 2024 23:57

Foren-Übersicht » Programmierung » Einsteiger-Fragen
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 14 Beiträge ] 
Autor Nachricht
BeitragVerfasst: Mo Nov 17, 2014 00:00 
Offline
DGL Member

Registriert: Di Jun 10, 2014 06:59
Beiträge: 17
Programmiersprache: Delphi XE6
Hallo zusammen,

ich schreibe derzeit ein Programm, welches eher in den CAD-Bereich gehört. Die Oberfläche selbst soll von der Bedienung her ähnlich dem Sketchup funktionieren. Bisher habe ich den Standard-Canvas von Delphi eingesetzt, was erstmal ganz gut funktioniert hat. Leider sind die Modelle immer komplexer geworden und somit bin ich mit der Darstellung an die Grenzen gestoßen. Nun stelle ich auf OpenGL um. Bin allerdings recht neu in der Materie und muss mir erst mal alles mühsam erarbeiten. Ihr kennt das sicher :D .

Mein aktuelles Problem ist, dass ich auf meiner gerenderten Zeichenfläche temporäre Dinge darstellen will. Temporär bedeutet z.B. ein Auswahlrahmen, der mit der Maus aufegezogen werden kann (siehe z.B. Sketchup). Auch möchte ich selektierte Objekte hervorheben und deren Selektion auch wieder wegnehmen ohne dass ich alles neu Rendern muss. Mein Gedanke wäre, die gerenderte Grafik im Puffer unverändert zu lassen und bei Bedarf wieder in den Vordergund zu holen. SwapBuffers geht da ja leider nicht, da es die Puffer immer nur austauscht. Auch müsste ich irgendwie zeichnen können ohne den bereits gerenderten Puffer zu zerstören (den brauche ich ja dann wieder). Mit dem Standard-Canvas habe ich für solche Fälle einfach mit BitBlt eine Kopie angelegt, dich dann bei Bedarf wieder in die Anzeige kopiert habe. Wie geht das mit OpenGL.

Ich hoffe ich habe mich einigermaßen Verständlich ausgedrückt. Ich habe die Frage in ähnlicher Form auch schon in einem Delphi-Forum gepostet. Leider ist da bis jetzt noch nichts zurückgekommen. Wäre auch für Tips zu guter Literatur sehr dankbar.

Alex


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Nov 17, 2014 08:58 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Nov 08, 2010 18:41
Beiträge: 769
Programmiersprache: Gestern
Hi,

SwapBuffer musst du immer machen wenn dein Fenster gezeichnet werden soll. Die meisten setzen da auf eine Schleife die alle paar Milisekunden das Fenster zeichnet. Wenn du allerdings keine Animationen oder so hast kannst du hier auch auf das Paint Event warten. Des weiteren bleibt das Gezeichnete erhalten solange du kein glClear machst. Du kannst also im Prinzip auch folgendes bauen:
Code:
  1.  
  2. void Paint(void) {
  3.      if(needsDraw) {
  4.          glViewPort
  5.          glClear
  6.          ...
  7.      }
  8.      SwapBuffer();
  9. }
  10.  


Zwischenspeichern ist unter OpenGL etwas tricky. Du kannst eigentlich nur direkt in eine Textur zeichnen (Framebuffer Objekte), allerdings leidet die Qualitaet darunter stark. Ein gute alternative waeren Vertexbuffer Objekte oder Displaylisten. Die VBOs speichern deine Geometrie so das du sie schneller zeichnen kannst. Displaylisten hingegen sind im Prinzip eine Art Makro und speichern die OpenGL Befehle.

_________________
Meine Homepage


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Nov 17, 2014 09:10 
Offline
DGL Member
Benutzeravatar

Registriert: Di Apr 29, 2008 18:56
Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,

yunharla hat geschrieben:
Zwischenspeichern ist unter OpenGL etwas tricky. Du kannst eigentlich nur direkt in eine Textur zeichnen (Framebuffer Objekte), allerdings leidet die Qualitaet darunter stark.


Warum leided darunter die Qualität? Solange der Buffer-Größe ein Vielfaches vom dargestellten Bereich ist, sieht man keinen Unterschied. Das einzige was FBOs nicht können ist Hardware-AntiAliasing, aber dafür gibt es Alternativen. Jede Deferred Engine arbeitet mit FBOs.
Ich denke FBOs sind hier die richtige Wahl. Zeichne deine Objekte in ein FBO und dann kannst du darüber deine Auswahlboxen und Co rendern. Wen du deine Modelle bis jetzt auf der normalen Canvas gezeichnet hat (und es da noch einigermaßen schnell gezeichnet wurde) dann kannst du die Modelle aber auch einfach komplett neu zeichnen (ohne FBO). OpenGL sollte da schnell genug sein...

MfG Bergmann.

_________________
Aktuelle Projekte: BumpMapGenerator, Massive Universe Online
Auf meiner Homepage gibt auch noch paar Projekte und Infos von mir.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Nov 17, 2014 10:26 
Offline
DGL Member

Registriert: Di Jun 10, 2014 06:59
Beiträge: 17
Programmiersprache: Delphi XE6
Vielen Dank für Eure Antworten. Vielleicht noch zur Info:

Meine Modelle bestehen im Prinzip aus Linien und Flächen. Diese werden - aufgrund mathematischer Berechnungen - später eingefärbt. Große Modelle können in den Bereich bis mehrere 100k Linien gehen. Diese jedesmal neu zu Zeichnen ist zu aufwändig. Gezeichnet wird natürlich immer nur dann wenn sich am Modell oder der Sicht etwas geändert hat. Dazu verwende ich das Paint einer von TCustomControl abgeleiteten Klasse. Hier mal der Ausschnitt:

Code:
  1.  
  2. procedure TfnmCustomOpenGLCanvas.Paint;
  3. var
  4.   ScreenRatio: Single;
  5.   C: ToglColor;
  6. begin
  7.   if FOpenGLReady then
  8.   begin
  9.     // aktuellen Kontext verwenden
  10.     wglMakeCurrent(FDC, FRC);
  11.  
  12.     // Tiefentest aktivieren
  13.     glEnable(GL_DEPTH_TEST);
  14.     glDepthFunc(GL_LEQUAL);
  15.  
  16.     // Alpha-Blending
  17.     if FFaceStyle.AlphaEnabled then
  18.     begin
  19.       glEnable(GL_Blend);
  20.       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  21.     end
  22.     else
  23.       glDisable(GL_Blend);
  24.  
  25.     // Backface Culling deaktivieren
  26.     glDisable(GL_CULL_FACE);
  27.  
  28.     // Hintergrund löschen
  29.     C.SetTColor(FViewStyle.BackgroundColor);
  30.     glClearColor(C.R, C.G, C.B, C.Alpha);
  31.     glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  32.  
  33.     // Einstellungen Projektionsmatrix ******************************************
  34.     glMatrixMode(GL_PROJECTION);
  35.  
  36.     // Identitätsmatrix laden
  37.     glLoadIdentity;
  38.  
  39.     with FViewStyle do
  40.     begin
  41.       // Perspektive einstellen (Blickwinkel, Verhältnis Breit / Höhe, Clipping vorne, Clipping hinten)
  42.       ScreenRatio := ClientWidth / ClientHeight;
  43.       gluPerspective(FieldOfViewAngle, ScreenRatio, ClippingNear, ClippingFar);
  44.  
  45.       // Kameraverschiebung X/Y/Z
  46.       glTranslatef(CamPosX, CamPosY, CamPosZ);
  47.  
  48.       // Rotation
  49.       glRotatef(ObjRotX, 1.0, 0.0, 0.0);
  50.       glRotatef(ObjRotY, 0.0, 1.0, 0.0);
  51.       glRotatef(ObjRotZ, 0.0, 0.0, 1.0);
  52.     end;
  53.  
  54.     // Einstellungen Modellmatrix **********************************************
  55.     glMatrixMode(GL_MODELVIEW);
  56.  
  57.     // Identitätsmatrix laden
  58.     glLoadIdentity;
  59.  
  60.     // Modell skallieren
  61.     with FViewStyle do
  62.       glScalef(ScaleFactor, ScaleFactor, ScaleFactor);
  63.  
  64.     // Ereignis "BeforeDraw"
  65.     if Assigned(FOnBeforeDraw) then
  66.       FOnBeforeDraw(Self);
  67.  
  68.     // Achsen zeichnen
  69.     DrawAxis;
  70.  
  71.     if Assigned(FProject) then
  72.     begin
  73.       // Zweige zeichnen
  74.       DrawBranches;
  75.  
  76.       // Flächen zeichnen
  77.       DrawFaces;
  78.     end;
  79.  
  80.     // Ausgabe
  81.     SwapBuffers(FDC);
  82.  
  83.     // Ereignis "AfterDraw"
  84.     if Assigned(FOnAfterDraw) then
  85.       FOnAfterDraw(Self);
  86.   end;
  87. end;
  88.  


"ToglColor" ist ein von mir erstellter Typ, der mir TColor-Werte in OpenGL konforme Farbwerte umrechnet oder umgekehrt. "DrawAxis" zeichnet die drei Achsen (X, Y und Z). "DrawBranches" zeichnet die Linien, "DrawFaces" die Flächen.

Es wäre halt schön, wenn man den BackBuffer solange als BackBuffer erhalten könnte wie er gültig ist und - das ist das Wichtige - ihn als BackBuffer bestehen lassen könnte. "SwapBuffer" tauscht ja immer aus. Es müsste also eine Funktion wie CopyBackToFront oder so geben. Da könnte man sich den Puffer immer wieder holen und - zur Not mit Standard-Canvas Funktionen drüber zeichnen. Die benötigten X/Y-Koordinaten sind ja mit gluProject leicht zu ermitteln...

Über VBOs habe ich auch schon nachgedacht. Allerdings muss dann ja auch immer neu gezeichnet werden, was bei dem Umfang zum einen Zeit kostet, zum anderen enormen Grafikspeicher voraussetzt. Wenn ich 100k Linien annehme und mal davon ausgehe, dass pro Line Anfangs- und Endkoordinaten (6 Werte) sowie der RGBA-Farbwert (4 Werte) gespeichert werden müssen, dann komme ich bei Single auf 100k * (6 + 4) * 4 Byte = 40 Byte pro Linie. Das wären dann schon 4 MB. Da fehlen dann noch die Flächen mit durchschnittlich 4 Eckpunkten. Bei 100k Linien sin das erfahrungsgemäß etwa 140k Flächen. Wie gesagt: Große Modelle können bis mehrere 100k Linien haben...

Wie würde das denn genau mit FBOs ablaufen? Ist das dann so ein unabhängiger Puffer wie ich ihn gerne hätte? Wie kann ich diesen Puffer dann in den BackBuffer übertragen? Wäre natürlich cool, wenn ich meine Ausgabe in einen Zwischenpuffer rendern könnte, den ich dann immer wieder verwenden kann, bis sich an der Geometrie was ändert. Wäre dann so in der Arte:

1. zeichne Zwischenpuffer auf BackBuffer
2. zeichne meine AddOns auf den BackBuffer
3. SwapBuffers

Den Zwischenpuffer müsste ich dann nur bei Bedarf aktualisieren...

Fragen über Fragen :-). Ich hoffe trotzdem ich finde da eine gangbare Lösung. In jedem Fall gehen die Antworten hier schon eher in die von mir erhoffte Richtung...

Alex


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Nov 17, 2014 12:47 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Nov 08, 2010 18:41
Beiträge: 769
Programmiersprache: Gestern
FBOs sind OpenGL Objekte fuer zusaetzliche Framebuffer. Im Gegensatz zum Default-Framebuffer des Context, hast du hier sehr viel mehr Freiraum und kannst eigene Puffer definieren in die gezeichnet werden soll. Die meisten verwenden hier, genau wie im Tutorial, Texturen um die Farbe zu speichern. Es gibt aber auch Faelle in denen man auch hier einen Renderbuffer benutzt (Beispiel).

Falls du Texturen benutzt solltest du dir ggf. noch das Textur Tutorial anschauen.

Btw:
SwapBuffer ist uebrigens per Default "CopyBackToFront" fuer einen Context mit DoubleBuffering, zumindest unter Windows.

_________________
Meine Homepage


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Nov 17, 2014 13:11 
Offline
DGL Member

Registriert: Di Jun 10, 2014 06:59
Beiträge: 17
Programmiersprache: Delphi XE6
Vielen Dank für die Informationen. Da habe ich ja mal was zum studieren :-).

Es ist echt doof, das man den BackBuffer per Standard nicht mehrmals verwenden kann. Das SwapBuffers zerstört ja auch den aktuellen BackBuffer bzw. er wird ungültig. Das mit den FBOs scheint sehr aufwändig (aber in meinem Fall erforderlich) zu sein...

Werde mich also mal damit beschäftigen.

Danke nochmal

Alex


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Nov 17, 2014 13:36 
Offline
DGL Member
Benutzeravatar

Registriert: Di Apr 29, 2008 18:56
Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,

ich werf da mal noch den OpenGLCore in den Raum. Ich bin mir zwar nicht 100%tig sicher, ob der mit Delphi läuft, aber ads sollte schnell angepasst sein. ;)

MfG Bergmann.

_________________
Aktuelle Projekte: BumpMapGenerator, Massive Universe Online
Auf meiner Homepage gibt auch noch paar Projekte und Infos von mir.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Nov 17, 2014 21:48 
Offline
DGL Member

Registriert: Di Jun 10, 2014 06:59
Beiträge: 17
Programmiersprache: Delphi XE6
Bergmann89 hat geschrieben:
Hey,

ich werf da mal noch den OpenGLCore in den Raum. Ich bin mir zwar nicht 100%tig sicher, ob der mit Delphi läuft, aber ads sollte schnell angepasst sein. ;)

MfG Bergmann.


Zumindest ist der Code recht interessant zum Lesen.

Was ich bis jetzt noch nicht verstanden habe: Wie bekomme ich einen Framebuffer auf den Bildschirm? Ich kann zwar einen Frambuffer generieren und in diesen rendern. Aber der muss ja dann auch irgendwie in den Backbuffer oder auf den Bildschirm gelangen. So richtig schlau bin ich da noch nicht draus geworden... Ich habe zwar eine Funktion "glBlitFramebuffer" gefunden, aber von der ist in den Turorials nirgendwo die Rede...

Alex


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Nov 17, 2014 21:53 
Offline
DGL Member
Benutzeravatar

Registriert: Di Apr 29, 2008 18:56
Beiträge: 1213
Programmiersprache: Delphi/FPC
Wie yunharla schon gesagt hat, es gibt 2 Typen: RenderBuffer und TextureBuffer (also normale Texturen). Render BUffer sind dazu gut, wenn du etwas zeichnest und dann mit irgend einer glRead-Funktion Daten aus dem Buffer lesen willst z.B. für (Color-)Selektion. TexturBuffer sind dazu da um das gerenderte später als Textur zu nutzen. Das brauchst du. Zum Schluss zeichnest du einfach ein Quad, das genau so groß ist wie dein Bildschirm und legst da die Textur drauf. Funktioniert praktisch genau so als wenn du die Textur aus einer Datei lädst und dann zum Zeichnen nutzt, nur das der inhalt der Textur eben dynamisch vom FBO erstellt wird.

_________________
Aktuelle Projekte: BumpMapGenerator, Massive Universe Online
Auf meiner Homepage gibt auch noch paar Projekte und Infos von mir.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Nov 17, 2014 22:07 
Offline
DGL Member

Registriert: Di Jun 10, 2014 06:59
Beiträge: 17
Programmiersprache: Delphi XE6
Jetzt macht das Sinn...

Danke!


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Nov 17, 2014 23:07 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Bergmann89 hat geschrieben:
Render BUffer sind dazu gut, wenn du etwas zeichnest und dann mit irgend einer glRead-Funktion Daten aus dem Buffer lesen willst z.B. für (Color-)Selektion.
N.B.: RenderBuffer kann man auch gebrauchen, wenn man das Ergebnis überhaupt nicht weiter verwenden möchte, den Puffer aber aus anderen Gründen braucht (Tiefenpuffer z.B.)

viele Grüße,
Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Nov 18, 2014 10:50 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Nov 08, 2010 18:41
Beiträge: 769
Programmiersprache: Gestern
Ausserdem kann man sie auch als Blitobjekte benutzen. Wenn du also zum Beispiel einen rechteckigen Bereich nur ersetzen willst, sind sie hervorragend geeignet.

_________________
Meine Homepage


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mi Nov 19, 2014 10:11 
Offline
DGL Member

Registriert: Di Jun 10, 2014 06:59
Beiträge: 17
Programmiersprache: Delphi XE6
Hallo,

nach mehreren Versuchen klappt es jetzt super. Zuerst hatte ich in einen zusätzlichen Framebuffer gezeichnet und diesen dann mit Blit-Copy bei Bedarf in den Backbuffer kopiert. Nach der kopie konnte ich dann beliebig auf dem Backbuffer noch zusätzliche Zeichenaktionen machen ehe ich ihn dann angezeigt habe. Das Problem dabei war, dass die Zeichnung recht "kantig" war. Nix "smoothing" usw.. Das Probem ist bekannt und es gibt da einige Workarrounds dazu, welche dann Multisampling usw. durchführen. Die laufen dann aber wohl je nach Grafikkarte mal besser, mal schlechter... Ich habe mir da was viel Einfacheres überlegt - und es funktioniert :-):

Ich zeichne grundsätzlich nur in den Backbuffer. Nachdem die Zeichnung fertig ist, sichere ich diese mit Blit-Copy in einen Framebuffer. Benötige ich die Zeichnung dann später wieder, dann hole ich sie einfach mit Blit-Copy zurück. Der Vorteil dabei ist, dass das Ziel meiner Zeichnaktionen immer der Backbuffer ist. Den zusätzlichen Framebuffer nutze ich nur als Backup. Ein weiterer Vorteil ist, dass ich bei Bedarf auch nur einen Teil meiner Zeichnung aktualisieren könnte...

Wollte ich nur loswerden.

Vielen Dank nochmal Euch allen!

Alex


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mi Nov 19, 2014 15:48 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Nov 08, 2010 18:41
Beiträge: 769
Programmiersprache: Gestern
Mhh ja das ist echt ne super Idee werde ich mir mal fuer die Zukunft merken.

Danke fuers Feedback

_________________
Meine Homepage


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 14 Beiträge ] 
Foren-Übersicht » Programmierung » Einsteiger-Fragen


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 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:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.010s | 14 Queries | GZIP : On ]