Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

hi guys,

 

I'm trying to check for intersections with meshes in my scene(to find out which tile the user clicked on). I am developing a fake isometric(ortho view) tile based game in c# and MDX. I found an example of how to do this in vb.net(intersecting teapot mesh). I played around with it in vb, added extra meshes and changed the view and projection matrices etc. just to mimic how I would be using it in my game. I can't however seem to get the ray picking to work now that I have converted the code. any ideas on where I could be going wrong?

 

here is the vb ver

 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

'=======Parameters

presentParams = New PresentParameters

presentParams.Windowed = True

presentParams.SwapEffect = SwapEffect.Discard

'=======Device

dev = New Direct3D.Device(0, DeviceType.Hardware, pic3d, CreateFlags.HardwareVertexProcessing, presentParams)

'=======Mesh

mesh = mesh.Teapot(dev)

mesh2 = mesh.Teapot(dev)

 

'=======Camera

dev.Transform.View = Matrix.LookAtLH(New Vector3(0.0F, 2.0F, 2.0F), New Vector3(0, 0, 0), New Vector3(0, 1, 0))

'dev.Transform.View = Matrix.LookAtLH(New Vector3(0.0F, 30.0F, 30.0F), New Vector3(1, 1, 0), New Vector3(0, 1, 0))

'dev.Transform.View = Matrix.LookAtLH(Me.Width / 35, Me.Height / 35, -1000.0F, 10000.0F)

 

dev.Transform.Projection = Matrix.OrthoLH(CSng(Math.PI / 4), 1.3333, 1, 100)

'=======Loop

Me.Show()

MainLoop()

End Sub

 

Private Sub MainLoop()

Do

Render()

Application.DoEvents()

Loop

End Sub

 

Private Sub Render()

dev.Clear(ClearFlags.Target, System.Drawing.Color.CornflowerBlue, 1.0F, 0)

dev.BeginScene()

'==========

vec1 = New Vector3(1.7, 0, 0)

vec2 = New Vector3(-1.7, 0, 0)

 

dev.Transform.World = Matrix.Translation(vec1)

mesh.DrawSubset(0)

 

 

dev.Transform.World = Matrix.Translation(vec2)

mesh2.DrawSubset(0)

'==========

dev.EndScene()

dev.Present()

End Sub

 

 

 

Private Sub Form1_Mousedown(ByVal sender As System.Object, ByVal e As _

System.Windows.Forms.MouseEventArgs) Handles pic3d.MouseDown

If e.Button = MouseButtons.Left Then

Intersect(e.X, e.Y, vec1, mesh)

Intersect(e.X, e.Y, vec2, mesh2)

 

End If

End Sub

 

 

Public Sub Intersect(ByVal x As Single, ByVal y As Single, ByVal t As Vector3, ByVal m As Direct3D.Mesh)

Dim Near As Vector3

Dim Far As Vector3

Dim Closest As IntersectInformation

Dim locMesh As Mesh

Dim tran As Vector3

 

 

Near = New Vector3(x, y, 0)

Far = New Vector3(x, y, 1)

tran = New Vector3(0, 0, 0)

 

locMesh = m

 

 

Near.Unproject(dev.Viewport, dev.Transform.Projection, dev.Transform.View, Matrix.Translation(t))

Far.Unproject(dev.Viewport, dev.Transform.Projection, dev.Transform.View, Matrix.Translation(t))

Far.Subtract(Near)

'=======================================================

' Here is where you check for an intersection

If locMesh.Intersect(Near, Far, Closest) Then

dev.RenderState.FillMode = FillMode.WireFrame

 

Else

'dev.RenderState.FillMode = FillMode.Solid

End If

 

 

 

 

End Sub

 

 

 

 

 

here is some important snippets from the c# ver

 

private void SetupCamera()

{

 

 

device.Transform.Projection = Matrix.OrthoLH(this.Width / 35, this.Height / 35,-1000.0f, 10000.0f);

//device.Transform.View = Matrix.LookAtLH(new Vector3(0f,0f, 18.0f), new Vector3(28f,28f,0), new Vector3(1,1,0));

device.Transform.View = Matrix.LookAtLH(new Vector3(0f,0f, 18.0f), new Vector3(28f,28f,0), new Vector3(1,1,0));

 

//device.RenderState.Ambient = Color.DarkBlue;

device.Lights[0].Type = LightType.Directional;

device.Lights[0].Diffuse = Color.White;

device.Lights[0].Direction = new Vector3(0, -1, -2);

device.Lights[0].Enabled = true;

 

 

}

 

protected override void OnMouseDown(MouseEventArgs e)

{

 

if(e.Button == MouseButtons.Left)

{

 

intersection(grassMesh);

 

 

}

 

}

 

private void intersection(StaticMesh staticMesh)

{

IntersectInformation closest = new IntersectInformation();

 

Vector3 near = new Vector3(xMousePos,yMousePos,0);

Vector3 far = new Vector3(xMousePos,yMousePos,1);

 

 

Vector3 vec = (Vector3) tilesCoOrd[0];

 

 

near.Unproject(device.Viewport,device.Transform.Projection,device.Transform.View,Matrix.Translation(vec));

far.Unproject(device.Viewport,device.Transform.Projection,device.Transform.View,Matrix.Translation(vec));

far.Subtract(near);

 

 

Mesh mesh = staticMesh.getMesh();

 

 

if( mesh.Intersect(near,far,out closest))

{

 

//handle intersection

 

 

}

 

 

}

Posted

I recently implemented Ray Picking myself, I'm not an expert but here is what I did. I tranformed back through the Project and View matrix's and created a ray. Then I used this ray with a bounding sphere in the world to detect my own collisions, instead of using the mesh.intersect() method. Using that method requires you to tranform the ray back through the mesh's world tranform. Which I never got to work properly.

 

I'm not familiar with how the DirectX unproject functions work but I suspect you are getting a translation component in your far vector. Which mesh.intersect() expects a Ray Orgin and Ray Direction (no translation in direction).

 

Anyway, here is how I transformed the mouse click into world co-ordinates

 

       private void HardwareToWorld(int x, int y, out Vector3 RayOrig, out Vector3 RayDir)
       {
           Matrix invView = Matrix.Invert(device.Transform.View);
           Vector3 v = new Vector3();
           //Reverse the Projection transformation
           v.X = (float)(((2.0 * x) / container.Width) - 1) / device.Transform.Projection.M11;
           v.Y = (float)-(((2.0 * y) / container.Height) - 1) / device.Transform.Projection.M22;
           v.Z = -1;  //We are looking down the Z
           //Multiplying by the inverse Matrix in this way prevents the translation component
           //of the Matrix from taking affect.
           RayDir.X = v.X * invView.M11 + v.Y * invView.M21 + v.Z * invView.M31;
           RayDir.Y = v.X * invView.M12 + v.Y * invView.M22 + v.Z * invView.M32;
           RayDir.Z = v.X * invView.M13 + v.Y * invView.M23 + v.Z * invView.M33;
           RayDir.Normalize();
           RayOrig.X = invView.M41;
           RayOrig.Y = invView.M42;
           RayOrig.Z = invView.M43;

           RayOrig += RayDir * camera.Near; //Move it to the near plane
       }

 

Hope it helps!

Posted
thanks a lot for the reply. I have tried implementing your method, I haven't been able to get it working yet,but I think that may be because I'm scrolling my tile map by changing the tile meshes position in world co-ords. I'll have a go at it again when I set up scrolling based on the view matrix.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...