Object Selection in TGE/A 1.7 trying to kill me slowly
by Ted Southard · in Torque Game Engine Advanced · 05/28/2008 (1:33 pm) · 9 replies
Edit: Solved. See posts from Jeff Faust near bottom.
I have no idea why this is happening, but when I ported my object selection code from TSE to TGEA 1.7, it has stopped working properly. It works somewhat, but it's behavior is so odd that it makes me want to jump out of my first-story window. This involves the updated object selection resource originally created by Dave Myers and updated by Rubes.
The basic behavior of it is that if you click on an object in the game, it does not always return the object you are clicking on, as if the mouse vector is coming from another part of the screen, or it is not created correctly. For example, I have several statics (rocks, tree), two interiors, and the ability to spawn bots. Clicking on the center of the largest rock will return a TSStatic, but clicking on it towards the edge will not- it returns TerrainBlock. If I move the "aim" of the player viewpoint (assumed to be the center of the screen) to look at the rock directly, then I can get TSStatic returned when I click on that same area towards the edge of the rock.
If I click below the midpoint of the screen, the behavior is such that many clicks on the terrain result in the deselection function being called. Some of these points can be covered by GUI's, though some are not. As well, it appears at times as if the ray is colliding with bots or objects where it should not ever be intersecting their bounding boxes.
I have cut and paste the code from my previous TSE porting of the script and code which was converted from the above resources (and still works fine), and have compared them with what I have, and there are no differences. I have compared the code sections, and even looked at some of the engine functions to compare them, and aside from D3D/GFX code differences, everything looks the same.
So, my question is: Does anyone else have these resources running in TGEA 1.7, and if so, have they run into any issues like this, or have they had to make code or script changes aside from simple function name changes that occured between TGEA versions? Any help given is greatly appreciated. Thanks in advance!
I have no idea why this is happening, but when I ported my object selection code from TSE to TGEA 1.7, it has stopped working properly. It works somewhat, but it's behavior is so odd that it makes me want to jump out of my first-story window. This involves the updated object selection resource originally created by Dave Myers and updated by Rubes.
The basic behavior of it is that if you click on an object in the game, it does not always return the object you are clicking on, as if the mouse vector is coming from another part of the screen, or it is not created correctly. For example, I have several statics (rocks, tree), two interiors, and the ability to spawn bots. Clicking on the center of the largest rock will return a TSStatic, but clicking on it towards the edge will not- it returns TerrainBlock. If I move the "aim" of the player viewpoint (assumed to be the center of the screen) to look at the rock directly, then I can get TSStatic returned when I click on that same area towards the edge of the rock.
If I click below the midpoint of the screen, the behavior is such that many clicks on the terrain result in the deselection function being called. Some of these points can be covered by GUI's, though some are not. As well, it appears at times as if the ray is colliding with bots or objects where it should not ever be intersecting their bounding boxes.
I have cut and paste the code from my previous TSE porting of the script and code which was converted from the above resources (and still works fine), and have compared them with what I have, and there are no differences. I have compared the code sections, and even looked at some of the engine functions to compare them, and aside from D3D/GFX code differences, everything looks the same.
So, my question is: Does anyone else have these resources running in TGEA 1.7, and if so, have they run into any issues like this, or have they had to make code or script changes aside from simple function name changes that occured between TGEA versions? Any help given is greatly appreciated. Thanks in advance!
About the author
Started with indie games over a decade ago, and now creates tools and tech for games. Currently working as a contractor for startups and game studios.
#2
05/29/2008 (10:29 am)
Can you post your code in your TSCtrl object that handles the mouse click and casts the ray?
#3
05/29/2008 (10:44 am)
Just a hint if you want to rule out the mouse vector. Project the start position and end position onto your screen and use GFX->drawLine () so you can spot if an error occurs by eye. Hope you fix it!
#4
Server Script:
Client Script (double-click script was commented out for debugging the problem, which existed before I put that portion in, so I omitted it here, as it had no impact either way):
I changed the executef() function's second argument to be "1" instead of 1, due to errors being kicked by that on compiles. It really seems like the center of the screen is shooting the vector, which agrees with getting the camera transform, though it seems like that vector isn't correct for some reason. Thanks for taking a look!
05/29/2008 (10:51 am)
Code:void GameTSCtrl::onMouseDown(const GuiEvent &evt)
{
MatrixF mat;
Point3F vel;
if ( GameGetCameraTransform(&mat, &vel) )
{
//get the camera position
Point3F pos;
mat.getColumn(3,&pos);
//take our mouse coordinates and create (x,y,z) screen coordinates
Point3F screenPoint(evt.mousePoint.x, evt.mousePoint.y, -1);
//take our screen coordinates and get the corresponding
//world coordinates (this is what unproject does for us)
Point3F worldPoint;
if (unproject(screenPoint, &worldPoint))
{
mMouse3DPos = pos;
//create a vector that points from our starting point (the
//camera position) and heads towards our point we have chosen
//in the world
mMouse3DVec = worldPoint - pos;
mMouse3DVec.normalizeSafe();
Con::executef(this, "1", "onMouseDown");
}
}
}Server Script:
function serverCmdSelectObject(%client, %mouseVec, %cameraPoint)
{
//Determine how far should the picking ray extend into the world?
%selectRange = 1000; //200;
// scale mouseVec to the range the player is able to select with mouse
%mouseScaled = VectorScale(%mouseVec, %selectRange);
// cameraPoint = the world position of the camera
// rangeEnd = camera point + length of selectable range
%rangeEnd = VectorAdd(%cameraPoint, %mouseScaled);
// Search for anything that is selectable - below are some examples
%searchMasks = $TypeMasks::StaticObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ShapeBaseObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::PlayerObjectType | $TypeMasks::ItemObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::CorpseObjectType | $TypeMasks::DebrisObjectType | $TypeMasks::PhysicalZoneObjectType | $TypeMasks::StaticTSObjectType | $TypeMasks::DamagableItemObjectType | $TypeMasks:AIPlayerObjectType;
// Search for objects within the range that fit the masks above
// If we are in first person mode, we make sure player is not selectable by
// setting fourth parameter (exempt
// from collisions) when calling ContainerRayCast
if ($firstPerson)
{
%scanTarg = ContainerRayCast (%cameraPoint, %rangeEnd, %searchMasks, %player);
}
else //3rd person - player is selectable in this case
{
%scanTarg = ContainerRayCast (%cameraPoint, %rangeEnd, %searchMasks);
}
// a target in range was found so select it
if (%scanTarg)
{
%name = %scanTarg.getClassName();
%targetObject = firstWord(%scanTarg);
%client.setSelectedObj(%targetObject);
}
else
{
%client.DeselectObj();
}
}Client Script (double-click script was commented out for debugging the problem, which existed before I put that portion in, so I omitted it here, as it had no impact either way):
function PlayGui::onMouseDown(%this, %modifiers, %point, %doubleClick)
{
// mouseVec = vector from camera point to 3d mouse coords (normalized)
%mouseVec = %this.getMouse3DVec();
// cameraPoint = the world position of the camera
%cameraPoint = %this.getMouse3DPos();
commandToServer('SelectObject', %mouseVec, %cameraPoint);
}I changed the executef() function's second argument to be "1" instead of 1, due to errors being kicked by that on compiles. It really seems like the center of the screen is shooting the vector, which agrees with getting the camera transform, though it seems like that vector isn't correct for some reason. Thanks for taking a look!
#5
I would suggest implementing Stefan's suggestion of rendering the Raycast line so you can see it. The only thing I can think of right now is that because the direction of the ray is taken from the Camera, you may think you are clicking on an object but are really "missing" high or low. That is just a guess, however.
05/29/2008 (12:41 pm)
You code looks correct (though I would day the Raycast right in the C++ and just return the object hit to script).I would suggest implementing Stefan's suggestion of rendering the Raycast line so you can see it. The only thing I can think of right now is that because the direction of the ray is taken from the Camera, you may think you are clicking on an object but are really "missing" high or low. That is just a guess, however.
#6
05/29/2008 (12:49 pm)
@Mark: I'm thinking the exact same thing. We'll see what the line tells us...
#7
In your case, in onMouseDown(), you would switch from:
Point3F screenPoint(evt.mousePoint.x, evt.mousePoint.y, -1);
to:
Point3F screenPoint(evt.mousePoint.x, evt.mousePoint.y, 1);
It probably sounds farfetched, but try it.
05/29/2008 (2:15 pm)
I never understood exactly why, but to get my selection code to work in TGEA 1.7 I had to invert the z component of the 3D screen point from -1 to 1. Simply doing this fixed it.In your case, in onMouseDown(), you would switch from:
Point3F screenPoint(evt.mousePoint.x, evt.mousePoint.y, -1);
to:
Point3F screenPoint(evt.mousePoint.x, evt.mousePoint.y, 1);
It probably sounds farfetched, but try it.
#8
::recompile::
::test::
::blinks::
::tests again::
::cries::
Jeff, you rock, kudos! Of course, it's still painful to know that a minus sign just cost me 9 days...
05/29/2008 (3:20 pm)
::changes -1 to 1::::recompile::
::test::
::blinks::
::tests again::
::cries::
Jeff, you rock, kudos! Of course, it's still painful to know that a minus sign just cost me 9 days...
#9
If I recall correctly, the z component of the screen point is used to determine if you want to unproject to the near plane (0.0), the far plane (1.0) or somewhere in between.
In your onMouseDown() you want a vector that goes from the camera towards a point on the far plane, so a z of 1.0 would be correct. A -1 would provide a wonky result as you saw (far plane, but behind the camera perhaps?).
See projectScreenToWorld() in mathUtils.cpp for the actual implementation and how the screen point's z component is used. Also EditTSCtrl::make3DMouseEvent() for a direct usage example.
- LightWave Dave
05/29/2008 (9:13 pm)
Greetings!If I recall correctly, the z component of the screen point is used to determine if you want to unproject to the near plane (0.0), the far plane (1.0) or somewhere in between.
In your onMouseDown() you want a vector that goes from the camera towards a point on the far plane, so a z of 1.0 would be correct. A -1 would provide a wonky result as you saw (far plane, but behind the camera perhaps?).
See projectScreenToWorld() in mathUtils.cpp for the actual implementation and how the screen point's z component is used. Also EditTSCtrl::make3DMouseEvent() for a direct usage example.
- LightWave Dave
Torque 3D Owner Ted Southard