HowTo:Radiosity baking in Blender

From VsWiki
Revision as of 22:33, 21 September 2005 by Pirx (talk | contribs) (first draft)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search


As I promised (quite) some time ago here's a little howto for baking radiosity in blender. I tried making it easy for non-blenderheads to use it too but a bit of know how of blender is good (look at [1] if you need something to get you started). The method described here was developed and tested with 2.37, and may be incomplete or incorrect.

Our goal

There is no such thing as the ambient lighting most 3D applications and games use, period. An exposed part of the model will receive more ambient light than parts hidden deep beneath pipes and plates. Since we can't simulate this in real-time (at the moment, at least) putting this information in the texture is the way to go. How you ask? The most straight forward method is guessing and painting by hand, but it is also very time consuming and not to mention getting good results is hard.

Compare the following two pictures:


Even though I used two slightly different meshes they should illustrate the difference, clearly the lighting on the latter picture looks more natural.


In the end, this should slightly alleviate the texturing process and make for promising results.

Our weapon of choice: WikiPedia:Radiosity

The Way

As I mentioned above our goal is to calculate some kind of ambient light dependent on the geometry, which we'll use radiosity for. If you don't know what radiosity is, please visit the link above to find out. All right! Just follow these steps:

  1. Load your UV-mapped object into Blender and put it on layer 1. Make sure it is UV-mapped! Also get rid of any lamps lingering in the scene.
    1. Add an icosphere with its center roughly in the middle of your model ([SPACE]->Add->Mesh->Icosphere). This will be our ambient light source. Higher subdivision yeilds better results (you need a higher value for a mesh with many polygons, play around!) but longer calculation times, 4 should be sufficient.
    2. Scale up [S] the ico-sphere to encompass your entire model.
    3. In edit mode [TAB] select all the faces [A] and flip the normals [W],[9]. Turn on normal drawing and make sure they're really pointing inward the sphere ([F9] and enable "Draw normals").
    4. Go to the material buttons [F5] and add a new material to the sphere. Choose the desired light color (white, normally) and give the material some emission, you have to experiment with the emit value but 0.02 should be a good starting point.
  2. You're now ready to start calculating the radiosity. But before you start you might want to subdivide your mesh a few times, to get better results. Do it, say, twice (W, 1 and repeat).
    1. Go to the shading context [F5] and then the radiosity buttons. Select both the meshes and press Collect meshes. Switch from Solid to Gourad.
    2. i'IMPORTANT': Set MaxEl (not ElMax!) to 1. This will ensure that Blender doesn't alter the mesh in any way.
    3. Hit [Go] and lean back. Press [ESC] when you're happy with what you see or wait until it finishes. It shouldn't be all black, if it is something went wrong.
    4. This is optional but if your results are a little spotty or have artifacts you might want to perform "Face filter" or "Element filter", or both.
    5. Save the radiosity information in a new mesh by pressing "Make new mesh". Move it to layer 2 ([M],[2]).
  3. Now it's time for a little cleaning up before we can bake the radiosity information to a texture. Remove the icosphere from the newly created mesh with the radiosity information. If you're not comfortable with blender, here's how you do it (if your mesh is one solid mesh!):
    1. Go to layer 2 ([2]). Select the mesh and enter edit mode [TAB]. Split the meshes by pressing P, 2. Leave edit mode [TAB] and delete the sphere.
    2. Now, since using the radio tool erases all UV-information from the baked mesh we'll need to transfer the vertex color information from it to our original mesh somehow. After trying various methods for doing this, none of which worked, I hacked together a small little script (see #Script) in python to do it.
      Load it, change the mesh names at the top of the file, run it and voila! For the blender impaired here's what you do:
  4. [Shift]+[F11] to bring up the text editor, load the script from the menu or paste it and then press [Alt]+[P] to run it.

    Your original, UV-mapped, mesh should now have all the shading information stored safely in the color of each vertex. You should be able to verify this if you set your viewport shading to "Shaded" (make sure VCol Light is enabled for your material).

    The final step is to bake the vertex color information to texture using your favorite baking script.
  5. Enable "VCol Paint" and "Shadeless". Run "Texture baker" (found under Scripts->UV and included with Blender). If it doesn't work the first time make sure your mesh is indeed on layer 1 and try again.

That's it!

You can do even more

Using the same technique you can do even more nifty stuff, such as baking glowmaps:



You have to pardon my python n00bness, this is all I could come up with. Feel free to improve it!

import Blender

# This script copies the vertex color information from one mesh
# to another, and does so correctly assuming the meshes have the
# same geometry, vertex-wise.

# IMPORTANT: Assumes meshes with exactly equal geometry, vertex-wise.

fromObj = "Mesh"  # Set this to the resulting mesh from radio calcuation
toObj = "Fuselage_default" # Set this to the name of your original, UV-mapped mesh.

me_from = Blender.Object.Get(fromObj).getData()
me_to = Blender.Object.Get(toObj).getData()

if not me_to and not me_from:
	print "ERROR: Source/destination object does not exist"

elif len(me_to.verts) != len(me_from.verts)
	print "ERROR: Source and destination objects must have the same number of vertices"
	# make two lists sorted on coordinates,
	# containing a face and vertex index i and j respectively
	l_to = []
	l_from = []
	# format: [ (x,y,z, face index, vertex index), ... ]
	for i in range(len(me_to.faces)):
		for j in range(len(me_to.faces[i].v)):
			vert = me_to.faces[i].v[j].co
			l_to.append((vert[0], vert[1], vert[2], i, j))
		for j in range(len(me_from.faces[i].v)):
			vert = me_from.faces[i].v[j].co
			l_from.append((vert[0], vert[1], vert[2], i, j))
	# Sort the lists after vertex coordinates
	for i in range(len(l_to)):
		to_f = l_to[i][3]
		from_f = l_from[i][3]
		to_v = l_to[i][4]
		from_v = l_from[i][4]
		me_to.faces[to_f].col[to_v] = me_from.faces[from_f].col[from_v]

	print "Copied vertex color information from object "+fromObj+" to object "+toObj+"."