To test that a 3D animatable character is visible to another character surely one raycast is not enough and several would need to be used to check for elements e.g. limbs/sides/head/feet.
How do you solve the LOS problem in Unity?
To test that a 3D animatable character is visible to another character surely one raycast is not enough and several would need to be used to check for elements e.g. limbs/sides/head/feet.
How do you solve the LOS problem in Unity?
i did a tutorial once where you make a shotgun blast and it is just a bunch of raycast and a little math to constrain them within a cone.
Maybe you could do that, then get the number of hits and divide by number of rays. If a certain percentage was hit, you could surmise that a target was seen.
some other conditions could be added into the check. Like 10% raycast hits AND not within some collider consider hidden, for example.
Spherecast can shoot a fat ray. Or do a sequence of rays that sweep, ideally batched in a job.
In my 3D top-down game I have a custom navmesh, and I have an algorithm that checks that.
public static List<(int,int)> InViewPath((int,int) start, (int,int) end, CellWalkableState[,] grid) // trying to copy https://github.com/scikit-image/scikit-image/blob/main/skimage/draw/_draw.pyx
{
// r = row = y = item2
// c = column = x = item1
List<(int, int)> output = new List<(int, int)>();
var steep = false;
var r = start.Item2;
var c = start.Item1;
var dr = math.abs(end.Item2 - start.Item2);
var dc = math.abs(end.Item1 - start.Item1);
int sr, sc, d = 0;
if((end.Item1 - c) > 0)
{
sc = 1;
}
else
{
sc = -1;
}
if((end.Item2 - r)>0)
{
sr = 1;
}
else
{
sr = -1;
}
if(dr>dc)
{
steep = true;
var c_temp = c;
c = r;
r = c_temp;
var dc_temp = dc;
dc = dr;
dr = dc_temp;
var sc_temp = sc;
sc = sr;
sr = sc_temp;
}
d = (2 * dr) - dc;
for (int i = 0; i < dc; i++)
{
if (steep)
{
output.Add((r, c));
}
else
{
output.Add((c, r));
}
while (d >=0)
{
r = r + sr;
d = d - (2 * dc);
}
c = c + sc;
d = d + (2 * dr);
}
output.Add(end);
if(output.Any(xxx => grid[xxx.Item1,xxx.Item2] == CellWalkableState.InteractableObject || grid[xxx.Item1,xxx.Item2] == CellWalkableState.Unwalkable))
{
return null;
}
else
{
return output;
}
}
Iâm planning on doing several raycast to different parts of the player like you suggested.
I did a rough build and was happy with the results.
Iâve seen a few videos on the principles of this and a few methods of how itâs executed.
Thereâs a good Game Makerâs Toolkit video on it I believe, talking about the various line of sight âzonesâ that you could employ to make more realistic NPC vision (primarily for stealth games, but itâs no doubt applicable to all sorts of games).
Perhaps a combination of Trigger zones and ray-casting could be worthwhile? Trigger zones for the various zones of sight (long range vision, close vision, peripheral vision and âsixth-senseâ vision), and should the player be in the forward/peripheral zones it perhaps ray-casts to certain places on the players body (head, hands, body, feet, etc). The Sixth-Sense zone would probably run on a countdown timer before alerting an NPC.
I believe some Splinter Cell games use this, but are generally always drawing lines between NPCâs and the player to check for intersections.
I usually combine a number of casts. Such as a sphere cast in combination with various rays, etc.
If the core character collision youâre using for other game stuff isnât working well enough, you can make unique spheres and child them under specific bones and cycle through them in a list doing a raycast check for hands, head and feet (disable the mesh render obviously). Set these volumes to a unique collision layer so that your less accurate character collisions arenât interfering. Then make sure the raycast is happening on the correct physics layers (CharacterRaycast and environment + whatever else your scene is made of that should block sight). You will need to make sure these collision volumes arenât interacting with any other collision layers.
The thing is, sphere or capsule casts can be confusing since they fail if even a tiny part of the sphere is blocked. A spherecast to the chest says theyâre not visible if a sapling covers their left shoulder. Even if you do smaller spherecasts two saplings could block them all. It feels as if there should be some sort of negative-spherecast thatâs true unless theyâre completely blocked (somewhat like how people want triggers that fire when an object is completely inside) but Iâve never seen a way to make that.
Iâve found that very small spherecasts are useful to solve the âraycasts can hit 1 pixelâ problem. If you raycast to their left shoulder and see itâs visible, it may be only the tiniest sliver which no one would notice for real. A very small spherecast can help ensure it has to be a decent-sized chunk.
Maybe if there was a reverse silhouette shadow cast mask from the target to the observer. Could use shadow casting algorithms for speed.
Or some way to collapse the 3D object into a 2d silhouette that can then be traced with recasts to outline points. In theory this could be obtained from a LOD system that generates 2D imposters, the imposters could also provide more detailed LOS checks.