Game Development Community

Screen to World coordinates

by Soeren Vesti · in Torque Game Engine · 01/23/2007 (6:12 am) · 5 replies

Hi

I want to get the coordinates in the world that the center of the screen hit.
Is there a function that does that in TGE or should is it necessary to create
my own?


Regards
S

#1
01/23/2007 (7:08 am)
This is how I get the mouse cursor position in 3D world coordinates, so I'm sure you can follow the lead and get what you need out of it:

From the function GameTSCtrl::onMouseMove(GuiEvent &evt):
MatrixF mat;
Point3F vel;
if(GameGetCameraTransform(&mat, &vel))
{
	// Get the camera pos
	Point3F pos;
	mat.getColumn(3, &pos);

	// Convert mouse coords to screen coords
	Point3F screenPoint(evt.mousePoint.x, evt.mousePoint.y, -1);

	// Convert screen coords to world coords
	Point3F worldPoint;
	if(unproject(screenPoint, &worldPoint))
	{
		mMouse3DPos = pos;
		mMouse3DVec = worldPoint - pos;
		mMouse3DVec.normalizeSafe();

		//Con::executef(this, 1, "onMouseMove");
	}
}
#2
01/30/2007 (5:40 am)
Hi

I am having some problems with this and It all comes down to getting hold of that unproject method.

I can't really get hold of the GuiTSCtrl object, or maybe it is just my ignorance. So if somebody could come with some pointers on how to proceed it would be most appreciated.

Here is what I do now:

I am in the ShapeBase::getMuzzleVector(U32 imageSlot,VectorF* vec), method.
From here I want to alter the muzzle vector to point at, the same spot that the center of the screen points to.
// 1. find center of screen
Point3F screenPoint(Platform::getWindowSize().x/2,Platform::getWindowSize().y/2, -1.0f);		
   
// 2. get correct muzzle vector and muzzle point
Point3F pos;
mat.getColumn(3,&pos);
mat.getColumn(1,vec);

// 3. adjust muzzle vector
GuiTSCtrl* some = new GuiTSCtrl(); // not the way to do it
   
if(some)
{
   Point3F worldPoint;
   some->unproject(screenPoint,&worldPoint); // this doesn't work due to the fact that the viewport, modelview, projection matrices are wrong	
  
   vec->set(worldPoint - pos);
   vec->normalizeSafe();
}
else
   Con::printf("Error - some does not exist");
So how do I get the proper object? I have tried to use Sim::findObject(const char* name), with the class name as argument, but this result in a null pointer. What is this 'name'? class name or object name?

Hope that someone can be of assistance

regards
#3
01/30/2007 (5:59 am)
Well, for findObject you can pass in the object name or ID.

Can you describe in a little more detail what you need this functionality for, or why you have to do it in getMuzzleVector?

It's possible we can have this core code moved into GameTSCtrl, get the coordinates you need, and pass them where ever else you need them.
#4
01/30/2007 (6:14 am)
Yeah sure here is what I am trying to accomplish.

I am trying to adjust the direction of the projectiles for all my weapons, such that they will hit the point at which my crosshair points at. Crosshair allways exist in the center of the screen. I figured that by adjusting the muzzle vector the projectile direction would be changed.

Regards
#5
01/30/2007 (6:46 am)
Ok, we'll continue with this functionality then, but just as an alternative, using the muzzlepoint of a weapon might be an easier and more realistic way of determining projectile velocity and positioning.

So, here's what I'd do:

In engine\game\GameTSCtrl.h, add this in a public location:
void onMouseDown(const GuiEvent &evt);

In engine\game\GameTSCtrl.cc, add this at the end of the file:
void GameTSCtrl::onMouseDown(const GuiEvent &evt)
{
    [b]//.. Whatever functionality you want to do before script execution goes here[/b]

   [b]//.. Call script function[/b]
   Con::executef(this, 1, "onMouseDown");
}
ConsoleMethod( GameTSCtrl, project, const char *, 3, 3, "(Point3F WorldPos")
{
   Point3F src;
   Point3F dst;
   
   dSscanf(argv[2],"%f %f %f",&src.x,&src.y,&src.z);
   object->project(src, &dst);
   char* buff = Con::getReturnBuffer(100);
   dSprintf(buff, 100,"%i %i",(int)(dst.x),(int)(dst.y));
   return buff;
}
ConsoleMethod( GameTSCtrl, unproject, const char *, 3, 3, "(Point2F ScreenPos")
{
   Point3F src;
   Point3F dst;
   
   dSscanf(argv[2],"%f %f",&src.x,&src.y);
   src.z = -1;
   object->unproject(src, &dst);
   char* buff = Con::getReturnBuffer(100);
   dSprintf(buff, 100,"%g %g %g",dst.x,dst.y,dst.z);
   return buff;
}

In example\starter.fps\client\scripts\PlayGui.cs:
function PlayGui::onMouseDown(%this)
{
   %extent = PlayGui.getExtent();  [b] // Get width and height [/b]

   %width = getWord(%extent, 0); [b] // Just for testing purposes[/b]
   %height = getWord(%extent, 1);

   %center = %width / 2 @ "  " @ %height / 2;  [b] // Silly way to get center into one variable [/b]

   %worldPosition =   PlayGui.unproject(%center);  [b] Get 3D world position of screen center point[/b]

  [b] // Now do whatever you want with the %worldPosition.[/b]
}


This provides you with the world coordinates of the screen center whenever you press the left mouse button. You can always set up a function that just returns the center of the PlayGui without a mouse click, and now you have the basic script syntax and code to do it.

As always, this is just one way. May not be the best, but it is a good tutorial on TS, engine to script interfacing, and more.

Let me know how that works out for you.