# JAVA3D Rotation um einen bestimmten Punkt



## Chrissy09 (19. Okt 2009)

Hallo zusammen,

da ich ein Java3D-Newbie bin, hoffe ich dass ihr mir bei meinem Problem weiterhelfen könnt.
Also ich bin gerade dabei Zauberwürfel in JAVA3D zu programmieren.
Ich habe den Würfel schon soweit fertig.
Jetzt fehlen allerdings noch die Rotationen der einzelnen Seiten.

Bei mir hat jeder kleine Würfel (3x3x3) seine eigene TransformGroup.
Jetzt möchte ich irgendwie den Drehpunkt für jeden Würfelteil bestimmen, so dass ich den Würfelteil um den Mittelpunkt (x) drehen kann:  
OOO
OXO
OOO

Ich weiß, dass da allgemein so geht, dass man den Punkt um den man drehen will auf 0,0,0 verschiebt, dann dreht und dann wieder zurückschiebt.

Allerdings soll die Drehung nicht direkt sichtbar sein, sondern es soll eine Interaktion bzw. Animation sein. 
Also dass der Benutzer z.B. eine Taste drückt und dann nicht der Würfel in die Position springt wie es sein soll, sondern dass sich die Würfelseite langsam (sichtbar) um den Mittelpunkt dreht.

Ich hoffe es ist verständlich was ich meine.
Hoffentlich kann mir jemand helfen...ich weiß echt nicht weiter.

Danke schonmal!!!


----------



## Marco13 (20. Okt 2009)

Das schwierigste dabei wird das, was in dem lapidaren Beisatz steht: "...wie es sein soll" - also, sich das ganze so bedienen zu lassen, dass man einfach z.B. durch Klicken+Ziehen irgendwo eine "intuitiv passende" Drehung erreicht ist nicht ganz trivial. 
Zur "langsamen Rotation" kannst du dir mal die Klassen "Alpha" und "RotationInterpolator" ansehen...


----------



## Chrissy09 (20. Okt 2009)

Also das mit der Bedienung habe ich schon einige Ideen, die soweit auch funktionieren.

Es geht mir nur um die Drehung.
Ich hab mich die Klasse Alpha und RotationInterpolator schon angesehen...
hatte da auch schon was ausprobiert. aber ich habe nicht rausbekommen, ob bzw. wie man da einen Mittelpunkt wählen kann um den gedreht wird. -.-

Also mein Quelltext sieht so aus:


```
....
Transform3D axisRot = new Transform3D();
//für jeden Teilwürfel (insgesamt 9):
//Hole ich mir die TransformGroup
TransformGroup cubePart = (TransformGroup) tg.getChild(0); 

//dann mache ich folgendes:
Alpha timer = new Alpha(1, 10000);
/*Für x,y,z setze ich die Werte, so dass ich von dem jeweiligen Teilwürfel zu dem Punkt komme, um den ich drehen will... allerdings weiß ich nicht, was ich mit dem Winkel machen soll...Kann mir das jemand sagen?*/
AxisAngle4d rot = new AxisAngle4d(x,y,z,Math.toRadians(-90.0));
axisRot.set(rot);

RotationInterpolator rotInterp = new RotationInterpolator(timer,cubePart);
rotInterp.setMaximumAngle((float)Math.toRadians(90.0));
rotInterp.setMinimumAngle((float)Math.toRadians(0.0));
rotInterp.setSchedulingBounds(new BoundingSphere());
rotInterp.setAxisOfRotation(axisRot);

cubePart.setTransform(axisRot);
```

Ich habe das ganze jetzt nur mal für eine Seite getestet..
Und das Ergebnis sieht so aus, dass alles falsch gedreht wird. Also die äußeren Würfel oben und unten stehen komplett schief usw. (siehe Bild)

Hat jemand einen Tipp für mich?


----------



## Developer_X (20. Okt 2009)

Schau dir mal dies an:

Das kannst du am besten an einem kleinen selbstgemachtem sonnensystem lernen.
Also
im Punkt 0 0 0 gibt es einen Sphere.
Diese TransformGroup am Punkt 0 0 heißt Sun.

JEtzt kannst du eine TransformGroup namens Earth erstellen, und sie hinstellen wo hin du willst, also sagen wir mal 0 0 5.
Dann musst du die TransformGroup Sun die TransformGroup Earth adden lassen.
Wenn du jetzt die TransformGroup Sun rotierst, dreht sich die TransformGroup Earth um die TransformGroup Sun.
Im Code sieht dass dann so aus:

```
public BranchGroup build_3D_World()
{
BranchGroup X = new BranchGroup();

Transform3D sun = new Transform3D();
sun.rotX(Math.toRadians(20));
sun.setTranslation(new Vector3f(0,0,0));
TransformGroup Sun = new TransformGroup();
Sun.setTransform(sun);
Sun.addChild(new Sphere());
X.addChild(Sun);

Transform3D earth = new Tranform3D();
earth.setTranslation(new Vector3f(0,0,5));
TransformGroup Earth = new TransformGroup();
Earth.setTransform(earth);
Earth.addChild(new Sphere());
Sun.addChild(Earth);

add_lights(X);

return X;
}
	public void add_lights(BranchGroup X)
	{
        Color3f lightColor = new Color3f(1f,.6f,1f);
        AmbientLight ambientLight= new AmbientLight(lightColor);
        ambientLight.setInfluencingBounds(bounds);
        X.addChild(ambientLight);
        DirectionalLight directionalLight = new DirectionalLight();
        directionalLight.setColor(lightColor);
        directionalLight.setInfluencingBounds(bounds);
        X.addChild(directionalLight);     
	}
```

Verstehst du das?


----------



## Marco13 (20. Okt 2009)

Hm... das ist nicht sooo einfach (dass ich das jetzt in der Mittagspause mal kurz hinschreiben könnte), und mir ist nicht ganz klar, wie du x,y,z setzt, aber ... ein paar spontane, UNVERBINDLICHE(!) Gedanken:

Die Position/Bewegung eines Segmentes besteht aus einer Translation zur "Ausgangslage", und einer Rotation, aber diese Rotation besteht zu jedem Zeitpunkt aus der Hintereinanderausführung mehrerer Rotationen, und einzelne Teile dieser Hintereinanderausführung sollen animiert sein. Eine Überlegung wäre, das ganze wirklich im Sinne eines "Datenmodells" zu beschreiben. Also keine Transformationsmatrizen in TransformGroups zu speichern, sondern nur irgendeinen Array von Winkeln, oder noch allgemeiner: Eine Abfolge von "Rotationsbefehlen". Sowas bräuchte man spätestes für einen "Solver", oder schon wenn man nur erkennen will, dass der Würfel fertig gelöst ist. Diese Winkel oder Befehle könnten dann immer "on the fly" in die jeweiligen Matrizen umgerechnet werden - aber da müßte man sich GENAU überlegen, wie dieses Modell aussehen könnte.... auch wenn es da sicher schon 1000e Ansätze im Web gibt.

Aber back to reality  Ich nehme an, das Problem liegt wirklich bei 
"_Für x,y,z setze ich die Werte, so dass ich von dem jeweiligen Teilwürfel zu dem Punkt komme, um den ich drehen will... _
Für ein AxisAngle übergibt man ja keinen Punkt, sondern eine Rotations_achse_ - und das ist bei dir IMMER nur die X- Y- oder Z-Achse. Und du willst ja auch nicht jeden Teilwürfel um seinen Mittelpunkt drehen. Die Rotation findet immer um den Ursprung statt. 

Der Versuch, das in einer Pseudo-Szenegraphstruktur anzudeuten:

```
// TransformGroups, die die AUSGANGSLAGE jedes Segments beschreiben
// (Dort hängen direkt die Segmente dran!)

// Für das Segment rechts oben vorne (Right Top Front)
positionRTF = TransformGroup(1,1,1) 
positionRTF.add(segmentRTF);

// Für das Segment rechts oben mitte
positionRTM = TransformGroup(1,1,0) 
positionRTM.add(segmentRTM);

...

// Jedes einzelne Segment kann aus seiner Ausgangslage raus rotiert werden
// Deswegen eine Rotations-Transformgroup für jedes Segment, und 
// AN dieser rotations-TG hängen die positions-TGs

rotationRTF = TransformGroup() 
rotationRTF.addChild(positionRTF);

rotationRTM = TransformGroup() 
rotationRTM.addChild(positionRTM);

...
```

