- Home /
How to get 3D worldspace position from 2D touch/mouse position
Hi, I clicked or touched a point on screen. Now I am looking for a solution by which I can do like: vector3 worldpos=convertInto3D(mousepos);
I know what you are thinking, camera.ScreenToWorldPoint() method. I know of that. But that can not give me accurate Z position. Now you will probably say, cast a ray by Camera.ScreenPointToRay(). I know. and then by hit.point, I can know the 3D position precisely. But today I have heard from my colleague a different story.
He said, without ray-casting I can get mouse z or touch z position. So I am asking all of you, is there any way of doing this without any ray-casting?
Answer by kaiyum · Aug 28, 2014 at 11:19 AM
Looks like I have found what I sought. Without raycasting it is possible to get 3d position from 2d input co-ordinates. camera.screentoworldpoint(x,y,z) generates a 3d point in a plane, z distance far from the camera.
Idea is: at least one point must be known in 3D. Lets call it origin. Now calculate z distance from camera and use it as z argument within screentoworldpoint() method. This way, we can generate a worldspace point within a plane.
When user move mouse up or touch ahead, they want objects to go ahead. But the readonly Y field of camera.screeentoworldpoint(vector3 screenspacepos) will make them to go up! So we flip converted axis here. Now if we use Y value as Z, what happens about Y position of converted point? Lets us remind this at last. For now, lets talk about X value of converted point's position. From the FOV of camera and origin's x and detecting going left or right, we can deduce X co ordinate.
Consider the case of a footbal. The more strong kick, the more we expect the "velocity" of ball. And the more close the ball's angle w.r.t Z axis, close to 45 degree we expect. Becaue angle of a projectile should be 45 to get maximum horizontal distance. From the screenspace input data vs time.time, we can get a velocity reading, which can be used as velocity. And we can interpolate angle too. With angle and velocity, we can accurately measure del-Y(difference of Y between "processing point" and "origin") for Given Z distance from origin. So Y of ball=origin's Y+del-Y
Lets review back X component: For orthographcis camera, X component of converted point=origin.x + or - delZ*tan(fov/n)
here delz is difference of z component between ball's converted point and origin. n is a modifier which must be less than 1. As we lookup 3d poin up or down from middle, this value will be smaller. + or - depends, as we are going left or right. For left, unity x is lessened, so we have to minus this delz*tan(fov/n). For right, we have to add this.
By the way, fov is field of view of camera.
Hope this helps anyone for this matter.
Answer by alishka · Aug 21, 2014 at 09:24 PM
Generally speaking, in the CG pipeline, any interaction from screen with object in 3d space requires a raycast. So I believe your colleague has either found a method that defies some "laws of computer graphics", or has discovered an even quicker way than using Camera.ScreenPointToRay()
.
You can check this link for a moderately deep article on interaction with 3d space.
Cheers !
Thanks for kind replay. You are right, we can not avoid raycast. But I have discovered, I can avoid unity's raycast. And as robertbu pointed out, it depends upon specific set up. Check my answer.
Answer by robertbu · Aug 21, 2014 at 04:24 PM
If the object are on a plane parallel to the camera plane, you just set the 'z' value in the Vector3 you pass to ScreenToWorldPoint() to the distance in front of the camera plane. If the the objects are on a plane, but that plane is not parallel to the camera plane (such as when the camera is angled down on a surface), you can use Unity's mathematical Plane class and and Plane.Raycast(). If you are dealing with a surface that is uneven, but you don't have to worry about objects, then you can use Collider.Raycast(). If you are dealing with both an uneven surface and objects you must detect, then you can use Physics.Raycast().
I am told, "no raycast". Is there any way without using raycast?
You need to describe your specific setup...camera angle, type of camera, nature of the point you are trying to get for me to give you a list of solution. I suspect that you just used ScreenToWorldPoint() incorrectly, but you may need something else. Note that Plane.Raycast() is a mathematical solution that does not require a collider and is efficient. In addition, the math is not hard, so it could be done without using the Plane class and therefore the word 'Raycast'.