Entwickler-Ecke

Multimedia / Grafik - OpenGL Delphigl Tutorial 2


JungerIslaender - Sa 03.12.11 02:14
Titel: OpenGL Delphigl Tutorial 2
Ich wollt mich mal in die OpenGL Welt begeben und hab auf delphigl gestöbert und von anfang an die Tutorials gemacht. Dabei ist folgendes bei rausgekommen:

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:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DGLOpenGL, ExtCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure Init;
    procedure FormResize(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure IdleHandler(Sender: TObject; var Done: Boolean);
  private    { Private declarations }
    StartTime, TimeCount, FrameCount  : Cardinal; //FrameCounter
    Frames, DrawTime                  : Cardinal; //& Timebased Movement
    procedure SetupGL;
    procedure Render;
    procedure ErrorHandler;
  public    { Public declarations }
    DC                                : HDC;  //Handle auf Zeichenfläche
    RC                                : HGLRC;//Rendering Context
  end;

var
  Form1: TForm1;

const
  NearClipping = 1;
  FarClipping  = 1000;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  DC:= GetDC(Handle);
  if not InitOpenGL then Application.Terminate;
  RC:= CreateRenderingContext( DC,
                               [opDoubleBuffered],
                               32,
                               24,
                               0,0,0,
                               0);
  ActivateRenderingContext(DC, RC);
  SetupGL;
  Init;
  Application.OnIdle := IdleHandler;
end;


procedure TForm1.SetupGL;
begin
  glClearColor(0.00.00.00.0); //Hintergrundfarbe: Hier ein leichtes Blau
  glEnable(GL_DEPTH_TEST);          //Tiefentest aktivieren
  glEnable(GL_CULL_FACE);           //Backface Culling aktivieren
end;


procedure TForm1.Init;
begin
//Nichts zu Initialisieren
end;


procedure TForm1.FormResize(Sender: TObject);
var tmpBool : Boolean;
begin
  glViewport(00, ClientWidth, ClientHeight);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(45.0, ClientWidth/ClientHeight, NearClipping, FarClipping);    
 
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;
  IdleHandler(Sender, tmpBool);
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
  DeactivateRenderingContext;
  DestroyRenderingContext(RC);
  ReleaseDC(Handle, DC);
end;


procedure TForm1.Render;
begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
 
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(45.0, ClientWidth/ClientHeight, NearClipping, FarClipping);
 
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;

  glTranslatef(00, -10);
 
  glBegin(GL_QUADS);
    glColor3f(1,0,0); glVertex3f(-1, -10);
    glColor3f(1,0,0); glVertex3f( 1, -10);
    glColor3f(1,0,0); glVertex3f( 1,  10);
    glColor3f(1,0,0); glVertex3f(-1,  10);
  glEnd;
 
  SwapBuffers(DC);
end;


procedure TForm1.Timer1Timer(Sender: TObject);
begin
(*  inc(FrameCount);
   Render;
   If FrameCount = 20 then
      begin
           ErrorHandler;
           FrameCount := 0;
      end; *)

end;


procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);
begin
  StartTime:= GetTickCount;
  Render;
  DrawTime:= GetTickCount - StartTime;
  Inc(TimeCount, DrawTime);
  Inc(FrameCount);
 
  if TimeCount >= 1000 then begin
    Frames:= FrameCount;
    TimeCount:= TimeCount - 1000;
    FrameCount:= 0;
    Caption:= InttoStr(Frames) + 'FPS';
    ErrorHandler;
  end;
 
  Done:= false;
end;


procedure TForm1.ErrorHandler;
begin
  Form1.Caption := gluErrorString(glGetError);
end;


end.


Funtioniert auch wunderbar.

Sobald ich in TForm1.Render allerdings etwas anderes einfüge, wie z.B. ein Beispiel wie das hier:

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:
  // Der Bildschirm wird "gecleart"
  glClear(GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT);

  // Die World-Matrix wird zurück gesetzt
  glLoadIdentity;
  // Kamera leicht weg bewegen vom Objekt (sinngemäß!!!)
  glTranslatef( 0,  0,  -10);

  glColor3f(1,0,0);
  glBegin(GL_TRIANGLES);
    glVertex3f(-1.0,-1.00.0);
    glVertex3f( 0.01.00.0);
    glVertex3f( 1.0,-1.00.0);
  glEnd();

  glLoadIdentity;
  // Nun ein kleines Stück darüber ein Dreick zeichnen
  glTranslatef( 0,  2,  -10);

  glColor3f(1,1,1);
  glBegin(GL_TRIANGLES);
    glVertex3f(-1.0,-1.00.0);
    glVertex3f( 0.01.00.0);
    glVertex3f( 1.0,-1.00.0);
  glEnd();

  glLoadIdentity;
  glTranslatef( 0, -2,  -10); // Und ein kleines Stück darunter!

  glColor3f(0,0,1);
  glBegin(GL_TRIANGLES);
    glVertex3f(-1.0,-1.00.0);
    glVertex3f( 0.01.00.0);
    glVertex3f( 1.0,-1.00.0);
  glEnd();

  {  Technisch gesehen würde man dieses Problem eher mit glPopMatrix und       }
  {  glPushMatrix lösen. Wir setzen hingegen jedesmal die Einheits-Matrix und  }
  {  dann die Transformations-Matrix mitsamt Camera-Abstand neu!               }


