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

Aktuelle Zeit: Sa Jul 05, 2025 11:09

Foren-Übersicht » Programmierung » Einsteiger-Fragen
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 22 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Autor Nachricht
 Betreff des Beitrags: Rotation wie in CATIA / GLC Player
BeitragVerfasst: Fr Okt 08, 2010 13:06 
Offline
DGL Member

Registriert: Do Mär 05, 2009 20:17
Beiträge: 284
Wohnort: Kaiserslautern
Hallo,

für meinen Betrachter wünsche ich mir eigentlich schon immer eine Rotation wie in der Konstruktions Software CATIA.
Leider habe ich das nie hinbekommen, und es ist auch etwas schwer zu beschreiben wie diese Rotation genau funktioniert.

Jetzt habe ich vor kurzem einen Modell Viewer gefunden, der genau wie CATIA rotiert und das tolle dabei ist, es ist ein open source projekt namens

GLC Player.

Man kann den Player sowie den code hier downloaden.
Das Gute ist ja schonmal das wohl OpenGL verwendet wird, von daher ist es vielleicht für den ein oder anderen hier interessant anzuschauen...
Leider ist das Programm größtenteils in C++ geschrieben und ich scheitere schon in den hunderten von .h und .cpp Datein am Finden der richtigen Stelle.

Was ich genau suche habe ich hier mal in einem gif festgehalten:

Bild

Das Geniale bei dieser Art der Rotation ist, das man das "Gefühl" hat eine Glaskugel zu drehen oder einen Ball. Meine Erfahrung zeigt, das sich Menschen, die sonst nicht mit 3D Software arbeiten damit intuitiv zurechtfinden.

Wenn also jemand von euch eine solche Rotation für delphi hat, oder Lust hat sie aus dem gegebenen C++ source code auszugraben wäre das quasi wie Weihnachten für mich!

liebe Grüße

Wölfchen


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 13:17 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Ich verwende eine derartige Rotation auch in UltimateConquest. Genau genommen ist es nicht genau diese Variante, sondern die meiner Meinung nach bessere stabilisierte Variante.

*snip
Code:
/**
 * Copyright 2009 Martin Weusten (spam 'at' martin-weusten 'dot' de)
 *
 * This file is part of WGT and published under the terms of the
 * GNU Public License (GPL) Version 3.0.
 *
 * WGT is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * WGT is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with WGT. If not, see <http://www.gnu.org/licenses/>.
 */

package com.delphigl.wgt.scene;

import com.delphigl.wgt.math.*;
import com.delphigl.wgt.WebGL;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.delphigl.wgt.Log;
import com.delphigl.wgt.InputManager;

public class SphereCamera extends Camera {
   private static final double SQRT_2 = Math.sqrt(2.0);
   private static final double MAX_LATITUDE = 0.45*Math.PI;
   private static final double MAX_ZOOM = 20.0;
   private static final double MIN_ZOOM = 2.0;

   private double newLookAtSpeed = 3.0;
   private double movementSpeed = 0.4;
   private double longitude = 1;
   private double latitude = 0.5;
   private double zoom = 5;
   private double distance = Math.pow(2, zoom);

   private Vector3d up = new Vector3d(0,1,0);
   private Vector3d currentEye = new Vector3d(2,0,0);
   private Vector3d currentLookAt = new Vector3d(0,0,0);
   private Vector3d targetLookAt = currentLookAt;

   private Vector2i viewport;
   private Vector2i oldCursor = null;

   private SceneObject hoverObject = null;

   private static InputManager im = InputManager.getInstance();

   public SphereCamera() {
      update(0.0);
   }

   public Vector3d getCurrentEye() {
      return currentEye;
   }

   public Vector3d getCurrentLookAt() {
      return currentLookAt;
   }

   public SceneObject getHoverObject() {
      return hoverObject;
   }

   public void setTargetLookAt(Vector3d targetLookAt) {
      this.targetLookAt = targetLookAt;
   }

