Entwickler-Ecke

Open Source Units - OpenGl Unit zum einfachen körper zeichnen


seawolf - Mi 29.11.06 22:25
Titel: OpenGl Unit zum einfachen körper zeichnen
Hi diese Unit (koerper_draw.pas) hab ich aus Langerweile in der Berufsschule geschrieben und weil mir des Körper zeichnen zu umständlich war.

In dieser unit verwende ich den DGLOpenGl Header welchen ihr unter http://www.delphigl.com saugen könnt.
Sollte der Header gegebenenfalls nicht mehr funktionieren (z.B.: durch Aktualisierung) kann ich euch auch gern die Version des Headers schicken die ich jetzt verwende.

die Proceduren zum erstellen der Körper sind alle in der Klasse "koerper" unter gebracht.

Die Variablen "height", "width", "deep" sidn für "Höhe", "Breite", "Länge" (z-Achse) des Körpers.
Die Variable "diffi" (kommt z.b. beim Trapez vor) bestimmt das einrücken mancher punkte.
Diese Variablen sind single Werte und werden in OpenGl Standart angegeben.


eckpunkte eines quadrates x,y,z: (0,0,0); (0.5,0,0); (0.5,0.5,0); (0,0.5,0);

parallelogram mit selbigen punkten + "diffi" (0,0,0); (0.5,0,0); (0.5,0.5,0); (0,0.5,0); (0.2);
das parallelogramm wird nun an folgenden koordinaten gezeichnet:
(0,0,0); (0.5,0,0); (0.3,0.5,0); (-0.2,0.5,0);



kurze Übersicht der Körper die ihr damit einfach zeichnen könnt:

Würfel
Quader
Pyramide
Pyramidenstumpf
Trapez-Körper
Parallelogramm-Körper

Kugel
Kegel
Zylinder




ihr könnt auch Flächen zeichnen...

Quadrat
Rechteck
Dreieck
Trapez
Parallelogramm





mit Kommentaren bin ich noch relativ unbeholfen, daher ist sie wahrscheinlich eher schlecht als recht kommentiert.
Ich arbeite weiter und versuche noch andere Körper hinzuzufügen.




Über euer feedback würdsch mich sehr freuen

Greetz
Seawolf


seawolf - Fr 08.12.06 11:48



ub60 - So 10.12.06 14:28

Hallo seawolf,

der Code sieht ja erst mal sehr verheißungsvoll aus.
Könntest Du evtl. mal ein kleines Demoprojekt (Quelltext) mit anhängen, damit man gleich mal richtig "loslegen" kann, ohne sich groß einzuarbeiten?

ub60


seawolf - Di 12.12.06 14:02

Hi hier ma der Quelltext eines kleinen Demoprojekts womit ich z.Zt. paar amtrix-Übungen mach ^^


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:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, AppEvnts, ExtCtrls, dglopengl, glbmp, koerper_draw, texture_load_glbmp;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    ApplicationEvents1: TApplicationEvents;
    procedure Timer1Timer(Sender: TObject);
    procedure ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure render;
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    DC    : HDC; //DeviceContext
    RC    : HGLRC; //RenderingContext

    timefactor : double;
    fps : integer;

    texloader:tex_loader_glbmp; //tex_loader_glbmp ist klasse aus Unit texture_load_glbmp
    formen:koerper; //Koerper ist Klasse aus der Unit koerper_draw

    texture, texture2, texture3:tglbmp; //variablen für die texturen

    dreh:single; //variable für die Drehung der drei Würfel
  end;

var
  Form1: TForm1;

implementation


{$R *.dfm}


procedure TForm1.FormCreate(Sender: TObject);
begin
 dreh:=0;

 timefactor :=0.05//Standart-timefaktor bis zur ersten Fps Messung
 fps :=1;

 //OpenGl initialisieren und festlegen von extentitiellen Sachen
 InitOpenGL;

 DC:=GetDC(form1.Handle);
 RC:=CreateRenderingContext(DC, [opDoubleBuffered], 32240000);
 ActivateRenderingContext(DC, RC);

 glEnable(GL_LINE_SMOOTH);
 glEnable(GL_TEXTURE_2D);
 glDepthFunc(GL_LEQUAL);
 glEnable(GL_DEPTH_TEST);
 glenable(gl_cull_face);
 glcullface(gl_front);

 texloader:=tex_loader_glbmp.Create; //Meine Texturenladeklasse createn
 formen:=koerper.create; //Meine Koerperklasse createn

