The solution in Unity is as follows:
- Compute the circle's center point
- Compute the circle's radius
- Create a projection using a randomly selected point in 3D coordinates and point P
- Use the center point and the radius to position the point, which results in finding S', such that PS' is tangent to the sphere
using UnityEngine;
public class Script : MonoBehaviour
{
private readonly float _accuracy = 0.1f;
private readonly int _vectorsCount = 1000;
private readonly Vector3 _point = new Vector3(600, 600, 600);
private readonly float _sphereRadius = 500f;
private void Start()
{
// This value will be used to calculate both the circle coordinates and its radius.
var quadraticSum = Mathf.Pow(_point.x, 2) + Mathf.Pow(_point.y, 2) + Mathf.Pow(_point.z, 2);
// Find out coordinates of the circle created by the intersection of the plane with the sphere
Vector3 circleCenter;
circleCenter.x = _point.x * Mathf.Pow(_sphereRadius, 2) / quadraticSum;
circleCenter.y = _point.y * Mathf.Pow(_sphereRadius, 2) / quadraticSum;
circleCenter.z = _point.z * Mathf.Pow(_sphereRadius, 2) / quadraticSum;
// Find out radius of the above circle
var circleRadius = _sphereRadius * Mathf.Sqrt(quadraticSum - Mathf.Pow(_sphereRadius, 2)) /
Mathf.Sqrt(quadraticSum);
/*
* At this point, we can start drawing - let's draw:
*
* - the point using red colour
* - the sphere using blue colour
* - the circle using green colour
*
* Below assumes center of the sphere is at (0, 0, 0)
*/
Debug.DrawLine(Vector3.zero, _point, Color.red, 1000);
DrawSphere();
DrawCircle(circleCenter, circleRadius);
}
private void DrawSphere()
{
for (var theta = -Mathf.PI; theta < Mathf.PI; theta += _accuracy)
{
for (var phi = -Mathf.PI; phi < Mathf.PI; phi += _accuracy)
{
var ray = new Vector3(
_sphereRadius * Mathf.Sin(theta) * Mathf.Cos(phi),
_sphereRadius * Mathf.Sin(theta) * Mathf.Sin(phi),
_sphereRadius * Mathf.Cos(theta)
);
Debug.DrawLine(Vector3.zero, ray, Color.blue, 1000);
}
}
}
private void DrawCircle(Vector3 center, float radius)
{
for (int i = 0; i < _vectorsCount; i++)
{
// Since I wanted random vectors, I am repeatedly drawing a random vector on the circle
var tangentPoint = Vector3.ProjectOnPlane(Random.insideUnitSphere, _point).normalized * radius + center;
Debug.DrawLine(Vector3.zero, tangentPoint, Color.green, 1000);
//Debug.DrawLine(_point, tangentPoint, Color.cyan, 1000);
}
}
}
See the screenshots for visualisation:



Here is an angle with the red line drawn after the sphere and the circle are drawn, to see the center of the sphere:
