I have been making a lightmap generating system for
Unity for the last few days and I figured I should release something before I get bored of it and forget about it like so many other things. Heres the basic fetures:
-Render only the objects you want to by selecting multiple objects or groups of objects and do a batch render.
-Generate lightmaps on imported meshes with 2 uv channels.
-Lightmaps are generated from all lights in the scene.
-Ghetto material management, for keeping lightmapped materials updated with their source materials.
-4X modualted lightmaps for over exposure.
Download current Lightmapper for Unity
Extract contents into your Project/Assets folder.
Download Sample Project
now for the media:
If you have the Unity web player installed you can walk around in the example project here:
http://keenleveldesign.com/pimp/unitylightmaps/lightmapper_web_1.0.html
and windows standalone if you dont have the web player it also has a better camera
http://keenleveldesign.com/pimp/unitylightmaps/lightmapperexample01standalone.zip
How to use:
-Extract lightmapperX.X.zip into your Project/Assets folder.
-Export an object from your 3d package, and make sure it has 2 uv channels. The second uv channel is what the lightmap uses. Make sure you leave a bit of bleed room around the uv islands for the lightmap.
-Add the object into the scene.
Make a material with a shader type Lightmapper>DiffuseModulate4. This is important. The standard Unity lightmap shaders wont work correctly.
-Assign the materials(s) to your model
-Add a 'Lightmapper' component to your object (Scripts/Lightmapper). This will automatically add a MeshCollider component to the object. This is nessessary for the object to cast shadows on other objects.
-Add some point lights in the scene.
-In the menu bar at the top of Unity click "Lightmapper>Bake Selection And Children". If you dont see this menu then you didnt extract it correctly.
-You should see a progress window, this could take a while with lots of lights. When its done your object should show up with a lightmap.
-Adjust the settings in the Lightmapper component on the object if the lightmap looks low res or "spotty".
Things still todo:
-Make more materials.
-Fix the problem of unwanted objects casting shadows. (you can put them in the "Ignore Raycast" layer, or add them to layer 29)
-Add support for spot and directional lights.
-Probably more
Tips:
-Keep lightmap texel density even throughout the scene to avoid artifacts on smaller objects.
-Try to use smaller lights around smaller objects. Large area lights dont work too well on small objects. Using smaller lights will also help calculation time.
Replies
I've looked into your code. And having written a similar tool for luxinia once, here is some hints towards better efficiency and higher quality results:
raycast vs raytrace
Don't trace from lightsource to object, but do the opposite. That is shoot a ray from every lightmap texel thru the world. You either have to rasterize the uvmesh of every node yourself, and generate worldpositions for it. Or you use a "raytrace hack". Ie you create a dummy mesh for the pyhsics engine, passing the texcoord2 as positions. Then you raytrace within the 0,1 region on that uvmesh (parallel rays perpendicular to xy plane), and you get back triangle and barycentric coordinates of the hitpoint. Using those you get the object position of that texel. Transform it with the node's matrix and you have the world position.
That way you get a much better ratio of rays that are meaningful and contribute well (with your current approach you might have many rays hitting the same uv spots on the lightmap texture). Yes this setup takes more time to do, but once you have it, it's a huge benefit and allows to do much more cool stuff, as you gained efficiency.
soft shadows / area lights
instead of directly shooting from worldpos to lightpos, you can offset positions. Using the direction vector between the two, and another non parallel vector. You use the crossproduct to create a perpendicular vector to light direction. That vector you add to worldpos or lightpos. (be sure you also have random ones every time). Do an average over the result and you have soft shadows.
ambient occlusion
you can shoot random rays from worldpos. Ideally you take the triangles normal into account and just shoot on one hemisphere. But if you dont have the normal at hand, just brute force fire in all directions. Depending on the range of your hit (or no hit) you would give each sample a weight, at the end sum them all and you have a nice AO term.
for approximating many random vectors in a circle, look into poison disc distribtion. It gives good results using less samples.
do normal based lighting
at the moment you purely light on radial falloff. That is cool as one can fake GI easily with many small lights. And if remember right, this was also the way things were done in q2 and maybe even q3. But for higher quality (depending on the style you want to achieve) using classic diffuse and ambient lighting terms might further boost quality. Then you need to have per-texel normals. Which can be derived similar to the per-texel world positions.
All these are just suggestions and hints if you want to further enhance it, but don't put in tons of time if the current results are cool with you and serve their purpose.
Thomas P.
Do your materials work on the iPhone?
CrazyButcher, thanks these are all very good suggestions. The original idea was to trace from texel to light, but couldnt find an easy way to do that so I gave up :P. Area lights is something I want to do and is pretty easy. For normal based lighting I think theres actually a few lines in there that attempt to do it but fail more or less. I will try to get this working better.
I will try some things with it as soon as i have time.
I hope you dont get bored and you will continue working on it!
edit: working on a luxinia tutorial for this task. lua and javascript are similar, so you shall be able to adjust the important bits for your tool.
Did a rough version of the lightmapper in Lua, only collision is handled in C by ODE. Api of unity and luxinia shouldnt be too different, so in theory you should be able to follow this. The "interpolator" code is a bit rough, as I made it generic (any vectors of any length can be passed). So if you need help about it, ask, or wait until the full tutorial is done.
Anyway for the proper tutorial I will do more effects and add plenty more descriptions. Nevertheless the current code can be found here:
http://crazybutcher.luxinia.de/code/lua/lightmapgen.lua
The rasterizer is based on an implementation by Diogo Teixeira, who based his implementation on this article series by Chris Hecker. It is a very robust rasterizer, doesnt create "holes" or overlaps.
http://chrishecker.com/Miscellaneous_Technical_Articles
And another shot. Its pretty fast if you get the settings right.
http://www.paulnettle.com/pub/FluidStudios/Radiosity/
and another link with good sublinks
http://kevinbeason.com/smallpt/
great work! is there a possibility to save the lightmap as an external file to do some cosmetics in photoshop?
thx
Been waiting for this for a while now, so it was a pleasant surprise to see this one
Keep up the excellent work!