Jump to content

  • Log In with Google      Sign In   
  • Create Account


Screen to World Ray


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
29 replies to this topic

#1 Medo3337   Members   -  Reputation: 665

Like
0Likes
Like

Posted 03 December 2012 - 03:15 AM

Hi guys,

I'm trying to raycast from the center of the screen towards anything in front of the camera.

My goal is that I make the player able to shoot enemies according to the "+" symbol in the center of the screen.

How can I get D3DXVECTOR3 of the center of the screen?

Any help would be appreciated.

ray.jpg

Edited by Medo3337, 03 December 2012 - 07:57 AM.


Sponsor:

#2 Tispe   Members   -  Reputation: 978

Like
0Likes
Like

Posted 03 December 2012 - 05:43 AM

Use D3DXIntersect() maybe?

#3 Medo3337   Members   -  Reputation: 665

Like
0Likes
Like

Posted 03 December 2012 - 07:22 AM

I use Bullet physics raytest, how do I get the 3D position that appear exactly infront of the camera (at the center of the screen)?

I'm trying to get the 3D position of the symbol "+" so I can raycast from it.

Edited by Medo3337, 03 December 2012 - 07:24 AM.


#4 GuyWithBeard   Members   -  Reputation: 764

Like
0Likes
Like

Posted 03 December 2012 - 07:59 AM

Assuming that in the coordinate system you are using Y is up, X is to the right and Z is forward, the camera forward vector is (X=0, Y=0, Z=1) in view space. You just multiply this by the view-to-world matrix to get the vector in world space. Remember to set W to 0 since this is a direction rather than a point. The origin for the ray would be (X=0, Y=0, Z=0) in view space. To get that into world space you do the same but with W as 1. Then you can just scale the direction vector with something large like 10 000 to get a really long ray vector. If I remember correctly, these two vectors (ie. a ray origin and direction) is what Bullet expects.

#5 Medo3337   Members   -  Reputation: 665

Like
0Likes
Like

Posted 03 December 2012 - 08:20 AM

@GuyWithBeard: I have the point of the cursor which is x, y, from this point how can I get the x, y, z in the 3D world? the idea is the same like picking 3D mesh, you get the 3D world from the cursor x, y cursor point and raycast from this position to for example 1000.0f forward (1000.0f is the distance).

Edited by Medo3337, 03 December 2012 - 08:22 AM.


#6 GuyWithBeard   Members   -  Reputation: 764

Like
0Likes
Like

Posted 03 December 2012 - 08:23 AM

Is your crosshair in the middle of the screen (or to be more exact in the middle of the view)?. In that case you don't need to work with 2D coordinates at all. The ray will originate from the view space origin (where your camera is) and go straight forward in the direction the camera is facing.

#7 Medo3337   Members   -  Reputation: 665

Like
0Likes
Like

Posted 03 December 2012 - 08:28 AM

Here is what I want to do, I am trying to do two things:
1. Allow the player to shoot the enemy raycast(centerOfScreenWorld.x, centerOfScreenWorld.y, centerOfScreenWorld.z, 1000.0f); // 1000.0f = distance
How can I get centerOfScreenWorld?

2. This is something completely different (picking mesh), it should be something like pickMesh(cursorPoint.x, cursorPoint.y, 500.0f); // 500.0f = distance
pickMesh should return information about the picked mesh (in other word mesh that was hit by the ray), How can I raycasting from cursorPoint to the distance?

Edited by Medo3337, 03 December 2012 - 08:33 AM.


#8 GuyWithBeard   Members   -  Reputation: 764

Like
0Likes
Like

Posted 03 December 2012 - 08:38 AM

1. The center of the screen = the center of the near plane. This would be (X=0, Y=0, Z=NearPlaneDistance) in view space. Use what I told you before to get into world space.

Update: actually that's not right. The "center of the screen" would probably be the camera position, not the near plane. My bad.

2. http://halogenica.net/ray-casting-and-picking-using-bullet-physics/ That article should give you all you need.

#9 Tispe   Members   -  Reputation: 978

Like
0Likes
Like

Posted 03 December 2012 - 08:56 AM

Nabbed this from dxtut
    // get the current transform matrices
    D3DXMATRIX matProjection, matView, matWorld, matInverse;
    d3ddev->GetTransform(D3DTS_PROJECTION, &matProjection);
    d3ddev->GetTransform(D3DTS_VIEW, &matView);
    d3ddev->GetTransform(D3DTS_WORLD, &matWorld);
    // use the mouse coordinates to get the mouse angle
    GetCursorPos(&MousePos);
    float xAngle = (((2.0f * MousePos.x) / SCREEN_WIDTH) - 1.0f) / matProjection(0, 0);
    float yAngle = (((-2.0f * MousePos.y) / SCREEN_HEIGHT) + 1.0f) / matProjection(1, 1);
    D3DXVECTOR3 origin, direction;
    origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
    direction = D3DXVECTOR3(xAngle, yAngle, 1.0f);
    // find the inverse matrix
    D3DXMatrixInverse(&matInverse, NULL, &(matWorld * matView));
    // convert origin and direction into model space
    D3DXVec3TransformCoord(&origin, &origin, &matInverse);
    D3DXVec3TransformNormal(&direction, &direction, &matInverse);
    D3DXVec3Normalize(&direction, &direction);