   public Vector3d getTargetLookAt() {
      return targetLookAt;
   }

   public void update(double timeElapsed) {
      viewport = WebGL.getInstance().getFramebufferSize();

      updateZoom();
      updateMovement(timeElapsed);
      updateLongitudeAndLatitude();

      Vector3d moveDir = targetLookAt.sub(currentLookAt);
      double moveScale = newLookAtSpeed * timeElapsed;
      if (moveScale > 1) { moveScale = 1; }
      currentLookAt = currentLookAt.add(moveDir.scale(moveScale));
      double sinLong = Math.sin(longitude);
      double cosLong = Math.cos(longitude);
      double sinLat = Math.sin(latitude);
      double cosLat = Math.cos(latitude);
      currentEye = currentLookAt.add(new Vector3d( distance * cosLat * cosLong,
                                                   distance * sinLat,
                                                   distance * cosLat * sinLong  ));
      view = Matrix44d.lookAt(currentEye, currentLookAt, up);
      projection = Matrix44d.perspective(45.0, (double)viewport.x/viewport.y, 0.2, 500.0);

      extractFrustum();
   }

   public void set() {
      MatrixStack.loadView(view);
      MatrixStack.loadProjection(projection);
   }

   private void updateZoom() {
      int wheelDelta = im.getWheelDelta(true);
      if (wheelDelta == 0) { return; }
      zoom += wheelDelta / 20.0;
      if (zoom < MIN_ZOOM) { zoom = MIN_ZOOM; }
      if (zoom > MAX_ZOOM) { zoom = MAX_ZOOM; }
      distance = Math.pow(2, zoom);
   }

   private void updateMovement(double timeElapsed) {
      if (sceneView != null) {
         Ray ray = im.getCursorRay(projection, view);
         hoverObject = sceneView.rayCast(ray);
      }
      else {
         hoverObject = null;
      }

      if (im.isKeyDown(NativeEvent.BUTTON_LEFT)) {
         if (hoverObject != null) {
            targetLookAt = hoverObject.getPosition();
         }
      }
      else {
         double move = distance * movementSpeed * timeElapsed;
         Vector3d leftMove = up.cross(currentLookAt.sub(currentEye)).normalized();
         Vector3d frontMove = leftMove.cross(up).normalized();
         frontMove = frontMove.scale(move);
         leftMove = leftMove.scale(move);
         Vector3d upMove = up.scale(move);

         boolean forward = im.isKeyDown('W');
         boolean backward = im.isKeyDown('S');
         boolean leftward = im.isKeyDown('A');
         boolean rightward = im.isKeyDown('D');
         boolean upward = im.isKeyDown('Q');
         boolean downward = im.isKeyDown('E');

         if (forward && backward)   { im.resetKey('W'); im.resetKey('S'); forward = backward = false;   }
         if (leftward && rightward) { im.resetKey('A'); im.resetKey('D'); leftward = rightward = false; }
         if (upward && downward)    { im.resetKey('Q'); im.resetKey('E'); upward = downward = false;    }

         if      (forward  ) { currentLookAt = currentLookAt.add(frontMove); targetLookAt = currentLookAt; }
         else if (backward ) { currentLookAt = currentLookAt.sub(frontMove); targetLookAt = currentLookAt; }
         if      (leftward ) { currentLookAt = currentLookAt.add(leftMove);  targetLookAt = currentLookAt; }
         else if (rightward) { currentLookAt = currentLookAt.sub(leftMove);  targetLookAt = currentLookAt; }
         if      (upward   ) { currentLookAt = currentLookAt.add(upMove);    targetLookAt = currentLookAt; }
         else if (downward ) { currentLookAt = currentLookAt.sub(upMove);    targetLookAt = currentLookAt; }
      }
   }

