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.

75648-diagram.jpg

The diagram above is two-dimensional but I’m working in 3D. Hopefully it demonstrates what I’m trying to accomplish anyway.

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.