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

hi
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

hi
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

hi
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...

Tuesday, December 30, 2008

Visibility System And Shadow Casters

hi, last days i'v been working on my visibility system, rendering system and redesign few things related to them, also fix some low performance issues in big levels.
so in order to attack those issues i stared so see what could be optimized, one thing was the pvs data set which was basically a list of visible objects created from specific view point.
this pvs is needed for both camera and lights, also mirror materials needs to generate this set for the mirror generation pass.
those list was filled in few places but the thing is that we could do alot of the work in load time and achive better performance and still get the same thing.
so instead of keeping list of scene objects which could be changed doring the game (for example: another bot got in or out), i'm using a bit set for lights and camera pvs.
each entity update which areas they belong to, lights only update thier bit set when they move/change.
when i want to render the scene, i only need to check camera pvs bit set and see which areas are visible. to know which entity is visible is just a matter of checking the right bits in camera bit set.
in lighting pass we need to know which areas the current light influenced, so to get this info we need to do an AND bit operator between current light bit set and camera bit set, the result is the areas the light can influence and the camera can see.
the same thing is done for shadows generation, that using the same light bit set pvs with an exception.
when we are generating shadows we still need to consider shadows that comes from unvisible objects, object that is not visible still can cast visible shadow!
to solve this issue, we should check if the shadow volume of that object is intersecting our view frustum, if so it means this object needs to be rendered into the shadow map even if its not visible!.
if you dont handle those object you will get wrong shadows.
for example: if you have an open space scene with sun as the only light source and simple cave built from floor, ceiling and walls. when you enter the cave and look down (ceiling is not visible!) you still want to see the shadow of the ceiling.
here is screenshots from medium scene with unvisible shadow caster

shadows off

shadows generating from unvisible ceiling of this hallway

Sunday, December 14, 2008

Portals

hi, this time i had to recreate my portals visibility system, why? well i had some nasty bug that pop out when doing my pvs (possible visibility set) on complicated levels with lots of portals crossing each other.
i will try to explain the problem so when you see one you could attack it :)
little info about portals for some of you who don't familiar with it.
portals is related to visibility system because they help to cull scene areas, how?
think for a moment on a door that connecting two rooms room A and room B, if you stand in room A and looking through the door you only can a portion of room B.
now if you doesn't look through the door, you probably wont see room B (if you cant see the door, you cant see the room/s it leads to)
so portals basically hand placed (can be places automatically) in few places (not just corridors) as convex polygons (usually quads).
now, when you want to know which areas are visible, you start from camera area and check which portals inside this area, for each portal you clip your current frustum planes (the camera planes) against the portal and check again with the new clipped planes as the new frustum (yes its recursive function) and so on and on for each portal until there is nothing to see/visit.
now each portal you enter lead you to a new area so you flag this area so you know it is visible.
after you quit this function you end up with a list of areas that are potentially visible from camera area. this is the basic idea but few trick here and there could do this faster!
now that you know whats portals, i try to explain why i think recursive function for portals visibility are not so good in complicating levels with lots of portals!
the thing is that every portal you pass, the current frustum get clipped and pass for the next check, for every area you visit you also flag it so you wont check it again (this also helps to break the recursion, if not you can get stack overflow) because other portals can also leads to it.
because of this you can have few routes (in the recursion tree) that can lead to the same area! but not all of them will result in a visible area at the end! this is because we flag all the visited areas so the other routes that start like the first one but ends different (in terms of areas) wont even ends! meaning the area at the end of their route wont even visit because the first ones was flagged as visited - resulting in a none visible area that needs to be visible!!
i hope you didn't get lost in this long explanation and get the idea, so here is my solution to this problem:
the way i solve it is to look at the problem as a tree where the camera eye placed at the root, each portal is node, each branch is an area. (this is just how it help me to solve the problem).
i scan this tree by levels!, this way the areas are visited in a sorted order relative to eye pos (the root) and all the routes advance one step at a time and not allowing one route to get to the end (leaf) and others stay at the beginning.
here is few screenshots that shows portals in action:

visible portals in green, none visible in red

visible portals in green, none visible in red
yellow lines are current frustum planes
NOTE: portals are clipped against current frustum thats why part of the portal is red and the other part is green

Wednesday, December 3, 2008

Gamma Correction

hi, after reading the article "the importance of being linear" in gpu gems 3, i decided that its a good thing to add gamma correction into my engine.
by setting the right gamma value everything will look more real and the colors get the right felling.
there is few tecniques to do that, i decided to do it as a post process on the final pixel color by applying the function:
gammaCorrectedColor = pow(finalColor, 1/gammaValue)
as a bonus we can now optimize light interaction because the light bounds doesn't need to be big in order to make the effected area more clear and bright.
also, its a good idea to make the gamma value controllable so every player could set it as needed, i'm using the console to change it.
here is a screenshot of the effect:

without gamma correction

with gamma correction