# j3d Rotation um mehr als eine Achse



## bob_sheknowdas (11. Apr 2012)

Hi,
ich habe folgendes Problem: Ich will ein Objekt um die X- und die Y-Achse drehen. Dabei sollen die Rotation in abhängigkeit zueinander stehen. Ich habe bis jetzt 

```
transform3D.setEuler(new Vector3d(anglex, angley, anglez));
```
verwendet. Dabei ist allerdings nur die X-Rotation von der Y-Rotation abhhängig und nicht umgedreht.
Das soll laut Dokumentation wohl auch so sein ( Transform3D (Java 3D 1.5.0)) ) passt mir aber gar nicht in den Kram 
Hat vllt von euch einer eine schlaue Idee, wie ich beide Drehungen in Abhängigkeit voneinander bekomme?


----------



## Marco13 (11. Apr 2012)

Wuhh.. "setEuler"? Wußte gar nicht, dass es diese Gimbal Lock ? Wikipedia - Fabrik in J3D gibt. Im Zweifelsfall kannst du dir 2 Matrix4fs erstellen, eine mit der X- und eine mit der Y-Rotation, und die in beliebiger Reihenfolge aneinander multiplizieren...


----------



## bob_sheknowdas (11. Apr 2012)

kannst du mir vllt in 5 codezeilen zeigen wie man sowas macht?
(wie du siehst arbeite ich bisher mit floatwerten, die die winkeldrehung repräsentieren  -  wäre nett, wenn du in deiner erklärung das auch so machen könntest)


----------



## Marco13 (11. Apr 2012)

Leider nicht. Es sind 9.

```
Matrxi4f m0 = new Matrix4f();
m0.setIdentity();
m0.rotX(a0);
Matrxi4f m1 = new Matrix4f();
m1.setIdentity();
m1.rotX(a1);
Matrxi4f result = new Matrix4f();
result.mul(m0, m1); // Oder umgekehrt
transform.set(result);
```


----------



## bob_sheknowdas (12. Apr 2012)

funktioniert 1a
danke :toll:


----------



## bob_sheknowdas (12. Apr 2012)

ui, offensichtlich klappt das doch nicht so perfekt.
ich habe wieder nur eine einseitige abhängigkeit, je nachdem wie rum ich multipliziere...

ich würde aber ganz gerne gegenseitige abhängigkeit haben...


----------



## Marco13 (12. Apr 2012)

Gut, dass meine Glaskugel frisch poliert ist  

Du willst ein Objekt z.B. mit der Maus drehen, aber es soll immer um x oder y gedreht werden, egal, wie vorher schon gedreht wurde?

Dann kann man das grundsätzlich nicht mit drei Winkeln machen, weil es keinen Homöomorphismus vom R^3 auf den SO3 gibt. 

