• Advertisement
Sign in to follow this  

detect mouse over 3d model

This topic is 3228 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am programming wheel of fortune.You know that user select letter to solve puzzle.My problem is to detect which letter is clicked.I generate Ray with mouse corrdinates.Then for 26 letters,I tried to detect collision using BoundingSphere. this is the piece of code.Please help. private bool mouseOverModel(MouseState mouseState) { Vector3 nearScreenPoint = new Vector3(mouseState.X, mouseState.Y, 0); Vector3 farScreenPoint = new Vector3(mouseState.X, mouseState.Y, 1); Vector3 near3DWorldPoint = graphics.GraphicsDevice.Viewport.Unproject(nearScreenPoint, cameraProjectionMatrix, cameraViewMatrix, Matrix.Identity); Vector3 far3DWorldPoint = graphics.GraphicsDevice.Viewport.Unproject(farScreenPoint, cameraProjectionMatrix, cameraViewMatrix, Matrix.Identity); Vector3 pointerRayDirection = far3DWorldPoint - near3DWorldPoint; pointerRayDirection.Normalize(); Ray pointerRay = new Ray(near3DWorldPoint, pointerRayDirection); for(int i=0;i<alphabet.Length;i++) { BoundingSphere collision = new BoundingSphere(); collision.Radius = alphabet.scale; collision.Center = alphabet.position; Nullable<float> dist = pointerRay.Intersects(collision); if (!dist.HasValue) { return false; } if (dist.Value <= pointerRayDirection.Length())//check whether it is the closest object intersected so far. { selectedLetterIndex = i; alphabet.isclicked = true; Console.WriteLine(selectedLetterIndex); return true; } } return false; }

Share this post


Link to post
Share on other sites
Advertisement
What exactly is your problem? For letters it would probably be better to use a bounding box the size of your characters. Spheres may intersect with eachother.

Share this post


Link to post
Share on other sites
you are right.I use BoundingSphere.I don't know how to use BoundingBox.I want to find which letter is clicked.Can you see any fault in my code.

Share this post


Link to post
Share on other sites
if (dist.Value <= pointerRayDirection.Length())//check whether it is the closest object intersected so far. 

Nope. The only thing you are checking with this test is whether the intersection point is closer to the viewer than the length of the ray. Since you normalized the ray this distance is 1.0 in world space. Do not confuse this with the depth ranging from 0.0 to 1.0 of the 2d points you unproject.

You have to store the first dist that has a value and compare all following valid distances against that one distance. Each time you have a closer distance then store that one. Assuming that all of your letters are next to each other it is valid to return true upon the first hit because it will then be the only one possible:


float best_hit = MAX_FLOAT;

for(int i=0;i<alphabet.Length;i++)
{

BoundingSphere collision = new BoundingSphere();
collision.Radius = alphabet.scale;
collision.Center = alphabet.position;
Nullable<float> dist = pointerRay.Intersects(collision);
if (dist.HasValue && dist.Value <= best_hit)//check whether it is the closest object intersected so far.
{
selectedLetterIndex = i;
alphabet.isclicked = true;
Console.WriteLine(selectedLetterIndex);
best_hit = dist.Value; // if you do not want to return upon first hit this is required
return true;
}

Share this post


Link to post
Share on other sites
Waterwalker your answer is logical.It can work.But I could't understand what can I wrote for MAX_FLOAT value.Can you help.

Share this post


Link to post
Share on other sites
Um ... sorry that is actually FLOAT_MAX as defined in <limits> that you need to include. This represents infinity in this case and stands for "I have not found any intersection yet".

Share this post


Link to post
Share on other sites
I don't want to seem lazy.But I am searching for FLOAT_MAX in XNA and <limits>.But I couldn't related things.Can these library can be c++ or anything else.I couldnt find in XNA.

Share this post


Link to post
Share on other sites
Assuming you're using C# you can use Single.MaxValue to get the maximum value a float can hold. If not using C#, please mention what language you are using.

Share this post


Link to post
Share on other sites
I am using c# and discovered float.MaxValue.I ran the code after applying changes.Bıt it doesn't work.

Share this post


Link to post
Share on other sites
How do you render the letters?

If they are textured quads then it should be strait forward: as you print the letters just store coordinates for each quad in a array and then use that array to search for the quad mouse cursor is inside (in screen space).

Share this post


Link to post
Share on other sites
I generate a new class for Alphabet.I render letters from left to right in two row.That is the code.I generate class properties(position,scale,text,rotation...).The code above doesn't work.What is the problem.I made changes Waterwalker said.
Last piece of code is my draw method.I made necassary transform.But I couldn' detectcollision



alphabet = new Alphabet[26];
int k = 0;
for (int i = 0; i < 26; i++)
{
alphabet = new Alphabet();
alphabet.model = Content.Load<Model>("Model\\letters\\" + (i + 1));
if (i < 13)
{
alphabet.position.Y = 80;
alphabet.position.X = -12+10 * i;
alphabet.position.Z = -20;
alphabet.text = alfabe.ToString();
alphabet.scale = 400.0f;
alphabet.rotation = new Vector3(MathHelper.ToRadians(45), 0.0f, 0.0f);

}
else if (i > 12 && i < 26)
{

alphabet.position.Y = 70;
alphabet.position.X = -12+10 * k++;
alphabet.position.Z = -20;
alphabet.text = alfabe.ToString();
alphabet.scale = 400.0f;
alphabet.rotation = new Vector3(MathHelper.ToRadians(45), 0.0f, 0.0f);


}

}




void DrawAlphabet(Alphabet alphabet)
{
foreach (ModelMesh mesh in alphabet.model.Meshes)
{
foreach(BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.PreferPerPixelLighting = true;
effect.World = Matrix.CreateFromYawPitchRoll(alphabet.rotation.Y, alphabet.rotation.X, alphabet.rotation.Z) *
Matrix.CreateScale(alphabet.scale) *
Matrix.CreateTranslation(alphabet.position);
effect.Projection = cameraProjectionMatrix;
effect.View = cameraViewMatrix;
if (alphabet.isclicked == false)
{
effect.DiffuseColor = new Vector3(255.0f, 255.0f, 0.0f);


}


}
mesh.Draw();

}

Share this post


Link to post
Share on other sites
Well you need to be more specific. Is the picking entirely wrong so that you find no intersection at all? Or does it sometimes find an intersection but with the wrong mesh? How does the mesh looks like (provide a screenshot)?

If you mesh is not centered at the origin then scaling and translating it leads to a different position that a sphere centered at the translation position with scale radius.

Actually, the way you do it now should work even if using rectangles or boxes instead of spheres would be better :)

Note that it might also be easier if you transform the bounding rectangle of each Alphabet instance to screen space by projecting it and then test for intersection witht the 2D mouse point.

Share this post


Link to post
Share on other sites
I find no intersection.I couldn't use Bounding rectangle in 3d model.But Boundingbox may be.As you said maybe <ı must try transforming 3d cooordinates to 2d coordinates.

Share this post


Link to post
Share on other sites
can anyone help me how to project 3d model coordinates to screen coordinates.please by example.I use scale factor 400 to draw letters.consider this.(center can change)

Share this post


Link to post
Share on other sites
Without having any clue about XNA I would suggest looking at graphics.GraphicsDevice.Viewport.Project [grin]

Share this post


Link to post
Share on other sites
I have implemented code in msdn page(draw a sprite over a model).But to detect collision with mouse pointer I need model.width and model.height is 2d.Bounding box no method for width and height.I get these values.As a result I can implement like this.

private bool mouseOverSprite(Vector2 mouseposition)
{
for(int i=0;i<alphabet.Length;i++)
{
if(mouseposition.X>=alphabet.position.X && mouseposition.X<alphabet.position.X+alphabet.image.Width &&mouseposition.Y>=alphabet.position.Y && mouseposition.Y<alphabet.position.Y+alphabet.image.Height)
{

selectedLetterIndex =i;
return true;
}
}

return false;
}




private void from3dpointto2d(MouseState mouseState)
{
for (int i = 0; i < alphabet.Length; i++)
{

totalbounds = new BoundingSphere();
modelworldtransform=Matrix.CreateFromYawPitchRoll(
alphabet.rotation.Y,
alphabet.rotation.X,
alphabet.rotation.Z) *

Matrix.CreateScale(alphabet.scale) *

Matrix.CreateTranslation(alphabet.position);
foreach (ModelMesh mesh in alphabet.model.Meshes)
{
totalbounds = BoundingSphere.CreateMerged(totalbounds, mesh.BoundingSphere);
}
center=GraphicsDevice.Viewport.Project(totalbounds.Center,cameraProjectionMatrix,cameraViewMatrix,
modelworldtransform);
letterposition.X = center.X;
letterposition.Y = center.Y;
extend = BoundingBox.CreateFromSphere(totalbounds);


}

}

Share this post


Link to post
Share on other sites
I have no value for width and height.Bounding box doesn't return values for these.
this desn't work

Share this post


Link to post
Share on other sites
- You have the mesh
-> Get its 3d bounding box
-> project all 8 points of the box to 2d
-> calculate the 2d bounding rectangle
-> calculate the bounding rect's width and height
=> done

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement