Sunday, January 25, 2009

Improving Shadows System Continued

hi, last post i let you think on answer to some question about shadow updating scheme.
in short, the problem was that if dynamic entity gets into influence area of the light it means the light needs to update his shadow map, but this turns to be very intensive if this area contains lots of detail models which is static (read the last post to get the details and comments...)
ok, so the solution to this problem could be one of:
(1) two shadow maps for each light
(2) stay with one shadow map per light but...
(3) other
lets check those options:
(1) two shadow maps for each lights is the way to go but still raise some problems:
a. more memory (twice), if the light taken 1.5 mb per cube shadow map, now it will take 3mb!,
not so good as the reason i use shadow cache system is to maximize shadows cound and minimize the memory used by them.
b. we need to merge those shadow maps to get final one so we could use it when rendering, so we need another shadow maps for this! still the merging process isn't for free so i think you get the idea way this option isn't so good.
(2) here i stay with one shadow map per light but i use another shadow map which will be shared for all lights, this second shadow map will only used for dynamic geometry, so the unique shadow map per light stay ONLY for static geometry and the shared one ONLY for dynamic geometry.
so the memory issue solved, what about the merging? well, instead of merging those shadow maps in cpu, we merge them on gpu.
sound good but that means we need another shadow map right? not necessity, what i do is binding those shadow maps and merge them inside ps, and then i compute shadow map as usual. so instead of using the value sampled from one shadow map, i use the merged sample.
this method saved the need for another shadow map and the extra pass for merging them.
(3) other? nothing i see now, but maybe you could think of something?...
in practice its work very well and the performance gain is huge.
here is two screenshots show the results using this method:

using both static & dynamic shadows

using only static shadows

i see those screenshots but what is so special about them? its just shadow maps...
well yes and no, the first screenshot shows simple scene with few static geometry and one dynamic pickup item (armor), the only shadow map that is being updated is the dynamic shadow map, so what you see is the result of merging two shadow maps in the ps, so you can see both static and dynamic shadows.
the second screenshot shows the same scene but this time we picked up this item, so the resulting shadow map taken only from the static shadow map (dynamic one is empty!)

Monday, January 19, 2009

Improving Shadows System

recently i'm working on performance issues and such, one of the biggest challenge in this area is shadows and how do we make them faster?
the answer to this question is another question:
how much cpu and memory can we sacrifice for this?
the answer to this one is: it depends on other process in the game and your platform.
so here i'm working on pc platform where memory is not an issue (like in ps2/xbox/ps3) so the main question is:
what do you do if you have big scene with 5000 point lights that need to cast dynamic shadows?
lets say we can determine their visibility very fast, so the bottleneck is the shadows generation and not the visibility of the lights. another assumption is that the lights is mostly static but if at any time we want some of the lights become dynamic, we could.
so the answer to this question can be one of those:
1. use light maps
2. compute all shadow map at load time
3. other
well, lets check those methods one by one:
1. light maps is out of the question because they are static and if a light is moving, his shadows wont be updated. also if we have a bridge and we walk beneath, the shadows of the bridge wont cast on our character, because when we compute those light maps, our character wasn't there.
2. this sound promising, it solved the problems in 1 but has another problem.
each point light using cube map for his shadow maps, that means 6 maps for each side, so if we take for example 256 by 256 cube map for all the lights we get something like 1.5 mb per light (assuming 4 bytes per pixel), this become 1.5*5000=7500 mb!! = 7.5 gigs, this is huge and of course cant be done in the real world when we have limited memory.
3. so what we need is a solution that solve both 1 and 2 and take reasonable memory, so the solution i come with is to use a cache system for shadows.
this system will have specific amount of memory dedicated to shadows and based on priority value we computed for each light the system will give cache entry for the most important lights (that is for example: the lights with large range and closer to the viewer).
so basically the system work with x entries that keeps shadow maps and set them as needed to the right lights, when we set shadow entry, we flag the light that he needs to update his shadows, this way we wont spend memory for far lights the viewer wont even see.
so when the scene loaded, the system set shadow entries for the most important lights and when the light tries to generate his shadows we check:
a. is this light have shadow entry? if not it means this light is not important and wont generate shadows.
b. is this light already updated his shadows or not? if not it means the light become dirty or someone flag the light that he need to update shadows (see below)
if we have shadow entry and the light needs to update his shadows, we get the shadow maps from cache entry and generate shadow maps for shadow maps stored in this entry.
when we done, we flag this light that he update his shadows so next frame we wont update it again.
few thing we need to consider:
1. if entity that cast shadows get inside light bounds, the light must update his shadows so the shadows of the entity will get in.
2. if the light is moving we need to update his shadows maps.
ok, so this is the main idea of the system and it is very fast and generic and as any algorithm, this have some tiny things that need to be done correctly so it works smoothly and handle all the special cases.
before i finish, here is another question:
what if we have a room with 500,000 faces with one point light that cast shadows?
we use this great shadows cache system :)
right, but what if an entity, lets say a small ball with 16 faces get inside that room?
hmm, the light need to update his shadows so the shadows of the entity will get in.
well, thats right but that means that for this tiny entity with only 16 faces you need to generate shadows from 500,000+16 faces???
think about it until next time...

Tuesday, January 13, 2009

Volumetric Flares

while changing some of my render batches design to support static and dynamic batches better and faster, i decided to add this nice fake volume effect that i called light flares or volume flares.
unlike the simple 4 vertices billboard/sprite flares that we rotate to face the camera those flares are different and look much better.
when editing the map i place quad shapes aligned with scene geometry and gives them the special flares material, inside the engine i build special border extruded by specific size (defined inside material script) and make sure they always face the viewer.
i also make sure the flare wont be visible if the camera position placed behind.
when the position of the camera is at front and smoothly become behind, i take the distance from camera position to the flare plane and use it to compute flare intensity so the flare will smoothly become invisible the more the camera become closer.
also i bind it a built-in texture which encoded a quadratic function so the borders of will have a smooth falloff effect.
there are few tiny things here and there (setting texcoords and such) but this is the main idea.
here is a screenshot to show this in action:

Volumetric Flare Around Fluorescent

note that this volume shape changed relative to viewer position so it will be different when looking from other position, but the volumetric effect will be preserved.

Sunday, January 11, 2009

Improving Area Visibility

last time i talked about my new visibility system and how i compute lights and areas visibility, this time i improved my visibility system in a way that i could know the visibility inside each area and not just which areas are visible.
i call it internal area pvs, this pvs use the same mechanism of bitsets and gives me information about all the entities/surfaces etc that are visible inside specific area.
at first it sound like, why do you need it? well, when running big levels each area have lots of detail in term of level design and also game play by placing high detail models and pickup items, those can take a lot of power when rendering.
also note that computing internal area pvs is very fast and done when doing the portal traversal, so with a few lines i save lots of rendering, also what you don't see does not need to be lit so the saving is huge when doing the lighting pass!
here is 2 screenshots that shows it in action:
NOTE: the images in wireframe mode so you could see the data the visible without and with internal area pvs system.

without internal area pvs
notice the small red entities at the right side

with internal area pvs
notice the red entities at the right side was removed along with other surfaces

the red entities in the images are light flares, which is a nice effect to fake volume light effects. note that unlike billboard/sprites those are not simple quad aligned to camera view, next time i talked about them...