- Home /
ViewPortToWorldPoint problem
I have a crosshair that should shoot targets with raycasting. The raycasting part is OK, however I can´t make the transition between the screen point to the world point in order to fill the raycast method. My ViewPortToWorldPoint always return the same point regardless of where is the crosshair transform.
This is how it looks like:
public void Shoot()
{
Vector3 currentShootPositionInViewPort = new Vector3(crosshair.position.x, crosshair.position.y, crosshair.position.z);
print(currentShootPosition); //gives me changing values when I move the crosshair
Vector3 worldPos = cam.camera.ViewportToWorldPoint(currentShootPosition);
print(worldPos); //Always give me the same value???
}
If someone can point me something wrong I am doing.... thanks!
By the way, the ScreenToWorldPoint also gives me the same value... I´ve tested that too. Possibly a problem with the crosshair transform?
Answer by aldonaletto · Aug 05, 2011 at 01:29 PM
The viewport is 2d, but the world is 3d. ViewportToWorldPoint combines x and y viewport coordinates with a distance z from the camera to generate a 3d point. For instance: ViewportToWorldPoint(Vector3(0.5f,0.5f,100f)) will trace an imaginary straight line from the center of the camera to a point 100m ahead, and return this point's coordinates. That's why you're always having the same result: the z coordinate at the GUITexture position probably is 0, what always returns the camera position.
If you want to shoot at the crosshair position, you must create a ray using ViewportPointToRay:
public void Shoot() { // only x and y are considered; z is ignored by ViewportPointToRay Ray ray = camera.ViewportPointToRay(crosshair.position); RaycastHit hit; if (Physics.Raycast(ray, out hit)){ // something was hit } }This function was kind of "stolen" from the ViewportPointToRay example.
Yep, that's the problem with a perspective projection: Everything meets at the camera origin :D.
Just set the z value to something greater 0.0f If you want the point to be on the near-clipping plane just set z to Camera.nearClipPlane.
Hmm that was indeed the problem. However my ray seems to have a strange behavior. Even if I change it´s direction to forward it doesn´t go forward... I´ll give a few more tries here!
Even more strange now....when I do Debug.DrawLine with the ray stuff it points one place. When I do Debug.DrawRay it points another place. How could that be ? And just to get better, no collision is detected!!! Well at least Debug.DrawRay shows a ray in the right direction...however it´s very short and even if I put some stub objects in front of it just to test, it does not collides...
But aren't you using the ray created by ViewportPointToRay? Like @Bunny83 said, the ray will start at the camera position and go ahead passing through the crosshair - what you see at the crosshair should be hit by the ray.
Answer by cj_coimbra · Aug 05, 2011 at 06:39 PM
I just made it a screen point before turning into a world point because I had to add the texture offset to center the aim both in X and Y. Then I turned it into a Ray with ScreenPointToRay method.
When I switch between DrawLine and DrawRay I see different things... Also, it does not collide with the huge cube just in front of camera, certainly being hit by the ray. Probably a mistake by my part?
public void Shoot() { Vector3 scrp = Camera.main.ViewportToScreenPoint(this.transform.position); scrp = new Vector3(scrp.x + 24, scrp.y + 24, scrp.z); ray = Camera.main.ScreenPointToRay(scrp); //ray.direction = new Vector3(0, 0, -10); RaycastHit hit; if (Physics.Raycast(ray.origin, Vector3.forward, out hit, Mathf.Infinity)) { print("hit!"); } else print("not hit!"); print(ray.ToString());
}
// Update is called once per frame
void Update ()
{
Debug.DrawRay(ray.origin, ray.direction, Color.red);
//Debug.DrawLine(ray.origin, ray.direction);
}
I´ve figured it out. $$anonymous$$y Z axis was inverted but not may Ray drawning so I thought the ray was there but it was just it´s inverted virtual line...
Also, it looks like the ray is not going to the right direction but when I tried it on the iOS device it actually goes to the right aimed spot... strange but anyway...
It's wrong! You must use ray.direction ins$$anonymous$$d of Vector3.forward:
public void Shoot() { Vector3 scrp = Camera.main.ViewportToScreenPoint(this.transform.position); scrp = new Vector3(scrp.x + 24, scrp.y + 24, scrp.z); ray = Camera.main.ScreenPointToRay(scrp); RaycastHit hit; // use ray.direction ins$$anonymous$$d of Vector3.forward in Raycast: if (Physics.Raycast(ray.origin, ray.direction, out hit, $$anonymous$$athf.Infinity)) { print("hit!"); } else print("not hit!"); print(ray.ToString()); }
// Update is called once per frame
void Update ()
{
Debug.DrawRay(ray.origin, ray.direction * 100, Color.red);
//you must supply two points to Debug.DrawLine:
//Debug.DrawLine(ray.origin, ray.origin+ray.direction);
}
Vector3.forward is a fixed direction - it will only work if the camera is looking exactly to the Z axis direction.
Another thing: if this script is attached to the GUITexture, the point scrp will be correct only if your crosshair measures 48x48 and have Pixel Inset X and Y zeroed - this will make the ray pass exactly at the center of the crosshair.
To finish: Debug.DrawRay draws a ray with the length of the vector used as direction (2nd parameter) - I multiplied this parameter by 100 to draw a longer ray.
Answer by Antho · Sep 01, 2011 at 12:59 AM
It seems to be a bug in the current version of unity. However ViewportPointToRay works, so I can suggest you temporarily replace
cam.camera.ViewportToWorldPoint(currentShootPosition); with cam.camera.ViewportPointToRay(currentShootPosition).origin;
Your answer
![](https://koobas.hobune.stream/wayback/20220612171123im_/https://answers.unity.com/themes/thub/images/avi.jpg)