#10 Medo3337   Members   -  Reputation: 665

Like
0Likes
Like

Posted 03 December 2012 - 09:27 AM

Focusing on number 1 (player shooting raycasting) I tried doing something close to what you said, but it's not working as expected, can you show an example?

#11 Medo3337   Members   -  Reputation: 665

Like
0Likes
Like

Posted 03 December 2012 - 09:34 AM

@Tispe: This code is dealing with model transformation, I'm not doing anything related to models, instead, I'm trying to raycast from the center of the camera to the forward area.

I'm looking to do something exactly like the following:
http://forum.unity3d.com/threads/37637-RayCasting-from-screen-centre-point-(cross-hair)

Edited by Medo3337, 03 December 2012 - 09:37 AM.


#12 GuyWithBeard   Members   -  Reputation: 764

Like
2Likes
Like

Posted 03 December 2012 - 10:48 AM

Focusing on number 1 (player shooting raycasting) I tried doing something close to what you said, but it's not working as expected, can you show an example?


This is how I do it in my engine:

void Camera::getPickRay(int screenX, int screenY, Vec3& rayOrigin, Vec3& rayDirection, Math::CoordinateSpace space)
{
  float vx = (((2.0f * screenX) / (float)mGraphicsEngine->getScreenWidth()) - 1.0f ) / mProjectionMatrix._11;
  float vy = (((-2.0f * screenY) / (float)mGraphicsEngine->getScreenHeight()) + 1.0f ) / mProjectionMatrix._22;
  switch (space)
  {
  case Basis::Math::SpaceLocal:
	rayOrigin.set(0.0f, 0.0f, 0.0f);
	rayDirection.set(vx, vy, 1.0f);
	rayDirection.normalize();
	break;
  case Basis::Math::SpaceWorld:
	Mat4& worldMatrix = mParentNode->getLocalToWorldTransform();
	Vec4 o(0.0f, 0.0f, 0.0f, 1.0f);
	Vec4 d(vx, vy, 1.0f, 0.0f);
	o = o * worldMatrix;
	d = d * worldMatrix;
	rayOrigin.set(o);
	rayDirection.set(d);
	rayDirection.normalize();
	break;
  }
}

Basically you give the function the screen coordinates, a ray origin vector, a ray direction vector and the space you want the ray in (world or local). Since this is the camera we are talking about, the local space is effectively the view space.

So, first you get the ray in view space. For that we need the projection matrix of the camera, the screen coordinates and the screen size. If you are cool with with view space you just fill in the vectors and you are good to go.

If you want the ray in world space you need to transform it with the world matrix, aka "local-to-world-matrix", aka "view-to-world-matrix". If you happen to have the "world-to-view-matrix" instead, like most camera implementations, the one you want is just the inverse of that. You fill out two 4D vectors (the origin with W=1, the direction with W=0) and transform them by the matrix. After that you should probably normalize the direction.

Voila, you now have the "start-point" of the ray (which is still just the camera position btw) and a unit-length direction vector of the ray, both in world space. Multiply the direction with whatever huge number you want to get a long ray cast.

Does this help?

Edited by GuyWithBeard, 03 December 2012 - 10:52 AM.


#13 Tispe   Members   -  Reputation: 978

Like
0Likes
Like

Posted 03 December 2012 - 02:08 PM

@Tispe: This code is dealing with model transformation, I'm not doing anything related to models, instead, I'm trying to raycast from the center of the camera to the forward area.


The matrices are not only for mesh/models. You use them in inverse to get from screen coordinates (your crosshair) to world space, origin and direction vectors.

#14 GuyWithBeard   Members   -  Reputation: 764

Like
0Likes
Like

Posted 03 December 2012 - 02:58 PM

Yes, if you look closely at Tispe's code you'll notice that it does exactly the same as mine. With the added bonus that it probably compiles for you out of the box, if you use D3DX.

#15 Medo3337   Members   -  Reputation: 665

Like
0Likes
Like

Posted 07 December 2012 - 04:42 PM

Sorry for the delay, I have tried to implement the idea from the above code but couldn't get it to work, If you can just show example on getting the two values RayFrom and RayTo it would be greatly appreciated:

