movement|navigation problem

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
LuMo
Posts: 410
Joined: Sun Aug 21, 2005 2:45 am
Location: Austria
Contact:

movement|navigation problem

Post by LuMo »

i now updated my movement
(
had the problem that you rotate left --> rotates left
you rotate up 180° and rotate left --> rotates right
)

changed that now -> works fine
one problem still left.
when i move the object out of center it rotates around center instead around model-axis.

download here to test
start = reset
select = screenshot

greets
lumo
"Good artists copy, great artists steal."
Pablo Picasso
go2lumo.com
sg57
Posts: 144
Joined: Fri Oct 14, 2005 2:26 pm

Post by sg57 »

hey how do you rotate an image??? a example that would be perfect for everyone would be rotating an image to the direction of the analog nub. It would show the rotate function, demonstrate its use, and show how to change angles, all in one, think you could make an example or soemthing
LuMo
Posts: 410
Joined: Sun Aug 21, 2005 2:45 am
Location: Austria
Contact:

Post by LuMo »

i am not rotating images;
i am working in 3d --> rotate meshes

greets
lumo
"Good artists copy, great artists steal."
Pablo Picasso
go2lumo.com
Ess
Posts: 16
Joined: Thu Apr 20, 2006 8:16 am

Post by Ess »

yes but a 2d example would be beneficial, for simplicity's sake.
cheriff
Regular
Posts: 258
Joined: Wed Jun 23, 2004 5:35 pm
Location: Sydney.au

Post by cheriff »

The rotate operation works on the centre of the world, you need to:
  • * push the current matrix
    * do the rotation
    * translate to the centre of the object you wish to rotate
    * draw the object
    * pop the matrix back
not sure if psp can push/pop (i assume so) but if not just translate again by the opposite amount

EDIT: thanks to PlayfulPuppy for pointing out that I had the translate & rotate backwards. (can you tell its been a while since i've actually done any coding 'for fun' ??)
Last edited by cheriff on Fri May 12, 2006 7:48 pm, edited 2 times in total.
Damn, I need a decent signature!
Ess
Posts: 16
Joined: Thu Apr 20, 2006 8:16 am

Post by Ess »

Why doesn't mine work?

http://pastebin.com/713028
LuMo
Posts: 410
Joined: Sun Aug 21, 2005 2:45 am
Location: Austria
Contact:

Post by LuMo »

Ess... what does not work? (did not check the whole code)
"Good artists copy, great artists steal."
Pablo Picasso
go2lumo.com
PlayfulPuppy
Posts: 22
Joined: Fri May 05, 2006 12:04 am

Post by PlayfulPuppy »

cheriff wrote:The rotate operation works on the centre of the world, you need to:
  • * push the current matrix
    * translate to the centre of the object you wish to rotate
    * do the rotation
    * pop the matrix back
not sure if psp can push/pop (i assume so) but if not just translate again by the opposite amount
Or you could cut out the middle-man and just do the rotation before you do the translation.
PlayfulPuppy
Posts: 22
Joined: Fri May 05, 2006 12:04 am

Post by PlayfulPuppy »

Ess wrote:Why doesn't mine work?

http://pastebin.com/713028
Same problem with you.

Code: Select all

       sceGumTranslate(&pos);
       sceGumPushMatrix();
       sceGumRotateZ(rotationAmount);
       // Draw Array
       sceGumPopMatrix();
Should be:

Code: Select all

       sceGumRotateZ(rotationAmount);
       sceGumTranslate(&pos);
       // Draw Array
Note you shouldn't really have to push or pop the matrix stack unless you want to do something hierachically (Parent/Child objects).

The reason you were getting problems is because, as mentioned earlier, the rotate functions ONLY rotate around the origin (0, 0, 0). So even when you translated the object away from the origin, it would still be rotating around it, which is why it was moving around in a circle.
cheriff
Regular
Posts: 258
Joined: Wed Jun 23, 2004 5:35 pm
Location: Sydney.au

Post by cheriff »

ah crap, i got it backwards..
PlayfulPuppy: cheers for catching that one out, original post edited ;)
Damn, I need a decent signature!
PlayfulPuppy
Posts: 22
Joined: Fri May 05, 2006 12:04 am

Post by PlayfulPuppy »

cheriff wrote:ah crap, i got it backwards..
PlayfulPuppy: cheers for catching that one out, original post edited ;)
Ah it's all good, I confuse them myself quite often and I do this stuff for a living! ;)

