bool CameraUnProject(Vector3 p, Matrix4x4 cameraToWorld, Matrix4x4 clipToWorld, Rect viewport, out Vector3 outP) { // pixels to -1..1 Vector3 in_v; in_v.x = (p.x - viewport.x) * 2.0f / viewport.width - 1.0f; in_v.y = (p.y - viewport.y) * 2.0f / viewport.height - 1.0f; // It does not matter where the point we unproject lies in depth; so we choose 0.95, which // is further than near plane and closer than far plane, for precision reasons. // In a perspective camera setup (near=0.1, far=1000), a point at 0.95 projected depth is about // 5 units from the camera. in_v.z = 0.95f; Vector3 pointOnPlane; if (clipToWorld.PerspectiveMultiplyPoint3(in_v, out pointOnPlane)) { // Now we have a point on the plane perpendicular to the viewing direction. We need to return the one that is on the line // towards this point, and at p.z distance along camera's viewing axis. Vector3 cameraPos = cameraToWorld.GetPosition(); Vector3 dir = pointOnPlane - cameraPos; // The camera/projection matrices follow OpenGL convention: positive Z is towards the viewer. // So negate it to get into Unity convention. Vector3 forward = -cameraToWorld.GetAxisZ(); float distToPlane = Vector3.Dot(dir, forward); if (Mathf.Abs(distToPlane) >= 1.0e-6f) { bool isPerspective = clipToWorld.IsPerspective(); if (isPerspective) { dir *= p.z / distToPlane; outP = cameraPos + dir; } else { outP = pointOnPlane - forward * (distToPlane - p.z); } return(true); } } outP = new Vector3(0.0f, 0.0f, 0.0f); return(false); }