# Get vector3 position of Cursor on a fixed 2D plane within a 3D scene

How is it possible to get a cursors X and Y Location relative to the scene planes rather than using co-ordinates based upon pixels of screen height and width?

I have the start of a very basic game, picture with a few physical aids shown below.

I want to find out how far away the cursor is on the X and Y axis from an object in the scene. The Z axis is irrelevant due to the nature and orientation of the game, so z = 0. (Note that in Unity, the Y axis is vertical)

Basically, the distance of the cursor from the cube on the X Axis upon clicking will define the power of an action.

Because of this. I want to get the cursor X position relative to the 0 point of the scene ( or the object ), not relative to the bottom left corner of the screen.

I could then use Vector3.Magnitude() to get the distance.

How is this possible?

Since you're aiming at a known constant plane, you can do this without physics raycasting.

Vector3 GetCursorPositionOnScenePlane(float zValue = 0f)
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

float depth = zValue - ray.origin.z;
float zDirection = ray.direction.z;

if(Mathf.Approximately(zDirection, 0f) // Ray parallel to XY plane.
|| depth * zDirection < 0f)         // Ray looking away from plane.
{
// Error - this ray can't see the plane!
// This won't happen if your camera is looking at the scene plane.
return new Vector3(float.NaN, float.NaN, float.NaN);
}

// Calculate how many times we need to travel along the direction vector
// from the ray's origin before hitting our desired zValue:
float scale = depth/zDirection;

return ray.origin + scale * ray.direction;
}


Note that this differs from Camera.ScreenToWorldPoint in that the zValue here is a z position in world space, so your outputs are always in a world-XY-aligned plane. ScreenToWorldPoint's z is a distance from the camera, so if the camera is rotated then the plane of its outputs may be tilted relative to the world XY plane.

• Thanks DM, I'll have to try this - it's a lot cleaner and makes more sense to me than the other script. – Panomosh Feb 25 '16 at 13:25
• @Panomosh I've made a quick edit so the script works for arbitrary z values. – DMGregory Feb 25 '16 at 13:50

It is possible and Unity documentation is very helpful in this matter. First you need a ray to raycast from mouse position, the documentation for mouse position provides an example how to get a ray from mouse position:

public class ExampleClass : MonoBehaviour {
void Update() {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
}
}


because you are not interested in all of the objects(just the plane*), following to documentation of Physics.Raycast will tell you all possible overloads, one of them having a layer mask. You are also interested in position, so choosing an overlaod with RaycastHit and following documentation to RaycastHit tells you there is a ".position":

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
void Update() {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
int maskOfPlane = 1 << planeLayer;
if (Physics.Raycast(ray, out hit, maskOfPlane)) {
//one of coordiantes being always zero for aligned plane
var position = hit.position;//this is relative to 0,0,0
var relativePosition = other.transform.position - position; //relative to a gameObject other
}
}
}


*literally place an invisible plane in the world aligned with your games logical plane and move it to a custom layer, you will need to set the mask against it.

• This is perfect, thank you wondra. I Appreciate the effort. – Panomosh Feb 25 '16 at 12:28