Search Unity

3D Shadows Collider

Discussion in 'General Discussion' started by lolreplay92, Feb 8, 2020.

  1. lolreplay92

    lolreplay92

    Joined:
    Dec 17, 2017
    Posts:
    13
    Hello guys,

    Is there any way to create colliders on shadows?
    I can basically get to the point i know the proportions and position of the shadow using rays, then clone my object and apply these proportions and position changes and then use collider on the clone but since the objects are 3D and the shadows are 2D, there is a distortion which i don't know how to apply to the cloned 3D object so my collisions are not accurate.

    Anyone has any idea how can i work this out or give me another approch?
     
  2. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,569
    What are you trying to achieve?

    Shadows are not 2d. They're 3-dimensional volumes.

    This technique was quite common before shadowmapping got popular:
    https://en.wikipedia.org/wiki/Shadow_volume


    By using similar technique you could calculate precise shadow geometry, although this is not quite "trivial".

    However, if you are trying to determine "is the object in a shadow" then a simpler option would be to shoot raycasts at the object from the light and if they hit level geometry instead of the object, then the object is in shadow.
     
    angrypenguin and neoshaman like this.
  3. lolreplay92

    lolreplay92

    Joined:
    Dec 17, 2017
    Posts:
    13
    I'm trying to add a collider to a shadow of an object (obstacle) so that my player will stop whenever he encounters shadow of an object and of course the player can pass simply by moving on the outline of the object shadow.
     
  4. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    10,151
    You can't just add a collider to a shadow because a shadow is not an object. If you want to do this you're going to have to look into creating shadow volumes, as mentioned.
     
    neoshaman likes this.
  5. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,569
    Well.

    You can't do that easily, because while shadow is not an actual thing. Even though they can be represented as a 3d objects in unity, they're not objects.

    You can generate shadow geometry using shadow volume technique I mentioned earlier. This is not a beginner level task, however. Also be aware that collider shadow volumes may allow player to walk through air.

    Alternative is scripting and tons of raycasts. You'd need to scan the area around the player and determine if it is in the shadow, and whether the player is allowed to go there. This would be easier to work with if the player is using CharacterController collider and not a rigidbody.
     
  6. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    10,151
    Theoretically, if you can get a shadow volume working, it's not too much more to do some depth testing to make it so it only extends a bit off of surfaces to get rid of air walking, though really either one of these means you're going to have to constantly be remeshing colliders, which isn't really the fastest thing in the world
     
    angrypenguin likes this.
  7. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,569
    That's not quite how it works...


    Shadow volume generates a geometry that is similar to, well, god rays. Except those are shadow rays. The front is generated from object geometry, but the end extends all the way to the end of the light range. Basically you don't get the geometry of the actual shadow on the floor, as they're supposed to clip through geometry. Here's a picture (in ms paint)
    upload_2020-2-8_22-33-54.png
    Yellow dot is light. Green is the shadow you actually SEE, but light purple is shadow volume geometry. And black is the level/shadowcaster. The volume passes through walls, as you can see.

    By using shadow volumes for collider, you will be using purple parts for collider, and the player may end up being able to walk on them. Obviously.

    Trying to calculate shape of green part (i.e. if you want player to collide when it steps on shadow, and not when it is within shadow volume) is actually hard, unless only care about the floor and it is perfectly flat, then it is easy (as you can squish the geometry and use result to make a collider). In general case scenario it is hard, because you end up in amazing world of manual collision detection between shadow volume (which can end up being non-convex polygon) and polygonal soup which is the level. In this case you'll need to extract portion of the soup hit by the volume, and then clip it with the volume, except the volume is likely a concave object that contains overlapping geometry.

    While this can certainly be done, it is a royal pain and is not worth it.

    A better option would be to do something else. For example, you could cast "laser array" of raycasts from vicinity of the player and determine which parts are within the shadow. Then generate simmple colliders that approximate shadow on the flooor. This will be a simpler, but less precise approach.
     
  8. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    10,151
    It's not as complicated as you're making it out to be if you have access to the geometry info, which you can use to determine where the volume hits, you just have to take a hybrid approach. Consider:

    upload_2020-2-8_15-7-33.png

    The formula for generating the volume can be extended to do this. I actually did this way back in Unity 3.x since I was trying to get around the lack of realtime shadows before 5.x. It wasn't performant at all, but that was also many versions of PhysX ago. Theoretically, with the improvements, you could do it in real time. The main benefits here are that it covers a lot of edge cases that a raycast solution may stumble with.

    My inspiration for the project was actually a digipen project called Perspective. I wanted to make a stealth game where you could travel through shadows projected in 2D space, but also those shadows could exclude visibility from NPCs. I never managed to get above 10fps, largely because of the collision mesh redraws, but allegedly that's much faster now.
     
  9. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,569
    No. It is EXACTLY as complicated as I said, because it has to be solved in general case.
    Have you ever implemented real-time collision detection from scratch? Same business.

    The difficulty is "cull geometry outside of volume".
    Because the volume can be anything, and geometry can be anything.

    For example. This is your possible input for shadow volume.


    Here's another one:
    https://en.wikipedia.org/wiki/Klein_bottle

    Unless you specialize and narrow down the problem ("the floor is perfectly flat infinite surface", "shadowcasters are convex", "shadowcasters do not overlap", "shadowcasters are water-tight", "the light is a spot-light"), this is a hard problem which approaches comlexity of realtime booleans.
    ------------

    Additionally: Traditional shadow volumes do not generate shadow geometry. They render those huge "shadow cones" and use them to fill up stencil buffer. The resulting mask is then used to render shadow regions one way or another (either by not painting light there, or by painting darkness there). With exception of "shadows only on perfectly flat floor scenario", games do not generate shadow geometry.
     
    Last edited: Feb 8, 2020
  10. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    The more important part to me about @Murgilod's post is this bit:
    Whether or not this will be an issue depends on how many colliders need to change at once, and presumably their complexity.

    It could be worth figuring out the rough characteristics of the resulting shadow volume meshes and doing some simple performance tests on your target hardware to see if changing them in real-time is feasible. I would guess that it'll be fine, but no point doing all of the challenging stuff only to run into this later if it does turn out to be an issue.

    If you tell us more about the game we might be able to come up with simpler solutions. As @neginfinity points out, being able to make assumptions could cut the complexity significantly.
     
  11. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,569
    @angrypenguin shadow volume generation could be done on cpu without much problem, but that is only talking about the classic wall penetrating one. Physx collider, however, uses optimized data structure, and rebuilding that will be costly. Precise extraction of shadow silhouette, however, will produce explosive garbage generation and potentially unknown amount of geometry.

    Long story short, wall piercing volumes I suggested work as triggers, and could possibly be updated often. Building of a polygonal silhouette is likely not worth it, and it is possible to get away with a ton of raycasts instead.
     
  12. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    This is what I was referring to.

    I agree that a bunch of raycasts could detect collisions well enough at a lower cost, but then resolution of those collisions needs to be considered. There may well be very simple answers to that, depending on the design of the game.
     
  13. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,569
    I think the OP has ran away in horror at this point.

    Anyway, one possible solution for shadow collision would be this:
    upload_2020-2-9_11-29-43.png
    We pick a spot above head of the character.
    From that spot we fire a laser grid of raycasts. (marked green)
    To each poiunt where ray hits the level geometry, we determine whether it is in the shadow or not,
    by firing a ray from lightsource towards that point (if it hits level geometry before reaching the point, it is in the shadow). (yellow is light, red - blocked light)
    Then, on shadowed spot, we spawn... normal rigidbody colliders that span all the way from floor to ceiling, so the player can't jump over them. (marked purple on the floor)

    This solution can be made adapative, in the sense that closest rays will form denser grid.
    This solution also won't require re-meshing of colliders. Cylinders, boxes and the like will do.
     
  14. lolreplay92

    lolreplay92

    Joined:
    Dec 17, 2017
    Posts:
    13
    Thank you all for the replies, sorry for not answering till now.
    I want to implement something similar to this game:

    I understand that i can do it using Shadow Volumes but is there any easier way to achieve this game functionality.
     
  15. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,569
    You can do that without shadow colliders.

    1. Use directional light.
    2. Behind the camera place an invisible collider that matches orientation of the furniture but otherwise lined up.
    3. Have a protagonist jump over lined up colliders behind the camera casting shadow.

    Given that the furniture is just bunch of cubes (when it comes to collider), then you can create invisible collliders with them, even taking orientation into account.

    upload_2020-2-10_18-47-15.png
    upload_2020-2-10_18-51-36.png
    Given the furniture is boxes, like I said, it is fairly easy to calculate sizes for hidden colliders:
    upload_2020-2-10_18-54-11.png
     
    Ryiah likes this.
  16. lolreplay92

    lolreplay92

    Joined:
    Dec 17, 2017
    Posts:
    13
    Right now what i'm doing is making the player cast only shadows and then change his position everytime he passes the right side of an object in the objects array sorted by Z index, which is the player direction (using raycast).
    Of course i'm changing the size of the player each time i set the position to the default size so it won't get bigger or shrink.
    It is not 100% accurate tho since shadows are stretched so part of the player shadow can go through some object shadows depends on their angle from the light.
    What do you think about that method and does your answer handle this type of problem?@neginfinity
    Oh and btw, i'm using point light not directional.
     
  17. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,569
    I think I wouldn't do it this way. Having actual scene positioned beyond the camera where it actually casts shadows or using invisible colliders - the way I described ion the answer - that match shapes of shadows would be much simpler and movement would be handled by physics engine. My answer uses directional light, by the way, simply because it is less hassle as you dont' need to take perspective into account.

    Basically you need to mentally seaparate visualization and actual movement/collision. What you see in shadows is not necessarily what is being done in physics/movement engine.
     
  18. lolreplay92

    lolreplay92

    Joined:
    Dec 17, 2017
    Posts:
    13
    I see, your answer probably more efficient but i still don't get how it solves the problem with shadows that are stretch due to the light angle.
    Sorry if you covered it already and i missed it.
     
  19. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,569
    .... In the demo you linked there's a shadowy sillhoette jumping over shadows and controlled by the player. So, basically, there are multiple collision layers - one layer where you move furniture, and other layer is where shadow movement happens. The player moves in the "shadow layer", and invisible colliders are also placed there.

    The trick is that there's no collision between shadows and the shadow-player, but instead based on light and shadow position the game spawns invisible colliders, and character jumps over that. The colliders can be spawned along the walls, behind the camera, doesn't matter.

    There's no collision with shadows. There's invisible collider that matches the shadow.

    Also, the demo appears to be using directional light, so no stretching and enlarging takes place. Additionally, in case of the demo, the furniture likely is boxes. As in single box collider. In case of box collider determining sizes is trivial.

    If you INSIST on using spot lights, point lights and other things where closer objects create bigger shadows, then you'll need to, once again, process box colliders like shadowvolume and use resulting colliders in the second layer.
    Because a box has only six faces this is not difficult, and resulting geometry will be always convex, which simplifies things.
     
  20. lolreplay92

    lolreplay92

    Joined:
    Dec 17, 2017
    Posts:
    13
    Oh i didn't know directional light does not stretch the object, i will try that thank you!
    btw, i hope directional light handles enlarging since that is what i need and you can see it in the demo.
     
  21. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,569
    In directional light, light beam runs in parallel, so no enlarging ever occurs. It is like a laser beam.

    It seems I did overlook enlarging in the demo, however. However, after looking at it one more time, I've noticed that you can't move furniture and jump over shadows at the same time. So, the moment the user switches from "move furniture mode" to "jump over shadows mode" (there's click in the demo at this point), they build colliders for shadows and freeze them. The colliders can be built using shadow volume method, using invisible collider method, and so on.

    --------

    At this point you have multiple ways to approach the problem. Give them a whirl. Have fun.