code: def intersection_ray_sphere(
      sphere_center,
      sphere_radius,
      ray,
      point_on_ray,
      name="ray_intersection_ray_sphere",
  ):
      """Finds positions and surface normals where the sphere and the ray intersect.
  
      Note:
        In the following, A1 to An are optional batch dimensions.
  
      Args:
        sphere_center: A tensor of shape `[3]` representing the 3d sphere center.
        sphere_radius: A tensor of shape `[1]` containing a strictly positive value
          defining the radius of the sphere.
        ray: A tensor of shape `[A1, ..., An, 3]` containing normalized 3D vectors.
        point_on_ray: A tensor of shape `[A1, ..., An, 3]`.
        name: A name for this op. The default value of None means
          "ray_intersection_ray_sphere".
  
      Returns:
        A tensor of shape `[2, A1, ..., An, 3]` containing the position of the
        intersections, and a tensor of shape `[2, A1, ..., An, 3]` the associated
        surface normals at that point. Both tensors contain NaNs when there is no
        intersections. The first dimension of the returned tensor provides access to
        the first and second intersections of the ray with the sphere.
  
      Raises:
        ValueError: if the shape of `sphere_center`, `sphere_radius`, `ray` or
          `point_on_ray` is not supported.
        tf.errors.InvalidArgumentError: If `ray` is not normalized.
      """
      with tf.name_scope(name):
          sphere_center = tf.convert_to_tensor(value=sphere_center)
          sphere_radius = tf.convert_to_tensor(value=sphere_radius)
          ray = tf.convert_to_tensor(value=ray)
          point_on_ray = tf.convert_to_tensor(value=point_on_ray)
  
          shape.check_static(
              tensor=sphere_center,
              tensor_name="sphere_center",
              has_rank=1,
              has_dim_equals=(0, 3),
          )
          shape.check_static(
              tensor=sphere_radius,
              tensor_name="sphere_radius",
              has_rank=1,
              has_dim_equals=(0, 1),
          )
          shape.check_static(
              tensor=ray, tensor_name="ray", has_dim_equals=(-1, 3)
          )
          shape.check_static(
              tensor=point_on_ray,
              tensor_name="point_on_ray",
              has_dim_equals=(-1, 3),
          )
          shape.compare_batch_dimensions(
              tensors=(ray, point_on_ray),
              last_axes=(-2, -2),
              broadcast_compatible=False,
          )
          sphere_radius = asserts.assert_all_above(
              sphere_radius, 0.0, open_bound=True
          )
          ray = asserts.assert_normalized(ray)
  
          vector_sphere_center_to_point_on_ray = (
              sphere_center - point_on_ray
          )
          distance_sphere_center_to_point_on_ray = tf.norm(
              tensor=vector_sphere_center_to_point_on_ray,
              axis=-1,
              keepdims=True,
          )
          distance_projection_sphere_center_on_ray = vector.dot(
              vector_sphere_center_to_point_on_ray, ray
          )
          closest_distance_sphere_center_to_ray = tf.sqrt(
              tf.square(distance_sphere_center_to_point_on_ray)
              - tf.pow(distance_projection_sphere_center_on_ray, 2)
          )
          half_secant_length = tf.sqrt(
              tf.square(sphere_radius)
              - tf.square(closest_distance_sphere_center_to_ray)
          )
          distances = tf.stack(
              (
                  distance_projection_sphere_center_on_ray
                  - half_secant_length,
                  distance_projection_sphere_center_on_ray
                  + half_secant_length,
              ),
              axis=0,
          )
          intersections_points = distances * ray + point_on_ray
          normals = tf.math.l2_normalize(
              intersections_points - sphere_center, axis=-1
          )
          return intersections_points, normals
  
file_path: graphics/tensorflow_graphics/geometry/representation/ray.py
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from typing import Tuple, Union
  from six.moves import range
  import tensorflow
  from tensorflow_graphics.math import sampling
  from tensorflow_graphics.math import vector
  from tensorflow_graphics.util import asserts
  from tensorflow_graphics.util import export_api
  from tensorflow_graphics.util import shape
  from tensorflow_graphics.util.type_alias import TensorLike
label_desc: Use image node_id 6 for calling a global function with example usage: intersection_ray_sphere(sphere_center, sphere_radius, ray, point_on_ray, name) and returns: intersections_points,  normals