- Home /
Drag/Move an object perpendicular to starting point
I am attempting to move an object using a ray, but only across two axes. I would like to write a solution which uses linear algebra (i.e. dot, cross product etc), but my understanding of this area of games programming and geometry is very limited and I don't know how to approach this. Obviously, I need to return a new Vector3 position.
The diagram below shows an object O which I want to move. If I were to use a raycast from camera C:
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
I need to find the point along ray R which would be perpendicular to the Object O's starting point from the camera's position. Hopefully the diagram explains what I mean. Presumably I need to find the theta angle first, and then I can somehow calculate the distance R and then use ray.GetPoint() to return the new position, but I need a little help with the maths first before I can write this, and I'm drawing a blank. I have never found an explanation of this kind of problem which has made me particularly comfortable with this stuff, and I don't have any formal training as a programmer. To be honest, it makes me feel pretty stupid that I just can't seem to get a handle on vectors, so if anyone could help me understand this better I'd be very grateful.
The diagram above is two-dimensional but I'm working in 3D. Hopefully it demonstrates what I'm trying to accomplish anyway.
$$anonymous$$ark this as solved. The Plane class helped me achieve what I was trying to do. $$anonymous$$y code:
void Update()
{
if (dragging)
{
var plane = new Plane(Vector3.forward, transform.position);
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
float distance = 0.0f;
Vector3 hit = new Vector3();
if (plane.Raycast(ray, out distance))
{
hit = ray.GetPoint(distance);
transform.position = new Vector3(hit.x, hit.y, hit.z);
}
}
}
Answer by r3david · Aug 08, 2016 at 09:44 PM
You can accomplish the same results using ScreenToWorldPoint instead :
void Update()
{
if (dragging)
{
float zDistToCamera = Mathf.Abs(Camera.main.transform.position.z - transform.position.z);
transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, zDistToCamera );
}
}
In your approach, you have to create a plane that is always oriented with normal Vector3.forward, and then you find out the distance of the camera to that plane. Actually that distance, for a plane that has that kind of normal (I mean normal always parallel to Vector3.forward), can be computed directly as
float zDistToCamera = Mathf.Abs(Camera.main.transform.position.z - transform.position.z);
and therefore applying ScreenToWorldPoint is more straight forward.
Thanks, that does seem better. I'd forgotten about ScreenToWorldPoint.
The way you calculate the distance from the camera makes not much sense. It would only work if the camera isn't rotated at all and points along the world z axis.
You basically have two options to calculate the right distance:
Vector3 dir = transform.position - Camera.main.transform.position
float zDistToCamera = Vector3.Dot(dir, Camera.main.transform.forward);
Here we basically project the vector from the camera to the point onto the camera's forward vector. This gives you the distance to the "plane" that is parallel to the camera plane that contains the given point.
The other way would be to use "InverseTransformPoint" with the camera transform and use the resulting z component. This works since the resulting coordinate is in localspace of the camera.
Vector3 localPos = Camera.main.transform.InverseTransformPoint(transform.position);
float zDistToCamera = localPos.z;
yes, that is the general case, but as you see his code, he is assu$$anonymous$$g always that the camera plane has a normal parallel to the Vector3.forward, that is why i made the clarification. In this case, the easiest way is the one that I have pointed out.
Your answer
