Perpendicular movement bug

Started by mystara, August 09, 2009, 07:44:23 PM

Previous topic - Next topic

mystara

Agh!

I've come across a problem, and I cannot figure out if it's a bug in JPCT or a bug in my code. I've double and triple checked everything and I cannot seem to find the cause of the problem.

I have reproduced the problem by modifying the fps demo. My aim is to store independent camera settings in a set of object array variables. Note that in this example, there is only one setting in the arrays:


private SimpleVector[] storedPosition = {new SimpleVector(STARTING_POS)};
private SimpleVector[] storedDirection = {new SimpleVector()};
private Matrix[] storedPlayerDirection = {new Matrix()};


A new function swaps the camera object with one of the values in the settings. Again, for the purposes of this demo, the value which is swapped in is arbitrarily fixed at index 0.


protected void swapCameraWithStoredVariables()
{
SimpleVector swap;
SimpleVector swap2;
Matrix otherSwap;

swap = storedPosition[0];
storedPosition[0] = camera.getPosition();
camera.setPosition(swap);

swap2 = storedDirection[0];
storedDirection[0] = camera.getDirection();
camera.setBack(swap2.getRotationMatrix().invert3x3());

otherSwap = storedPlayerDirection[0];
storedPlayerDirection[0] = playerDirection;
playerDirection = otherSwap;
}


This function (swapCameraWithStoredVariables ) gets called at the top and bottom of the doMovement() function.

Finally, in gameLoop, I added two lines to set the camera to use the stored values. This occurs immediately before the poll() function:


camera.setPosition(storedPosition[0]);
camera.setBack(storedDirection[0].getRotationMatrix().invert3x3());


Once more, in this example, the camera is set to display a single camera.

To my knowledge, adding this code should have no effect to the operation of the fps demo. All it does is copy the stored variables in to the current camera to carry out any movement. When the movement is calculated, the values are copied back to the stored variables. When the scene is displayed, the variables are loaded in to the camera object.
Therefore, it should behave as the original fps does.

However, in practice, the forward/backward controls move at right angles to the camera direction. For example, if the camera is pointing straight ahead, the forward/backward controls move the camera left and right (strafing).

I cannot for the life of me, determine why this is happening. Is it a bug in my code, or a bug in jpct?

I can supply the modified fps demo code if required.


EgonOlsen

Hard to tell from a distance (i'm still on vacation, i.e. on a mobile device only). However, the part with the rotation matrix would be my first guess. The matrix in the camera is actually an inverse world transformation, so i'm not sure if the matrix derived from the direction vector really fits. Try to invert that matrix before using it for setBack or, maybe even better, work with the matrices directy (i.e. clones of them).

mystara

I'm a little confused by your reply.
The matrix is already inverted before being used in setback:

camera.setBack(swap2.getRotationMatrix().invert3x3());

EgonOlsen

I couldn't see that part. The phone's display cuts the code box right after the getRotationMatrix. Have you tried without the invert?


mystara

The view is inverted in two places. One in which the camera/stored values are swapped (which is called twice) and one in which the scene is rendered.

Removing the invert from the swap function causes the display to flicker between two viewpoints. It looks as if it changes between the camera direction and 90 degrees to the camera angle. But it's hard to tell.

Removing the invert from the rendering function (in gameLoop) reverses the left/right rotation as well as causing the forward/backward controls to strafe left/right.

Removing the invert from both functions causes flickering, similar to the first case.

EgonOlsen

Have you tried to work with the matrices directly instead of using the direction vector? If that works, the logic of the matrix-vector-matrix conversion you are now using is flawed somehow. If that doesn't work either, something else is fishy...

mystara

Okay, yes, you were right.
If I use the matrix directly (rather than a modification of the vector) then it works correctly.

I still don't see the problem with the code I have though. My debugging so far suggested that the vector was being correctly preserved. Since the matrix is behaving correctly, I'll see if I can do some debugging this evening to determine why/where/how the matrix is differing from the converted vector.

EgonOlsen

#7
I think the problem is, that getRotationMatrix actually is a kind of lookAt-implementation IIRC. That means that the result for the vector its called on is correct, but it doesn't make any assumptions about the remaining axis of the coordinate system.

mystara

I had understood from this thread that the accepted way to set a camera's direction (as provided by getDirection()) was to do: theVector.getRotationMatrix().invert3x3()

That's all I'm really doing here. The same technique has worked in all the other cases that I've provided - even in the FPS example itself
???

mystara

Okay, I changed the swap function to the following:

protected void swapCameraWithStoredVariables()
{
// TODO

SimpleVector swap;
SimpleVector swap2;
Matrix otherSwap;

System.out.println("The back of the camera matrix looks like this:");
System.out.println(storedDirectionMatrix[0]);
System.out.println("The vector looks like this:");
System.out.println(storedDirection[0]);
System.out.println("And the adjusted vector looks like this:");
System.out.println(storedDirection[0].getRotationMatrix().invert3x3());

swap = storedPosition[0];
storedPosition[0] = camera.getPosition();
camera.setPosition(swap);

swap2 = storedDirection[0];
storedDirection[0] = camera.getDirection();
storedDirectionMatrix[0] = camera.getBack();
camera.setBack(swap2.getRotationMatrix().invert3x3());

otherSwap = storedPlayerDirection[0];
storedPlayerDirection[0] = playerDirection;
playerDirection = otherSwap;
}


The value of storedDirectionMatrix[0] is always the same as storedDirection[0].getRotationMatrix().invert3x3()
Thus, the transformation of storedDirection seems to be correct.

Example output:


The back of the camera matrix looks like this:
(
0.3522742 0.0 0.9358968 0.0
0.0 1.0 0.0 0.0
-0.9358968 0.0 0.3522742 0.0
0.0 0.0 0.0 1.0
)

The vector looks like this:
(0.9358968,0.0,0.3522742)
And the adjusted vector looks like this:
(
0.3522742 -0.0 0.9358968 0.0
0.0 1.0 0.0 0.0
-0.9358968 0.0 0.3522742 0.0
0.0 0.0 0.0 1.0
)


and


The back of the camera matrix looks like this:
(
0.40776044 0.0 0.9130889 0.0
0.0 1.0 0.0 0.0
-0.9130889 0.0 0.40776044 0.0
0.0 0.0 0.0 1.0
)

The vector looks like this:
(0.9130889,0.0,0.40776044)
And the adjusted vector looks like this:
(
0.40776044 -0.0 0.9130889 0.0
0.0 1.0 0.0 0.0
-0.9130889 0.0 0.40776044 0.0
0.0 0.0 0.0 1.0
)

EgonOlsen

And for this test case, you are setting the camera matrix to the saved one or to created one? I'm asking because just that they are equal does not mean that they are correct in case that the saved matrix is somehow set to a wrongly created one.

mystara

During the rendering, it makes absolutely no difference if I do:


camera.setBack(storedDirection[0].getRotationMatrix().invert3x3());


or


camera.setBack(storedDirectionMatrix[0]);


i.e. setting the camera matrix to the stored direction matrix instead of a calculation on the stored direction vector has no effect (which I would expect).

In the swap function (which I previously supplied) the camera matrix is being set by performing a calculation on the vector:

camera.setBack(swap2.getRotationMatrix().invert3x3());
.

EgonOlsen

But the movement is wrong? I guess i can't solve this without a real pc with a keyboard in front of me. Maybe it something that the movement method itself does. I've no idea. If you could upload your test case somehow, i'll try to have a look at it the next week.

mystara


EgonOlsen

Sure, but please wait until next week. Bandwidth of the mobile connection isn't very high.