In Wirklichkeit würde man das natürlich irgendwie geschickter schreiben, und nicht mit 81 Variablen mit so abstrusen Namen...  :autsch:  Wie man Rotationen auf einen bestehenden Würfel anwenden könnte (d.h. wie man rausfindet, welche Segmente durch eine Rotation betroffen sind) muss man sich auch überlegen, aber vielleicht hast du das ja schon.


```
// Wenn jetzt die rechte Seite des würfels um 90° gedreht werden soll, könnte
// man das GANZ GROB vielleicht so machen:

// Die Rotation ausrechnen:
Vector3f xAxis = new Vector3f(1,0,0);
AxisAngle4f axisAngle = new AxisAngle4f(xAxis, angle);
Transform3D rotation = new Transform3D(axisAngle);

// Die Rotation auf alle betroffenen Segmente anwenden:
for (Segment s : affectedSegments)
{
    TransformGroup tg = rotationTransformGroupFor(s);
    Transform3D oldRotation = tg.getTransform();
    Transform3D newRotation = rotation.mul(oldRotation);
    tg.setTransform(newRotation);
}
```

Um die Animation da rein zu bringen würde ich jetzt kaum eine andere Möglichkeit sehen, als 9 RotationInterpolators zu erstellen - andernfalls müßte man noch eine TransformGroup dazwischenschalten, die nur die Animation übernimmt (das könnte fummelig werden). Den RotationInterpolator würde man im Pseudocode-Beispiel oben dann jeweils auf die "newRotation" andwenden.

So. Mittagspause.


----------



## Chrissy09 (20. Okt 2009)

Zu DeveloperX:

also wenn ich so ein Sonnensystem habe und ich habe als Baum dargestellt

....-----------TransformGroup Sun-----------------------TransformGroup Earth

also sun.add(earth) sozusagen.
Dann dachte ich, dass es so ist, dass wenn man zur sun-TG sagt: dreh dich um X Grad, dass dann alles was an SUN dranhängt..also in dem Fall die Sonne und alles was drunter hängt...also auch TG Earth und die Erde gedreht wird.
Lieg ich mit der Annahme falsch?

zu Marco:
Danke für die Tipps, ich werd mal ein bisschen rumprobieren und dann mich dann nochmal melden wenn es nicht klappt.


----------



## Chrissy09 (20. Okt 2009)

Aaaalso...ich nochmal.
Wenn ich nun folgendes verwende:

```
AxisAngle4d rot = new AxisAngle4d(0.0,0.0,1.0,Math.toRadians(-90.0));
```

dann dreht sich jeder kleine Würfel einzeln um -90° allerdings ist das ja nicht das was ich will, weil als rotationszentrum der mittelpunkt von jedem kleinen würfel genommen wird.
Ich will aber dass der mittelpunkt vom mittleren Würfel (X) genommen wird:
O O O
O X O
O O O

Wie bekomm ich das hin?

Bzw. wenn ich sage :

```
rotInterp.setMaximumAngle((float)Math.toRadians(90.0));
rotInterp.setMinimumAngle((float)Math.toRadians(0.0));
```
Was genau bewirkt das?
Weil im Moment springt das Ereignis, also nix dreht sich langsam. Sondern einfach zack und die Würfel sind gedreht.

Ich glaube ich versteh das ganze irgendwie falsch ^^

Helft mir bitte.


----------



## Marco13 (20. Okt 2009)

Mit der ersten Antwort hast du die Frage aus der zweiten Antwort ja schon beantwortet  
Also ja: In diesem Beispiel würde die Rotation auf die Sonne angewendet werden, UND auf alles, was an der Sonne hängt. 

Deswegen irritiert mich die zweite Frage: Wenn deine Szenegraphstruktur so ist

