OpenGL Mauskamerasteuerung

Für Probleme bezüglich Grafik, Audio, GL, ACS, ...
Hartkern
Beiträge: 69
Registriert: Sa 5. Dez 2015, 20:03
OS, Lazarus, FPC: Win10 IDE 1.6
CPU-Target: 64Bit
Wohnort: Leipzig

OpenGL Mauskamerasteuerung

Beitrag von Hartkern »

Hallo,

ich hänge fest an meiner "Kamera" Steuerung. Ich versuche diese mit der Maus aus einer Ich Perspektive zu steuern. Jedoch scheitere ich an setzen der Mauscursorpositionen, irgendwann ist die Maus aus dem fenster und nix klappt mehr.
Die Tastenvariante funktioniert dagegen :evil: :cry:

Code: Alles auswählen

procedure tOpenGlKamera.MouseMove(x, y: integer);
var NewCursorPos: TSmallPoint;
begin
 NewCursorPos.x:=x;
 NewCursorPos.y:=y;
 
  if CursorPos.y-NewCursorPos.y>0  then  //hochschauen
     begin
         RotY:=RotY+fRot_speed;
         If RotY>45 then RotY:=45; //Kopf-Nick-Begrenzung
     end;
 
  if  CursorPos.y-NewCursorPos.y<0 then   //Runterschauen
      begin
          RotY:=RotY-fRot_speed;
          If RotY<-45 then RotY:=-45; //Kopf-Nick-Begrenzung
       end;
 
  if  CursorPos.x-NewCursorPos.x>0 then //Rechtsschauen
     begin
          RotZ:=RotZ+fRot_speed;
          If RotZ>360 then RotZ:=360;
     end;
 
  if CursorPos.x-NewCursorPos.x<0 then //Linkschauen
     begin
          RotZ:=RotZ-fRot_speed;
          If RotZ>-360 then RotZ:=-360;
     end;
 
  SetCursorPos(fOpenGLControl.Width div 2,fOpenGLControl.Height div 2); //hier ist die unknackbare Nuss
  CursorPos.X:=fOpenGLControl.Width div 2; //oder hier ist die unknackbare Nuss
  CursorPos.Y:=fOpenGLControl.Height div 2;//könnte auch hier sein
end;   


bei Bedarf zur Verbesserung kann ich meine gesamte Klasse TOpenGlKamera nachreichen.

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OpenGL Mauskamerasteuerung

Beitrag von Mathias »

Auf deinem Code sieht man zu wenig, aber ich habe da eine fertige Lösung, welche du angucken kannst.
Dateianhänge
Wuerfel.zip
(125.78 KiB) 116-mal heruntergeladen
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: OpenGL Mauskamerasteuerung

Beitrag von wp_xyz »

Leider hat diese Lösung wie viele andere in dieser Richtung das Problem, dass die Bedienung bzgl. Drehung irgendwann nicht mehr intuitiv ist. Unter "intuitiv" meine ich: Wenn ich die Maus nach rechts ziehe, dreht sich das Modell um die y-Achse nach rechts. So ist es zu Beginn des Programm, ok. Aber nun starte ich neu und ziehe als erstes die Maus vertikal so lange, bis die grüne Rückseite des Würfels durch Drehung um die x-Achse vorne ist. Ziehe ich jetzt die Maus horizontal, dreht sich der Würfel um die y-Achse (ok), aber entgegengesetzt zur Maus! Noch verrückter ist es, wenn ich nach dem Programmstart den Würfel nur um 90° um die x-Achse drehst (also pink- oder cyan-Fläche vorne). Dann bewirkt eine anschließende horizontale Bewegung der Maus nicht mehr eine Drehung um die y-Achse, sondern um die in den Bildschirm reichende z-Achse. Dieses Verhalten finde ich bei vielen einfachen 3D-Programmen extrem frustrierend.

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OpenGL Mauskamerasteuerung

Beitrag von Mathias »

Meinst du so sei es besser ?
Dateianhänge
Wuerfel.zip
(126.06 KiB) 101-mal heruntergeladen
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: OpenGL Mauskamerasteuerung

Beitrag von wp_xyz »