//Texturen laden, hab da auch meine eigene Unit geschrieben, ladehier Texturen mit GLBmp 
 texture:=texloader.load_tex_2D_RGBA_NOSPHERE_GLBMP('.\verschiedene Texturen\Holzkiste04.JPG');
 texture2:=texloader.load_tex_2D_RGBA_NOSPHERE_GLBMP('.\verschiedene Texturen\crashing_electrolites.jpg');
 texture3:=texloader.load_tex_2D_RGBA_NOSPHERE_GLBMP('.\verschiedene Texturen\Holzlatten07.JPG');


end;





procedure TForm1.render;
begin
 fps:=fps+1;
 glViewport(00, ClientWidth, ClientHeight);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity;
 gluPerspective(45, ClientWidth/ClientHeight, 0.51000);
 glMatrixMode(GL_Modelview);
 glLoadIdentity;
 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

 gltranslatef(0,0,-2); // alles um 2 nach hinten verschieben

 //Linker würfel
 glpushmatrix;
  gltranslatef(-0.5,0,0);//Position links
  glrotatef(dreh,1,1,1);//dreh-grad um alle Achsen drehen
  texture.Bind;//erste texture auf Würfel legen
  formen.wuerfel(0.3);// Würfel zeichnen koerper.wuerfel(site_length)
 glpopmatrix;

 //Rechter Würfel
 glpushmatrix;
  gltranslatef(+0.5,0,0);//Position rechts
  glrotatef(dreh,1,1,1);//dreh-grad um alle Achsen drehen
  texture2.Bind;//zweite texture auf Würfel legen
  formen.wuerfel(0.3);// Würfel zeichnen koerper.wuerfel(site_length)
 glpopmatrix;

 //Mittlerer Würfel
 glpushmatrix;
  glrotatef(dreh,1,1,1);//dreh-grad um alle Achsen drehen
  texture3.Bind;//dritte texture auf Würfel legen
  formen.wuerfel(0.3);// Würfel zeichnen koerper.wuerfel(site_length)
 glpopmatrix;



 Swapbuffers(dc); //ausgabe auf bildschirm
 
 
 dreh:=dreh+0.05+(1*timefactor);//Drehung den Fps anpassen
 if dreh>=360 then
 begin
  dreh:=0;//if schleife notwendig um zu hohe werte für den Datentyp zu vermeiden
 end;
end;








procedure TForm1.ApplicationEvents1Idle(Sender: TObject;
  var Done: Boolean);
begin
 render;//---> enthält alles was gerendert wird
 done:=false;
end;


//Meine Fps Ausgabe funktion
procedure TForm1.Timer1Timer(Sender: TObject);
var
stri:string;
begin
 str(fps,stri);
 form1.Caption:= stri;
 timefactor := 40 / fps*2;
 fps := 0;
end;

//Alles auf neue Größe anpassen
procedure TForm1.FormResize(Sender: TObject);
begin
 if HandleAllocated then
 begin
 glViewport(00, ClientWidth, ClientHeight);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity;
 gluPerspective(45, ClientWidth/ClientHeight, 0.11000);
 end;
end;

//Deinitialisieren von Opengl bei "brutalem" Schliessen des Fensters
procedure TForm1.FormDestroy(Sender: TObject);
begin
 DeactivateRenderingContext;
 wglDeleteContext(RC);
 ReleaseDC(Handle, DC);
end;

//Deinitialisieren von Opengl bei Beenden des Progs
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 DeactivateRenderingContext;
 wglDeleteContext(RC);
 ReleaseDC(Handle, DC);
end;




end.


im Anhang hab ich ma mein "RumProbierProgramm" beigelegt.

Greetz
Seawolf

//EDIT: Wenn ich hier endlich ma Delphi hab zeig ich euch noch d2 andere Körper wo des dann mit "Diffi" schöner zum Ausdruck kommt, spätestens nächstes We werd ich des hier ma schreiben.


F34r0fTh3D4rk - Di 12.12.06 20:21

schön wäre es, wenn du noch die normalen berechnen und an opengl übergeben würdest ;)
positionen wären auch was nettes, dann erspart man sich die ganzen pushes und pops sowie das ganze translate und wenn du da schon bei bist kannst du auch rotationen mit rein nehmen ;)

und die quadrics die du für zylinder und kugeln brauchst kannst du auch direkt im code erstellen, das ist irgendwie komfortabler:

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:
procedure DrawCylinder(aCylinder: TCylinder);
var
  quad: PGLUQuadric;
begin
  with aCylinder do
  begin
    quad := gluNewQuadric;
    try
      gluQuadricTexture(quad, true);
      glPushMatrix();
        glTranslatef(position.x, position.y * 2, position.z);
        glRotatef(90100);
        gluCylinder(quad, radius, radius, height, detail, detail);
      glpopmatrix;
    finally
      gluDeleteQuadric(quad);
    end;
  end;
end;

procedure DrawSphere(aSphere: TSphere);
var
  quad: PGLUQuadric;
begin
  with aSphere do
  begin
    quad := gluNewQuadric;
    try
      gluQuadricTexture(quad, true);
      glPushMatrix();
        glTranslatef(position.x, position.y, position.z);
        gluSphere(quad, radius, detail, detail);
      glpopmatrix;
    finally
      gluDeleteQuadric(quad);
    end;
  end;
end;


mfg


seawolf - Di 12.12.06 20:55

Hi

hier erstma der Code wo man sich die variable Diffi genauer anschauen kann ;-)
habe noch 2 neue texturen hinzu genommen derr rets entspricht dem vorherigen code. Datei siehe Anhang.

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:
procedure TForm1.render;
begin
 fps:=fps+1;
 glViewport(00, ClientWidth, ClientHeight);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity;
 gluPerspective(45, ClientWidth/ClientHeight, 0.51000);
 glMatrixMode(GL_Modelview);
 glLoadIdentity;
 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  gltranslatef(0,0,-2);

 glpushmatrix;
  gltranslatef(-0.7,0,0);
  glrotatef(dreh/2,1,0,0);
  texture.Bind;
  formen.trapez_koerper(0.5,0.4,0.5,0.2);//width,height,deep,diffi - Diffi bestimmt wie weit die Oberen Punkte der Seiten eingerückt werden
 glpopmatrix;

 glpushmatrix;
  gltranslatef(+0.7,0,0);
  glrotatef(dreh/2,0,1,0);
  texture2.Bind;
  gldisable(gl_cull_face);
  formen.para_rect_noFrontBack(0.3,0.5,0.3,0.1);//width,height,deep,diffi - hier bestimmt diffi die schräglage des Parallelogramms
  glenable(gl_cull_face);
 glpopmatrix;

 //Minihaus zeichnen
 glpushmatrix;
  //"Grundform"
  glrotatef(dreh/2,0,1,0);
  texture3.Bind;
  formen.quader(0.4,0.2,0.3);

  //zu gespitztes Dach
  gltranslatef(0,0.2,0);
  texture4.bind;
  formen.dach_trapez(0.4,0.2,0.3,0.1);//width,height,deep,diffi - Hier bestimmt diffi wie weit die Spitze der Dreiecke des dachs eingerückt werden

  //Schornstein
  gltranslatef(0.05,0.1,0.05);
  texture5.Bind;
  formen.quader(0.05,0.2,0.05);
 glpopmatrix;



 Swapbuffers(dc); //ausgabe auf bildschirm
 
 dreh:=dreh+0.05+(1*timefactor);
 if dreh>=2160 then
 begin
  dreh:=0;
 end;
end;


@F34rofTh3D4rk: das mit den Positionen und der Rotation is ne Supa Idee danke werd ich morgen mal einbauen :-D, was die Normalen angeht so weis ich nicht wirklich wie man die berechnet. Hatte die mir ma vor einiger Zeit angesehn aber habs nich vertsanden und immo wegen weniger zeit schleifen lassen :-(. kannst du mir erklären wofür die gebraucht werden und wie die Berechnung genau funktioniert? Danke.

Greetz
Seawolf


F34r0fTh3D4rk - Di 12.12.06 22:10

mach doch statt deinen ganzen flächen ein objekt mit vier ecken oder gleich ein polygon dass mittels TriangleFan oder strip oder wie auch immer gezeichnet wird, weil ich glaube net, dass jemand solche funktionen wie für das trapez gut gebrauchen kann.

du kannst noch diverse nurbs einbauen, dazu zähle ich auch rotationskörper über eine funktion.