Native Ambient Occlusion for Interiors in TGE
by Ryan Mounts · 06/25/2008 (12:52 pm) · 24 comments
If you've followed any of my blogs at all, you've probably noticed my desire to get more advanced lighting into Torque. So far I've been using 3dsmax to do that with good success. The only problem is that the process can be somewhat time consuming and complicated at times. It'd be much nicer if I could do some simple advance lighting directly inside Torque. I've noticed that ambient occlusion really adds alot to a scene, so that seemed like a good place to start.
So here's some progress from my current endeavor: ambient occlusion for an interior calculated in Torque and added to its lightmap. It's a simple AO algorithm that shoots rays out from each lexel in the lightmap to determine that lexel's occlusion. This AO value is then used to modulate the ambient light.

There are three different quality settings: low, medium, and high. Low shoots 40 rays, Medium shoots 160, and High shoots 360. You can see that there are some artifacts in the corners using the Low setting. Medium got rid of the artifacts and smoothed the result considerably. High didn't change the visual quality much, but the shadowing is slightly smoother where the taller box touches the floor. I haven't profiled this, but approximate relight times for the above images on a Dell Inspiron 8600 laptop/1.5 GHz/512MB RAM were... Low: 5 seconds, Medium: 12 seconds, High: 30 seconds. Looks like Medium is sufficient to get good AO.

Changing the ray length adjusts the "size" of the AO effect. Longer rays will generally result in darker shadowing (more accurate), but will take longer to calculate.
Next I need to expose these parameters to the World Editor and make an option to lock the AO in. That way it won't have to recalculate with every relight. Then I plan on releasing this as a resource. And porting this over to TGEA should only take a few minutes. :)
So here's some progress from my current endeavor: ambient occlusion for an interior calculated in Torque and added to its lightmap. It's a simple AO algorithm that shoots rays out from each lexel in the lightmap to determine that lexel's occlusion. This AO value is then used to modulate the ambient light.

There are three different quality settings: low, medium, and high. Low shoots 40 rays, Medium shoots 160, and High shoots 360. You can see that there are some artifacts in the corners using the Low setting. Medium got rid of the artifacts and smoothed the result considerably. High didn't change the visual quality much, but the shadowing is slightly smoother where the taller box touches the floor. I haven't profiled this, but approximate relight times for the above images on a Dell Inspiron 8600 laptop/1.5 GHz/512MB RAM were... Low: 5 seconds, Medium: 12 seconds, High: 30 seconds. Looks like Medium is sufficient to get good AO.

