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

Aktuelle Zeit: Di Jul 15, 2025 21:03

Foren-Übersicht » Programmierung » OpenGL
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 9 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Off-Screen-Rendern
BeitragVerfasst: Do Mai 13, 2004 15:19 
Offline
DGL Member

Registriert: Do Mai 13, 2004 14:52
Beiträge: 10
Hi folks!

Ich steige grad erst in die OGL-Programmierung ein.
Ich progge unter Delphi6 mit "uses OpenGL".
Folgendes Problem:
Ich möchte OpenGL nutzen um eine 3D-Grafik zu erstellen und auszudrucken.
Da OpenGL mir bei überlappten Fenstern usw. kein gescheites Bild liefert und ich zum Ausdruck hohe Auflösungen brauche möchte ich die Grafik gerne "off-screen" rendern. Ich weiß dass ich dann keine Hardware-Beschleunigung mehr habe, aber das ist nicht weiter wichtig.
Meine Frage ist jetzt: Wie erstelle ich so einen Context ?
Alle meine versuche das ganze intern zu erstellen und mit glReadPixels auszulesen scheitern - vermutlich an diesem "Pixel Ownership Test".
Kann mir da irgendwer helfen ?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mai 13, 2004 15:46 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Moin. An deiner Stelle würde ich gar nicht so kompliziert denken.

Als erstes solltest du dir einen anderen OpenGL Header zulegen. Die Unit OpenGL von Borland ist so ziemlich das Älteste was man im Bezug auf OpenGL finden kann. Die besste Alternative ist der boardeigene Header.

Und um dein Problem zu lösen schau dir mal diese Seite von Tom Nuydens an. Da findest du ziemlich genau in der Mitte eine Datei namen Hiresshot.zip. In dieser Quelle erzeugt er mit Hardwarebeschleunigung Onscreen ein sehr großes Bitmap. Er rendert mehrfach kleine Stückchen. Schau es dir einfach mal an. Bei Fragen stehen wir dir gerne zur Verfügung.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mai 13, 2004 16:05 
Offline
DGL Member

Registriert: Do Mai 13, 2004 14:52
Beiträge: 10
Hab mir die Header-Datei geladen.
Die Möglichkeit Hi-Res-Shots zu kacheln ist mir bekannt.
Aber bei meiner Anwendung soll definitiv im Hintergrund gerendert werden, die Grafik soll gar nicht auf dem Monitor erscheinen.
Der Anwender klickt auf drucken und es werden 3 - 4 Ansichten im Hintergrund erstellt und auf dem Drucker ausgegeben.

Hier mein bisheriger (nicht funktionierender) Code:
(Ursprünglich habe ich in ein Panel gerendert, was auch funktionierte)

