Camera Rotation Problem

I am having a little trouble wrapping my head around the proper use of the “setLocalRotation” function. Looking at the source code, it seems that it directly sets the local transform rotation quaternion directly. However, there are two lines in the “SimpleWorldEditor” program that are making me scratch my head if that is the case. In particular:

[java]
chaseGeneralNode.setLocalRotation(chaseGeneralNode.getLocalRotation().mult(yRot));
chaseGeneralNode.setLocalRotation(chaseRotateHelper.getWorldRotation());
[/java]

If set local translation was just overwriting the local transform rotation, then the first line would be unnecessary right? But it is not. I understand it is essentially performing the same command as:

[java]
chaseGeneralNode.setLocalRotation(chaseGeneralNode.getLocalRotation().mult(yRot).mult(chaseRotateHelper.getWorldRotation()));
[/java]

but how is it possible to do that, when setLocalRotation should just be overwriting local transform and not multiplying it?

the first one should have no effect on the second one, unless chaseRotateHelper is a child of chaseGeneralNode (which would have its world rotation changed by chaseGeneralNode on the first line). Which seems very strange to me.

In theory, yes the first one should have no effect, yet it does. which is the part that perplexes me. chaseGeneralNode is completely independent of chaseRotateHelper.

This whole “SimpleChaseCamera” update loop is throwing me for a loop.

SimpleChaseCamera.update()
[java]
public void update() {

    if (enabled) {
        // MOVE TO SPATIAL
        updatePosition();

        if (canRotate && doRotate) {

            // HORIZONTAL
            Quaternion chaseRot = chaseGeneralNode.getLocalRotation().clone();
            chaseGeneralNode.setLocalRotation(new Quaternion());
            chaseRotateHelper.setLocalRotation(chaseRot);

            Quaternion yRot = new Quaternion().fromAngleAxis(horizontRotate * rotateSpeed, Vector3f.UNIT_Y);
            chaseGeneralNode.setLocalRotation(chaseGeneralNode.getLocalRotation().mult(yRot));
            chaseGeneralNode.setLocalRotation(chaseRotateHelper.getWorldRotation());


            // VERTICAL
            Quaternion xRot = new Quaternion().fromAngleAxis(verticalRotate * rotateSpeed, Vector3f.UNIT_X);
            chaseGeneralNode.setLocalRotation(chaseGeneralNode.getLocalRotation().mult(xRot));


            // VERTICAL LIMITATION
            if (doVerticalConstraint) {
                constraintCamera();
            }

            horizontRotate = 0f;
            verticalRotate = 0f;
        }

        if (canZoom && doZoom) {
            Vector3f zoomVec = Vector3f.UNIT_Z.clone().multLocal(zoomStep);
            if (zoomRelativeToDistance) {
                zoomVec.multLocal(0.5f + (0.05f * chaseCamNode.getLocalTranslation().getZ()));
            }

            if (zoomIn) {
                chaseCamNode.setLocalTranslation(chaseCamNode.getLocalTranslation().add(zoomVec.negateLocal()));
            } else {
                chaseCamNode.setLocalTranslation(chaseCamNode.getLocalTranslation().add(zoomVec));
            }

            if (chaseCamNode.getLocalTranslation().z > zoomMax) {
                chaseCamNode.setLocalTranslation(new Vector3f(0, 0, zoomMax));
            } else if (chaseCamNode.getLocalTranslation().z < zoomMin) {
                chaseCamNode.setLocalTranslation(new Vector3f(0, 0, zoomMin));
            }

            doZoom = false;
        }

        app.getCamera().setLocation(chaseCamNode.getWorldTranslation());
        app.getCamera().setRotation(chaseCamNode.getWorldRotation());

    }
}

[/java]

If just looking at the horizontal part:
[java]
// HORIZONTAL
Quaternion chaseRot = chaseGeneralNode.getLocalRotation().clone();
chaseGeneralNode.setLocalRotation(new Quaternion());
chaseRotateHelper.setLocalRotation(chaseRot);

            Quaternion yRot = new Quaternion().fromAngleAxis(horizontRotate * rotateSpeed, Vector3f.UNIT_Y);
            chaseGeneralNode.setLocalRotation(chaseGeneralNode.getLocalRotation().mult(yRot));
            chaseGeneralNode.setLocalRotation(chaseRotateHelper.getWorldRotation());

[/java]

I feel like this could be rewritten as:
[java]
// HORIZONTAL
chaseRotateHelper.setLocalRotation(chaseGeneralNode.getLocalRotation().clone());

            Quaternion yRot = new Quaternion().fromAngleAxis(horizontRotate * rotateSpeed, Vector3f.UNIT_Y);
            chaseGeneralNode.setLocalRotation(yRot.mult(chaseRotateHelper.getWorldRotation()));

[/java]

but the above modification only works when chaseGeneralNode is “reset” to the identity quaternion. Which once again why this is. I am essentially giving a new local rotation of absolute value that is not dependent on the current general node rotation. Am I missing something?

@deMimsy said: In theory, yes the first one should have no effect, yet it does. which is the part that perplexes me. chaseGeneralNode is completely independent of chaseRotateHelper.

Not in theory. In fact, if the two are independent then the first one will have no effect. Therefore, they must be dependent. It’s provable just by looking at the code.

And actually, it’s trivially easy to debug:
[java]
System.out.println(“Before:” + chaseRotateHelper.getWorldRotation());
chaseGeneralNode.setLocalRotation(chaseGeneralNode.getLocalRotation().mult(yRot));
System.out.println(“After:” + chaseRotateHelper.getWorldRotation());
chaseGeneralNode.setLocalRotation(chaseRotateHelper.getWorldRotation());
[/java]

If the first setLocalRotation() is required then the values Before and After will be different… because the two are somehow dependent on each other.