Autor Beitrag
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: Sa 06.09.08 11:31 
Hi,

ich möchte eine Szene in OpenGL als Bild speichern. Indem ich hier etwas rumgespielt habe (4x so große Fläche, nur ein Viertel aufm Bildschirm rendern), konnte ich ber "Druck"-Taste 4 Screenshots erstellen und diese zusammenfügen.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
  glViewport(00, VPanel.ClientWidth, VPanel.ClientHeight);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(45.0, VPanel.ClientWidth/VPanel.ClientHeight, NearClipping, FarClipping);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;


Ja, das ist Mist, ich weiß :mrgreen: Vor allem weil es nicht mit mehr als doeppelte Auflösung geht. Gibt es da nicht eine vernünftige Art, sowas zu machen?

Danke, Xion

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 06.09.08 17:39 
Ja, indem man sich einen Textur-Puffer anlegt und in diesen Rendert und dann diesen in ein Bitmap. Beispiele gibt's bei DelphiGL ...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
toenne
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 51



BeitragVerfasst: So 07.09.08 01:53 
Vielleicht hilfts: www.delphigl.com/for...viewtopic.php?t=7772
Das überflüssige Zeugs mit dem leeren Bitmap in das dann der Snapshot kopiert wird kannst du ja weglassen ;).

Gruss
Toenne
Xion Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: So 07.09.08 10:44 
@toenne: bei deinem Code raucht bei mir irgendwie die Grafikkarte ab oO

@BenBE: irgendwie find ich nix. ich find nie was bei DelhpiGL, kA, ich glaube ich bediene die Suche falsch :P

ich habs mal so gemacht ( von hier )

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
procedure SnapShot;
var ATarget: TBitmap;
begin
 ATarget:=TBitmap.Create;
 ATarget.PixelFormat := pfDevice;
 ATarget.Width := Screen.Width;
 ATarget.Height := Screen.Height;
 BitBlt(ATarget.Canvas.Handle, 00, Screen.Width, Screen.Height, DC, 00, SRCCOPY);
 ATarget.SaveToFile('test.bmp');
end;


Das Problem ist aber, dass ich damit ja nicht über die Bildschirmgröße rauskomme. Ich hätte es eigentlich gerne so groß, dass man es drucken kann (also ca. 3*3-fache Bildschirmgröße)

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 07.09.08 12:45 
Bzgl. Screenshots siehe auch wiki.delphigl.com/index.php/Screenshot

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
toenne
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 51



BeitragVerfasst: So 07.09.08 15:35 
Zitat:
@toenne: bei deinem Code raucht bei mir irgendwie die Grafikkarte ab oO

Hast du ihn doch komplett kopiert oder wie?
Du brauchst doch nur...
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
//Snapshotroutine von WhiteHunter
 glGetIntegerv(GL_VIEWPORT, @Viewport);
 Rohbild := TBitmap.Create;
 try
 Rohbild.Width := Viewport[2];
 Rohbild.Height := Viewport[3];
 Rohbild.PixelFormat := pf24bit;
 for i := 0 to Viewport[3] - 1 do
 glReadPixels(0, Viewport[3] - i, Viewport[2], 1, GL_BGR, GL_UNSIGNED_BYTE, Rohbild.ScanLine[i]);

...und schon hast du eine Kopie in 'Rohbild'. Der ganze andere Krempel ist für dich irrelevant.
Aber wie ich dich jetzt verstehe willst du gar nicht den Bildschirminhalt kopieren sondern die ganze Szene? Hmm, was über die Bildschirmgrenzen hinausgeht wird doch gar nicht gerendert denke ich?

Gruss
Toenne
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 07.09.08 16:18 
Ich denke, er will eine Kopie eines Viewports haben, der größer als der Bildschirm ist ...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Mo 08.09.08 11:18 
Xion: Ich denke du hast 2 Möglichkeiten.