Changing the ray length adjusts the "size" of the AO effect. Longer rays will generally result in darker shadowing (more accurate), but will take longer to calculate.
Next I need to expose these parameters to the World Editor and make an option to lock the AO in. That way it won't have to recalculate with every relight. Then I plan on releasing this as a resource. And porting this over to TGEA should only take a few minutes. :)
About the author
#2
06/25/2008 (2:03 pm)
nay vhance this code will be release so that it can be added to TGEA?
#3
06/25/2008 (2:25 pm)
Yeah, after I get it tweaked in TGE, I'll try to get a TGEA version out (hopefully next week).
#4
06/25/2008 (9:37 pm)
I've been following this for a time, I really like the outcome. Congrats.
#5
06/26/2008 (7:44 am)
Great stuff Ryan, cant wait
#6
06/26/2008 (8:09 am)
Looks really good. This has the potential to be a permanent engine addition, I think.
#7
Just a thought, it looks very nice. Great work!
06/27/2008 (5:50 pm)
I can't recall, but doesn't map2dif calculate lightmaps when it exports? The engine at load time only adds the sun shadows IIRC. Maybe this could be integrated with map2dif, so it generates ambient occlusion on any dif lights exported. The sun light is only useful in dif's that have an opening towards the exterior. Just a thought, it looks very nice. Great work!
#8
06/27/2008 (10:15 pm)
Yes, this could very easily be integrated into map2dif. The only problem is if you want to tweak the effect, you would have to re-export with the new parameters and open up Torque again every time. This would quickly get annoying after a few iterations. It could also be integrated directly into Constructor, but I don't have the code for that. ;) Calculating the AO inside Torque gives an additional benefit over both those options... it allows the shadowing to interact with other things in the world, like the terrain, static objects, and other nearby interiors.
#9
@ryan:
in the picture of the with it at high above. On the floor on the right hand side the shadow of the small box still seems to be pixelated while all of the other angled stuff appears to be" at least from the picture angle" smooth. Is there any explanation of this or are other edges this way as well and we just cant see them?
one more question is this process fully threaded so that it would take advantage of SMP systems? and is it Video hardware Dependant for its generation or would it work on pretty much anything that is capable of the running the engine
06/28/2008 (8:32 am)
yeah keep it in torque. no exporter non-sense.@ryan:
in the picture of the with it at high above. On the floor on the right hand side the shadow of the small box still seems to be pixelated while all of the other angled stuff appears to be" at least from the picture angle" smooth. Is there any explanation of this or are other edges this way as well and we just cant see them?
one more question is this process fully threaded so that it would take advantage of SMP systems? and is it Video hardware Dependant for its generation or would it work on pretty much anything that is capable of the running the engine
#10
The pixelated shadow you're referring to is a diffuse light shadow cast from the sun, so it doesn't have anything to do with the ambient occlusion code. If you notice, that shadow is exactly the same in every image, since I didn't change the sun. Not really sure why that little section is rougher than the rest.
The algorithm itself is single threaded. This doesn't mean that it wouldn't benefit from SMP systems. I don't know for a fact, but the way the light manager handles queued lighting events is most likely multi-threaded. If so, this would distribute the AO calculations for different interiors to different cores. And no, it's not tied to any video hardware. It should work on anything. :)
06/28/2008 (9:49 am)
@JamesThe pixelated shadow you're referring to is a diffuse light shadow cast from the sun, so it doesn't have anything to do with the ambient occlusion code. If you notice, that shadow is exactly the same in every image, since I didn't change the sun. Not really sure why that little section is rougher than the rest.
The algorithm itself is single threaded. This doesn't mean that it wouldn't benefit from SMP systems. I don't know for a fact, but the way the light manager handles queued lighting events is most likely multi-threaded. If so, this would distribute the AO calculations for different interiors to different cores. And no, it's not tied to any video hardware. It should work on anything. :)
#11
Are you doing these calculations in scene-relighting or somewhere else? Really interesting work!
06/30/2008 (4:09 am)
Ryan,Are you doing these calculations in scene-relighting or somewhere else? Really interesting work!
#13
thx
07/09/2008 (1:38 pm)
I had a problem adding the code to tgea 1.7.1 I got a fatal error after compiling it. I was wondering did anyone else have it too. I think the error was coming from the interior I/O. If someone could help me out it would be great!thx
#14
07/09/2008 (3:07 pm)
any update on getting this in to TGEA?
#15
I think you meant to post in the thread for custom lightmaps in TGEA. The code in this thread hasn't been released yet. The only thing that was changed in the Interior I/O was the four places where "smFileVersion == 0" was changed to "smFileVersion == 1". You might try changing them back to "smFileVersion == 0" and just adding " || smFileVersion == 1" to each of the if-statements. I think that should allow you to load old map2dif files and still leave the backwards compatibility that might have been causing the error.
@James
I just got the persistence part of the code working the way I wanted today in TGE. So I'll try to package it up and post a resource within the next day or two. If you're familiar enough with TGEA, you might be able to port it over yourself. The persistence code was actually very difficult for me to iron out, and I have a feeling TGEA might pose some more problems... so I'm not sure when a TGEA version will be posted.
07/09/2008 (10:39 pm)
@KoryI think you meant to post in the thread for custom lightmaps in TGEA. The code in this thread hasn't been released yet. The only thing that was changed in the Interior I/O was the four places where "smFileVersion == 0" was changed to "smFileVersion == 1". You might try changing them back to "smFileVersion == 0" and just adding " || smFileVersion == 1" to each of the if-statements. I think that should allow you to load old map2dif files and still leave the backwards compatibility that might have been causing the error.
@James
I just got the persistence part of the code working the way I wanted today in TGE. So I'll try to package it up and post a resource within the next day or two. If you're familiar enough with TGEA, you might be able to port it over yourself. The persistence code was actually very difficult for me to iron out, and I have a feeling TGEA might pose some more problems... so I'm not sure when a TGEA version will be posted.
#16
07/29/2008 (4:02 pm)
That is really useful Ryan. Congratulations!
#17
Thx a bunch, and bravo on your work.
Dalo.
10/29/2008 (7:57 am)
Ryan, I just want to say........brilliant. It makes my interiors looks really good. I do have one question. I have searched the forums and can't find the answer so I'm hoping you can answer for me. When I turned on all occlusion for my interiors for 1 mission it takes about 6 hours to relight. No biggy, do it once and it's all done, but for some reason when I bring it to the mac it wants to relight also sometimes on different windows machines it also wants to relight. Once the mission has been relit, is there a way to disable relighting?Thx a bunch, and bravo on your work.
Dalo.
#18
Yes, if you implemented the LM Persistence and Caching portion of the resource found in Appendix B, then it will "disable" relighting for AO enabled interiors. There is a workflow that needs to be followed in order to get the persistence to work consistently between Torque sessions, though. The CRC for the mission needs to match the CRC for the lighting file. To make sure this happens properly, you need to always save the mission before the final relight.
So for example, you relight the entire scene with AO enabled on all interiors, and it takes 6 hours. Now all the AO lightmaps are cached. So here's the "trick." To make absolutely sure that the CRCs match between the mission and lighting files, save the mission (the new mission CRC is recalculated here) and then hit "alt-L" to relight the scene (the lighting file uses the new mission CRC here). This relight should only take a matter of seconds. At this point, you could close Torque, reopen it, load the mission, and no relight would take place... your AO lightmaps that took hours to calculate would instantly pop up. You might test this workflow out on a small scene that doesn't take quite so long to relight. :)
Also, I suggest enabling AO on one interior at a time and doing a filtered relight. This way you can check to make sure there aren't any errors or artifacts before moving on. For example, sometimes there are black spots in the lightmap, which can be fixed by increasing the Bias parameter, which could be different for each interior. But that's just the way I do it.
10/29/2008 (9:23 am)
@ DALOYes, if you implemented the LM Persistence and Caching portion of the resource found in Appendix B, then it will "disable" relighting for AO enabled interiors. There is a workflow that needs to be followed in order to get the persistence to work consistently between Torque sessions, though. The CRC for the mission needs to match the CRC for the lighting file. To make sure this happens properly, you need to always save the mission before the final relight.
So for example, you relight the entire scene with AO enabled on all interiors, and it takes 6 hours. Now all the AO lightmaps are cached. So here's the "trick." To make absolutely sure that the CRCs match between the mission and lighting files, save the mission (the new mission CRC is recalculated here) and then hit "alt-L" to relight the scene (the lighting file uses the new mission CRC here). This relight should only take a matter of seconds. At this point, you could close Torque, reopen it, load the mission, and no relight would take place... your AO lightmaps that took hours to calculate would instantly pop up. You might test this workflow out on a small scene that doesn't take quite so long to relight. :)
Also, I suggest enabling AO on one interior at a time and doing a filtered relight. This way you can check to make sure there aren't any errors or artifacts before moving on. For example, sometimes there are black spots in the lightmap, which can be fixed by increasing the Bias parameter, which could be different for each interior. But that's just the way I do it.
#19
Thanks a bunch.
*EDIT*
I just noticed that the console removes all the lighting files. I double checked to make sure that appendix B was included in the engine and sure enough it is. Why would the engine remove all the light files?
Would it help if I put each mission in seperate folders? or would all folders be searched anyways?
10/30/2008 (8:01 pm)
Hey Ryan, thanks for responding. So I did what you said and all day at work I would load the mission, enable AO, save, then hit alt-L, let it relight, close torque right down and restart it. I did that for 12 arena levels. They all would start the mission instantly afterwards. It worked, but as soon as I got home and tried it on my computer here, some missions would work and others would have to relight. This is what's baffling me. We are trying to get our game ready for the IGF and really want to get this working. Any other ideas why a different pc would want to relight it?Thanks a bunch.
*EDIT*
I just noticed that the console removes all the lighting files. I double checked to make sure that appendix B was included in the engine and sure enough it is. Why would the engine remove all the light files?
Would it help if I put each mission in seperate folders? or would all folders be searched anyways?
#20
1. Maybe you didn't copy the correct mission/lighting file pair to your other computer.
2. Maybe some of your art assets aren't exactly the same between the two computers. Each DIF has its own CRC that gets factored into the total mission CRC. So, you may have a DIF on each computer named, "Building.dif", but if you changed textures or modified geometry at work, this would create a situation where the mission would load fine on both but have different CRCs, causing a relight at home.
To verify that the CRCs are not matching, you could modify the code to print the mission lighting CRC in the console. So in\engine\lightingSystem\sgSceneLighting.cc you could find the lines:
and add right above it something like this:
Now as the mission is loading, if it tries to relight just cancel it immediately and check the console to see what lighting file it's looking for (or if it gets hung up while canceling, close TGE and go look at the "console.log" file). FYI, the numbers at the end of the file name are the CRC. If this file does not match any of the lighting files at work, you've probably got a different art asset somewhere (a.k.a one of your DIFs are different), so just make sure everything's up-to-date at home.
10/31/2008 (8:17 am)
Hmmm, I've never seen stock TGE delete any lighting files. The fact that some of the missions will load and others won't tells me some of your mission CRCs aren't matching your lighting file CRCs. Here's a couple of possibilities:1. Maybe you didn't copy the correct mission/lighting file pair to your other computer.
2. Maybe some of your art assets aren't exactly the same between the two computers. Each DIF has its own CRC that gets factored into the total mission CRC. So, you may have a DIF on each computer named, "Building.dif", but if you changed textures or modified geometry at work, this would create a situation where the mission would load fine on both but have different CRCs, causing a relight at home.
To verify that the CRCs are not matching, you could modify the code to print the mission lighting CRC in the console. So in
// check for some persisted data, check if being forced..
if(!flags.test(ForceAlways|ForceWritable))
{
if(loadPersistInfo(mFileName))
{
Con::printf(" Successfully loaded mission lighting file: '%s'", mFileName);and add right above it something like this:
Con::printf("LIGHTING FILE: %s", mFileName);Now as the mission is loading, if it tries to relight just cancel it immediately and check the console to see what lighting file it's looking for (or if it gets hung up while canceling, close TGE and go look at the "console.log" file). FYI, the numbers at the end of the file name are the CRC. If this file does not match any of the lighting files at work, you've probably got a different art asset somewhere (a.k.a one of your DIFs are different), so just make sure everything's up-to-date at home.

Torque Owner Stephan - viKKing - Bondier
Really nice. Awesome work.