Code:
  1.  
  2. unit FormMain;
  3.  
  4. interface
  5.  
  6. uses
  7.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  8.   Dialogs, StdCtrls, ExtCtrls, Menus, OpenGL;
  9.  
  10. type
  11.  
  12.   TBmpHeader = Packed Record
  13.     bfType1         : Byte;
  14.     bfType2         : Byte;
  15.     bfSize          : LongInt;
  16.     bfReserved1     : Word;
  17.     bfReserved2     : Word;
  18.     bfOffBits       : LongInt;
  19.     biSize          : LongInt;
  20.     biWidth         : LongInt;
  21.     biHeight        : LongInt;
  22.     biPlanes        : Word;
  23.     biBitCount      : Word;
  24.     biCompression   : LongInt;
  25.     biSizeImage     : LongInt;
  26.     biXPelsPerMeter : LongInt;
  27.     biYPelsPerMeter : LongInt;
  28.     biClrUsed       : LongInt;
  29.     biClrImportant  : LongInt;
  30.   end;
  31.  
  32.   Tform_main = class(TForm)
  33.     ...
  34.   private
  35.     { Private-Deklarationen }
  36.     oglDC :hDC;
  37.     oglRC :hGLRC;
  38.     oglPalette :hPALETTE;
  39.     hPic  :hBITMAP;
  40.     procedure SetupPixelFormat;
  41.   public
  42.     { Public-Deklarationen }
  43.     procedure render;
  44.   end;
  45.  
  46. var
  47.   form_main: Tform_main;
  48.  
  49. implementation
  50.  
  51. {$R *.dfm}
  52.  
  53. { TForm1 }
  54.  
  55. procedure Tform_main.FormCreate(Sender: TObject);
  56. begin
  57.   oglDC := CreateCompatibleDC(panel_ogl.Handle);
  58.   hPic := CreateCompatibleBitmap(oglDC,panel_ogl.Width,panel_ogl.Height);
  59. //  SelectObject(oglDC,hPic);
  60.   SetupPixelFormat;
  61.   oglRC := wglCreateContext(oglDC);
  62.   wglMakeCurrent(oglDC, oglRC);
  63.   glEnable(GL_DEPTH_TEST);
  64.   glLoadIdentity;
  65. end;
  66.  
  67. procedure Tform_main.SetupPixelFormat;
  68. var
  69.   hHeap :THandle;
  70.   nColors :integer;
  71.   i :integer;
  72.   lpPalette :PLogPalette;
  73.   byRedMask,
  74.   byGreenMask,
  75.   byBlueMask :Byte;
  76.   nPixelFormat :Integer;
  77.   pfd :TPixelFormatDescriptor;
  78. begin
  79.   FillChar(pfd, SizeOf(pfd), 0);
  80.   with pfd do
  81.   begin
  82.     nSize := sizeOf(pfd);
  83.     nVersion := 1;
  84.     dwFlags := PFD_DRAW_TO_BITMAP or PFD_SUPPORT_OPENGL;
  85.     iPixelType := PFD_TYPE_RGBA;
  86.     cColorBits := 24;
  87.     cRedBits := 8;
  88.     cGreenBits := 8;
  89.     cBlueBits := 8;
  90.     cDepthBits := 16;
  91.     iLayerType := PFD_MAIN_PLANE;
  92.   end;
  93.   nPixelFormat := ChoosePixelFormat(oglDC, @pfd);
  94.   SetPixelFormat(oglDC, nPixelFormat, @pfd);
  95.   DescribePixelFormat(oglDC, nPixelFormat, sizeOf(TPixelFormatDescriptor), pfd);
  96.   if ((pfd.dwFlags and PFD_NEED_PALETTE) <> 0) then
  97.   begin
  98.     nColors := 1 shl pfd.cColorBits;
  99.     hHeap := GetProcessHeap;
  100.     lpPalette := HeapAlloc(hHeap, 0, sizeOf(TLogPalette)+(nColors*sizeOf(TPaletteEntry)));
  101.     lpPalette^.palVersion := $300;
  102.     lpPalette^.palNumEntries := nColors;
  103.     byRedMask := (1 shl pfd.cRedBits) -1;
  104.     byGreenMask := (1 shl pfd.cGreenBits) -1;
  105.     byBlueMask := (1 shl pfd.cBlueBits) -1;
  106.     for i := 0 to pred(nColors) do
  107.     begin
  108.       lpPalette^.palPalEntry[i].peRed := (((i shr pfd.cRedShift) and byRedMask) *255) div byRedMask;
  109.       lpPalette^.palPalEntry[i].peGreen := (((i shr pfd.cGreenShift) and byGreenMask) *255) div byGreenMask;
  110.       lpPalette^.palPalEntry[i].peBlue := (((i shr pfd.cBlueShift) and byBlueMask) *255) div byBlueMask;
  111.       lpPalette^.palPalEntry[i].peFlags := 0;
  112.     end;
  113.     oglPalette := CreatePalette(lpPalette^);
  114.     HeapFree(hHeap, 0, lpPalette);
  115.     if (oglPalette <> 0) then
  116.     begin
  117.       SelectPalette(oglDC, oglPalette, false);
  118.       RealizePalette(oglDC);
  119.     end;
  120.   end;
  121. end;
  122.  
  123. procedure Tform_main.render;
  124. begin
  125.   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  126.   glLoadIdentity;
  127.  
  128.   glColor3f(random,random,random);
  129.   glBegin(gl_quads);
  130.     glVertex3f(1,1,-6);
  131.     glVertex3f(-1,1,-6);
  132.     glVertex3f(-1,-1,-6);
  133.     glVertex3f(1,-1,-6);
  134.   glEnd;
  135.  
  136.   glFinish;
  137. end;
  138.  
  139. procedure Tform_main.bt_initClick(Sender: TObject);
  140. begin
  141.   glViewPort(0,0,panel_ogl.Width,panel_ogl.Height);
  142.   glMatrixMode(GL_PROJECTION);
  143.   glLoadIdentity();
  144.   gluPerspective(45.0, panel_ogl.Width/panel_ogl.Height, 1.0, 100.0);
  145.   glMatrixMode(GL_MODELVIEW);
  146.   glLoadIdentity;
  147. end;
  148.  
  149. procedure Tform_main.bt_offscreenClick(Sender: TObject);
  150. var
  151.   pic :TBitmap;
  152.   x,y :integer;
  153.   w,h :integer;
  154.   pba :pByteArray;
  155.   buf :^Byte;
  156.   PByte :^Byte;
  157. begin
  158.   screen.Cursor := crHourGlass;
  159.  
  160.   pic := TBitmap.Create;
  161.   pic.Width := panel_ogl.Width;
  162.   pic.Height := panel_ogl.Height;
  163.   pic.PixelFormat := pf24Bit;
  164.  
  165.   w := panel_ogl.Width;
  166.   h := panel_ogl.Height;
  167.   GetMem(Buf,3 * w * h);
  168.   glReadPixels(0,0,w,h,GL_RGB,GL_UNSIGNED_BYTE,buf);
  169.   PByte := @(buf^);
  170.   for y := pred(h) downto 0 do
  171.   begin
  172.     pba := pic.ScanLine[y];
  173.     for x := 0 to pred(w) do
  174.     begin
  175.       pba[x*3+2] := PByte^;
  176.       inc(PByte);
  177.       pba[x*3+1] := PByte^;
  178.       inc(PByte);
  179.       pba[x*3] := PByte^;
  180.       inc(PByte);
  181.     end;
  182.     for x := 1 to w mod 4 do
  183.       inc(PByte);
  184.   end;
  185.   FreeMem(buf);
  186.  
  187.   img_ogl.Picture.Bitmap.Assign(pic);
  188.   pic.Free;
  189.  
  190.   screen.Cursor := crDefault;
  191. end;
  192.  
  193. end.
  194.  


Irgendwelche Ideen ?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Mai 14, 2004 07:46 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Es besteht auch noch die Möglichkeit, dass du dir einen PBuffer (PixelBuffer) erstellt. Da du es gerne OffScreen haben möchtest ist dies genau das richtige für dich.

Aber vorher noch eine kleine Anmerkung. Deine OpenGL initialisierung hat ein kleines Problem. Sobald ein Fehler auftritt macht du so lange weiter bis es irgendwann in Fehlern erstickt. Oder anders gesagt. Du überprüfst nicht ob deine Aktionen auch tatsächlich erfolgreich waren. Als beispiel hier nur mal der Befehl ChoosePixelformat. So habe ich das in meinem Programm gelöst.
Code:
  1.   PixelFormat := ChoosePixelFormat(FDC, @pfd);
  2.   if (PixelFormat = 0) then begin
  3.     MessageBox(0, 'Unable to find a suitable pixel format', 'Error', MB_OK or MB_ICONERROR);
  4.     Exit;
  5.   end;

Aber wie gesagt. Dein Code funktioniert auch sollange es keine Fehler gibt. ;-)

Jetzt zu den PBuffern. Im normalfall würde ich dich auf die Seite von Jason Allen verweisen. Aber die ist schon seit monaten tot. Hmmmm. Und per Zufall habe ich seine Klasse zur Verwendung von PBufferm noch auf meinem System gefunden. Was ein Glück, dass ich so gut wie nie meine Quellen aufräume. :twisted:

So du benötigst für die PBuffers 3 Extension. Als erstes die WGL_ARB_extensions_string. Diese wird von so ziemlich jeder OpenGL unterstützt.
Die beiden Folgenden sind da schon etwas anspruchsvoller. WGL_ARB_pixel_format und WGL_ARB_pbuffer
Bei den beiden letzten musst du schauen ob diese auch unterstützt werden. Andernfalls musst du dir etwas anderes einfallen lassen.
Hier findest du eine Liste mit allen Extensions und im Detail eine Liste von Treibern/Hardware die diese Extension unterstützen.

Für die Initialisierung des PBuffers musst du Allerdings auf einen aktuellen OpenGL Header zurückgreifen. Siehe erstes Post von mir.

Und ich habe dir mal die Klasse von Jason Allen angehangen. Wenn du die Methoden Init und Release in dein Program umsetzt sollte das schon funktionieren.

Für den Fall, dass diese Extensions nicht unterstützt werden (je nachdem welche Zielhardware du ansprechen möchtest) Kannst du entweder einen Fehler ausgeben oder aber du musst es sichtbar rendern.


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Mai 14, 2004 07:57 
Offline
DGL Member

