I'm currently writing a 2D AI simulation, but I'm not completely certain how to check whether the position of an agent is within the field of view of another.

Currently, my world partitioning is simple cell-space partitioning (a grid). I want to use a triangle to represent the field of view, but how can I calculate the cells that intersect with the triangle?

Similar to this picture:

The red areas are the cells I want to calculate, by checking whether the triangle intersects those cells.

Thanks in advance.

EDIT:

Just to add to the confusion (or perhaps even make it easier). Each cell has a min and max vector where the min is the bottom left corner and the max is the top right corner.

Couldn't you split the cells into triangles, and test triangle-triangle?
–
The Communist DuckJan 24 '11 at 20:11

The cells aren't physical polygons, just a spatial representation, and it takes advantage of the O(1) access times of an array. If I had a neighbourhood circle around the agent, to approximate the cells, I could create an AABB using the radius of the circle and easily find the intersections. The problem here is that only want the cells that are in front of me. I'm sure there's some geometric equations to help out, I just can't think of any for the life of me.
–
Ray DeyJan 24 '11 at 20:17

5 Answers
5

Calculate the three corners of your fov triangle, rotate them to be facing the correct way and such, and then do one of:

1) do a point-in-triangle test for all the potential targets

2) calculate the bounding box of the this triangle, and do a point-in-triangle test for all
potential targets in cells in this bounding box - this will be very straightforward code to debug

A similar approach is to use a quadtree rather than a grid and do the intersections on that. If the O(1) tile access is speeding you up, then just testing all the cells in the bounds of the fov triangle for in-triangle ought to be so fast as to be instant. As you're looking at other options, I presume its not and that the O(1) is actually taking a massive cache miss cost as you thrash your cache. You could of course perhaps look at prefetch instructions to annotate your bounding box walk with...

3) 'rasterise' this triangle and check the cells that it 'paints' - likely the most efficient code, but perhaps only marginally as I'd speculate its all dominated by cache miss times and depends on how complex your cells are and how occupied they are.

An alternative approach is to render the FOV to an off-screen bitmap and then read the pixel value for each of your objects; you can't 'unmix paint' but with a limited number of objects and by carefully choosing your paint you can deduce who saw who. This approach is similar to how many games work out what the user clicked on - they draw the scene off-screen using solid colours for the hit-areas. GPUs are very fast at triangle fill...

+1 thanks for this, I've used a bounding box for the triangle to quickly select the appropriate cells and have used a point-in-triangle test to determine which members of those cells are within the Field-of-View :)
–
Ray DeyJan 25 '11 at 4:40

The canonical solution in software renderers (which must do this exact algorithm every time they rasterize a triangle) is, I believe, to scan the triangle one row of pixels at a time. The left and right edges of each row and calculated by walking down the sides of the triangle using Bresenham, and then you fill in the row between them.

I'm glossing over lots of details but that's the basic idea. If you hunt around for "software render" and "triangle rasterization", you'll probably find some more details. This is a well-solved problem. Your graphics card is doing this millions of times a frame.

If you want a more roguelike-specific solution, here's how I implemented FOV in mine. It seems to work pretty quickly. It's essentially a simple shadow caster, working on octant at a time, scanning outwards from the player.

I'm using a variation of the scanline algorithm to solve the exact same problem. I started by sorting the three triangle points by their height. I then basically check whether two edges are on the left or on the right side. For the side with two edges, you have to mark they row where you change which edge delimits your rows. For the side with one edge, you can just always use that.

So then for each row, I know which two edges delimit the it, and I can compute upper and lower bounds in x-direction. It sounds quite complicated, but it condenses down to just a few lines of code. Make sure you handle the special-case where one edge is completely horizontal!

How about maintaining a range of columns for each row that are in the triangle? What you can do is set the min and max column for each row where each point is, and where each triangle line crosses a horizontal row separator line.