And LuMo, after you make this change you'll probably discover that your object won't move in the direction he's facing anymore (I don't know if this is what you were trying to do, your site wont load for me).

Anyway, if you are, there's an easy way to get around it.

Matricies are stored in such a fashion that you can extract vectors from them that represent the X, Y and Z axis' even after the object has been rotated. Since it's in 3D, an axis is represented as a 3D point in space (That's exactly 1.0 units away from the origin). Matricies are ordered like this (First row is matrix.f[0][0], last row is matrix.f[4][0]):

Code: Select all

Matrix4x4:
    [x.x][y.x][z.x][0]
    [x.y][y.y][z.y][0]
    [x.z][y.z][z.z][0]
    [p.x][p.y][p.z][1]
Where P is the position of the object.

So to grab a vector that represents the direction your character is facing, do the following after you've set the rotation of the matrix:

Code: Select all

scePspFVector3 dirVec;		// Vector to store our direction in
ScePspFMatrix4 mat;		// Copy of the matrix that's currently on the stack

sceGumStoreMatrix(&mat);	// Get a copy of the current matrix on the stack

// Retrieve the X axis from the matrix
dirVec.x = mat.f[0][0];
dirVec.y = mat.f[1][0];
dirVec.z = mat.f[2][0];
(Note: This is assuming your character is facing down the positive X axis, or to the right of the screen)

Now you can just add that vector (dirVec) to the position of your object, and it will move forwards one unit in the direction it's facing.

Code: Select all

scePspFVector3 objPos;		// Position of the object

objPos.x += dirVec.x;
objPos.y += dirVec.y;
objPos.z += dirVec.z;

// Apply the object position to the current matrix
sceGumTranslate(&objPos);
If you want your object to move faster or slower, you can just multiply the vector to change its length:

Code: Select all

float length = 0.5;

dirVec.x *= length;
dirVec.y *= length;
dirVec.z *= length;
And now the object will only move forwards 0.5 units.

Hope this has been useful to someone!
Ess
Posts: 16
Joined: Thu Apr 20, 2006 8:16 am

Post by Ess »

how would i go about rotating around an arbitrary axis with pspgu?
PlayfulPuppy
Posts: 22
Joined: Fri May 05, 2006 12:04 am

Post by PlayfulPuppy »

Ess wrote:how would i go about rotating around an arbitrary axis with pspgu?
You could use Quaternions to do an axis-angle rotation (Which you'd have to implement yourself, and quaternions are bloody difficult to understand), or you could multiply several matricies together.

Start by creating one matrix by rotating around the Y axis:

Code: Select all

ScePspFMatrix4 angleMat;
gumRotateY(&angleMat, angle);
That's the easy part. Now we need to create a matrix from the axis you've specified. We can do this one of two ways; By retrieving the X, Y and Z rotation angles from the vector and rotating a matrix using them (You can find information about doing that on the 'net), or we can construct a matrix manually which is what I'm going to demonstrate here.

Now, this method isn't perfect. First of all, it doesn't deal well if your Y axis is pointing down positive Z, but we can compensate for that.

Anyway, what we're going to do is create 3 axis' from the one axis you supply. We can do this by using the cross product, which creates a vector that's orthogonal to 2 other vectors. Basically, if means that if you used the cross product on the X and Y vectors, you'd get the Z vector. If you used the cross product on the Y and Z vectors, you'd get the X vector. It's kinda hard to describe without pictures, but have a look around on the 'net and you should be able to find something.

Anyway, I'll start with the code first, then explain it in more detail:

Code: Select all

	ScePspFVector3 axis;	// This is our axis to rotate around (Set it to whatever you want)

	ScePspFVector3 xAxis, yAxis;
	ScePspFVector3 zAxis = {0.0f, 0.0f, 1.0f};	// Create a dummy Z axis for reference

	yAxis = axis;			// We're going to be rotating around the Y axis (Up) with our angle
	gumNormalize(&yAxis);	// Make sure this vector is normalized (Has a length of 1.0f)

	// NOTE:	These cross-products are untested, you may have to switch the last 2 values
	//			if your object/rotation seems to be inverted after applying the matrix
	gumCrossProduct(&xAxis, &zAxis, &yAxis);		// Create the X axis from the Z and Y axis'
	gumCrossProduct(&zAxis, &xAxis, &yAxis);		// Fix up the Z axis so it's correct

	ScePspMatrix4 axisMat;
	gumLoadIdentity((ScePspFMatrix4*)&axisMat);

	axisMat.f[0][0] = xAxis.x;	// Copy the X axis into our matrix
	axisMat.f[1][0] = xAxis.y;
	axisMat.f[2][0] = xAxis.z;

	axisMat.f[0][1] = yAxis.x;	// Copy the Y axis into our matrix
	axisMat.f[1][1] = yAxis.y;
	axisMat.f[2][1] = yAxis.z;

	axisMat.f[0][2] = zAxis.x;	// Copy the Z axis into our matrix
	axisMat.f[1][2] = zAxis.y;
	axisMat.f[2][2] = zAxis.z;
So what we're doing here is first creating a dummy Z axis that's pointing down the positive Z. This allows us to extract the potential X axis from the Y axis you supplied. The Y axis is then normalized, to make sure our matrix is also normalized (If your Y axis length is greater or less than 1.0f, the scale of your object will be off and could make some wierd results).

Then, we create the X axis by doing a cross product between our dummy Z axis and our supplied Y axis. This axis will be correct, even though we're using a 'fake' Z axis. HOWEVER, if your supplied axis (Y) is equal to (0, 0, 1), or facing directly down the Z axis, the X axis will equal 0. This is a problem using this technique. There is a way around it, however. Insert this code before doing the cross products:

Code: Select all

	if(yAxis.z == 1.0f)
	{
		zAxis.x = 0.0f;
		zAxis.y = -1.0f;
		zAxis.z = 0.0f;
	}
	else if(yAxis.z == -1.0f)
	{
		zAxis.x = 0.0f;
		zAxis.y = 1.0f;
		zAxis.z = 0.0f;
	}
This will avoid the Y and the Z axis' being the same, and will avoid getting a zero-lenth X axis.

There's still one last problem, being that if the Y axis is below the horizon (Its Y component is < 0), the Z axis will be pointing in the wrong direction and our X axis will invert, due to the way the cross-product works. Yet again, we can account for this by doing the following before the above code:

Code: Select all

	if&#40;yAxis.y < 0.0f&#41;
	&#123;
		zAxis.x = 0.0f;
		zAxis.y = 0.0f;
		zAxis.z = -1.0f;
	&#125;
Basically, depending on the order you do the cross product in, you'll get a vector pointing in one of two directions. Z cross Y will get you a positive X axis, while Y cross Z will get you a negative X axis (Note: I can't actually remember the order correctly, so this has a 50/50 chance of being wrong. If so, and your model seems to be facing the wrong way, just try switching the values).

Due to the fact our Z axis is an approximation, we just need to be sure that it's facing the right way. This code should take care of that (Although may require tweaking).

Anyways, after we've got the X axis, we need to fix up the Z axis. If we just left it the way it was at this point, your model would skew because the Z axis is not correct, we were only using the previously set values as an approximation. However, since we now have the X and Y axis', we can do a cross product on them and get the correct Z axis! The cross product is a very useful little function like that. (Yet again, I may have got these values the wrong way around, even if the one above it was correct. If your model seems to be facing the wrong way down the Z axis, swap these values).

And that's basically it! Now we just copy the values into our matrix, and we've successfully created a whole matrix out of a single vector.

Now all that's left to do is to apply our rotation matrix (angleMat) to this matrix. We can do this by multiplying them together:

Code: Select all

	ScePspFMatrix4 finalMat;

	gumMultMatrix&#40;&finalMat, &angleMat, &#40;ScePspFMatrix4*&#41;&axisMat&#41;;
And finally add our object position:

Code: Select all

	ScePspFVector3 objPos;	// The position of our object

	gumTranslate&#40;&finalMat, &objPos&#41;;
And congratulations! You've created an axis/angle rotation matrix. Put this all into a function such as RotateAxisAngle(ScePspFMatrix4 &result, ScePspFVector3 axis, float angle), and it'll be there whenever you need it.

Man, that's a long-arse post. I should write an FAQ on this or something. :P
Ess
Posts: 16
Joined: Thu Apr 20, 2006 8:16 am

Post by Ess »

Thank you PlayfulPuppy for your response.

How about doing the rotation on a new matrix, and then doing the translation on another new matrix and then multiplying them?

I don't know if that would be easier, but I would understand it easier.
PlayfulPuppy
Posts: 22
Joined: Fri May 05, 2006 12:04 am

Post by PlayfulPuppy »

Ess wrote:Thank you PlayfulPuppy for your response.

How about doing the rotation on a new matrix, and then doing the translation on another new matrix and then multiplying them?

I don't know if that would be easier, but I would understand it easier.
Oh, you mean rotating around an arbitrary point! Rotating around an arbitrary axis is quite a different thing.

Yes, to do that you need a point of rotation, a point in space (Relative to the object) that determines where the rotation will take place.

1) Translate using the negative point of rotation. (0 minus Point of rotation)
2) Rotate the object
3) Translate back to the origin using the point of rotation
4) Translate to where you want the object to be in the world.
Ess
Posts: 16
Joined: Thu Apr 20, 2006 8:16 am