   private void updateLongitudeAndLatitude() {
      if (   !im.isKeyDown(KeyCodes.KEY_CTRL)
          && !im.isKeyDown(NativeEvent.BUTTON_RIGHT) ) {
         oldCursor = null;
         return;
      }
      Vector2i newCursor = im.getCursor();
      Vector3d n = mapToSphere(newCursor);
      Vector3d o = mapToSphere(oldCursor);
      if (o == null || n == null) {
         oldCursor = newCursor;
         return;
      }
   
      double diffLong = acosStable((o.x*n.x + o.z*n.z) / (Math.sqrt(o.x*o.x + o.z*o.z) * Math.sqrt(n.x*n.x + n.z*n.z)));
      double diffLat  = acosStable((o.y*n.y + o.z*n.z) / (Math.sqrt(o.y*o.y + o.z*o.z) * Math.sqrt(n.y*n.y + n.z*n.z)));
      longitude += 1.5 * ((o.x > n.x) ? -diffLong : diffLong);
      latitude  += 1.5 * ((o.y > n.y) ? -diffLat  : diffLat);
      if (longitude < 0) { longitude += 2*Math.PI; }
      if (longitude >= 2*Math.PI) { longitude -= 2*Math.PI; }
      if (latitude < -MAX_LATITUDE) { latitude = -MAX_LATITUDE; }
      if (latitude >  MAX_LATITUDE) { latitude =  MAX_LATITUDE; }
      oldCursor = newCursor;
   }

   private double acosStable(double x) {
      if (x < -1) { return Math.PI; }
      if (x >  1) { return 0;       }
      return Math.acos(x);
   }

   private Vector3d mapToSphere(Vector2i cursor) {
      if (   cursor == null
          || cursor.x < 0 || cursor.x > viewport.x
          || cursor.y < 0 || cursor.y > viewport.y ) {
         return null;
      }
      
      Vector3d cursor3D = new Vector3d();
      // scale viewport to [-sqrt(0.5),sqrt(0.5)]
      cursor3D.x = (double)(cursor.x - 0.5*viewport.x) / (double)viewport.x * SQRT_2;
      cursor3D.y = (double)(cursor.y - 0.5*viewport.y) / (double)viewport.y * SQRT_2;
      // numercially stable sqrt (in case 1-x*x-y*y less than zero!)
      cursor3D.z  = Math.sqrt(Math.max(1 - cursor3D.x*cursor3D.x - cursor3D.y*cursor3D.y, 0));
      cursor3D.normalize();
      return cursor3D;
   }
}

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 13:37 
Offline
DGL Member

Registriert: Do Mär 05, 2009 20:17
Beiträge: 284
Wohnort: Kaiserslautern
hui danke für die schnelle Antwort!

Sieht so aus als hätte die Adventszeit angefangen! Aber C++ kann ich nicht und ehrlich gesagt - ich verstehe nichteinmal Bahnhof.

Ich zeige einfach mal, wie ich zur Zeit rotiere:

Code:
{...}
var RollAxis, TurnAxis, TiltAxis      : TGLVector3f;
{...}


procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin

      TurnAxis := glNormalize(RotateAxis(TurnAxis, TiltAxis,(-OldMousePos.Y + Y)/180*Pi));
      TiltAxis := glNormalize(RotateAxis(TiltAxis, TurnAxis,(OldMousePos.X - X)/180*Pi));

      OldMousePos := Point(X, Y);

{...}
und beim rendern dann:

RollAxis := glVectorProd(TiltAxis, TurnAxis);
    gluLookAt(0,0,0,
            RollAxis[0], RollAxis[1], RollAxis[2],
            TurnAxis[0], TurnAxis[1], TurnAxis[2]);


das funktioniert zwar, und ist auch nicht schlecht, fühlt sich aber nicht so gut an, weil man je nach zoomfaktor schneller oder langsamer dreht als die maus sich bewegt.
echt schwer in worte zu fassen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 13:42 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Aber C++ kann ich nicht und ehrlich gesagt - ich verstehe nichteinmal Bahnhof.

Könnte daran liegen das es sich um Java handelt ;) Abgesehen davon das man statt begin...end eben {...} schreibt ist die Syntax doch fast gleich.

Der Schlüssel liegt in der Methode mapToSphere, weil die Cursor-Koordinaten auf die Kugel abbildet. In updateLongitudeAndLatitude() werden mit Hilfe dieser Methode die Winkel-Differenzen diffLong bzw. diffLat und auf die beiden Winkel longitude bzw. latitude angewendet.
In update() wird mit Hilfe der beiden Winkel und dem Rotationszentrum currentLookAt die Position der Camera currentEye berechnet. Matrix44d.lookAt ist nichts anderes als gluLookAt. Das war es auch schon.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 14:13 
Offline
DGL Member

Registriert: Do Mär 05, 2009 20:17
Beiträge: 284
Wohnort: Kaiserslautern
okay ich bin am basteln, aber was ist:

Code:
viewport = WebGL.getInstance().getFramebufferSize();


macht das das gleiche wie:

Code:
glGetIntegerv(GL_VIEWPORT, @fviewport);


weil bei mir ist fviewport eigentlich ein
Code:
var fViewport     : TGLVectori4;


und bei dir scheinbar nur ein 2D?

Code:
private Vector2i viewport;


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 14:33 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Code:
viewport = WebGL.getInstance().getFramebufferSize();

und bei dir scheinbar nur ein 2D?

Es interessiert hier nur die Höhe und Breite des Viewports, wozu soll man da einen 4D-Vektor benutzen? GL_VIEWPORT liefert ja zusätzlich die Koordinaten der linken unteren Ecke....die sind aber in 99% der Fälle sowieso (0,0). ;)

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 15:16 
Offline
DGL Member

Registriert: Do Mär 05, 2009 20:17
Beiträge: 284
Wohnort: Kaiserslautern
ok das mit dem viewport habe ich dann wohl...

jetzt hänge ich an diesen beiden zeilen:

Code:
     
longitude += 1.5 * ((o.x > n.x) ? -diffLong : diffLong);
latitude  += 1.5 * ((o.y > n.y) ? -diffLat  : diffLat);


+= ist wohl soviel wie longitude := longitude + ... ? (hab ich mal so in c++ gesehen glaub ich)

aber was macht das "?" und der ":"?

(ich hoffe ich nerv nicht zu sehr :roll: )


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 15:26 
Offline
DGL Member

Registriert: Mi Okt 16, 2002 15:06
Beiträge: 1012
Wölfchen hat geschrieben:
ok das mit dem viewport habe ich dann wohl...

jetzt hänge ich an diesen beiden zeilen:

Code:
     
longitude += 1.5 * ((o.x > n.x) ? -diffLong : diffLong);
latitude  += 1.5 * ((o.y > n.y) ? -diffLat  : diffLat);


+= ist wohl soviel wie longitude := longitude + ... ? (hab ich mal so in c++ gesehen glaub ich)

aber was macht das "?" und der ":"?

(ich hoffe ich nerv nicht zu sehr :roll: )


Die ? : syntax in C liefert für eine Boolean expression einen false und true wert zurück.
Bedeutet für die zeile oben:

var
xxx : Single;
begin
if (o.x > n.x)
xxx := -diffLong
else
xxx := diffLong;
longitude := longitude + 1.5 * xxx;
...
end;


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 15:30 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
A ? B : C
Wenn A wahr ist wird B verwendet, ansonsten C. Ist einfach eine Kurzform für if-then-else.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 16:40 
Offline
DGL Member

Registriert: Do Mär 05, 2009 20:17
Beiträge: 284
Wohnort: Kaiserslautern
hmm ich "glaube" soweit hab ichs hinbekommen longitude und latitude zu berechnen...

aber das hier gibt mir neue rätsel auf:

