I am shooting a raycast on a 3d sphere and i want a method which can get a float number between 0 (center of spehere) to 1 (circumference or outline of sphere) depending upon the raycasthit point (position). How can i achieve this.
I have tried calculating diffrence between the position of sphere and raycast impact point, it works somewhat but is very complex to implement in code.
Is there any other way of doing this or am i missing some math functions or vector functions which can help in this case.
CodePudding user response:
public class Example : MonoBehaviour
{
public Camera mainCamera;
private float result;
private Ray ray;
private Vector3 hitPoint;
private Vector3? hitObjectCenter;
private Vector3 planeHitPoint;
private void Awake()
{
if (!mainCamera) mainCamera = Camera.main;
}
private void Update()
{
ray = mainCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out var hit) && hit.collider is SphereCollider hitSphere)
{
hitPoint = hit.point;
// This is assuming that your sphere is actually a sphere with uniform local scales
var sphereRadius = hitSphere.radius * hitSphere.transform.lossyScale.x;
hitObjectCenter = hit.collider.bounds.center;
var plane = new Plane(-ray.direction, hitObjectCenter.Value);
if(plane.Raycast(ray, out var hitDistance))
{
var planeHitPoint = ray.GetPoint(hitDistance);
var result = Vector3.Distance(hitObjectCenter, planeHitPoint) / sphereRadius;
}
}
else
{
hitObjectCenter = null;
}
}
private Mesh planeMesh;
private void OnDrawGizmos()
{
// if not hitting a sphere do nothing
if (!hitObjectCenter.HasValue)
{
return;
}
// lazy initialize plan visualization
if (!planeMesh)
{
planeMesh = new Mesh
{
vertices = new Vector3[4]
{
new Vector3(-1, -1),
new Vector3(-1, 1),
new Vector3(1, 1),
new Vector3(1, -1)
},
triangles = new[]
{
0, 1, 2,
0, 2, 3,
// backfaces
0, 2, 1,
0, 3, 2
},
normals = new Vector3[4]
{
Vector3.forward,
Vector3.forward,
Vector3.forward,
Vector3.forward,
}
};
}
// Visualize ray
Gizmos.color = Color.green;
Gizmos.DrawLine(ray.origin, hitPoint);
// Visualize hit point on sphere
Gizmos.DrawWireSphere(hitPoint, 0.05f);
// Visualize Plane
Gizmos.color = Color.cyan;
Gizmos.DrawWireMesh(planeMesh, hitObjectCenter.Value, Quaternion.LookRotation(ray.direction));
// visualize hit point on plane
Gizmos.DrawWireSphere(planeHitPoint, 0.05f);
// Visualize distance
Gizmos.color = Color.red;
Gizmos.DrawLine(planeHitPoint, hitObjectCenter.Value);
// print result on screen
Handles.Label((planeHitPoint hitObjectCenter.Value) / 2f, $"RESULT: {result:0.000}", new GUIStyle(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleCenter });
}
}