Du musst die aktuelle Rotation als Matrix speichern, und jede neu hinzukommende Rotation an diese Matrix ranmultiplizieren (ob von links oder rechts... egal was ich sage, ich verwechsle es IMMER ;(  )


```
private Matrix4f currentRotation = new Matrix4f(); 
public Constructor()
{
    currentRotation.setIdentity();
}

public void rotate(float deltaX, float deltaY) // Wird z.B. bei Mausbewegungen aufgerufen
{
    // Die "result"-Matrix wie oben berechnen, aber dann
    currentRotation.mul(result, currentRotation); // Oder umgekehrt...
    transform.set(currentRotation);
}
```
Andernfalls könnte man sich überlegen, ob man aus den Rotationswinkeln eine "gewünschte Rotationsachse" berechnen könnte, und aber das ist kaum praktikabel und könnte mir kaum vorstellen, wo und warum das notwendig oder auch nur sinnvoll sein sollte.


----------



## bob_sheknowdas (13. Apr 2012)

Ich hab mal versucht das umzusetzen, aber irgendwie haut das nicht so ganz hin...
Ich poste am besten mal meine move()-Methode.
Wichtig ist dass ich mit einem Threat arbeite, der diese Methode in regelmäßigen Abständen aufruft. Über Pfeiltasten werden die Winkel (anglex, angley [können entweder -0.1 oder 0.1 sein]) sowie der speed gesetzt.
Mein "Flugzeug" ist eine eigene Klasse, die im wesentlichen 2 Spheren enthällt. Aus dem Verhältnis wie diese 2 Kugeln geografisch zueinander stehen wird die Bewegungsrichtung ermittelt. Die mainTfGroup (welche hier bewegt werden soll) enthällt genau dieses Flugzeug.
Wenn du diese implementation mal bei dir testen könntest siehst du wahrscheinlich was nicht hinhaut. Das zu beschreiben fällt mir ziemlich schwer.


```
private void move(){
		Transform3D tempTransform1 = new Transform3D();
		Vector3f tempVector1 = new Vector3f();
		flugzeug.getSphere().getLocalToVworld(tempTransform1);
		tempTransform1.get(tempVector1);

		Transform3D tempTransform2 = new Transform3D();
		Vector3f tempVector2 = new Vector3f();
		flugzeug.getSphere2().getLocalToVworld(tempTransform2);
		tempTransform2.get(tempVector2);
		
		xloc=tempVector1.x + (tempVector1.x-tempVector2.x) * speed;
		yloc=tempVector1.y + (tempVector1.y-tempVector2.y) * speed;
		zloc=tempVector1.z + (tempVector1.z-tempVector2.z) * speed;
		
		if(up || down || left || right){
			Matrix4f m0 = new Matrix4f();
			m0.setIdentity();
			m0.rotX(anglex);
			Matrix4f m1 = new Matrix4f();
			m1.setIdentity();
			m1.rotY(angley);
			Matrix4f result = new Matrix4f();
			result.mul(m0, m1);
			currentRotation.mul(result, currentRotation);
			anglex=0;
			angley=0;			
		}
		trans.set(currentRotation);
		trans.setTranslation(new Vector3f(xloc,yloc,zloc));
		mainTfGroup.setTransform(trans);
		lightGroup.setTransform(trans);
}
```


----------



## Marco13 (13. Apr 2012)

Ein KSKB ist bei sowas immer gut....


Suchst du GROB sowas? 

```
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashSet;
import java.util.Set;

import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.Light;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.swing.JFrame;
import javax.vecmath.Color3f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;



class ObjectRotator implements KeyListener
{
    private final TransformGroup rotatedTransformGroup;
    
    private final int upKey = KeyEvent.VK_UP;
    private final int downKey = KeyEvent.VK_DOWN;
    private final int leftKey = KeyEvent.VK_LEFT;
    private final int rightKey = KeyEvent.VK_RIGHT;
 
    private float speed = 0.05f;
    
    private final Set<Integer> pressedKeys = new HashSet<Integer>();
    private Matrix4f currentRotation = new Matrix4f();
    
    public ObjectRotator(TransformGroup rotatedTransformGroup)
    {
        this.rotatedTransformGroup = rotatedTransformGroup;
        currentRotation.setIdentity();

        Thread t = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                while (true)
                {
                    updateMovement();
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }   
                }
            }
        });
        t.setDaemon(true);
        t.start();
    }
    
    private void updateMovement()
    {
        if (pressedKeys.contains(upKey))
        {
            rotate(-speed, 0);
        }
        else if (pressedKeys.contains(downKey))
        {
            rotate(speed, 0);
        }
        else if (pressedKeys.contains(leftKey))
        {
            rotate(0, -speed);
        }
        else if (pressedKeys.contains(rightKey))
        {
            rotate(0, speed);
        }
    }
 
    private void rotate(float angleX, float angleY)
    {
        Matrix4f m0 = new Matrix4f();
        m0.setIdentity();
        m0.rotX(angleX);
        Matrix4f m1 = new Matrix4f();
        m1.setIdentity();
        m1.rotY(angleY);
        Matrix4f result = new Matrix4f();
        result.mul(m0, m1);
        currentRotation.mul(result, currentRotation);
        Transform3D t = new Transform3D(currentRotation);
        rotatedTransformGroup.setTransform(t);
    }
 
    @Override
    public void keyTyped(KeyEvent e) 
    {
    }

    @Override
    public void keyPressed(KeyEvent e) 
    {
        pressedKeys.add(e.getKeyCode());
    }

    @Override
    public void keyReleased(KeyEvent e) 
    {
        pressedKeys.remove(e.getKeyCode());
    }
    
}


 
public class RotationExample extends JFrame 
{
    public RotationExample() 
    {
        setFocusable(true);
        setSize(600,600);
        setPreferredSize(getSize());
        setLayout(new BorderLayout());
        
        create3D();
        
        setVisible(true);
        
    }
    
    private void create3D() {
        Canvas3D canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration()); 
        SimpleUniverse su = new SimpleUniverse(canvas3D);
        su.getViewingPlatform().setNominalViewingTransform();
        
        BranchGroup root = new BranchGroup();      
        TransformGroup rootTG = new TransformGroup();
        root.addChild(rootTG);

        
        rootTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        rootTG.addChild(createLight());
        rootTG.addChild(new ColorCube(0.5f));
        ObjectRotator objectRotator = new ObjectRotator(rootTG);
        addKeyListener(objectRotator);

        su.addBranchGraph(root);
        canvas3D.setFocusable(false);
        add(canvas3D);
    }
    
    private static Light createLight()
    {
        Color3f lightColor = new Color3f(1.8f, 0.1f, 0.1f);
        BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
        Vector3f lightDirection = new Vector3f(1.0f, -3.0f, -12.0f);
        DirectionalLight light = new DirectionalLight(lightColor, lightDirection);
        light.setInfluencingBounds(bounds);
        return light;
    }
 
 
    public static void main(String[] args) {
        new RotationExample();
 
    }
}
```

(BTW: Eigentlich würde man das eher mit Behaviors machen....)


----------



## bob_sheknowdas (16. Apr 2012)

jetzt ist es genau so wie ich es haben wollte,
vielen dank


----------

