Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Line-of-sight based occlusion

Discussion in 'Shaders' started by DukeDuck, Feb 8, 2020.

  1. DukeDuck

    DukeDuck

    Joined:
    Feb 8, 2020
    Posts:
    1
    Hey guys,

    I have a very specific request that I'm trying to wrap my head around implementing, and I'd want a bit of a pointer before I start.

    What I'm looking for is a way to occlude objects, or parts thereof, from rendering to the scene based on whether or not the fragment of an object in the scene has unbroken line of sight to the player's "token", up to a given range defined in that token's parameters.

    Essentially, I guess I'm trying to make 3D fog of war that you can move around and move the game camera as close to or as far from as you want - and hence, the traditional 2D cases of rendering a plane texture on top of the scene and such aren't really going to be cutting it.

    In the end, I figure it'd behave much in the same way as a point light that casts shadows - except rather than casting shadows on any fragment, the fragment at that point would be skipped, or made transparent. Then, this separate set of geometry affected by fog of war would be rendered on top of any other objects which aren't affected, such as the volumetric fog I'm wanting to use for the fog of war.

    I've thought about sampling a cubemap of depth textures rendered from the objects' position and using these when deciding what to render in the scene, or using stencil buffers perhaps to define where pixels should be skipped, but I'm somewhat new to shaders and I'm a little unsure of whether I'm on the right track.

    MB if it's already been posted elsewhere, but I've taken an extensive look and ain't found much on it. Feel free to point me to somewhere that has the kinda stuff I need already.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    If you need a truly 3D representation, this is the only option. All other techniques really only work in 2D gameplay spaces, or in the case of stencils purely 2D.

    You'd have to sample the depth cubemap and use clip() in the shader to hide any area that's intended to be invisible.

    The one other option would be to do CSG on the CPU.
     
  3. AdamLacko

    AdamLacko

    Joined:
    Oct 10, 2017
    Posts:
    41
    I hope you won't mind a necro. I'm trying to implement a LOS solution for pretty much the same use-case as the OP. I need it to be responsive to 3D environment verticality.

    An example of what I'm trying to achieve:


    I think the solution you briefly described could achieve this effect. If it wouldn't be of much bother to you, could you possibly elaborate a bit more on how would one implement such a solution? Just a basic rundown of components that are required would be of great help.
     
  4. cgDoofus

    cgDoofus

    Joined:
    Jun 15, 2021
    Posts:
    48
    In that gif example it looks like it's using some sort of uniform voxel grid that the whole game infrastructure uses visually and mechanically. If you have no plans of building up from such a system, I can already think of a few hopefully not too complicated implementations of that using a combination of CPU and compute, where on the CPU side you'd define a voxel grid of certain boundaries and resolution and check which cells of it are inside/outside a mesh using physics queries, then use the player position to march in that voxel grid to various cells in the player's radius and setting some sort of "lit" property for each cell (this step can be done in a separate compute step, I think it'll be faster), then finally pass that grid to a full screen compute shader that based on the cell's "lit" property would apply something to screen pixels around it based on pixels' world position that can be computed from the depth buffer and camera matrices.
     
    AdamLacko likes this.
  5. AdamLacko

    AdamLacko

    Joined:
    Oct 10, 2017
    Posts:
    41
    I do know that the presented game used octrees so the voxel grid isn't out of question here.

    You mentioned a mesh that should be checked against voxel grid cells - but what mesh? The way I see it, there is no mesh or collision involved in this instance. Based on how geometry occludes the visible areas, I'd say the element that determines the visibility resembles a point light of sorts.

    This might be very dumb idea (I'm not a rendering expert) but if I could somehow render the scene top-down into a render texture while only rendering/writing pixels that are lit by some sort of point light representing the LOS, it would produce the desired effect. Although I don't know if something like this would even be possible.
     
  6. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,469
    - generate depth in cubemap from the player perspective, centered on player's head at eyes level

    Everything that share fog of war, share the same bit of shader:
    - sample the cubemap
    - compute distance from fragment to cubemap position
    - compare cubemap sample to distance
    - if sample is bigger, alpha is opaque, else transparent
    more:
    - PROBABLY, compute the normal direction from cubemap center to fragment
    - dot product of the player forward direction (or head direction, depending on gameplay) with the normal to fragment
    - if bigger than user define threshold AND positive, alpha is opaque, else is transparent
    //probably set all fragment to transparent first, then the test is a function that return opaque value without doing an if (when possible)