1
\$\begingroup\$

Hello guys so I'm implementing this mouse manager to be able to pick up objects.

My application uses mainly textured quads in 3d space. I'm using bounding boxes in monogame to do so, however my solution lacks accuracy.

Right now what I have is this: http://imgur.com/oySTCay

you can clearly see what the problem is, so this solution is probably not the best.

this is my method to calculate the bounding box:

        public BoundingBox GetBoundingBox()
    {
        Matrix transform = Node.GetTransformForBoundingBox();

        vertices[0] = Vector3.Transform(new Vector3(0, 0, 0), transform);
        vertices[1] = Vector3.Transform(new Vector3(Texture.Width * m_fTexturescale, 0, 0), transform);
        vertices[2] = Vector3.Transform(new Vector3(0, (Texture.Height * m_fTexturescale) * -1, 0), transform);
        vertices[3] = Vector3.Transform(new Vector3(Texture.Width * m_fTexturescale, (Texture.Height * m_fTexturescale) * -1, 0), transform);

        return BoundingBox.CreateFromPoints(vertices);
    }

And the mouse picking part is the standard ray tracing into near/far clipping planes with unproject.

So I was thinking, maybe if I do the other way around, and instead of un-projecting the mouse, i could project all the vertices and do some kind of polygon math to check if the mouse position is inside the polygon formed from the projected vertices, (occluded vertices are worrying me though).

Do you think is feasible, or is there any other option, should i just go for OBB?

Thanks alot,

Roger Martins

EDIT:

So after searching a bit for OBB's i found that CartBlanche had one implementation on his samples repo

this: https://github.com/CartBlanche/MonoGame-Samples/blob/master/CollisionSample/BoundingOrientedBox.cs

so I just used it and it works pretty well, now i just have one bug that i cant figure out, one transformation must be wrong.¨

result : http://imgur.com/QOsIbj7

what i'm doing: so now I have a box parameter in this class, nullable one.

how I build the bounding box :

  public SOrientedBoundingBox GetBoundingBox()
    {
        //create the initial bounding box
        if (obb == null)
        {
            //calculate the vertices for the textured quad in model space at the origin (inferior left corner is origin because we invert the y to conpensate for the perspective projection)
            vertices[0] = new Vector3(0, 0, 0);
            vertices[1] = new Vector3(Texture.Width * m_fTexturescale, 0, 0);
            vertices[2] = new Vector3(0, (Texture.Height * m_fTexturescale) * -1, 0);
            vertices[3] = new Vector3(Texture.Width * m_fTexturescale, (Texture.Height * m_fTexturescale) * -1, 0);
            //get bounding box and trasnform it to orientedboundingbox 
            //TODO : remove the middle step
            BoundingBox box = BoundingBox.CreateFromPoints(vertices);
            obb = SOrientedBoundingBox.CreateFromBoundingBox(box);
            return obb.Value;           
        }
        else
        {
            return obb.Value.Transform(Node.GetQuaternion(), new Vector3(Node.AbsolutePosition.X, Node.AbsolutePosition.Y * -1, Node.AbsolutePosition.Z)*Node.Scale);
        }



    }

I'm going to fiddle a bit more with it, but the problem is something minor, i think. But maybe one of you can detect something silly i did.

Thanks, Roger.

\$\endgroup\$
  • 1
    \$\begingroup\$ OBB is probably going to give you the best results, with the least amount of work. \$\endgroup\$ – MichaelHouse Mar 4 '14 at 15:04
  • \$\begingroup\$ I'm going to try and replicate monogame bounding box stuff for obb, but it seem's the best option. That solution will work for every case also, but stuff like, minimum containing box will be a pain I think, but well that's another problem. \$\endgroup\$ – Roger Martins Mar 4 '14 at 15:06
  • \$\begingroup\$ If you need stuff like minimum containing box isn't it easier to just multiply the vertices of your quads with your MVP matrix and get them into screenspace? And then find some inside generic vertex mesh code for 2d.. Seems like that's what you're gonna have to do with a OBB anyway more or less. \$\endgroup\$ – Jonkel Mar 4 '14 at 15:31
  • \$\begingroup\$ maybe, but having half logic for ray tracing the mouse all done, I just need to change the box it self, and probably OBB will be more useful for other stuff. I'm going to implement it today, and report back with results. \$\endgroup\$ – Roger Martins Mar 5 '14 at 6:38
1
\$\begingroup\$

in https://github.com/CartBlanche/MonoGame-Samples/blob/master/CollisionSample/BoundingOrientedBox.cs

the box is calculated based in a center vector and a distance to the edge. after transformations in the textured quad, that distance changes, so i had to basicaly update that to correct the bug. result: https://www.dropbox.com/s/5e02onl4ftsaett/BoundingBox.gif

method:

       public SOrientedBoundingBox GetBoundingBox()
{
    //create the initial bounding box
    if (obb == null)
    {
        //2-------3
        //|       |
        //|       |
        //0-------1
        //calculate the vertices for the textured quad in model space at the origin (inferior left corner is origin because we invert the y to compensate for the perspective projection)
        m_objVertices[0] = new Vector3(0, 0, 0);
        m_objVertices[1] = new Vector3(Texture.Width * m_fTexturescale, 0, 0);
        m_objVertices[2] = new Vector3(0, -(Texture.Height * m_fTexturescale), 0);
        m_objVertices[3] = new Vector3(Texture.Width * m_fTexturescale, -(Texture.Height * m_fTexturescale), 0);

        //get bounding box and trasnform it to orientedboundingbox 
        //TODO : remove the middle step

        BoundingBox box = BoundingBox.CreateFromPoints(m_objVertices);
        obb = SOrientedBoundingBox.CreateFromBoundingBox(box);
        return obb.Value;
    }
    else
    {
        //calculate the transformed vertices without rotations
        // this means they are in the model space, in the origin (0,0,0)
        m_objDummyVertices[0] = Vector3.Transform(new Vector3(0, 0, 0), Node.GetScaledTranslationInvY());
        m_objDummyVertices[1] = Vector3.Transform(new Vector3(Texture.Width * m_fTexturescale, 0, 0), Node.GetScaledTranslationInvY());
        m_objDummyVertices[2] = Vector3.Transform(new Vector3(0, -(Texture.Height * m_fTexturescale), 0), Node.GetScaledTranslationInvY());
        m_objDummyVertices[3] = Vector3.Transform(new Vector3(Texture.Width * m_fTexturescale, -(Texture.Height * m_fTexturescale), 0), Node.GetScaledTranslationInvY());

        //calculate the new length of the sides, this is needed beacause the bounding box uses the side size to calculate intersections, and not the vertices
        Vector3 half = new Vector3(Vector3.Distance(m_objDummyVertices[0], m_objDummyVertices[1]) * 0.5f, Vector3.Distance(m_objDummyVertices[0], m_objDummyVertices[2]) * 0.5f, 0);
        //get the original, its saved in the member box
        Vector3 halforig = obb.Value.HalfExtent;
        //find the diference to ajust the new translation
        Vector3 diference = (half - halforig);
        //ajust translation and add the diference, the Y flipping is needed to compensate for the perspective
        // TODO : figure something out for all the new vector3 used here
        Vector3 translation = (new Vector3(Node.AbsolutePosition.X, Node.AbsolutePosition.Y, Node.AbsolutePosition.Z) + diference) * new Vector3(1, -1, 1);
        //transform the original box
        return obb.Value.Transform(Node.GetQuaternion(), translation, half);
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.