Registriert: Do Mai 13, 2004 14:52
Beiträge: 10
@Lossy eX
Danke für die Tipps! Werd ich gleich mal ausprobieren!
Für mich ist es wichtig, dass das ganze auf möglichst vielen Rechnern läuft. Soll halt besser zuverlässig funktionieren als schnell!

Danke auch für die Tips bei der Initialisierung. Hab mich damit noch nicht näher beschäftigt, sondern einfach so aus 'nem Tut kopiert. Wollte mir das aber nochmal ansehen sobald ich weiß dass ich keine Probleme mit meinem Vorhaben unter OpenGL bekomme ;-)


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Mai 14, 2004 08:32 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Kein problem.

Um in ein Fenster zu Rendern genügt es normal schon, wenn GetDC(Panel.Handle) machst. Und dann diesen DC benutzt. Du musst dazu nicht mal einen Kompatiblen erstellen.

Um dich jetzt noch richtig mit Wissen zu bombardieren habe ich noch etwas für dich. ;-)

In der OpenGL 1.2 Header Konvertierung von Mike Lischke befindet sich ein Programm namens GLDiag. Dieses solltest du dir auch einmal anschauen. In diesem Programm erstellt er auch Testweise einen RC direkt auf der Canvas von einem Drucker. Allerdings sei dort ein Wort der Warnung angebacht (oder auch zwei). Wie man in dem Programm schön sehen kann wird für das Rendern in Bitmaps und auf dem Drucker die Software Implementation von Microsoft verwendet.
Da Microsoft nichts so sehr wie DirectX (Direct3D) am Herzen liegt kannst du dir selber ausmalen wie diese Implementation dieses OpenGL Treibers aussieht. So gut wie keine Extensions. Total langsam. OpenGL 1.1 und diverse Implementationsfehler die laut Kleinweich nicht behoben werden.

Falls dir Softwarerendering nichts ausmacht und du dennoch direkt auf den Drucker rendern willst solltest du dir mal die MesaGL anschauen. Das ist eine OpenGL 1.5 Softwareimplementation. Sollte genügen, wenn man nur die DLL dazu mit ins Programmverzeichnis legt. Bin ich aber der Falsche Ansprechpartner für. Solltest da mal Mars frage. Der hat mit Mesa schon recht viel gemacht.

So ich glaube das war es erst einmal. ;-)


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: So geht's
BeitragVerfasst: Fr Mai 14, 2004 12:31 
Offline
DGL Member

Registriert: Do Mai 13, 2004 14:52
Beiträge: 10
Prima Tip war das!
Hab mir Mesa mal angesehen, damit müsst's auch gehen.
Hab jetzt mit Mike Lischkes OpenGL12 rumgedoktert und das Ganze ans laufen gebracht. Der Code ist noch nicht ganz clean aber es funktioniert!

Danke nochmal @lossy eX

Für Interessierte:

