question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

misleading javadoc for Quaternion fromAngles()

See original GitHub issue

Currently the javadoc for Quaternion fromAngles() says:

Note that we are applying in order: (y, x, z) aka (yaw, pitch, roll)
but we've ordered them in x, y, and z for convenience.
  1. I believe that the angles are actually applied in the order (x, z, y) not (y, x, z). One could write a short console app to test this.
  2. There are actually six possible assignments of yaw/pitch/roll axes to x/y/z, so the information about yaw/pitch/roll is unhelpful.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
tlf30commented, Nov 23, 2020

So I wrote a test this morning while drinking my coffee. From zero, each axis does work correctly, but once changing multiple angles, it quickly becomes apparent that the order the rotation angles are applied is wrong.

package io.tlf.jme.test;

import com.jayfella.jme.jfx.JavaFxUI;
import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

public class RotationTest extends SimpleApplication {

    private boolean cursor = false;

    @Override
    public void simpleInitApp() {
        this.getViewPort().setBackgroundColor(ColorRGBA.White);
        //Import char
        Spatial player = assetManager.loadModel("Models/mixamo/strut_walking.j3o");

        //UI
        JavaFxUI.initialize(this);
        VBox box = new VBox();
        HBox h1 = new HBox();
        HBox h2 = new HBox();
        HBox h3 = new HBox();
        Label l1 = new Label("X: ");
        Label l2 = new Label("Y: ");
        Label l3 = new Label("Z: ");
        Label p1 = new Label();
        Label p2 = new Label();
        Label p3 = new Label();
        Slider x = new Slider(-Math.PI, Math.PI, 0);
        Slider y = new Slider(-Math.PI, Math.PI, 0);
        Slider z = new Slider(-Math.PI, Math.PI, 0);
        h1.getChildren().add(l1);
        h1.getChildren().add(x);
        h1.getChildren().add(p1);
        h2.getChildren().add(l2);
        h2.getChildren().add(y);
        h2.getChildren().add(p2);
        h3.getChildren().add(l3);
        h3.getChildren().add(z);
        h3.getChildren().add(p3);
        Button reset = new Button("Reset");
        reset.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                enqueue(() -> player.setLocalRotation(new Quaternion().fromAngles(0f, 0f, 0f)));
                x.valueProperty().setValue(0f);
                y.valueProperty().setValue(0f);
                z.valueProperty().setValue(0f);
            }
        });
        ChangeListener listener = new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
                enqueue(() ->
                        player.setLocalRotation(new Quaternion().fromAngles((float) x.getValue(), (float) y.getValue(), (float) z.getValue()))
                );
                float[] xyz = player.getLocalRotation().toAngles(new float[3]);
                p1.setText("X " + xyz[0] + " = " + x.getValue());
                p2.setText("Y " + xyz[1] + " = " + y.getValue());
                p3.setText("Z " + xyz[2] + " = " + z.getValue());
            }
        };
        x.valueProperty().addListener(listener);
        y.valueProperty().addListener(listener);
        z.valueProperty().addListener(listener);

        box.getChildren().add(h1);
        box.getChildren().add(h2);
        box.getChildren().add(h3);
        box.getChildren().add(reset);
        JavaFxUI.getInstance().attachChild(box);
        Node world = new Node("world");

        world.attachChild(player);
        rootNode.attachChild(world);

        cam.setLocation(new Vector3f(0, 10f, 50f));
        cam.setFrustumFar(5000f);
        flyCam.setMoveSpeed(20f);


        ActionListener tab = new ActionListener() {
            @Override
            public void onAction(String name, boolean isPressed, float tpf) {
                if (!isPressed) {
                    cursor = !cursor;
                    flyCam.setEnabled(cursor);
                }
            }
        };
        inputManager.addMapping("tab", new KeyTrigger(KeyInput.KEY_TAB));
        inputManager.addListener(tab, "tab");

    }

    public static void main(String[] args) {
        RotationTest main = new RotationTest();
        main.start();
    }
}
1reaction
pspeed42commented, Nov 1, 2020

I think because it IS a breaking change, that another option would be to create methods like fromAnglesYXZ(), etc. and deprecate this one.

…otherwise, I generally agree that it’s wrong. It’s written for an x=forward coordinate system where JME uses a z=forward coordinate system.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Javadoc Euler descriptions wrong - jMonkeyEngine Hub
I'm fairly certain that the Quaternion class Javadocs are wrong wherever they ... When using these methods, the float[3] constructor and to/fromAngles() ......
Read more >
engine/src/core/com/jme3/math/Quaternion.java - Google Git
<code>fromAngles</code> builds a quaternion from the Euler rotation. * angles (y,r,p). ... Get the angle between the 2 quaternions, and then store the...
Read more >
Quaternion * operator docs misleading for edge cases
I am not just being pedantic here, the quaternions being {0,0,0,0} is a common error - uninitialized quaternions look fine in the editor...
Read more >
How to Write Doc Comments for the Javadoc Tool - Oracle
If you add any documentation comment or tag to m() , the "Overrides" or "Specified by" subheading and link will still appear, but...
Read more >
How to properly rotate a quaternion along all axis?
To illustrate the resulting camera rotation when the mouse moves, I show you a hand drawing. On the left side the wrong rotation...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found