1) Wie es BenBE schon so vorgeschlagen hatte. Du erzeugst einen offscreen buffer und renderst dort dein Bild hinein. Das Problem ist aber Aufgrund des Formates den ein OffScreen Buffer (32Bit RGBA + Tiefenbuffer etc) hat steigt der Speicherverbrauch um ein vielfaches an. Und dessen Größe ist irgendwoe auch begrenzt. Oben drein kommt hinzu, dass du recht hohe Hardwareanforderungen hast. Aber mit einem FrameBuffer Object wäre es möglich einen solchen Buffer zu erstellen. Da der seine Daten in einer Textur ablegt wäre es ziemlich einfach die Daten abzufragen.

2) Du musst deine Szene X mal Rendern und immer die passenden Teile des Bildes kopieren und dir daraus ein großes Bild zusammen basteln. Es gab vor ewigen Zeiten auf delphi3d.net mal ein Demo dazu aber leider ist die Seite seit geraumer Zeit offline. Ich weiß es mittlerweile nicht mehr genau was der dort gemacht hatte deswegen kann ich nur einen eigenen Vorschlag machen. Allerdings habe ich keine Ahnung ob das immer so funktioniert.

Du kannst einen Viewport setzen der entsprechend groß ist. Allerdings der Framebuffer bekommt die maximal Größe des Fensters. Bei glViewport setzt du normal ClientHeight/ClientWidth. Wenn du aber deine gewünschte Größe einsetzt, dann wird das Bild entsprechend Groß gezeichnet. Du kannst bei X und Y dann aber entsprechende Werte setzen um den Viewport zu verschieben und einen anderen Teil in den Framebuffer zu verschieben. Der Einfachheit halber solltet du zu Begin erst mal mit einer Größe von 512x512 arbeiten. Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
glViewport(0081928192);
// zeichnen und kopieren

glViewport(512081928192);
// zeichnen und kopiren

glViewport(1024081928192);
// zeichnen und kopiren

usw.


Das müsstest du so häufig machen bist du alle Teile kopiert hast. Kopieren musst du dann Zeilenweise. Dazu solltest du dich mal in dem Screenshot Artikel im Wiki von DGL umschauen. Also prinzipiel mit glReadPixel. Du solltest glReadBuffer auf GL_BACK stellen und SwapBuffers nicht ausführen wärend du die Teile generierst. Dann wird aus dem nicht sichtbaren Backbuffer gelesen und niemand bekommt diese temporären Bilder zu sehen. Aber je nach Größe der Szene kann es dauern, da du im Falle von 8192x8192 die gesammte Szene 256 Mal zeichnen musst. Du kannst aber auch größere Stücke als 512x512 nehmen. Könnte nur beim Zusammenbauen etwas komplizierter/verwirrender werden.