```
root
    transformFürWürfel
        rotationFürSegment000
            translationFürSegment000
                segment000
        rotationFürSegment001
            translationFürSegment001
                segment001
        ...
```
dann sollten sich die Segment, wenn die Rotation auf die TGs "rotationFürSegmentXXX" angewendet werden, NICHT um ihr Zentrum, sondern um das Zentrum des gesamten Würfels drehen - immer verschoben um ihre Ausgangslage.

Oder anders gesagt: Hängt an der
TransformGroup cubePart = (TransformGroup) tg.getChild(0);
die du dir da holst NUR das Segment, oder eine TransformGroup für die Translation (an der dann das Segment hängt)?


EDIT: Wegen RotationInterpolator: Es gibt da Konstruktoren mit mehr Parametern (sowohl für den Interpolator als auch für das Alpha) - bei denen, die du benutzt, ist (mir, ohne nachlesen) erstmal nicht klar, welche Werte dort standardmäßig für die anderen Parameter angenommen werden...


----------



## Chrissy09 (20. Okt 2009)

also die struktur sieht folgendermaßen aus:

```
root
    TG_cube
        //und dann für jedes Segment:
            TG1_segment000
                  //via new TG(Transform3d)
                  Translation standard(startzustand)
                  TG2_segment000 (cubepart)
                         //via setTransform 
                         gewünschte Rotation für Drehung //das was ich eigentlich will
                         segment000
            TG1_segment001
                  //via new TG(Transform3d)
                  Translation standard(startzustand)
                  TG2_segment001
                         segment001
                              usw....
```

Ich hatte mal 2 TG's pro segement gemacht, da ich dachte, dass man immer nur entweder translation oder rotation speichern kann..aber anscheinend geht das beides.. Bin wie gesagt noch Newbie.

und das TG cubepart wäre dann immer das TG2 für jedes segment.
Wenn ich via setTransform bei einer TG ein Transform3d setze...ist das dann so als wäre das Transform3d ein Child von der TG ?


----------



## Developer_X (21. Okt 2009)

Chrissy09 hat gesagt.:


> Zu DeveloperX:
> 
> also wenn ich so ein Sonnensystem habe und ich habe als Baum dargestellt
> 
> ...


----------



## Chrissy09 (21. Okt 2009)

okay. Wenn ich das schonmal nicht falsch verstanden habe. Wo genau liegt dann mein Fehler,dass immer nur um den Mittelpunkt der Teilwürfel gedreht wird?


----------



## Developer_X (21. Okt 2009)

das ist nicht 1 würfel, sondern dass sind 3*3*3 Würfel.
UNd du hast nur die würfel, die an den ecken sind, gedreht.
Du musst das ganze große, also die TransformGroup die alle Würfel added, drehen.


----------



## Chrissy09 (21. Okt 2009)

Ja aber ich will ja nicht alle würfel drehen, sondern nur die auf der Vorderseite zB. Halt immer nur eine Seite. So wie bei Rubiks Cube normalerweise auch. Dass ich wenn ich 3*3*3 hab
und ich sag jetzt mal hinten unten links ist 0,0,0 
Dann will ich die Teilwürfel 002, 012, 022, 102, 112, 122, 202, 212, 222 drehen.
Und NUR die. nicht alle. Wie krieg ich das hin?


Im Moment sieht das ganze folgendermaßen aus:
siehe Bild


----------



## Marco13 (21. Okt 2009)

Wie gesagt: Du rotierst um die Mittelpunkte der Würfel, weil deine Szenegraphstruktur "falsch" ist (bzw. die Rotation auf die falschen Knoten angewendet wird).

Um mal zu Potte zu kommen...