Post by Ess »

The problem I am having is with a game I am trying to develop. It is (to be) a 2D overhead shooter. The player stays static on the screen and the "world" rotates and moves around him.

This means the world will always rotate around 0,0,0.

I tried rotating --> translating, but then when i tell the player to move forward, the player moves diagonally according to the angle I have rotated. And the "world" just keeps rotating on the same point. I want the point to move wherever the player is.

Does that make sense?
PlayfulPuppy
Posts: 22
Joined: Fri May 05, 2006 12:04 am

Post by PlayfulPuppy »

What you actually want to be doing here is not moving the world, but moving the camera and your character.

In the graphics pipeline, there are several matricies that are combined together to get the final 3D result of the verticies. The one's we're interested in here are:

- The World/Model matrix: This determines where in the object is in relation to the origin, or [0, 0, 0].

- The View matrix: This is the one we're interested in. This is like a camera looking into the world.

- The Projection matrix: This is a little more complex. It basically warps the scene so that, with a perspective view, objects that are further from the view appear smaller while objects that are closer to the view are larger (Foreshortening).

When you move your character around the world, the world itself shouldn't really be moving. What you should be doing is moving both the view and the character.

While the results are technically the same, it means that you only have to move 2 objects (The view and the character) rather than moving what could be potentially thousands or millions of objects in the world.