Code:
      currentEye = currentLookAt.add(new Vector3d( distance * cosLat * cosLong,
                                                   distance * sinLat,
                                                   distance * cosLat * sinLong  ));
      view = Matrix44d.lookAt(currentEye, currentLookAt, up);
      projection = Matrix44d.perspective(45.0, (double)viewport.x/viewport.y, 0.2, 500.0);


was macht "distance"? und wie muss ich jetzt glulookat füttern?

sieht immernoch so aus:
Code:
gluLookAt(0,0,0,
            RollAxis[0], RollAxis[1], RollAxis[2],
            TurnAxis[0], TurnAxis[1], TurnAxis[2]);


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 16:49 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
was macht "distance"?

Abstand der Kamera vom Rotationspunkt.

Zitat:
und wie muss ich jetzt glulookat füttern?

Code:
gluLookAt(currentEye.x, currentEye.y, currentEye.z, currentLookAt.x, currentLookAt.y, currentLookAt.z, up.x, up.y, up.z);

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 17:50 
Offline
DGL Member

Registriert: Do Mär 05, 2009 20:17
Beiträge: 284
Wohnort: Kaiserslautern
Coolcat hat geschrieben:
Zitat:
was macht "distance"?

Abstand der Kamera vom Rotationspunkt.

Zitat:
und wie muss ich jetzt glulookat füttern?

Code:
gluLookAt(currentEye.x, currentEye.y, currentEye.z, currentLookAt.x, currentLookAt.y, currentLookAt.z, up.x, up.y, up.z);



da steh ich auf dem Schlauch, ich weiss nicht was currentEye ist oder wie ich es bekomme.

auch aus
Code:
   public Vector3d getCurrentEye() {
      return currentEye;
   }


werd ich nicht schlau... genauso verhält es sich mit currentlookat oder "up".


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 18:25 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
currentlookat ist der Rotationspunkt, der wird von außen gesetzt.

currentEye ist die Position der Kamera. Diese wird hier berechnet:
Code:
 currentEye = currentLookAt.add(new Vector3d( distance * cosLat * cosLong,
                                                   distance * sinLat,
                                                   distance * cosLat * sinLong  ));


Also einfach nur:
Code:
currentEye.x = currentLookAt.x + distance * cosLat * cosLong;
currentEye.y = currentLookAt.y + distance * sinLat;
currentEye.z = currentLookAt.z + distance * cosLat * sinLong;



Edit:
Zitat:
auch aus
Code:
public Vector3d getCurrentEye() {
return currentEye;
}


werd ich nicht schlau...

Das ist ein Getter....die Methode macht nix anderes als den Inhalt einer Variable (eines Attributes um genau zu sein) zurückzugeben. Das verhindert das jemand von außen das Attribut verändern kann. In Delphi gibt es dafür Properties.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 08, 2010 19:11 
Offline
DGL Member

Registriert: Do Mär 05, 2009 20:17
Beiträge: 284
Wohnort: Kaiserslautern
ok keine ahnung ob das currentlookat ist aber ich hab jetzt einfach mal meinen drehpunkt eingesetzt...
Code:
 
    currenteye[0]:= Drehpunkt[0] + ATZ * cosLat * cosLong;
    currenteye[1]:= Drehpunkt[1] + ATZ * sinlong;
    currenteye[2]:= Drehpunkt[2] + ATZ * cosLat * sinLong;


gluLookAt(currentEye[0],currentEye[1],currentEye[2],
              Drehpunkt[0],Drehpunkt[1],Drehpunkt[2],0,1,0);

nun fehlt mir noch "up" - mit 0,1,0 kam ich nicht weit...


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Okt 09, 2010 11:02 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Ich denke nicht das es am Up-Vektor liegt. Da ist irgendwas anderes faul.

Edit: Und ich weiß auch was:
Code:
currenteye[1]:= Drehpunkt[1] + ATZ * sinlong;

=> sinLat

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 22 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Foren-Übersicht » Programmierung » Einsteiger-Fragen


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 17 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:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.010s | 14 Queries | GZIP : On ]