Passiert nichts mehr. Und ich verstehe nicht warum?


Xion - Sa 03.12.11 12:08

Du darfst ja auch nicht die Initialisierung der Matrix weglassen (Zeile 97-101).


JungerIslaender - Sa 03.12.11 15:31


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:
procedure TForm1.Render;
begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
 
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(45.0, ClientWidth/ClientHeight, NearClipping, FarClipping);
 
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;
  glTranslatef( 0,  0,  -10);

glLoadIdentity;
  // Nun ein kleines Stück darüber ein Dreick zeichnen
  glTranslatef( 0,  2,  -10);

  glColor3f(1,1,1);
  glBegin(GL_TRIANGLES);
    glVertex3f(-1.0,-1.00.0);
    glVertex3f( 0.01.00.0);
    glVertex3f( 1.0,-1.00.0);
  glEnd();

  glLoadIdentity;
  glTranslatef( 0, -2,  -10); // Und ein kleines Stück darunter!

  glColor3f(0,0,1);
  glBegin(GL_TRIANGLES);
    glVertex3f(-1.0,-1.00.0);
    glVertex3f( 0.01.00.0);
    glVertex3f( 1.0,-1.00.0);
  glEnd();

  {  Technisch gesehen würde man dieses Problem eher mit glPopMatrix und       }
  {  glPushMatrix lösen. Wir setzen hingegen jedesmal die Einheits-Matrix und  }
  {  dann die Transformations-Matrix mitsamt Camera-Abstand neu!               }
end;


Ok Hab das jetzt mit reingepackt. Es passiert trotzdem nichts.


Xion - Sa 03.12.11 17:28

user profile iconJungerIslaender hat folgendes geschrieben Zum zitierten Posting springen:
Ok Hab das jetzt mit reingepackt. Es passiert trotzdem nichts.

Hihi, da muss ich lachen...es passiert ziemlich viel, nur wirds nicht angzeigt :mrgreen:

Du hast das SwapBuffers am Ende vergessen. Außerdem brauchst du nur einmal LoadIdentity logischerweise...


Bergmann89 - Sa 03.12.11 18:42

Hey,


Delphi-Quelltext
1:
2:
3:
4:
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(45.0, ClientWidth/ClientHeight, NearClipping, FarClipping); 
  glMatrixMode(GL_MODELVIEW);

Das packt man normalerweiße nur ins FormResize, das spart Rechenleistung ;)

Das LoadIdentity kannst du bei deinem 2. Objekt auch weglassen, du musst dann nur mit der aktuellen Position der Matrix rechnen. Wenn du einfach noch ein Stück drüber was zeichnen willst, dann einfach mit glTranslatef(020) 2 Einheiten nach oben verschieben. Für das Dreieck darunter müsstest du dann glTranslatef(0, -40) aufrufen ODER du pushst die Matrix auf den Matrix Stack (glPushMatrix) verschiebst nach oben, zeichnest dein Dreieck, popst die Matrix vom Stack (glPopMatrix), schiebst nach unten (-2 Einheiten) und zeichnest das 2. Dreieck. Der zweite Weg ist zwar etwas kompilizierter, aber normalerweiße macht man das so.

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:
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;
  glTranslatef( 0,  0,  -10);

  glBegin(GL_TRIANGLES);  //mittleres Dreick zeichnen
    glVertex3f(-1.0,-1.00.0);
    glVertex3f( 0.01.00.0);
    glVertex3f( 1.0,-1.00.0);
  glEnd();
  
  glPushMatrix;          //Matrix speichern 
  glTranslatef(020); //2 Einheiten nach oben
  glBegin(GL_TRIANGLES); //oberes Dreick zeichnen
    glVertex3f(-1.0,-1.00.0);
    glVertex3f( 0.01.00.0);
    glVertex3f( 1.0,-1.00.0);
  glEnd();
  glPopMatrix;           //Matrix laden

  glPushMatrix;          //Matrix speichern 
  glTranslatef(0, -20); //2 Einheiten nach unten
  glBegin(GL_TRIANGLES); //unteres Dreick zeichnen
    glVertex3f(-1.0,-1.00.0);
    glVertex3f( 0.01.00.0);
    glVertex3f( 1.0,-1.00.0);
  glEnd();
  glPopMatrix;           //Matrix laden


Für einen Anfänger würde ich zuerst die Matrix-Tutorials [http://wiki.delphigl.com/index.php/Tutorial_Matrix2] empfehlen. Die kommen in der Tutorialliste erst relativ spät, sind aber die absolute Grundlage für jegliche Bewegung und Positionierung in OpenGL.

MfG Bergmann.