```
// From http://www.java2s.com/Code/Java/3D/HelloJava3Dbaltrendersasinglerotatedcube.htm
// Extended for http://www.java-forum.org/spiele-multimedia-programmierung/89915-java3d-rotation-um-bestimmten-punkt.html


import java.applet.Applet;
import java.awt.*;
import java.awt.Frame;

import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;

//   HelloJava3Dbalt renders a single, rotated cube.

public class HelloJava3Dbalt extends Applet {


  private TransformGroup translation[][][] = new TransformGroup[3][3][3];
  private TransformGroup rotation[][][] = new TransformGroup[3][3][3];

  private void createSegment(BranchGroup node, int x, int y, int z)
  {

      translation[x][y][z] = new TransformGroup();
      float dx = -1.0f + x;
      float dy = -1.0f + y;
      float dz = -1.0f + z;
      Transform3D t = new Transform3D();
      t.setTranslation(new Vector3f(dx,dy,dz));
      translation[x][y][z].setTransform(t);
      translation[x][y][z].addChild(new ColorCube(0.45f));

      rotation[x][y][z] = new TransformGroup();

      rotation[x][y][z].addChild(translation[x][y][z]);
      node.addChild(rotation[x][y][z]);


  }

  private void rotateSegmentsAtY(int y, float angleDeg)
  {
    AxisAngle4d rot = new AxisAngle4d(0.0,1.0,0.0,Math.toRadians(angleDeg));
    Transform3D t = new Transform3D();
    t.setRotation(rot);

    for (int x=0; x<3; x++)
    {
        for (int z=0; z<3; z++)
        {
            rotation[x][y][z].setTransform(t);
        }
    }
  }



  public BranchGroup createSceneGraph() {
    // Create the root of the branch graph
    BranchGroup objRoot = new BranchGroup();

    for (int x=0; x<3; x++)
    {
        for (int y=0; y<3; y++)
        {
            for (int z=0; z<3; z++)
            {
                createSegment(objRoot, x, y, z);
            }
        }
    }

    rotateSegmentsAtY(0,10);
    rotateSegmentsAtY(1,20);
    rotateSegmentsAtY(2,30);

    objRoot.compile();

    return objRoot;
  } // end of CreateSceneGraph method of HelloJava3Dbalt

  // Create a simple scene and attach it to the virtual universe

  public HelloJava3Dbalt() {
    setLayout(new BorderLayout());
    GraphicsConfiguration config =
       SimpleUniverse.getPreferredConfiguration();

    Canvas3D canvas3D = new Canvas3D(config);
    add("Center", canvas3D);

    BranchGroup scene = createSceneGraph();

    // SimpleUniverse is a Convenience Utility class
    SimpleUniverse simpleU = new SimpleUniverse(canvas3D);

    // This will move the ViewPlatform back a bit so the
    // objects in the scene can be viewed.

    Transform3D t = new Transform3D();
    t.setTranslation(new Vector3f(0,0,10));
    simpleU.getViewingPlatform().getViewPlatformTransform().setTransform(t);

    //simpleU.getViewingPlatform().setNominalViewingTransform();

    simpleU.addBranchGraph(scene);
  } // end of HelloJava3Db (constructor)

  //  The following allows this to be run as an application
  //  as well as an applet

  public static void main(String[] args) {
    Frame frame = new MainFrame(new HelloJava3Dbalt(), 256, 256);
  } // end of main (method of HelloJava3Dbalt)

} // end of class HelloJava3Dbalt
```


----------



## Chrissy09 (22. Okt 2009)

Super. Die Rotation funktioniert schonmal richtig.
Vielen Dank.

Allerdings habe ich noch ein Problem damit, dass es eine Animaiton sein soll, die sozusagen auf Knopfdruck gestartet wird.
Ich hätte jetzt einfach einen RotationsInterpolator auf Knopfdruck erstellt und diesen in den Szenegraph eingefügt.
Allerdings geht das ja zur Laufzeit so nicht.

Wie mache ich das dann anders?


----------



## Marco13 (22. Okt 2009)

Man könnte, wenn man wollte, was mit dem RotationInterpolator dengeln - ein eigener Thread ist aber vmtl. einfacher

