As Concealed Intent is a 3D game with objects free to move in any direction, development often throws up interesting 3D geometry problems (see old problems here and here). The latest problem was testing to see if an object is partially visible, or rather, if something is slightly blocking the view. Imagine that you have a spaceship and you want to know not only if it is visible on the screen, but also if a part of it is behind a planet or another ship.
There are well-known good solutions to finding if an object is on the screen or if there is something inbetween the camera and a single point in space (using Physics.Linecast). However, I wanted to know if part of the object was hidden and part visible. That is, if the object’s edge projected onto the plane with the line from the object’s center to the camera as its normal, is anything intersecting it when viewed from the camera. Luckily for me the objects I’m interested in are spheres and so become circles when projected onto a plane. Furthermore, I only tested 4 diametrically opposed points on these circles (plus the center). The problem then is to derive these points.
Firstly we know the position of the camera position C, center of the
object O and its radius r. Thus the plane passing through the point
O with the normal C - O is the plane the object needs to be
projected onto. Since the object is a sphere, all that is required is to
get orthogonal axes on this plane passing through O and the move along
them r distance in each direction (giving 4 opposite points on the
projected circle). To get one such axis cross the plane normal with any
vector other than the normal itself. To get the next axis cross the
derived axis with the normal. After normalising the axis vectors,
multiply each by the radius and the 4 opposite points are O plus/minus
these two vectors. In Unity3D use
Physics.Linecast to test
if there is anything inbetween the camera and these points.
Below is the
C\# code I used to perform these tests. The
result is an array of five booleans corresponding to whether the view of
the object center and 4 opposite bounding points is obscured by an
intervening object. What is done after this is up to the programmer. I
used the code to ensure that when focusing on an object it wasn’t
partially blocked. If it was blocked than the camera was moved in the
direction opposite to the blocking object and the view tested again. For
reference, I found the radius with the code
Comments: I have removed the commenting system (for privacy concerns), below are the comments that were left on this post before doing so…
Drew Ski @ 2013-10-14 - I was needing this for my game. I had the thought to use the multiple casting method. Didn’t think to approach it in this way. Thank you for this. It pushed me in the right direction. With a bit of tweaking for my own purposes it worked like a charm. Good job and thanks again.