Picking problems (SOLVED) with multiple units involved

Started by
0 comments, last by ironwill96 19 years, 1 month ago
I had another thread about Mesh movement which kind of turned into this issue, so i'm posting a new thread to state the new problem so people can help me figure it out. The basic problem i'm having is that whenever we do a device.Transform.World that is not tied to the currently selected object, it messes up the picking ray somehow so that it no longer hits anything. The code where the picking is done is shown below (an excerpt):

//Picking tests etc..for now just do the one unit..eventually handle multiple and only check
				//ones that are on-screen by using quad tree culling
				Vector3 pickRayOrigin, pickRayDirection;
				Matrix matProj = device.GetTransform(Microsoft.DirectX.Direct3D.TransformType.Projection);
				int x = e.X;
				int y = e.Y;


				Vector3 v;
				v.X =  ( ( ( 2.0f * x ) / device.PresentationParameters.BackBufferWidth  ) - 1 ) / matProj.M11;
				v.Y = -( ( ( 2.0f * y ) / device.PresentationParameters.BackBufferHeight ) - 1 ) / matProj.M22;
				v.Z =  1.0f;

				// Get the inverse of the composite view and world matrix
				Matrix matView, matWorld, m;			
				matView = this.device.GetTransform(Microsoft.DirectX.Direct3D.TransformType.View);
				matWorld = this.device.GetTransform(Microsoft.DirectX.Direct3D.TransformType.World);
				m = matWorld * matView;
				m = Matrix.Invert(m);

				// Transform the screen space pick ray into 3D space
				pickRayDirection.X  = v.X * m.M11 + v.Y * m.M21 + v.Z * m.M31;
				pickRayDirection.Y  = v.X * m.M12 + v.Y * m.M22 + v.Z * m.M32;
				pickRayDirection.Z  = v.X * m.M13 + v.Y * m.M23 + v.Z * m.M33;
				pickRayOrigin.X = m.M41;
				pickRayOrigin.Y = m.M42;
				pickRayOrigin.Z = m.M43;
				
				//start temporary code without quad-tree support
				Unit tempUnitData;
				bool matches = false;

				//for now just check all units for picking code using an arraylist
				for (int j = 0; j < this.createdUnitsList.Count; j++)
				{
					tempUnitData = (Unit) this.createdUnitsList[j];
					
					//uncomment below for OLD picking method before bounding boxes
					//if (tempUnitData.MeshData.Intersect(pickRayOrigin, pickRayDirection))
					//{


					//new picking code
					Matrix Wtrans = tempUnitData.returnRotateXTranslation() * 
						tempUnitData.returnRotateYTranslation() * tempUnitData.returnRotateZTranslation()
						* tempUnitData.returnObjectTranslation();
					Matrix InWTrans = Matrix.Invert(Wtrans);
					Vector3 IpickRayDirection = Vector3.TransformNormal(pickRayDirection, InWTrans);
					Vector3 IpickRayOrigin = Vector3.TransformCoordinate(pickRayOrigin, InWTrans);
					 
					if (tempUnitData.myCollisionObject.ORayProbe(IpickRayOrigin, IpickRayDirection))


The ORayProbe method being called in the code above is found below:

public bool ORayProbe(Vector3 rayPosition, Vector3 rayDirection)
		{
			return Geometry.BoxBoundProbe(this.OLowerLeft, this.OUpperRight, rayPosition, rayDirection);
		}


The OUpperRight and OLowerLeft parameters in the code above represent the location of a static boundingbox drawn around the mesh located at the origin (in WorldSpace). Here is the code where the model is actually drawn in our Unit class.

protected void DrawModel()
		{	
			//this method is dependent on the constructor being formed properly with meshMaterials and meshTextures properties
			for (int i = 0; i < this.meshMaterials.Length; i++)
			{
				this.device.Material = this.meshMaterials;
				this.device.SetTexture(0, this.meshTextures);		
				
				//we are doing an X, Y, Z, and translation here by multiplying 4 matrices together - ORDER matters!	
				Matrix Wtrans = this.returnRotateXTranslation() * 
					this.returnRotateYTranslation() * this.returnRotateZTranslation()
					* this.returnObjectTranslation();	
				this.device.Transform.World = Wtrans; 			
				//just debug code to render all meshes as wireframes for now - they look better than untextured!
				//device.RenderState.FillMode = FillMode.WireFrame;				
				device.RenderState.FillMode = FillMode.Solid;				
				this.mesh.DrawSubset(i);			
			}
		}


This is where we think the issue is. The code works fine with one unit loaded. You can select it, move it around etc with no issues. When you load more than one unit, you can select one, move it somewhere then shift-select another so that you have both selected. You can even move both to somewhere on the screen. As soon as you unselect them though, and then try to re-select either unit, you never detect a hit. It seems like moving the second unit renders the picking code invalid somehow b/c it doesnt account for the device.Transform.World change that took place. How can we rewrite the picking code to take in account the movement, or is there something we need to do when we draw to fix the world transform back to its original state? Thanks, Nathan [Edited by - ironwill96 on March 15, 2005 6:27:03 PM]
"There are those who said this day would never come, what do they have to say now?" - Halo 2 Trailer
Advertisement
I figured out the issue I was having.

The key is to keep track of whatever you transform the World matrix by, and then either set it back to its original state or multiply the world transform by the inverse of the change you made to change it back. After doing that and making sure that my bounding boxes were being moved everywhere I called move on a unit, the problem fixed itself!

Nathan
"There are those who said this day would never come, what do they have to say now?" - Halo 2 Trailer

This topic is closed to new replies.

Advertisement