You should have a section in your code where you call sceGumMatrixMode(GU_VIEW). In here, do all your translations and rotations before you call sceGumMatrixMode(GU_MODEL). This should move and rotate the view around the world.

As for making your character move in the correct direction, look earlier in the thread where I described retrieving the directional vector from a matrix. Note that it's not really possible to move a character around by constructing matricies each time, and you should at least store the characters position and a rotation angle.

All you need to do is rotate the character using the standard Gum matrix functions, extract and store the directional vector (As described in my earlier post), and translate the character to his pre-stored position. Any time you want to move the character forwards, just add the stored directional vector to the stored position.

I use ScePspFVector3's to do this. Adding vectors is easy, and you do it like so:

Code: Select all

// Somewhere in your class definition or as a global variable
ScePspFVector3 characterPosition, characterDirection;

// ... later in the code...

// When the forwards button is pressed
characterPosition.x += characterDirection.x;
characterPosition.y += characterDirection.y;
characterPosition.z += characterDirection.z;
Then you translate the model matrix using the characterPosition vector when you go to render it.

Let me know if any of this doesn't make sense.
Ess
Posts: 16
Joined: Thu Apr 20, 2006 8:16 am

Post by Ess »

It makes sense, but I can't seem to apply it to my game.

I translate, then rotate the view matrix, load my world, rotate back and translate back my model matrix, then load my player.

Now I am back to where I was, when i was moving the world instead. I don't think I am grasping how to do this.

Code: Select all

sceGumMatrixMode&#40;GU_VIEW&#41;;
		sceGumLoadIdentity&#40;&#41;;

		ScePspFVector3 pos = &#123; xAmount, yAmount, 0.0f &#125;;
		ScePspFVector3 pos2 = &#123; 0.0f - xAmount, 0.0f - yAmount, 0.0f &#125;;
		sceGumTranslate&#40;&pos&#41;;

		sceGumRotateZ&#40;rotationAmount&#41;;





		sceGumMatrixMode&#40;GU_MODEL&#41;;
		sceGumLoadIdentity&#40;&#41;;

		sceGumDrawArray&#40;GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 18*3, 0, vertices&#41;;








		sceGumRotateZ&#40;0.0f - rotationAmount&#41;;

		sceGumTranslate&#40;&pos2&#41;;

		sceGumDrawArray&#40;GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 2*3, 0, guy&#41;;
I'm thinking I could do some trigonometry to calculate how much to translate on the X and Y to simulate a strafe relative to the player.
PlayfulPuppy
Posts: 22
Joined: Fri May 05, 2006 12:04 am

Post by PlayfulPuppy »

You're translating and rotating the view in the wrong order.

