We’re the authors of Chipmunk2D physics engine and Cocos2D-SpriteBuilder maintainers. We recently rewrote the Cocos2D renderer and added lighting effects, and now we’re back to writing Unity plugins!
Super Fast Soft Shadows uses a unique shader based algorithm: Shadow projection occurs inside the vertex shader, not on the CPU. This allows us to achieve:
Speed on mobile platforms
High number of colored lights and shadowed objects
Flexibility in light size and softness of shadows
Shadow mask generation occurs in a single pass - it doesn’t use expensive image filters or pixel shaders to soften the shadows. This means it runs great on mobile!
Physically realistic penumbra, umbra, and antumbra rendering is based on configurable light sizes. This produces accurate rendering when the light source is larger than the objects casting the shadows.
It can produce nice, accurate penumbras, and even antumbras when the light source is bigger than the object casting the shadow. This is because we are calculating the actual occlusion percentages when casting the shadows instead of applying some sort of blur or other image based effect. Blurs are incredibly bandwidth intensive, and this is especially a problem on mobile. Even though the occlusion we calculate is per pixel, it’s a pretty short fragment shader and most of the math is done in the vertex shader. You are really just paying for the fillrate to blend the visible parts of the shadow masks and lights.
Sure! We’ll send you one at the end of the day. We’ve got some editor scripts for editing shadow shapes (in case you want different shadow casting shapes from your colliders). They might be a little rough, but they should be pretty good by the end of the day. Thanks!
It’s sort of like the popular 2D hard shadow mask algorithm. You outline your objects with a polyline. Each segment of the polyline gets projected and extruded into a quad. Each edge of the segment gets projected from a different position to accommodate for the size of the light. Then for each vertex, it calculates the amount of occlusion for either edge of the segment. The fragment shader just has to mix the occlusion values together, add some smoothstep, and do some clipping. What took the longest to figure out about is that you really can’t take many shortcuts. If you do, the shadows cast from two adjacent segments won’t interpolate exactly and you’ll get a hole in their shadow instead of blending together seamlessly.
Then it’s just rinse and repeat for each light. Generate the shadow mask, then multiply each light’s cookie by the mask and add it to the lightmap buffer.
I imagine it already has the meshes and merely uses a vertex shader to extrude them in similar manner as if you were performing stencil buffered shadows.
@hippocoder More or less yes. The vertex shader does most of the work, the CPU is just needs to batch the mesh data so it doesn’t make a separate draw call for each shadow caster. It caches what it can.
Here’s another demo where we’ve got a mouse-look flashlight in a platformer like game:
Some of the effects are pretty subtle, and don’t show up very well in the youtube video, but we also have a layer of dust over the scene that adds some depth and variety to the foggy light. The character also has a jetpack that receives lighting effects.
Yes. If you set the light’s radius to 0 then it will cast hard shadows. One of the advantages to doing things in a physically realistic way is that it usually “just works” the way you’d expect. Since the per-pixel cost isn’t a lot higher than hard shadows, it doesn’t waste a lot of fillrate either.
Shadow geometry can be calculated automatically from 2D polygon colliders, but you can also tweak the geometry by hand or add your own from scratch. Here’s the shadow geometry editor, in action.
The dust effect shows up better in the image than in the video