Hey, sehr gut! Dann kriegst du die nächste Stufe auch noch hin, die Drehung um die z-Achse, bei dir mit der mittleren Maustaste realisiert. Momentan bewirkt ein Ziehen der Maus nach rechts eine Drehung im, nach links entgegen dem Uhrzeigersinn. Ich habe aber die Vorstellung, ich würde mit der Maus einen Teil des Modells anfassen und herumdrehen. Das heißt, das Modell sollte der Bewegung der Maus folgen. Im Modell des Würfels: Fasse ich ihn an der oberen rechten Ecke an und bewege die Maus nach rechts, dreht er sich im Uhrzeigersinn - ok. Jetzt fasse ich die Maus an der unteren linken Ecke an und bewege die Maus nach rechts. Weil Rechtsziehen eine Drehung im Uhrzeigersinn bewirkt, dreht sich der Würfel anders herum als ich mir vorstelle. Das zweite Problem ist die Drehung bei vertikalem Ziehen, das passiert, je nachdem, wie "senkrecht" die Bewegung erfolgt, mehr oder weniger gar nichts. Im Idealfall sollte die Drehung durch den Vektor der Mausbewegung, nicht nur durch die horizontale Distanz bestimmt werden.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: OpenGL Mauskamerasteuerung

Beitrag von wp_xyz »

Ich antworte mal selber: mit diesem Code wird der Drehwinkel berechnet und in deiner Drehroutine eingesetzt:

Code: Alles auswählen

procedure TForm1.OpenGLControl1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: integer);
const
  MoveStep = 1.0 / 100;
  RotStep = 100;
var
  phi1, phi2, dphi: Double;
  ctr: TPoint;
begin
  if Shift = [ssLeft] then begin
    Translate(MyMatrix, (X - MousePos.x) * MoveStep, -(Y - MousePos.y) * MoveStep, 0.0);
  end;
  if Shift = [ssRight] then begin
    RotateB(MyMatrix, -(X - MousePos.x) / RotStep);
    RotateA(MyMatrix, (Y - MousePos.y) / RotStep);
  end;
  if Shift = [ssMiddle] then begin
    ctr := Point(Width div 2, Height div 2);
    phi1 := arctan2(MousePos.Y - ctr.Y, MousePos.X - ctr.X);
    phi2 := arctan2(Y - ctr.Y, X - ctr.X);
    dphi := phi2 - phi1;
    if (phi2 > pi/2) and (phi1 < -pi/2) then
      dphi := 2*pi - dphi
    else
    if (phi1 > pi/2) and (phi2 < -pi/2) then
      dphi := 2*pi + dphi;
    RotateC(MyMatrix, -RadToDeg(dphi) / RotStep);
  end;
 
  MousePos.x := X;
  MousePos.y := Y;
end;
 

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OpenGL Mauskamerasteuerung

Beitrag von Mathias »

Hey, sehr gut! Dann kriegst du die nächste Stufe auch noch hin, die Drehung um die z-Achse, bei dir mit der mittleren Maustaste realisiert.

Ich weiss optimal ist diese nicht.

Aber das du schon eine Lösung hast, werde ich diese bei mir einbauen, danke.
Vielleicht sollte noch erwähnt werden, das die Unit Math eingebunden werden muss.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1496
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OpenGL Mauskamerasteuerung

Beitrag von corpsman »

in meinem MAW Sample ist auch ne MAussteuerung drin, wenn dir die Gefällt, dort wird das ganze mittels Matrizen gemacht, eigentlich auch recht intuitiv *g*
--
Just try it

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OpenGL Mauskamerasteuerung

Beitrag von Mathias »

n meinem MAW Sample

Was meinst du mit MAW ?

dort wird das ganze mittels Matrizen gemacht

Meine Variante geht auch mit Matrixen, oder meinst du was anderes ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1496
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OpenGL Mauskamerasteuerung

Beitrag von corpsman »

hättest du auf MAW geklickt, wärst di hier http://corpsman.de/index.php?doc=opengl/maw rausgekommen ;)

Meine Variante nimmt den OpenGL Stack und manipuliert die Matrix damit, somit sind keine trigonometrischen Routinen notwendig *g*
--
Just try it

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: OpenGL Mauskamerasteuerung

Beitrag von wp_xyz »

