Orthographic camera with rotation and ScreenToWorldPoint

I have an ortho camera which used to have no rotation. When I used

ScreenToWorldPoint(Input.mousePosition)

I would get the desired result. I have a grid of tiles and I would use this to place a graphic over the tile that was under the mouse.

However, now that I have added some rotation to the camera, the selected tile isn’t actually the one that is under the mouse. I realise that this is to do with rotation and some answers I have already looked at suggest setting the Z to the cameras near clipping plane like so:

Vector 3 mousePosition = Input.mousePosition;
mousePosition.z = Camera.main.nearClipPlane;
Vector3 position = Camera.main.ScreenToWorldPoint(mousePosition);

However, this doesn’t work and produces the same results if I left the Z axis alone.

Ok Here is how I fixed it in my Game hope this helps. Lassade was correct btw here is how you do it:

You need to spin up a plane so that you can cast a ray at it in order to determine what the distance is from the camera.

So in my game I have a -30 rotation on the X of the camera which is ultimately means the ‘world’ is further from the top of the screen than it is from the bottom. That means that if I want to shoot a projectile say at the mouse. I need to know the exact mouse click position.

110727-camera-explain-1.png

What I did was spin up a Plane in the same position as my world and cast a ray at it to determine what distance it was from the camera.

// define a plane variable
// may be Vector3.up in your case depending on your camera orientation
Plane plane = new Plane(Vector3.forward, Vector3.zero);

// Shoot a ray at it when your event happens, in my case projectile

public void OnCastComplete()
    {
var projectile = Instantiate(projectile, somePoint.transform.position, transform.rotation);

        //Create a ray from the Mouse click position
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        //Initialise the enter variable
        float enter = 0.0f;

        if (plane.Raycast(ray, out enter))
        {
            Debug.Log("distance " + enter);
            //Get the point that is clicked
            Vector3 hitPoint = ray.GetPoint(enter);
            //Draw a debug ray to see where you are hitting
            Debug.DrawRay(ray.origin, ray.direction * enter, Color.green);

            // create a direction vector (hitPoint => somePoint
            Vector2 direction = new Vector2(
                hitPoint.x - somePoint.transform.position.x,
                hitPoint.y - somePoint.transform.position.y
                );

            // addforce force to the projectiles rigidbody in that direction.
            projectile.AddForce(direction * projectileSpeed);

        }

    }

Hope this clears it up a bit. This will certainly help in my game and it took me a long time to find the solution so I hope it helps others.

I think you have an complex rotation on your camera, like in the one of a isometric game, in this case you should convert your sceen point to ray then raycast it on a plane (look at Plane class) or in the collider geomtry of your game.