There are two ways to address this question that I can see. First, if you simply want to find a way to steer, then you just need to implement pathfinding (I find this quite helpful). That would be the end of that (and is the correct practical answer to this question), but I think you are more curious about a mathematical solution to your problem.
To address that, let's look at an equivalent problem. Take a 2D slice of your scene "ahead" of your pilot of a plane that is normal to the original vector. What you will get is a point that represents your original vector and a series of ellipses that are the 2D projections of your occlusion cones. Now what you want to do is to find The closest point to your original point (let's call it P
) that lies on the exterior of non-overlapping ellipses. It turns out that this is a pretty difficult problem to solve. There are 3 steps:
- Figure out the intersection points of all your ellipses
- Find any holes in the union of all your ellipses
- Figure out the closest point to
P
on all your ellipses outside the union (which can be inside a hole)
Okay, all of this requires Lagrange multipliers and angle checking and some other really complicated stuff to solve. Let's look at other options. If we transform our problem instead into angular space, we see that what we actually want to do is find the minumum distance between a point and multiple circles projected onto the surface of a sphere. In differential geometry, this is often called a 2-sphere and is useful here. So first, we need to find the distance between two points on the surface of the sphere, which we will use the 2-sphere metric to find. Luckily, it's pretty easy: ds^2 = (R^2)*(dth^2) + (R^2)*(sin(th)^2)*(dph^2)
, where we hold R
constant as the radius of our 2-sphere projected into 3-space. Coming from physics, I take th
to be the angle from positive z
and ph
to be the angle from positive x
with s
being the distance.
What does doing this accomplish? It allows us to remove the use of Lagrange multipliers to minimize distance, and allows us to work in "native" coordinate (since we define our cones in terms of an angle of occlusion). So now we need to find the radius of our cone-projections. Let's take one cone for now, and call the angle that defines it a
. The radius of the projection is then simply R*a
. That was easy enough -- what other quantity do we need to know about the cones? We need to know the center of the projection, which is defined by the look vector from the actor. First we convert x
, y
, and z
into spherical coordinates where we know we are at distance R
, and solve for th
and ph
, which we can do by simply plugging into our conversion formulas: th = acos(z/R)
and ph = atan2(y/x)
(use atan2
here to account for arctangent's quadrant ambigities). The process is the same to find the position of your original vector in spherical coordinates.
So the problem has been simplified. However, the problem is still quite difficult to solve, but now you only need to worry about circles and points instead of ellipses and points or angles and vectors. The rest of the process is rather procedural. You essentially need to find a bounding area formed by your circles, for which there are multiple solutions. I'll present one method which may not be the best, but will work.
I would first compare the sum of the radii of all circle pairs and the distance between the centers, and then if they sum is larger than the center distance, set them equal and solve for th
and ph
to find the intersections. You know that each pair of intersections describes "forbidden angles" for the circle in question, which you would store as an array of intersection point angles (from the center of the circle) for each circle that intersects this one -- importantly you must "merge" any ranges that overlap as you add them to the array for the next part to work correctly. Then you find the closest point on the edge of the circle to the original point (which is as simple as drawing a line through the center point of the circle and the original point, then finding the location on the line at the radius of the circle away from the center). Then loop through your stored array and test if that angle is in the range of each forbidden angle. If so, then select the closest edge. That is the closest point to the outside described inside this circle. Repeat the process for all circles (some optimization can be done in the selection process -- you don't actually need to calculate this for every circle). Now compare all your shortest distances, find the smallest, and that is your answer, described in the angles th
and ph
. Remember that distance is described with the 2-sphere metric while performing this calculation. Since you don't care about the sphere that all of this is on, only the angles, you can set R=1
and do these calculations on the unit sphere.
This is the simplest way I could think to do this. I'm not sure it's the absolute simplest way, but it would work pretty well. Practically for a game, however, you just want to implement pathfinding.