[solved]EBUAK (former BUG): Unattached and unrelated Spatial rotation causing rotation of attached S

Hi all!

This bug has caused quite a lot of frustration in the current program I’m working on, and it seems to be caused by core code and not my own ignorance as usual;) I tried to make a convenient test case for any coredev feeling the urge to fix this. If any more details or assistance is needed, I’m more than willing to help out.

[java]

package jme3test.helloworld;



import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;

import com.jme3.scene.shape.Quad;



import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Quaternion;

import com.jme3.scene.Node;





public class TestRotationBug extends SimpleApplication {



public static void main(String[] args){

TestRotationBug app = new TestRotationBug();

app.start();

}



// These two determine if the bug accours or not

private boolean attachToRoot = false; // Test rotating bug when attached to rootNode (or an additional parent node)

private boolean rotateUnattachedBefore = true; // Test rotating before adding content.



// These two just rule out the bug being spesific for a specific shape or Spatial subclass.

private boolean useBox = false;// Test rotating bug with box or Quad for proving it’s not shape related.

private boolean rotateNode = true; // Test rotating bug rotating unattached Quad or Node



@Override

public void simpleInitApp() {

Material matQuad = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

matQuad.setColor(“Color”, ColorRGBA.Red);



Geometry attachedSpatial;



if(useBox){

Box box = new Box(10,10,.01f); // A box created to resemble the quad beneath.

attachedSpatial = new Geometry(“Plane”, box);

attachedSpatial.setMaterial(matQuad);

}

else{

Quad quad = new Quad(10,10);

attachedSpatial = new Geometry(“Plane”, quad);

attachedSpatial.setMaterial(matQuad);

}





if(rotateUnattachedBefore){

if(rotateNode){

Node aNode = new Node(“A node”);

aNode.rotate(Quaternion.IDENTITY.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));

}

else{

Geometry boxG = new Geometry(“Box”);

boxG.rotate(Quaternion.IDENTITY.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));

}

}



if(attachToRoot){

rootNode.attachChild(attachedSpatial);

}

else{

Node pivot = new Node(“pivot”);

pivot.attachChild(attachedSpatial);

rootNode.attachChild(pivot);

}



if(!rotateUnattachedBefore){

if(rotateNode){

Node aNode = new Node(“A node”);

aNode.rotate(Quaternion.IDENTITY.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));

}

else{

Geometry boxG = new Geometry(“Box”);

boxG.rotate(Quaternion.IDENTITY.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));

}

}



cam.setLocation(new Vector3f(0f,.1f,20));

}

}

[/java]

Uh, you are setting the value of the constant Quaternion.IDENTITY here. I guess thats the correlation.

Uh no. I used a random preconfigured quaternion to be able to get access to the fromangleaxis methodthe returned quat. used is not the identity quat. Please read the code.

Yeah, I read the code and especially this line:

[java]Quaternion.IDENTITY.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X);[/java]

This sets a value to the static final constant Quaternion.IDENTITY, which is very bad…

2 Likes

Thanx a lot @normen for clearing up this “bug”. Oh how I love to be wrong after being a smartass :frowning:

[java]

new Quaternion().fromAngleAxis(-FastMath.HALF_PI,Vector3f.UNIT_X);

[/java]

1 Like
@makeshift said:
Please read the code.


Please, never underestimate Normen !

Hehe. I was so sure about my “bug” being a bug that I couldn’t think straight.

I made that mistake, too. Perhaps one could use a subclass for “constants” like “Quaternion.IDENTITY” that throws an exception when trying to alter it. It’s “clone()” has to return an instance of the parent class.

Just keep in mind “do not alter final variables” :).

No, we will not add ReadOnly primitives like Ardor, we’ll do that via annotations and annotation processors.

@survivor said:
I made that mistake, too. Perhaps one could use a subclass for "constants" like "Quaternion.IDENTITY" that throws an exception when trying to alter it. It's "clone()" has to return an instance of the parent class.


Normen is right. A subclass would add overhead to every Quaternion call for no other reason to catch an error that is easily avoided by a little diligence on the part of the developer. Or as Normen suggests, better annotations and processors.

Calling final classes and final methods can be faster for a variety of reasons. To support a special immutable subclass, these classes couldn't be final anymore.