Kamera (1): Unterschied zwischen den Versionen
Andyh (Diskussion | Beiträge) |
DGLBot (Diskussion | Beiträge) K (Der Ausdruck ''<pascal>(.*?)</pascal>'' wurde ersetzt mit ''<source lang="pascal">$1</source>''.) |
||
Zeile 36: | Zeile 36: | ||
FxRot und FyRot müssen mit 0 initialisiert werden. | FxRot und FyRot müssen mit 0 initialisiert werden. | ||
− | <pascal> | + | <source lang="pascal"> |
unit Example; | unit Example; | ||
Zeile 99: | Zeile 99: | ||
{$R *.dfm} | {$R *.dfm} | ||
{$R cursors.res} | {$R cursors.res} | ||
− | </ | + | </source> |
− | <pascal> | + | <source lang="pascal"> |
procedure TFExample.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); | procedure TFExample.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); | ||
begin | begin | ||
Zeile 137: | Zeile 137: | ||
FyRot := 0; | FyRot := 0; | ||
end; | end; | ||
− | </ | + | </source> |
− | <pascal> | + | <source lang="pascal"> |
procedure TFExample.FormMouseDown(Sender: TObject; Button: TMouseButton; | procedure TFExample.FormMouseDown(Sender: TObject; Button: TMouseButton; | ||
Shift: TShiftState; X, Y: Integer); | Shift: TShiftState; X, Y: Integer); | ||
Zeile 165: | Zeile 165: | ||
FMousePressY := Y; | FMousePressY := Y; | ||
end; | end; | ||
− | </ | + | </source> |
− | <pascal> | + | <source lang="pascal"> |
procedure TFExample.FormMouseUp(Sender: TObject; Button: TMouseButton; | procedure TFExample.FormMouseUp(Sender: TObject; Button: TMouseButton; | ||
Shift: TShiftState; X, Y: Integer); | Shift: TShiftState; X, Y: Integer); | ||
Zeile 181: | Zeile 181: | ||
Screen.Cursor := crCursorSelect; | Screen.Cursor := crCursorSelect; | ||
end; | end; | ||
− | </ | + | </source> |
− | <pascal> | + | <source lang="pascal"> |
procedure TFExample.FormCreate(Sender: TObject); | procedure TFExample.FormCreate(Sender: TObject); | ||
resourcestring | resourcestring | ||
Zeile 230: | Zeile 230: | ||
FCamera := TCamera.Create; | FCamera := TCamera.Create; | ||
end; | end; | ||
− | </ | + | </source> |
Das mit den unterschiedlichen Cursordarstellungen habe ich nur als Hinweis gelassen. Diese Anweisungen müsst Ihr rausnehmen es sei denn, dass Ihr eine Resourcendatei mit drei unterschiedlichen Cursorarten erstellt und sie unter "Cursors.res" abspeichert. | Das mit den unterschiedlichen Cursordarstellungen habe ich nur als Hinweis gelassen. Diese Anweisungen müsst Ihr rausnehmen es sei denn, dass Ihr eine Resourcendatei mit drei unterschiedlichen Cursorarten erstellt und sie unter "Cursors.res" abspeichert. | ||
Zeile 258: | Zeile 258: | ||
usw. | usw. | ||
− | <pascal> | + | <source lang="pascal"> |
procedure TFExample.Render; // wird aus der Methode Paint aufgerufen | procedure TFExample.Render; // wird aus der Methode Paint aufgerufen | ||
resourcestring | resourcestring | ||
Zeile 288: | Zeile 288: | ||
end; | end; | ||
end; | end; | ||
− | </ | + | </source> |
Den Kameracode findet ihr unter [[Kamera (2)]].<br> | Den Kameracode findet ihr unter [[Kamera (2)]].<br> |
Version vom 10. März 2009, 19:05 Uhr
Danke
Nachdem ich viel Zeit damit verbracht habe, eine funktionierende Kamera zu bauen und es nun endlich geschafft habe, wollte ich diese Funktionalität auch Anderen zur Verfügung stellen. Da mir schon viel geholfen wurde, kann ich so einen Teil meiner "Schuld" zurück zahlen.
Bitte seht ab und zu mal hier nach, ob es für diese Kamera Updates gibt. Sollte es so sein, habe ich das im Code (Kamera (2)) vermerkt. Ladet in diesem Fall bitte den Source Code der Kamera und(!) die Utilities herunter.
Meine Kamera
Die wie folgend beschriebene Kamera kann sich um alle drei Achsen drehen und sich in allen Ebenen bewegen. Der Drehpunkt um den sich die Kamera dreht wird mit dem Aufruf der Prozedur PositionCamera festgelegt. Sollte man diesen Drehpunkt benötigen (z.B. zum Anzeigen eines Koordinatenkreuzes, ...), so kann man auf die Property PointOfRotation zugreifen (read only).
Die Kamera kann bis zu zehn Positionen speichern und auch wiederherstellen. (SavePosition, RestorePosition)
Die Kamera kann sich selber zu jeder Zeit unter Beibehaltung der aktuellen Position senkrecht zur Welt ausrichten. (Adjust)
Um sicher zu sein, dass auch alle nötigen Definitionen und Funktionen zur Verfügung stehen, habe ich einfach mal einen Großteil meiner Funktionssammlung beigefügt (Kamera (3)). Diese Funktionen/Prozeduren werden so oder in leicht abgeänderter Form wohl bei jedem OpenGL Programmierer existieren.
Sollte es noch irgendwelche Fragen zu diesem Modul geben, so stehe ich gerne zur Verfügung.
Gebrauch der Funktionen:
Die hier vorzufindende Beschreibung stellt keine komplette Anleitung für die Verwendung der Kamera dar. Um bis in die "Tiefen" des Objekts hinabzusteigen seht Euch bitte das von mir bereit gestellte Beispielprogramm an (Kamera). Wenn Ihr das herunterladet habt Ihr auch auf jeden Fall die neueste Version der Sourcen, die ich zuletzt am 26.12.2007 aktualisert habe. Diese Sourcen vereinfachen die Verarbeitung von Tastatur- und Mausevents. Die u.a. Anleitung entspricht daher nicht mehr dem aktuellen vorgehen, kann aber auch weiterhin so angewendet werden.
1. PositionCamera mit Vektoren für Position, Blickpunkt und Ausrichtung aufrufen. Die Blickrichtung gibt auch gleichzeitig den Drehpunkt der Szene an, um den dann mit RotateCamera gedreht werden kann. PositionCamera positioniert den angegebenen Blickpunkt in der Mitte des Bildschirms. PositionCamera sollte nur zur Positionierung der Kamera benutzt werden, also einmal am Anfang. Alle weiteren Kameraveränderungen sollten mit den zur Verfügung gestellten Methoden durchgeführt werden.
2. Aufruf der Funktionen RotateCamera und TranslateCamera um die Ausrichtung/Lage der Kamera zu verändern. Um das unten angegebene Beispiel implementieren zu können, müssen folgende Variablen im aktuellen Modul definiert werden:
FMousePosX, FMousePosY, FMousePressX, FMousePressY, FRightMousePressed, FLeftMousePressed, FxDelta, FyDelta, FxStart, FyStart, FxRot und FyRot (sind alle als var im aktuellen Modul definiert)
FRightMousePressed und FLeftMousePressed müssen in der Prozedur MouseDown/MouseUp gesetzt werden.
FxRot und FyRot müssen mit 0 initialisiert werden.
unit Example;
interface
uses
Windows, ...
type
TFExample = class(TForm)
.
.
.
private
FCamera: TCamera;
FglDC: HDC; // device context der aktuellen komponente
FglRC: HGLRC; // rendering kontext der aktuellen komponente
ClearAlpha: GLclampd; // alpha wert der hintergrundfarbe
ClearRed: GLclampd; // rotanteil der hintergrundfarbe
ClearGreen: GLclampd; // grünanteil der hintergrundfarbe
ClearBlue: GLclampd; // blauanteil der hintergrundfarbe
public
.
.
.
published
.
.
.
var
FExample: TFExample;
FxStart, // berechnung der mausbewegungen.
FxDelta, // delta = aktuelle position minus start
FyStart, // start wird erfasst sobald eine maustaste
FyDelta:integer; // gedrückt wird.
FxRot, // umrechnung von delta in rotation wenn
FyRot:double; // drehung gewünscht ist (je nach taste)
FMousePressX, // aktuelle mausposition, wenn maustaste gedrückt wird
FMousePressY: integer;
FMousePosX, // aktuelle mausposition
FMousePosY: integer;
//mausaktivität überprüfen
FRightMousePressed:boolean; // ist die rechte maustaste gedrückt?
FLeftMousePressed:boolean; // ist die linke maustaste gedrückt?
const
crCursorMove = 1;
crCursorRotate = 2;
crCursorSelect = 3;
implementation
uses ...
{$R *.dfm}
{$R cursors.res}
procedure TFExample.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
// mausposition merken
FMousePosX := X;
FMousePosY := Y;
//das Ziehen der Szene kann nur bei gedrückter Maustaste passieren
if not (FRightMousePressed or FLeftMousePressed) then exit;
//ausrechenen um wieviel der Mauszeiger bewegt wurde
FxDelta := FxStart-X;
FyDelta := FyStart-Y;
//Rotation anpassen, damit es nicht zu schnell wird
FxRot := FxRot - FyDelta/20;
Fyrot := FyRot - FxDelta/20;
//das naechste mal ist das hier unser startpunkt:
FxStart := X;
FyStart := Y;
if FRightMousePressed then
begin
if FxRot <> 0 then FCamera.RotateCamera (FxRot, 0, 0);
if FyRot <> 0 then FCamera.RotateCamera (0, FyRot, 0);
end;
if FLeftMousePressed then
begin
if FxRot <> 0 then FCamera.TranslateCamera (FxRot, 0, 0);
if FyRot <> 0 then FCamera.TranslateCamera (0, FyRot, 0);
end;
Paint;
FxRot := 0;
FyRot := 0;
end;
procedure TFExample.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbRight then
begin
//rechte maustaste gedrückt
FRightMousePressed:=true;
//Startposition merken
FxStart:=X;
FyStart:=Y;
Screen.Cursor := crCursorRotate;
end
else if Button = mbLeft then
begin
//rechte maustaste gedrückt
FLeftMousePressed:=true;
//Startposition merken
FxStart:=X;
FyStart:=Y;
Screen.Cursor := crCursorMove;
end;
// aktuelle Mouseposition festhalten. so kann z.B. überprüft werden
// welches Objekt an der aktuellen Mausposition liegt
FMousePressX := X;
FMousePressY := Y;
end;
procedure TFExample.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbRight then
begin
FRightMousePressed:=false;
end;
if Button = mbLeft then
begin
FLeftMousePressed:=false;
end;
if not (FRightMousePressed or FLeftMousePressed) then
Screen.Cursor := crCursorSelect;
end;
procedure TFExample.FormCreate(Sender: TObject);
resourcestring
ResStrRCfailed = 'CreateRenderingContext failed ';
ResStrWGLfailed = 'wglMakeCurrent failed ';
begin
inherited;
// wenn das grafiksystem von OpenGL nicht aktiviert werden kann,
// müssen wir das programm beenden
if not InitOpenGL then
begin
raise Exception.Create('InitOpenGL failed '+IntToStr(GetLastError));
halt (100);
end;
FglDC := getDC(self.WindowHandle);
FglRC := CreateRenderingContext(FglDC,
[opDoubleBuffered],
32, 24, 0,0,0,0);
if FglRC=0 then
begin
raise Exception.Create(ResStrRCfailed + IntToStr(GetLastError));
halt (100);
end;
if not wglMakeCurrent(FglDC, FglRC) then
raise Exception.Create(ResStrWGLfailed + IntToStr(GetLastError));
FxRot:=0;
FyRot:=0;
FRightMousePressed := false;
FLeftMousePressed := false;
Screen.Cursors[crCursorMove] := LoadCursor(HInstance,'MOVE');
Screen.Cursors[crCursorRotate] := LoadCursor(HInstance,'ROTATE');
Screen.Cursors[crCursorSelect] := LoadCursor(HInstance,'SELECT');
Screen.Cursor := crCursorSelect;
ClearAlpha := 1; // bildschirm immer mit weiß löschen
ClearRed:= 1; // bildschirm immer mit weiß löschen
ClearGreen:= 1; // bildschirm immer mit weiß löschen
ClearBlue:= 1; // bildschirm immer mit weiß löschen
FCamera := TCamera.Create;
end;
Das mit den unterschiedlichen Cursordarstellungen habe ich nur als Hinweis gelassen. Diese Anweisungen müsst Ihr rausnehmen es sei denn, dass Ihr eine Resourcendatei mit drei unterschiedlichen Cursorarten erstellt und sie unter "Cursors.res" abspeichert.
Dieses Beispiel ist vereinfacht dargestellt und es ist sehr wahrscheinlich, dass Ihr daran noch etwas herumspielen müsst. Ich habe noch das Mausrad eingesetzt um in den Bildschirm hinein- oder aus ihm herauszuzoomen (TranslateCamera(0,0,?)). Durch modifizieren der Geschwindigkeit (+/-) für die einzelnen Achsen, die an die Prozeduren TranslateCamera und RotateCamera übergeben werden kann man entweder die Szene oder die Kamera bewegen.
3. Szene zeichnen:
Lichteigenschaften setzen
Materialeigenschaften setzen
... (die üblichen Vorbereitungen treffen)
FCamera.Apply
Szene zeichnen
wenn Terrain gewünscht:
FCamera.ApplyForTerrain Terrain zeichnen
ende wenn
Swapbuffers...
usw.
procedure TFExample.Render; // wird aus der Methode Paint aufgerufen
resourcestring
RestStrWGLfailed = 'TFExample.Render: wglMakeCurrent failed with ';
begin
// da mehrere fenster möglich sind, muss immer der aktuelle
// ausgabekontext ausgewählt werden
if wglMakeCurrent(FglDC,FglRC) then
begin
glMatrixMode (GL_MODELVIEW);
glClearColor(ClearRed, ClearGreen, ClearBlue, ClearAlpha);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
// View setzen
Camera1.Apply;
// Szene jetzt zeichnen
glFlush; // bearbeitung der GL-befehle beginnen
glFinish; // warten bis alle befehle ausgeführt sind
SwapBuffers(FglDC); // flackern verhindern
end
else
begin
raise Exception.Create(RestStrWGLfailed + IntToStr(GetLastError));
end;
end;
Den Kameracode findet ihr unter Kamera (2).
Die verwendete Toolsammlung findet ihr unter Kamera (3).