Also, if you want your character to be in the center of the screen, your view should be directly above the character (So pos2 should be the same as pos1 except with a Z value > 0, say about 20)
Ess
Posts: 16
Joined: Thu Apr 20, 2006 8:16 am

Post by Ess »

You are right, that code is in the wrong order. When I rotate first, then translate, The strafing is still on a diagonal. I am really starting to lose my mind on this... haha

Thank you for all of your help so far though, I feel like I am getting closer.
PlayfulPuppy
Posts: 22
Joined: Fri May 05, 2006 12:04 am

Post by PlayfulPuppy »

How are you getting the strafing coordinates? You should be extracting a vector from the matrix like I did in my earlier post, except grabbing the Y axis instead of the X axis (Or the other way around, depending on what you're doing)
PlayfulPuppy
Posts: 22
Joined: Fri May 05, 2006 12:04 am

Post by PlayfulPuppy »

How are you getting the strafing coordinates? You should be extracting a vector from the matrix like I did in my earlier post, except grabbing the Y axis instead of the X axis (Or the other way around, depending on what you're doing).
Ess
Posts: 16
Joined: Thu Apr 20, 2006 8:16 am

Post by Ess »

I got it working...

Code: Select all

while&#40; running&#40;&#41; &#41;
	&#123;
		sceCtrlReadBufferPositive&#40;&pad, 1&#41;;

		if &#40;pad.Lx > 160 || pad.Lx < 100&#41;
		&#123;
			rotationRate = &#40;float&#41; &#40;pad.Lx - 128&#41; / &#40;127 * 20&#41;;
			rotationAmount -= rotationRate;
		&#125;

		if &#40;pad.Ly > 160 || pad.Ly < 100&#41;
		&#123;
			yAmount -= &#40;float&#41;cos&#40;0.0f - rotationAmount&#41; * &#40; &#40;pad.Ly - 128.0f&#41; / &#40;127.0f * 10.0f&#41; &#41;;
			xAmount -= &#40;float&#41;sin&#40;0.0f - rotationAmount&#41; * &#40; &#40;pad.Ly - 128.0f&#41; / &#40;127.0f * 10.0f&#41; &#41;;
		&#125;

		if &#40;pad.Buttons != 0&#41;
		&#123;
			if &#40;pad.Buttons & PSP_CTRL_LTRIGGER&#41;
			&#123;
				yAmount -= &#40;float&#41;sin&#40;rotationAmount&#41; * 0.1f;
				xAmount -= &#40;float&#41;cos&#40;rotationAmount&#41; * 0.1f;
			&#125; 
			if &#40;pad.Buttons & PSP_CTRL_RTRIGGER&#41;
			&#123;
				yAmount += &#40;float&#41;sin&#40;rotationAmount&#41; * 0.1f;
				xAmount += &#40;float&#41;cos&#40;rotationAmount&#41; * 0.1f;
			&#125;
		&#125;

		sceGuStart&#40;GU_DIRECT, list&#41;;

		sceGuClearColor&#40;0&#41;;
		sceGuClear&#40;GU_COLOR_BUFFER_BIT&#41;;

		sceGumMatrixMode&#40;GU_PROJECTION&#41;;
		sceGumLoadIdentity&#40;&#41;;
		sceGumOrtho&#40;-12.0f, 12.0f, -1.0f, 12.6f, 0.0f, 1000.0f&#41;;





		sceGumMatrixMode&#40;GU_VIEW&#41;;
		sceGumLoadIdentity&#40;&#41;;

		ScePspFVector3 pos = &#123; 0.0f - xAmount, 0.0f - yAmount, 0.0f &#125;;

		sceGumRotateZ&#40;0.0f - rotationAmount&#41;;
		sceGumTranslate&#40;&pos&#41;;





		sceGumMatrixMode&#40;GU_MODEL&#41;;
		sceGumLoadIdentity&#40;&#41;;


		sceGumDrawArray&#40;GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 18*3, 0, vertices&#41;;






		pos.x = xAmount;
		pos.y = yAmount;

		sceGumTranslate&#40;&pos&#41;;
		sceGumRotateZ&#40;rotationAmount&#41;;

		sceGumDrawArray&#40;GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 2*3, 0, guy&#41;;






		sceGuFinish&#40;&#41;;
		sceGuSync&#40;0, 0&#41;;
		
		sceDisplayWaitVblankStart&#40;&#41;;

		sceGuSwapBuffers&#40;&#41;;
	&#125;
Post Reply