Ich weiß allerdings nicht ob es zu einem Problem führen kann, wenn der Viewport zu groß wird. Mitunter können einige Karten nur einen Viewport von 4096x4096 Pixel. Ich weiß nicht ob sich das auf die maximale Anzeigegröße bezieht oder wirklich auf Width und Height bei glViewport. Die größe kannst du wie folgt abfragen.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
var
  VP: array[0..1of Integer;
begin
  glGetIntegerv(GL_MAX_VIEWPORT_DIMS, @VP);

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
Xion Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: Fr 12.09.08 14:53 
wow, danke, ich hab momentan nicht so viel Zeit.

Also ich habs nach methode 2 schonmal probiert, hab sie jetzt auch einigermaßen zum laufen bekommen (bin am notebook fast verzweifelt, scheinbar kann es nicht mehr als 2x2 Bildschirme berechnen). Leider ist es nicht ganz einwandfrei, Size=2 funktioniert prima, Size=3 ist unten etwas abgeschnitten und Size=4 ist verzerrt oO

Hier mal der Code:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
procedure TOpenGLWorks.SnapShot(Redraw: TTickProc; GameTimer: TGameTimer);
var ATarget: Graphics.TBitmap;  X,Y,W,H: integer;  Size: integer;
begin
 Size:=3;
 
 W:=VPanel.ClientWidth;
 H:=VPanel.ClientHeight;

 glViewport( 00, W*Size, H*Size );
 Redraw(0);


 ATarget:=Graphics.TBitmap.Create;
 ATarget.PixelFormat := pfDevice;
 ATarget.Width := W*Size;
 ATarget.Height := H*Size;
 GameTimer.Enabled:=False;
 for X:= 0 to (Size-1do
   for Y:= 0 to (Size-1do
     begin
       glViewport( -X*W, -Y*H, W*Size, H*Size );
       Redraw(0);
       glViewport( -X*W, -Y*H, W*Size, H*Size );
       Redraw(0);
       BitBlt(ATarget.Canvas.Handle, X*W, ( (Size-1)-Y)*H, W,H, DC, 00, SRCCOPY);
     end;
 ATarget.SaveToFile('test.bmp');

 glViewport( 00, W, H );
 Redraw(0);
 GameTimer.Enabled:=True;
end;


Zudem verstehe ich nicht, warum ich 2x die Szene rendern muss, um ein anständiges Bild zu bekommen (sonst kommt jeder Block doppelt)

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
Xion Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: Sa 13.09.08 12:54 
das hier ist durch den obigen Code entstanden...das Ergebnis ist mir unerklärlich (das rausgeschnittene Eck).

Originalgröße: 4428x3328

Anmerkung: er scheint irgendwo nicht lange genug zu warten, bis er es als Screenshot ausliest. Ich denke mal das ist die differenz zwischen dem fertigen rendern und dem tatsächlichen anzeigen auf dem Bildschirm. Ich habs mal mit glReadPixels versucht, funktioniert aber leider so nicht:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
procedure TOpenGLWorks.SnapShot(Redraw: TTickProc; GameTimer: TGameTimer; Size: integer);
var ATarget, SubTarget: Graphics.TBitmap;  X,Y,W,H: integer; DestRect,TargetRect: TRect;
begin

 W:=VPanel.ClientWidth;
 H:=VPanel.ClientHeight;

 glViewport( 00, W*Size, H*Size );
 Redraw(0);

 DestRect.Left:=0;
 DestRect.Top:=0;
 DestRect.Right:=W;
 DestRect.Bottom:=H;


 ATarget:=Graphics.TBitmap.Create;
 ATarget.PixelFormat := pfDevice;
 ATarget.Width := W*Size;
 ATarget.Height := H*Size;

 SubTarget:=Graphics.TBitmap.Create;
 SubTarget.PixelFormat := pfDevice;
 SubTarget.Width := W;
 SubTarget.Height := H;

 GameTimer.Enabled:=False;
 for X:= 0 to (Size-1do
   for Y:= 0 to (Size-1do
     begin
       glViewport( -X*W, -Y*H, W*Size, H*Size );
       Redraw(0);
       glReadPixels( X*W, Y*H, W, H, GL_RGB, GL_BITMAP, @SubTarget );

       TargetRect.Left:=X*W;
       TargetRect.Top:=Y*H;
       TargetRect.Right:=W+X*W;
       TargetRect.Bottom:=H+Y*H;

       ATarget.Canvas.CopyRect(TargetRect,SubTarget.Canvas,DestRect);
     //  BitBlt(ATarget.Canvas.Handle, X*W, ( (Size-1)-Y)*H, W,H, DC, 0, 0, SRCCOPY);
     end;
 ATarget.SaveToFile('test.bmp');

 glViewport( 00, W, H );
 Redraw(0);
 GameTimer.Enabled:=True;
end;
Einloggen, um Attachments anzusehen!
_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
toenne
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 51



BeitragVerfasst: Mo 15.09.08 20:53 
Willkommen im Club: www.delphigl.com/for...ic.php?p=65288#65288
Ich habs mittlerweile aufgegeben mir über das zweifache Rendern den Kopf zu zerbrechen...ist halt so, Hauptsache es funktioniert...

Gruss
Toenne