```
// From [url=http://www.java2s.com/Code/Java/3D/HelloJava3Dbaltrendersasinglerotatedcube.htm]HelloJava3Dbalt renders a single, rotated cube : Cube3DJava[/url]
// Extended for [url]http://www.java-forum.org/spiele-multimedia-programmierung/89915-java3d-rotation-um-bestimmten-punkt.html[/url]


import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.Frame;

import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;

//   HelloJava3Dbalt renders a single, rotated cube.

public class HelloJava3Dbalt extends Applet {


  private TransformGroup translation[][][] = new TransformGroup[3][3][3];
  private TransformGroup rotation[][][] = new TransformGroup[3][3][3];

  private void createSegment(BranchGroup node, int x, int y, int z)
  {

      translation[x][y][z] = new TransformGroup();
      float dx = -1.0f + x;
      float dy = -1.0f + y;
      float dz = -1.0f + z;
      Transform3D t = new Transform3D();
      t.setTranslation(new Vector3f(dx,dy,dz));
      translation[x][y][z].setTransform(t);
      translation[x][y][z].addChild(new ColorCube(0.45f));

      rotation[x][y][z] = new TransformGroup();
      rotation[x][y][z].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
      rotation[x][y][z].addChild(translation[x][y][z]);
      node.addChild(rotation[x][y][z]);


  }

  private void rotateSegmentsAtY(int y, float angleDeg)
  {
    AxisAngle4d rot = new AxisAngle4d(0.0,1.0,0.0,Math.toRadians(angleDeg));
    Transform3D t = new Transform3D();
    t.setRotation(rot);

    for (int x=0; x<3; x++)
    {
        for (int z=0; z<3; z++)
        {
            Transform3D oldRotation = new Transform3D();
            rotation[x][y][z].getTransform(oldRotation);
            Transform3D newRotation = new Transform3D();
            newRotation.mul(t, oldRotation);
            rotation[x][y][z].setTransform(newRotation);
        }
    }
  }


  public void rotate()
  {
      Thread t = new Thread(new Runnable()
      {
          public void run()
          {
              for (int i=0; i<90; i++)
              {
                  rotateSegmentsAtY(0,1);
                  try
                  {
                      Thread.sleep(20);
                  }
                  catch (InterruptedException e)
                  {
                      Thread.currentThread().interrupt();
                  }
              }
          }
      });
      t.start();

  }



  public BranchGroup createSceneGraph() {
    // Create the root of the branch graph
    BranchGroup objRoot = new BranchGroup();

    for (int x=0; x<3; x++)
    {
        for (int y=0; y<3; y++)
        {
            for (int z=0; z<3; z++)
            {
                createSegment(objRoot, x, y, z);
            }
        }
    }

    rotateSegmentsAtY(0,10);
    rotateSegmentsAtY(1,20);
    rotateSegmentsAtY(2,30);

    objRoot.compile();

    return objRoot;
  } // end of CreateSceneGraph method of HelloJava3Dbalt

  // Create a simple scene and attach it to the virtual universe

  public HelloJava3Dbalt() {
    setLayout(new BorderLayout());
    GraphicsConfiguration config =
       SimpleUniverse.getPreferredConfiguration();

    JButton b = new JButton("rotate");
    add("North", b);
    b.addActionListener(new ActionListener()
    {
        public void actionPerformed(ActionEvent e)
        {
            rotate();
        }
    });


    Canvas3D canvas3D = new Canvas3D(config);
    add("Center", canvas3D);

    BranchGroup scene = createSceneGraph();

    // SimpleUniverse is a Convenience Utility class
    SimpleUniverse simpleU = new SimpleUniverse(canvas3D);

    // This will move the ViewPlatform back a bit so the
    // objects in the scene can be viewed.

    Transform3D t = new Transform3D();
    t.setTranslation(new Vector3f(0,0,10));
    simpleU.getViewingPlatform().getViewPlatformTransform().setTransform(t);

    //simpleU.getViewingPlatform().setNominalViewingTransform();

    simpleU.addBranchGraph(scene);
  } // end of HelloJava3Db (constructor)

  //  The following allows this to be run as an application
  //  as well as an applet

  public static void main(String[] args) {
    Frame frame = new MainFrame(new HelloJava3Dbalt(), 256, 256);
  } // end of main (method of HelloJava3Dbalt)

} // end of class HelloJava3Dbalt
```


----------



## Chrissy09 (22. Okt 2009)

Hi.

danke schonmal für die Anregung.
Würde das aber wenn möglich gerne via RotationInterpolator regeln.

Ich habe das soweit auch schon hinbekommen, indem ich bei der Initialisierung der Würfelteile folgendes mache:

```
Alpha timer = new Alpha(1, 5000);
                    
Transform3D axis = new Transform3D();
axis.rotX(Math.PI / 2);
                    
RotationInterpolator rotInterp = new RotationInterpolator(timer,rotation);
rotInterp.setSchedulingBounds(new BoundingSphere());
rotInterp.setMaximumAngle(0.0f);
rotInterp.setTransformAxis(axis);

rotation.addChild(rotInterp);
```

und bei bestimmten Tastendruck mache ich folgendes:

```
RotationInterpolator ri = (RotationInterpolator)rottg.getChild(0);
              
ri.setMaximumAngle((float)Math.toRadians(-90.0));
```

Die Seite dreht sich auch. Allerdings springt die Seite erstmal ruckartig um ca. 45° und dann dreht sie langsam weiter von 45° bis 90° (minus in dem Falle).

Hat jemand eine Ahnung woran das liegt, dass es so springt?

Wenn ich von Anfang an maxAngle auf -90 setze und den Alphawert pausiere bis eine Taste gedrückt wird, dann springt die Würfelseite schon bei der Initialisierung des RotationInterpolators um ca. 45°.
Woran liegt das?


----------



## Marco13 (22. Okt 2009)

Poste ggf. mal ein KSKB


----------



## Chrissy09 (22. Okt 2009)

```
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hellojava3dhelp;

/// From [url=http://www.java2s.com/Code/Java/3D/HelloJava3Dbaltrendersasinglerotatedcube.htm]HelloJava3Dbalt renders a single, rotated cube : Cube3DJava[/url]
// Extended for [url]http://www.java-forum.org/spiele-multimedia-programmierung/89915-java3d-rotation-um-bestimmten-punkt.html[/url]

import java.awt.*;
import java.awt.event.ActionEvent;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
import java.awt.event.ActionListener;
import javax.media.j3d.*;
import javax.swing.JButton;
import javax.swing.JFrame;

//   HelloJava3Dbalt renders a single, rotated cube.
public class HelloJava3Dbalt extends JFrame {

    private TransformGroup translation[][][] = new TransformGroup[3][3][3];
    private TransformGroup rotation[][][] = new TransformGroup[3][3][3];

    private void createSegment(BranchGroup node, int x, int y, int z) {

        translation[x][y][z] = new TransformGroup();
        float dx = -1.0f + x;
        float dy = -1.0f + y;
        float dz = -1.0f + z;
        Transform3D t = new Transform3D();
        t.setTranslation(new Vector3f(dx, dy, dz));

        translation[x][y][z].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        translation[x][y][z].setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

        translation[x][y][z].setTransform(t);
        translation[x][y][z].addChild(new ColorCube(0.45f));

        rotation[x][y][z] = new TransformGroup();
        rotation[x][y][z].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        rotation[x][y][z].setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

        rotation[x][y][z].addChild(translation[x][y][z]);


        Alpha timer = new Alpha(1, 100000);

        Transform3D axis = new Transform3D();
        axis.rotX(Math.PI / 2);
        //axis.set(new Vector3f(0.0f,0.0f,1.0f));

        RotationInterpolator rotInterp = new RotationInterpolator(timer, rotation[x][y][z]);
        rotInterp.setSchedulingBounds(new BoundingSphere());
        rotInterp.setMaximumAngle(0.0f);
        rotInterp.setTransformAxis(axis);

        if(z==2)
            rotation[x][y][z].addChild(rotInterp);

        node.addChild(rotation[x][y][z]);
    }

    public void rotate(){
        for(int i=0; i<3; i++)
            for(int j=0; j<3; j++){
                RotationInterpolator ri = (RotationInterpolator)rotation[i][j][2].getChild(1);
                ri.setMaximumAngle(-90.0f);
            }
    }

    public BranchGroup createSceneGraph() {
        // Create the root of the branch graph
        BranchGroup objRoot = new BranchGroup();

        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                for (int z = 0; z < 3; z++) {
                    createSegment(objRoot, x, y, z);
                }
            }
        }

        objRoot.compile();

        return objRoot;
    } // end of CreateSceneGraph method of HelloJava3Dbalt

    // Create a simple scene and attach it to the virtual universe
    public HelloJava3Dbalt() {
        setSize(256,256);
        setLayout(new BorderLayout());
        GraphicsConfiguration config =
                SimpleUniverse.getPreferredConfiguration();

        Canvas3D canvas3D = new Canvas3D(config);
        add("Center", canvas3D);
        JButton j = new JButton("Rotate");
        j.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                rotate();
            }
        });
        add("South", j);

        BranchGroup scene = createSceneGraph();

        // SimpleUniverse is a Convenience Utility class
        SimpleUniverse simpleU = new SimpleUniverse(canvas3D);

        // This will move the ViewPlatform back a bit so the
        // objects in the scene can be viewed.

        Transform3D t = new Transform3D();
        t.setTranslation(new Vector3f(0, 0, 10));
        simpleU.getViewingPlatform().getViewPlatformTransform().setTransform(t);

        //simpleU.getViewingPlatform().setNominalViewingTransform();

        simpleU.addBranchGraph(scene);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    } // end of HelloJava3Db (constructor)

    public static void main(String[] args) {
        new HelloJava3Dbalt();
        
    } // end of main (method of HelloJava3Dbalt)
} // end of class HelloJava3Dbalt
```

Habe mal folgendes gebastelt.

Wenn man auf rotate drückt, dann springt der Würfel erst.


----------



## Marco13 (22. Okt 2009)

Das Alpha läuft sofort los, und läuft innerhalb von 100 Sekunden von 0 bis 0. (Ja.)

Solange es nur zwischen 0 und 0 interpoliert, sieht man nichts. Aber wenn es dann zwischendrin gesagt bekommt, dass es innerhalb dieser 100 Sekunden 14 Drehungen machen soll (grad vs. radians!), hüpft es eben da hin, wo es zu diesem Zeitpunkt sein müßte.

Als ich oben gesagt habe, dass man "mit RotationInterpolator was *dengeln*" könnte, bezog sich das darauf, dass man ... auch mit einem Schraubenzieher einen Nagel in die Wand hauen kann ... also, dass du, wenn der Button geklickt wird (und nicht vorher) einen neuen RotationInterpolator erstellen musst, der sich auf eine andere "Hilfs"-Rotations-TransformGroup bezieht, als die, mit der du bisher die Rotation machst, und aus dieser Hilfs-TG dann, wenn der Interpolator fertig ist (wie auch immer man das feststellen soll), die Transform auslesen, sie für die eigentlche TransformGroup setzen, die Hilfs-TG auf die Identität setzen, und den Interpolator wieder entfernen musst. (Irgendwie muss das Endergebnis der Transformation ja so gespeichert werden, dass nachfolgende Transformationen sich auf die _schon Transformierten_ Segemente beziehen).

Mein Tipp: Lass' das mit dem Interpolator. Und *BEVOR* du jetzt wieder so spontan das einbaust, was ich da mit dem Thread gepostet hatte: Denke nach, wie du weitermachen willst. Überleg' dir, wie du die Hintereinanderausführung machst, wie du bestimmst, auf welche Segmente sich eine Transformation beziehen soll, und wie du den _Zustand das Würfels_ richtig speichern kannst (außer implizit, in einem Haufen TransformGroups...:autsch: ). Mit 5 Zeilen mal so einen schicken Würfel in 3D da hinmalen ist eine Sache, und vielleicht ein motivierendes Erfolgserlebnis, aber ... es ist nicht so leicht... und wenn man nicht überlegt und eine genaue Idee entwickelt, wie man vorgehen will, endet's in Rumprobieren, Hacken und Frust. Das hast du ja vielleicht schon gemerkt.


----------



## Developer_X (23. Okt 2009)

also wenn ich 3d applikationen mache, mache ich das immer mit einem mainthread für das programm.

alpha und andere laggen bei mir.


----------