float distance = 1000.0f;
D3DXVECTOR RayFrom; // According to the screen "+" symbol (middle of the screen)
D3DXVECTOR RayTo; // According to distance


#16 Tispe   Members   -  Reputation: 978

Like
0Likes
Like

Posted 08 December 2012 - 05:57 AM

Since your "+" symbol (cross-hair) is in the middle of the screen xAngle and yAngle are both 0.

You only need this code
D3DXVECTOR3 origin, direction;
origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
direction = D3DXVECTOR3(0, 0, 1.0f);
// find the inverse matrix
D3DXMatrixInverse(&matInverse, NULL, &(matWorld * matView));   //D3DXMatrixInverse(&matInverse, NULL, &matView); <- world space instead.
// convert origin and direction into model space
D3DXVec3TransformCoord(&origin, &origin, &matInverse);
D3DXVec3TransformNormal(&direction, &direction, &matInverse);
D3DXVec3Normalize(&direction, &direction);

You can remove matWorld and you will get the origin and direction in world space. By keeping matWorld you reverse the ray into the model space of the mesh. This is useful if you want to check if the mesh is intersecting with the ray.

#17 Medo3337   Members   -  Reputation: 665

Like
0Likes
Like

Posted 08 December 2012 - 07:25 AM

Okay, I tried the following:
D3DXVECTOR3 origin, direction;
origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
direction = D3DXVECTOR3(0, 0, 1.0f);
// find the inverse matrix
D3DXMATRIX matInverse;
D3DXMATRIX matView = camera->GetViewMatrix();
D3DXMatrixInverse(&matInverse, NULL, &matView);   //D3DXMatrixInverse(&matInverse, NULL, &matView); <- world space instead.
// convert origin and direction into model space
D3DXVec3TransformCoord(&origin, &origin, &matInverse);
D3DXVec3TransformNormal(&direction, &direction, &matInverse);
D3DXVec3Normalize(&direction, &direction);
DWORD hitResult = Raytest(origin, direction);
// Raytest() should return the ID of the mesh that was hit when the player is shooting

What's wrong in the above code? it's not hitting the correct mesh, also where is the distance? I'm trying to get hitResult so I can know which mesh was hit then I will apply damage to that mesh.

#18 Tispe   Members   -  Reputation: 978

Like
0Likes
Like

Posted 08 December 2012 - 03:01 PM

The Ray just has an origin and a direction, it goes on for infinity. When you do an intersect test you provide the mesh and the ray, and the function tests if the Ray intersects that mesh and at what distance away from the origin. You should use D3DXIntersect() unless you you completly trust your Raytest() function.

I think you can't test if you hit a mesh in World Space. You need to include matWorld when you reverse the ray from screen to model space. That way the Ray will be in the Model space, and only there can you test if the Ray intersect any polygons of the mesh.

So you gotta do this Ray test for each mesh, that means reverse transform the Ray for each model using a new matWorld.

Edited by Tispe, 08 December 2012 - 03:13 PM.


#19 Medo3337   Members   -  Reputation: 665

Like
0Likes
Like

Posted 08 December 2012 - 04:17 PM

I think you can't test if you hit a mesh in World Space. You need to include matWorld when you reverse the ray from screen to model space.


That's alittle confusing, I just use Bullet Physics Raytest which create a line in the world space and I can use it to get the closest hit and it return information about which mesh that was hit, I do nothing other than giving the start and end point and it tells me which mesh was intersected.

Edited by Medo3337, 08 December 2012 - 04:18 PM.


#20 GuyWithBeard   Members   -  Reputation: 764

Like
0Likes
Like

Posted 08 December 2012 - 04:46 PM

I think you can't test if you hit a mesh in World Space.


As far as I know, Bullet expects the ray origin and direction in world space. Also, I don't see why you could not do that in any case. Spaces are just different frames of reference. The important thing is that all data is in the same space.

A few questions for Medo3337:

1. Do your physics meshes have the exact same geometry as your visual meshes? Most games use vastly simplified physics meshes compared to their visual counterparts. This of course means that doing ray casts with the physics engine will not give you the exact face you are seeing on the screen, but the face of the physics mesh. Also, I don't remember if Bullet gives you faces at all, or just the rigid body, but you probably know that better than me.

2. If you have problems getting the right ray, have you tried drawing a line where it is going, to see if it is correctly lined up? Of course you cannot see the ray as you are casting it, since you are effectively looking along the ray itself, so it would appear as just a dot. Instead you can set up your game to cast a ray when you left click, or something like that. The ray info would then be stored in two vectors and drawn on the screen until you cast the next ray. That way you will have time to move your camera a bit to the side so that you can see the ray.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS