rotation prob

Started by
13 comments, last by turnpast 19 years, 1 month ago
I have a tile based map which I want to render in 3 layers. layer1. base tile 2. static models and 3. animated models. When I render a static model on a particular tile, it seems to render in the right place and it gets redrawn in the right place when I scroll the screen. The problem is I want to rotate the model to face a different direction so I use Matrix.RotationX(angleX) to rotate the model, but when I scroll the screen the model is not drawn on the right tile. Here is the code involved. thanks in advance for any help on this.

map class important snippets

		//initialise tiles 
		public void initTiles(int noTiles)
		{
			//set base tile value 		
			for(int i = 0;i < noTiles;i++)
			{
				TileClass tile = new TileClass();
				tile.setValue(0,0);
				tiles.Add(tile);
				
			}

			//set layer 2 values for static Models
			TileClass setTile = (TileClass) tiles[470];
			setTile.setValue(1,1);
			tiles[470] = setTile;

		}

		public void renderMapTiles()
		{
			
			//render horizontally
			for(int y = 0; y < mapHeight; y++)
			{
				//render vertically
				for(int x = 0; x < mapWidth; x++)
				{
					//figure out the tile to display
					TileClass ti = new TileClass();
					ti = (TileClass) tiles[x + (y * mapWidth)];
					tileToRender = ti.getValue(0);
					//calculate the position
					xPos = (0.7f * x) + xPosChange;
					yPos = (0.7f * y) + yPosChange;
					//int[] adjacency = adjBuffer.Read(typeof(int),
					//set the position of the tile and render
					renderTile(xPos,yPos);
					//render the second layer if need be
					if(ti.getValue(1) != 0)
					{
						
						tentMesh.setPos(xPos,yPos,0.0f);
						tentMesh.rotate(10,10,0);
						tentMesh.DrawMesh(ref device);
						
						
					}
				
				}
			}
		}
		public void renderTile(float xPos,float yPos)
		{
			// Draw the Mesh
			//DrawMesh(xPos, yPos, 0.0f,0);
			grassMesh.setPos(xPos,yPos,0.0f);
			grassMesh.DrawMesh(ref device);
		}
		/// <summary>
		/// We will initialize our graphics device here
		/// </summary>
		public void InitializeGraphics()
		{
			// Set our presentation parameters
			PresentParameters presentParams = new PresentParameters();

			presentParams.Windowed = true;
			presentParams.SwapEffect = SwapEffect.Discard;
			presentParams.AutoDepthStencilFormat = DepthFormat.D16;
			presentParams.EnableAutoDepthStencil = true;

			// Create our device
			device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);

			// Load our meshes
			grassMesh.LoadMesh(@"..\..\worldagrassa.x",ref device);
			tentMesh.LoadMesh(@"..\..\tent.x",ref device);
			tentMesh.rotate(100,100,100);

			//LoadMesh(@"..\..\worldagrassa.x");
			//LoadMesh(@"..\..\tent.x");
			

			
		}


public class StaticMesh
	{
		
		private Mesh mesh = null;
		private Material[] meshMaterials;
		private Texture[] meshTextures;

		//vars to handle rotation matrix
		private float angleX,angleY,angleZ;
		private float posX,posY,posZ;
		private Matrix meshView;

		public StaticMesh()
		{
				meshView = Matrix.Zero;
		}

		public void LoadMesh(string file,ref Device device)
		{
			ExtendedMaterial[] mtrl;

			// Load our mesh
			mesh = Mesh.FromFile(file, MeshFlags.Managed, device, out mtrl);

			// If we have any materials, store them
			if ((mtrl != null) && (mtrl.Length > 0))
			{
				meshMaterials = new Material[mtrl.Length];
				meshTextures = new Texture[mtrl.Length];

				// Store each material and texture
				for (int i = 0; i < mtrl.Length; i++)
				{
					meshMaterials = mtrl.Material3D;
					if ((mtrl.TextureFilename != null) && (mtrl.TextureFilename != string.Empty))
					{
						// We have a texture, try to load it
						meshTextures = TextureLoader.FromFile(device, @"..\..\" + mtrl.TextureFilename);
					}
				}
			}
		}

//		public void DrawMesh(float x, float y, float z,ref Device device)
//		{
//		
//			device.Transform.World =   Matrix.Translation(x,y,z) * meshView;
//				//Matrix.Translation(x,y,z) * Matrix.RotationX(rotX) * Matrix.RotationY(rotY) * Matrix.RotationZ(rotZ);
//			for (int i = 0; i < meshMaterials.Length; i++)
//			{
//				device.Material = meshMaterials;
//				device.SetTexture(0, meshTextures);
//				mesh.DrawSubset(i); 
//			}
//			
//		}
		public void DrawMesh(ref Device device)
		{
			
			device.Transform.World = Matrix.Translation(posX,posY,posZ)* Matrix.RotationX(angleX) * Matrix.RotationY(angleY)* Matrix.RotationZ(angleZ);
			for (int i = 0; i < meshMaterials.Length; i++)
			{
				device.Material = meshMaterials;
				device.SetTexture(0, meshTextures);
				mesh.DrawSubset(i); 
			}
			
		}
		public void setPos(float x, float y, float z)
		{
			posX = x;
			posY = y;
			posZ = z;
			
		}
		public void rotate(float x,float y,float z)
		{			
			
			angleX = x;
			angleY = y;
			angleZ = z;
			
		}
	}
}

Advertisement
Try reording your matrix multiplications:

From this:
Matrix.Translation(posX,posY,posZ)* Matrix.RotationX(angleX) * Matrix.RotationY(angleY)* Matrix.RotationZ(angleZ);

To this:

Matrix.RotationX(angleX) * Matrix.RotationY(angleY)* Matrix.RotationZ(angleZ) * Matrix.Translation(posX,posY,posZ);

Also consider using RotationYawPitchRoll instead of the three axis rotations or using AffineTransform which allows you to specify a center point as for the rotation.
yep, that worked. thanks a lot that was giving me a headache.
I still cant seem to get the mesh to rotate into the desired position. Is there a way to return the centre co-ordinates of a mesh? I could then maybe use this with Matrix.RotationAxis .
Hopefully your mesh is centered at 0,0, if it is not here is my advice:
1. Open up your 3D modeler whatever it is.
2. Move the mesh so that it is centered at 0,0.
3. Save it.

If you don't want to do that there are a number of ways to get the center of the mesh depending on how you define the "center of a mesh". You could use the center of the bounding sphere or the center of the bounding box (see the Geometry class) or you could average the verticies or you could open it in your modeler and see where it is.

Do what you want, but if its center is not at the origin you will probalby want to translate its center to the origin before rotating it:

World = TranslateCenterToOrigin * Rotation * TranslationToWorldPosition;

If you are moving your map around with the world matrix (maybe not such a good idea) you will additionally have to multiply the mesh's transform by the map's transform to get it to stay in the same place on the map.
so is its centered origin not related to where it is in 3d space? am I supposed to use Matrix.Translation or is there a TranslateCenterToOrigin method in MDX. thanks for the help.
If this is in 2 dimensions then you can just do the following.

1. Find the centre point of the quad and put it in a D2DXVECTOR2 like this -
(I assume that you are storing your quad as a RECT if not then I am sure you can work it out)

D3DXVECTOR2 CentrePosition;
CentrePosition.x = QuadRect.left + (QuadRect.right - QuadRect.left)/2;
CentrePosition.y = QuadRect.bottom + (QuadRect.top - QuadRect.bottom)/2;

2. The you subtract this from every vertex of the quad, it si much easier if you make the four corners of the quad into D3DXVECTOR2's first then you can just do this:

TopLeft -= CentrePosition;
TopRight -= CentrePosition;

etc etc

3. Apply the formula that I already mentioned to each of these points, but make sure that you save the the results to a different D3DXVECTOR2 for each point.

4. Then we need to translate the new poionts back, so you do the opposite of step 2 and add the centre position back on to each of the corner vectors that you have.

Note: If you are going to be rotating a lot of objects very often it may be better not to use a RECT and to make your own struct for the quad like this one.

struct Quad
{
D3DXVECTOR2 TopLeft;
D3DXVECTOR2 TopRight;
D3DXVECTOR2 BottomLeft;
D3DXVECTOR2 BottomRight;
};

Hope this helps, kind regards.

Mark Coleman
To help your understanding on spaces:

Object Space is the space the the mesh/quad is defined in. It's origin is is the point that all the vertices in the model are relative to. This is the space that define verts in or the space that they are specified in an x file or whatever.

World Space is an arbitrary space generally representing the scene, a model is moved from object space to world space when all its verticies are multiplied by the world transform. The world transform determines the position of models in the scene.

Screen Space is what you see on your monitor and is generated from world space by multiplying every world transformed vert by the View and Projection matrices.

All these transforms are done at once in the hardware, but this is conceptually what is going on.

So:
If you know the center of rotation of an object in object space (objectRotationCenter) and you know the position of the object in world space (worldPosition) and the rotation of the object rouund its rotation center (objRotation).
Than your world transform should be somehting like:
Translate( -objectRotationCenter) * Rotate(objRotation) * Translate( objectRotationCenter + worldPosition)
Or Better Yet:
Matrix.AffineTransformation(1, objectRotationCenter, Quaternion.RotationYawPitchRoll(objRotation), worldPosition);

Sorry if this is a bit confusing.

thanks for the feedback guys, I'm still in a bit of a rut though, the steps I have taken are.
s1. went into 3ds max and made sure that it was centred to 0,0,0
and exported it using panda exporter

s2. incremented the rot angle each time I draw the mesh so I can see the models movement in 3d space

s3. tried a few million different matrix combinations but can't seem to get the model in the position I want

I tried the following also, but the model just sinks into the map.

Vector3 one = new Vector3(0,0,0);
Vector3 two = new Vector3(posX,posY,posZ);
Vector3 vec = (Vector3) one + two;


device.Transform.World = Matrix.Translation(0,0,0) * Matrix.RotationAxis(new Vector3(0,0,0),angleX) * Matrix.Translation(vec);



Quote:Original post by dazscott
I tried the following also, but the model just sinks into the map.


What do you mean sinks into the map? Try to describe the behavior for us a little better. Is it in the right place but obscured partially by the background? How are you scrolling the screen? Are you using the view or the world matrix to do your scrolling?

Matrix.RotationAxis(new Vector3(0,0,0),angleX) is wrong. The first parameter is an axis and 0,0,0 does not specify an axis. I don't know what the result will be with 0,0,0. 0,1,0 is the y axis, 1,0,0 is the x axis. An axis really ought to be normalized vector.

This topic is closed to new replies.

Advertisement