• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3797
  • Last Modified:

pick object with mouse - Direct3D

How can I determine which object is drawn at a particular pixel?
Currently my program calls DrawUserPrimitives, which takes in as data CustomVertex.PositionColored[].
since z-buffer is enabled there must be easy way to determine the polygon at the pixel. but that still leaves the challenge to determine the array from which it came. Seems like I must use some other API to render the objects.

my other option is to compute on-screen bounds of the object. precision is not important. an approximate rectangular box is acceptable. this seems to be simpler but tedious on my part.

Then there is the issue of dragging the object around. The object moves along a horizontal surface. So this time I have to compute world coordinate from screen coordinate.

how should I go about solving this?

btw, I am using .NET 2.0 managed DirectX libs.
0
jhshukla
Asked:
jhshukla
  • 5
  • 2
1 Solution
 
Javin007Commented:
Well, as I use a prebuilt DirectX engine that has mouse picking included, I can't tell you the RIGHT way to go about it.  However, until you DO find the RIGHT way to go about it, I can give you a cheat.

Each of your objects on the screen will have a unique ID (however you decided to do this, be it a number in an Array, or the DirectX assigned mesh ID, whatever.)

For ONE frame draw the scene to a rendersurface instead of the screen.  Remove all lighting/shaders/etc. and draw each object with a unique color based on its ID.  Use GetPixel to see which color was "clicked."

I'm sure there's a "right" way to do this, but as I don't use DirectX natively, I can't help much more than that.
0
 
jhshuklaAuthor Commented:
what engine do you use? Is it available for free? is it open source?
0
 
Javin007Commented:
www.TrueVision3D.com

The old version (6.2) is available for free to play with, but it's only $150 for the commercial version, which is WAY worth it.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
jhshuklaAuthor Commented:
k, will check it out.
0
 
jhshuklaAuthor Commented:
Javin,

Thanks for the link (and tips) but I think it would be better if I coded this part myself. 1) so that I understand how it was done and don't have to rely on 3rd party libs. 2) computing bounds instead of using colors would be far more efficient as there is only one object that can be picked.

Additionally, [I just discovered] Vector3.Project() (and Unproject()) makes it darn easy to convert to and from screen coords.

will post complete solution after I get it working properly.
0
 
jhshuklaAuthor Commented:
The surface that I plan to pick is a horizontal circular disc making it very simple case and I can achieve the goal without using meshes.

pseudocode:

GUI:======================================
OnMouseDown()
{
  if ( game.IsOnObject(MouseEvent.Location) )
  {
    oldPos = game.GetWorldCoords(MouseEvent.Location);
    state = Drag;
  }
}

OnMouseMove()
{
  if ( state == Drag )
  {
    newPos = game.GetWorldCoords(MouseEvent.Location);
    game.Move(newPos-oldPos);
    oldPos = newPos;
  }
}

OnMouseUp()
{
  if( state == Drag )
  {
    state = Waiting;
  }
}

Game:========================
game.GetWorldCoords(Point p)
{
  Vector3 vnear = Vector3(p.X, p.Y, 0);
  Vector3 vfar = Vector3(p.X, p.Y, 1);

  vnear.Unproject(device.Viewport, device.Projection, device.View, device.World);
  vfar.Unproject(device.Viewport, device.Projection, device.View, device.World);

  // details of v1, v2, v3 are not important to this particular problem.
  return Plane.IntersectLine(Plane.FromPoints(v1, v2, v3), vnear, vfar);
}

game.IsOnObject(Point p)
{
  System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();

  // this is approximate but good enough for my needs
  gp.AddEllipse(pickedObject.GetBounds());

  return gp.IsVisible(point);  
}

PickedObject:=======================
PickedObject.GetBounds()
{
      int left = Int32.MaxValue, right = Int32.MinValue, up = Int32.MaxValue, down = Int32.MinValue;

      foreach (CustomVertex.PositionColored vert in top) // top is surface to be picked
      {
            Vector3 vect = vert.Position;
            vect.Add(new Vector3((float)tempPos.X, (float)tempPos.Y, 0));

            // convert from world space to screen space
            vect.Project(device.Viewport, device.Transform.Projection, device.Transform.View, device.Transform.World);

            // use extremeties as bounds
            left = Math.Min(left, (int)vect.X);
            up = Math.Min(up, (int)vect.Y);
            right = Math.Max(right, (int)vect.X);
            down = Math.Max(down, (int)vect.Y);
      }

      return new System.Drawing.Rectangle(left, up, right - left, down - up);
}
0
 
jhshuklaAuthor Commented:
I am sorry. I forgot to close the question.
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

  • 5
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now