Jump to content
  • Advertisement
123iamking

Algorithm to convert screen point to ray

Recommended Posts

I used to use ScreenPointToRay function to help me do this in Unity3d. But now I use Ogre and Bullet, I have to do this on my own.

I try to dig into Bullet's example and find out this function getRayTo which convert the point on that click on screen (camera) to the 3d world point with 'farPlane' distance from the camera (that what I think). Then they create the ray (vector AB) by set the A point is the camera position, B point is the point get from the function getRayTo above. I try to re-implement this function in my project (use Ogre for graphic, so I have to use Ogre's camera and world). But I can't get it right because I don't understand the function getRayTo from Bullet.

Please explain the algorithm to convert screen point to ray. If there is a better algorithm please teach me.

Note: the scenario to use this algorithm is to find out the position to go for the character - like in the game TouchLight - a point and click game.

https://github.com/bulletphysics/bullet3/blob/d52fb7510bbe3801431cc0a431e4c1847ee3e0f1/examples/CommonInterfaces/CommonRigidBodyBase.h#L17
Edited by 123iamking
add tag

Share this post


Link to post
Share on other sites
Advertisement

With this code

btVector3 rayToCenter = rayFrom + rayForward;
btVector3 dHor = hor * 1.f / width;
btVector3 dVert = vertical * 1.f / height;


btVector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical;
rayTo += btScalar(x) * dHor;
rayTo -= btScalar(y) * dVert;
return rayTo;

Look like they shift the center point to the point that clicked on the camera.

Here is my attempt to convert the function, and it looks pretty ok :)

Ogre::Camera* m_pCam;

btVector3	EmptyProjectGameState::getRayTo(int x, int y)
{
	float top = 1.f;
	float bottom = -1.f;
	float nearPlane = 1.f;
	float fov = m_pCam->getFOVy().valueRadians();

	btVector3 camPos;

	camPos.setX(m_pCam->getPosition().x);
	camPos.setY(m_pCam->getPosition().y);
	camPos.setZ(m_pCam->getPosition().z);

	btVector3	rayFrom = camPos;
	btVector3 rayForward;
	rayForward.setX(m_pCam->getDirection().x);
	rayForward.setY(m_pCam->getDirection().y);
	rayForward.setZ(m_pCam->getDirection().z);

	rayForward.normalize();
	float farPlane = 10000.f;
	rayForward *= farPlane;

	btVector3 rightOffset;
	btVector3 cameraUp = btVector3(0, 1, 0);

	btVector3 vertical = cameraUp;

	btVector3 hor;
	hor = rayForward.cross(vertical);
	hor.safeNormalize();
	vertical = hor.cross(rayForward);
	vertical.safeNormalize();

	float tanfov = tanf(0.5f*fov);


	hor *= 2.f * farPlane * tanfov;
	vertical *= 2.f * farPlane * tanfov;

	btScalar aspect;
	float width = float(mGraphicsSystem->getRenderWindow()->getWidth());
	float height = float(mGraphicsSystem->getRenderWindow()->getHeight());

	aspect = width / height;

	hor *= aspect;


	btVector3 rayToCenter = rayFrom + rayForward;
	btVector3 dHor = hor * 1.f / width;
	btVector3 dVert = vertical * 1.f / height;


	btVector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical;
	rayTo += btScalar(x) * dHor;
	rayTo -= btScalar(y) * dVert;
	return rayTo;
}

 

Edited by 123iamking

Share this post


Link to post
Share on other sites
	vec3 dir = DirectionFromScreen(CursorX, CursorY, SCREEN_WIDTH, SCREEN_HEIGHT,90.0, 2.0, 1000.0, float(SCREEN_WIDTH) / float(SCREEN_HEIGHT));
	ray_vb[1].v = FPP_CAM->pos + dir*(1000.0*depth*2.0);





vec3 DirectionFromScreen(int x, int y, int sw, int sh, float fov, float z_near, float z_far, float aspect)
{

mat4 mvm = CAM_MODEL * CAM_VIEW;
mvm.Transpose();
vec3 dirX, dirY;
	dirX.x = mvm.m[0];
	dirX.y = mvm.m[4];
	dirX.z = mvm.m[8];

	dirY.x =	mvm.m[1];
	dirY.y =	mvm.m[5];
	dirY.z =	mvm.m[9];


	float a = fov / 2.0;
float cotangent = 1.0 / tan( a * imopi );

float ax = z_near / cotangent;

float screen_w = 2.0*ax;

float screen_h = screen_w;// * yratio;

screen_w = screen_w * aspect;

float scr_coord_x = float(x) / float(sw);
float scr_coord_y = float(sh - y) / float(sh);


vec3 dir = FPP_CAM->ReturnFrontVector();

//move to lower left corner
vec3 start_pos = (FPP_CAM->pos + dir * z_near) + (-dirX * (screen_w / 2.0)) + (-dirY * (screen_h/2.0));

vec3 start = start_pos + (dirX * (screen_w * scr_coord_x)) + (dirY * (screen_h * scr_coord_y));

return Normalize( vectorAB(FPP_CAM->pos, start) );
}

Assuming that you have projection and view matrices defined

 

You end up with point on far plane by. Camera_pos+z_far*direction 

 

Front vector can be computed from dirx and diry

Edited by WiredCat

Share this post


Link to post
Share on other sites
const float aspect = (float)(m_renderbufferWidth) / (float)(m_renderbufferHeight);
const float fx = 2.0f * ((float)(x) / (float)(m_renderbufferWidth - 1)) - 1.0f;
const float fy = 2.0f * ((float)(y) / (float)(m_renderbufferHeight - 1)) - 1.0f;
const float tangent = tan(y_fov_radians / 2.0f);

last_click_float_x = aspect*tangent*fx;
last_click_float_y = -tangent*fy;

Here x, y is the pixel location that was clicked on by the mouse/stylus/finger user, and last_click_float_x, last_click_float_y is the location on the image plane (which is taken to be a distance of 1 from the camera). The y_fov_radians and m_renderBufferWidth, m_renderBufferHeight variables are self-explanatory (hopefully).

Edited by sjhalayka

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!