Corpsman hat geschrieben:hättest du auf MAW geklickt

Diese eingebetteten Links sind zwar chic, aber nur sehr schwer zu erkennen (zumindest mit Firefox unter Win10). Dazu hatte ich vor kurzem im englischen Forum dasselbe Problem

Corpsman hat geschrieben:wärst di hier http://corpsman.de/index.php?doc=opengl/maw rausgekommen

Da erhält man aber nur eine exe mit Steuerdateien, aber keinen Quellcode. Oder bin ich mal wieder völlig blind?

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OpenGL Mauskamerasteuerung

Beitrag von Mathias »

Diese eingebetteten Links sind zwar chic, aber nur sehr schwer zu erkennen

Genau dies habe ich auch gemerkt, wen ich jetzt genau gucke sehe ich ihn.

Meine Variante nimmt den OpenGL Stack und manipuliert die Matrix damit, somit sind keine trigonometrischen Routinen notwendig *g*

Ich werde mir dies mal angucken. Da ich letzte Zeit mit OpenGL 3.3 arbeitete, musste ich die Matrixen sowieso selbst berechnen.
Wen man mit dem alten OpenGL arbeitet, ist das mit dem Stack sicher sinnvoll.
Ich wollte es erst auch damit versuchen, aber es funktionierte nicht. :wink:

PS: Bei dem MAV Link hat es nur eine EXE, Code sieht man keinen.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1496
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OpenGL Mauskamerasteuerung

Beitrag von corpsman »

*g*

dann hier mal ein Code snippet :

Code: Alles auswählen

Procedure TMarionette.Rotate(ID: Glint; dx, dy, dz: GLfloat);
Begin
  glPushMatrix();
  glLoadIdentity();
  Case ID Of
    1: Begin // Drehung der Gesamtfigur , am Bauch
        glTranslatef(Bauch.rotateMatrix[3, 0], Bauch.rotateMatrix[3, 1], Bauch.rotateMatrix[3, 2]);
        glRotatef(dx, 1.0, 0.0, 0.0);
        glRotatef(dy, 0.0, 1.0, 0.0);
        glRotatef(dz, 0.0, 0.0, 1.0);
        glTranslatef(-Bauch.rotateMatrix[3, 0], -Bauch.rotateMatrix[3, 1], -Bauch.rotateMatrix[3, 2]);
        glMultMatrixf(@Bauch.rotateMatrix[0, 0]);
        glGetFloatv(GL_MODELVIEW_MATRIX, @Bauch.rotateMatrix[0, 0]);
      End;
..
 


Ich hoffe das hilft weiter ;)
--
Just try it

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: OpenGL Mauskamerasteuerung

Beitrag von wp_xyz »

Ich hab die MAW-exe gerade gestartet, aber ich muss sagen: das ist genau die Sorte von 3D-Programm, die ich oben erwähnt habe: Man bewegt die Maus nach links, und die Figur bewegt sich nach rechts.

Hartkern
Beiträge: 69
Registriert: Sa 5. Dez 2015, 20:03
OS, Lazarus, FPC: Win10 IDE 1.6
CPU-Target: 64Bit
Wohnort: Leipzig

Re: OpenGL Mauskamerasteuerung

Beitrag von Hartkern »

Entschuldigung für meine späte Antwort...ich war die letzten Tage damit beschäftigz OpenGl 3.3 zum laufen zu bringen!!! Mein erstes Dreieck..

so.. hier mal meine komplette Kameraklasse...

Code: Alles auswählen

