- Home /
Make a cursor following 3D surface in Unity 3D
Hello,
I need to move a cursor that always follows the 3D mesh of an object imported in unity. This cursor should move with a trackpad or with arrow keys but independently from the mouse screen position. I was able to made it using a raycast starting from an empty object (the one that is moved as defined previously) and calculate the normal to the surface. When this change, the empty object is correctly oriented (z axis normal to surface) and moved (distance on z axis constant). It seems to work correctly but I have problems when the surface angle change for more than 90 degrees, in this case in fact the raycast lost the hit point or can't move on. Does anybody know which can be the solution of this problem or an alternative approach? Thank you very much!
Here the script I'm using:
Ray![alt text][1]castHit hit;
Ray ray = new Ray (cursor.transform.position, cursor.transform.forward);
if (Physics.Raycast (ray, out hit)) {
Vector3 incomingVec = hit.point - obj.position;
Vector3 reflectVec = Vector3.Reflect (incomingVec, hit.normal);
Vector3 projectVec = Vector3.ProjectOnPlane (incomingVec, hit.normal);
Vector3 normalVec = hit.normal;
Vector3 uvWorldPosition = Vector3.zero;
MeshCollider meshCollider = hit.collider as MeshCollider;
Vector2 pixelUV = new Vector2 (hit.textureCoord.x, hit.textureCoord.y);
uvWorldPosition.x = pixelUV.x - canvasCam.orthographicSize;//To center the UV on X
uvWorldPosition.y = pixelUV.y - canvasCam.orthographicSize;//To center the UV on Y
uvWorldPosition.z = 0.0f;
cursorC.transform.position = uvWorldPosition;
float RX = Mathf.Acos (normalVec.x) * 180f / Mathf.PI;
float RY = Mathf.Acos (normalVec.y) * 180f / Mathf.PI;
float RZ = Mathf.Acos (normalVec.z) * 180f / Mathf.PI;
float XX = normalVec.x * 65;//hit.distance;
float YY = normalVec.y * 65;//hit.distance;
float ZZ = normalVec.z * 65;//hit.distance;
float angle = Vector3.Angle (normalVec, incomingVec);
//normal position
cube.transform.localPosition = new Vector3 (XX + hit.point.x, YY + hit.point.y, ZZ + hit.point.z);
cube.transform.forward = -hit.normal;
cursor.transform.position = cube.transform.position;
cursor.transform.eulerAngles = cube.transform.eulerAngles;
}
}
void move ()
{
if (Input.GetKey ("up")) {
cursor.transform.Translate (Vector3.up * Time.deltaTime * 100);
}
if (Input.GetKey ("down")) {
cursor.transform.Translate (Vector3.down * Time.deltaTime * 100);
}
if (Input.GetKey ("left")) {
cursor.transform.Translate (Vector3.left * Time.deltaTime * 100);
}
if (Input.GetKey ("right")) {
cursor.transform.Translate (Vector3.right * Time.deltaTime * 100);
}
}
}
[1]: /storage/temp/94592-whatsapp-image-2017-05-23-at-114111-am.jpeg
In the attached screenshot you can see the detecting ray (the green one) starting from the cube and the resulting normal ray (the red one) that is used to find the new position.
Your answer
![](https://koobas.hobune.stream/wayback/20220612122626im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Unity3D - RTS Game - Instantiate object on buttonclick and make it follow the cursors position 2 Answers
Does RaycastHit.textureCoord assume collider mesh and renderer mesh the same? 2 Answers
How to prevent mesh to not go through other meshes 1 Answer
Detecting how many times a raycast collides with a single concave meshcollider 2 Answers