Code:
  1.  
  2. unit FormMain;
  3.  
  4. interface
  5.  
  6. uses
  7.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  8.   Dialogs, StdCtrls, ExtCtrls, Menus, OpenGL12;
  9.  
  10. type
  11.  
  12.   Tform_main = class(TForm)
  13.     ...
  14.   private
  15.     oglPic :TBitmap;
  16.     oglDC  :hDC;
  17.     oglRC  :hGLRC;
  18.   public
  19.     procedure render;
  20.   end;
  21.  
  22. var
  23.   form_main: Tform_main;
  24.  
  25. implementation
  26.  
  27. {$R *.dfm}
  28.  
  29. { TForm1 }
  30.  
  31. procedure Tform_main.FormCreate(Sender: TObject);
  32. begin
  33.   InitOpenGL;
  34.   oglPic := TBitmap.Create;
  35.   oglPic.Height := panel_ogl.Height;
  36.   oglPic.Width := panel_ogl.Width;
  37.   oglPic.PixelFormat := pf24Bit;
  38.   randomize;
  39. end;
  40.  
  41. procedure Tform_main.FormDestroy(Sender: TObject);
  42. begin
  43.   if HasActiveContext then DeactivateRenderingContext;
  44.   if oglRC <> 0 then DestroyRenderingContext(oglRC);
  45.   if (oglPic.Canvas.LockCount > 0) then oglPic.Canvas.Unlock;
  46.   oglPic.Free;
  47. end;
  48.  
  49. procedure Tform_main.render;
  50. begin
  51.   if HasActiveContext then
  52.   begin
  53.     glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  54.     glLoadIdentity;
  55.  
  56.     glColor3f(random,random,random);
  57.     glBegin(gl_quads);
  58.       glVertex3f(1,1,-6);
  59.       glVertex3f(-1,1,-6);
  60.       glVertex3f(-1,-1,-6);
  61.       glVertex3f(1,-1,-6);
  62.     glEnd;
  63.  
  64.     glFinish;
  65.   end;
  66. end;
  67.  
  68. procedure Tform_main.bt_captureClick(Sender: TObject);
  69. begin
  70.   render;
  71.   img_ogl.Picture.Bitmap.Assign(oglPic);
  72. end;
  73.  
  74. procedure Tform_main.bt_initClick(Sender: TObject);
  75. const
  76.   BitCounts: array [pf4Bit..pf32Bit] of Byte = (4, 8, 15, 16, 24, 32);
  77. var
  78.   ColorDepth,
  79.   Dummy: HPALETTE;
  80. begin
  81.   try
  82.     oglPic.Canvas.Lock;
  83.     oglDC := oglPic.Canvas.Handle;
  84.     ColorDepth := BitCounts[oglPic.PixelFormat];
  85.     oglRC := CreateRenderingContext(oglDC, [], ColorDepth, 0, 0, 0, 0, Dummy);
  86.     ActivateRenderingContext(oglDC, oglRC);
  87.  
  88.     glViewPort(0,0,oglPic.Width,oglPic.Height);
  89.     glMatrixMode(GL_PROJECTION);
  90.     glLoadIdentity();
  91.     gluPerspective(45.0, oglPic.Width/oglPic.Height, 1.0, 100.0);
  92.     glMatrixMode(GL_MODELVIEW);
  93.     glLoadIdentity;
  94.   except
  95.     oglDC := 0;
  96.     if (oglPic.Canvas.LockCount > 0) then oglPic.Canvas.Unlock;
  97.   end;
  98. end;
  99.  
  100. end.
  101.  


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: So geht's
BeitragVerfasst: Fr Mai 14, 2004 13:58 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Prime hat geschrieben:
Hab jetzt mit Mike Lischkes OpenGL12 rumgedoktert und das Ganze ans laufen gebracht.


Hmmm. Ich kann noch mal auf mein erstes Post verweisen. Der boardeigene Header. Der besste, schönste und aktuellste OpenGL Header den es im Internet zu finden gibt.

Und er ist pflicht für jeden aufm Board. ;-) :twisted:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Mai 14, 2004 17:40 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Dez 13, 2002 12:18
Beiträge: 1063
Du kannst auch ein Bitmap (anstelle eines Fensters) verwenden - und dann den ganz normalen OpenGL Treiber verwenden - allerdings wird dann automatisch die Microsoft Software Implementation genutzt (OpenGL 1.1).

Da du fürs Drucken wahrscheinlich ohnehin damit auskommst, sollte dir dies hier weiterhelfen:
http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/Q132/8/66.asp&NoWebContent=1

Alternativ kannst du die Mesa Treiber verwenden - wenn du die Mesa-Bibliotheken erstellst (es ist ein Makefile für MingW dabei, sodass du dafür Freewareprogramme verwendenkannst - ansonsten google mal nach osmesa.dll - wenns gar nicht anders geht kann auch ich ihn dir kompilieren) - so erhältst du neben OpenGL32.dll und GLU32.dll auch OSMESA.DLL, das einfach anstelle von OpenGL32.dll geladen werden muss - und dann kann man direkt in einen Speicherbereich rendern.
Um OSMESA zu laden, kannst du genau so dglOpenGL nutzen, da der Name des OpenGL Treibers frei wählbar ist.

OSMESA hat den Vorteil, dass auch Floating Point Pixelformate möglich sind (sogar mit Double Werten) und dass OpenGL 1.5 unterstützt wird - der Nachteil ist, dass du nicht einfach in ein TBitmap rendern kannst, als das Ganze betriebssystemunabhängig ist und du somit deinen Speicher selbst verwalten musst (bzw. interpretieren, was Mesa da nun hineingerendert hat - Mesa "sieht" einen Speicherblock und interpretiert diesen als rechteckinge Matrix von den entsprechenden Komponenten, die du für dein Pixelformat wählst).

[edit]
die Antwort mit dem Bitmap wäre eh schon dagewesen ...
[/edit]

_________________
Viel Spaß beim Programmieren,
Mars
http://www.basegraph.com/


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


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 ]