unit uOpemGLKamera;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  ExtCtrls,OpenGLContext, dglOpenGL, math, Windows,video,keyboard;
 
  type
 
    { tKamera }
 
    { tOpenGlKamera }
 
    tOpenGlKamera = class
      private
       fOpenGLControl : TOpenGLControl;
       Matrix : Array[0..15] of glFloat;
       fKey_vor : char;
       fKey_zurueck : char;
       fKey_strafe_links : char;
       fKey_strafe_rechts : char;
       fKey_hoch : char;
       fKey_runter : char;
       fKey_drehen_links : char;
       fKey_drehen_rechts : char;
       fKey_drehen_hoch : char;
       fKey_drehen_runter : char;
       fmovespeed : glFloat;
       fRot_Speed : glFloat;
       pi         : glFloat;
       PosX_Aktuell : glFloat;
       PosY_Aktuell : glFloat;
       PosZ_Aktuell : glFloat;
       RotY, RotZ   : glFloat;
       CursorPos : TSmallPoint;
      public
        constructor create(OGL: TOpenGLControl);
        destructor free;
        procedure Update;       // kommt dorthin wo gerendert wird
        procedure KeyPress(Key : char); // kommt ins OnKeyPress Event des Forms, oder OpenglContext ?
        procedure MouseMove(x,y : integer); //kommt ins On MouseMove Event von OpenGLContext
        procedure SetKey_Bewegung(vor,zurueck,strafe_rechts,strafe_links,hoch,runter : char);   //Wird im Create vorbelegt
        procedure SetKey_Drehung(links, rechts, oben, unten : char); //Wird im Create vorbelegt
        procedure SetMoveSpeed(value : glFloat);   //Wird im Create vorbelegt
        procedure SetRotSpeed(value : glFloat)//Wird im Create vorbelegt
        procedure SetKameraPos(PosX, PosY, PosZ : GLFloat)//Wird im Create vorbelegt
    end;
 
implementation
 
{ tOpenGlKamera }
 
constructor tOpenGlKamera.create(OGL: TOpenGLControl);
begin
       fOpenGLControl:=OGL;
       fKey_vor :='w';
       fKey_zurueck :='s';
       fKey_strafe_links :='a';
       fKey_strafe_rechts :='d';
       fKey_hoch :='q';
       fKey_runter :='e';
       fKey_drehen_links :='f';
       fKey_drehen_rechts :='h';
       fKey_drehen_hoch :='t';
       fKey_drehen_runter :='g';
       fmovespeed:=0.1;
       fRot_Speed :=1.0;
       PosX_Aktuell :=0;
       PosY_Aktuell :=0;
       PosZ_Aktuell :=-15;
       pi := arccos(-1);
       CursorPos.X:=fOpenGLControl.Width;
       CursorPos.Y:=fOpenGLControl.Height;
end;
 
destructor tOpenGlKamera.free;
begin
 
end;
 
procedure tOpenGlKamera.SetKameraPos(PosX, PosY, PosZ : GLFloat);
begin
  PosX_Aktuell :=PosX;
  PosY_Aktuell :=PosY;
  PosZ_Aktuell :=PosZ;
 
end;
 
procedure tOpenGlKamera.Update;
begin
    matrix[0]:=cos(RotZ*pi/180);
    matrix[1]:=sin(RotY*PI/180)*-sin(RotZ*PI/180);
    matrix[2]:=cos(RotY*PI/180)*-sin(RotZ*PI/180);
    matrix[3]:=0;
    matrix[4]:=0;
    matrix[5]:=cos(RotY*PI/180);
    matrix[6]:=-sin(RotY*PI/180);
    matrix[7]:=0;
    matrix[8]:=sin(RotZ*PI/180);
    matrix[9]:=sin(RotY*PI/180)*cos(RotZ*PI/180);
    matrix[10]:=cos(RotY*PI/180)*cos(RotZ*PI/180);
    matrix[11]:=0;
    matrix[12]:=PosX_Aktuell*cos(RotZ*PI/180)+PosZ_Aktuell*sin(RotZ*PI/180);
    matrix[13]:=-PosX_Aktuell*sin(RotY*PI/180)*sin(RotZ*PI/180)+PosZ_Aktuell*sin(RotY*PI/180)*cos(RotZ*PI/180)+PosY_Aktuell*cos(RotY*PI/180);
    matrix[14]:=-PosX_Aktuell*cos(RotY*PI/180)*sin(RotZ*PI/180)+PosZ_Aktuell*cos(RotY*PI/180)*cos(RotZ*PI/180)-PosY_Aktuell*sin(RotY*PI/180);
    matrix[15]:=1;
glLoadMatrixf(matrix);
end;
 
procedure tOpenGlKamera.KeyPress(Key: char);
begin
 
  if Key = fKey_vor then   //Vorwärtsbewegung
  begin
    PosX_Aktuell+=fmovespeed*sin(-RotZ*PI/180);
    PosZ_Aktuell+=fmovespeed*cos(-RotZ*PI/180);
  end;
 
  if Key = fKey_zurueck then //Rückwärtsbewegung
  begin
    PosX_Aktuell-=fmovespeed*sin(-RotZ*PI/180);
    PosZ_Aktuell-=fmovespeed*cos(-RotZ*PI/180);
  end;
 
  if Key = fKey_strafe_links  then //Strafe Links
  begin
     PosX_Aktuell+=fmovespeed*sin((-RotZ+90)*PI/180);
     PosZ_Aktuell+=fmovespeed*cos((-RotZ+90)*PI/180);
  end;
 
  if Key = fKey_strafe_rechts then //Strafe Rechts
  begin
     PosX_Aktuell-=fmovespeed*sin((-RotZ+90)*PI/180);
     PosZ_Aktuell-=fmovespeed*cos((-RotZ+90)*PI/180);
  end;
 
  if Key = fKey_hoch then //Hochschweben
  begin
    PosY_Aktuell-=fmovespeed;
  end;
 
  if Key = fKey_runter then //Runterschweben
  begin
    PosY_Aktuell+=fmovespeed;
  end;
 
  if Key = fKey_drehen_hoch then //Hochschauen
  begin
    RotY:=RotY+fRot_speed;
    If RotY>45 then RotY:=45;
  end;
 
   if Key = fKey_drehen_runter then //Runterschauen
  begin
    RotY:=RotY-fRot_speed;
    If RotY<-45 then RotY:=-45;
  end;
 
   if Key = fKey_drehen_links then //Linkschauen
  begin
    RotZ:=RotZ-fRot_speed;
    If RotZ<-360 then RotZ:=-360;
  end;
 
  if Key = fKey_drehen_rechts then //Rechtsschauen
  begin
    RotZ:=RotZ+fRot_speed;
    If RotZ>360 then RotZ:=360;
  end;
 
end;
 
 
procedure tOpenGlKamera.MouseMove(x, y: integer);
var NewCursorPos: TSmallPoint;
begin
 NewCursorPos.x:=x;
 NewCursorPos.y:=y;
 
  if CursorPos.y-NewCursorPos.y>0  then  //hochschauen
     begin
         RotY:=RotY+fRot_speed;
         If RotY>45 then RotY:=45; //Kopf-Nick-Begrenzung
     end;
 
  if  CursorPos.y-NewCursorPos.y<0 then   //Runterschauen
      begin
          RotY:=RotY-fRot_speed;
          If RotY<-45 then RotY:=-45; //Kopf-Nick-Begrenzung
       end;
 
  if  CursorPos.x-NewCursorPos.x>0 then //Rechtsschauen
     begin
          RotZ:=RotZ+fRot_speed;
          If RotZ>360 then RotZ:=360;
     end;
 
  if CursorPos.x-NewCursorPos.x<0 then //Linkschauen
     begin
          RotZ:=RotZ-fRot_speed;
          If RotZ<-360 then RotZ:=-360;
     end;
 
  SetCursorPos(fOpenGLControl.Width div 2,fOpenGLControl.Height div 2);
  CursorPos.X:=fOpenGLControl.Width div 2;
  CursorPos.Y:=fOpenGLControl.Height div 2;
end;
 
procedure tOpenGlKamera.SetKey_Bewegung(vor, zurueck, strafe_rechts, strafe_links, hoch,
  runter: char);
begin
   fKey_vor :=vor;
   fKey_zurueck :=zurueck;
   fKey_strafe_links :=strafe_links;
   fKey_strafe_rechts :=strafe_rechts;
   fKey_hoch :=hoch;
   fKey_runter :=runter;
end;
 
procedure tOpenGlKamera.SetKey_Drehung(links, rechts, oben, unten: char);
begin
   fKey_drehen_links :=links;
   fKey_drehen_rechts :=rechts;
   fKey_drehen_hoch :=oben;
   fKey_drehen_runter :=unten;
end;
 
procedure tOpenGlKamera.SetMoveSpeed(value: glFloat);
begin
  fmovespeed:=value;
end;
 
procedure tOpenGlKamera.SetRotSpeed(value: glFloat);
begin
  fRot_Speed:=value;
end;
 
 
 
end

Antworten