Lighting flat objects

(an application of normal maps and rayDiffuse)



If you need an explanation about what normal maps are you can check here : normal_maps, however you will have much faster render times using the plugins and methods described here, it's just for a (even) more verbose explanation on the subject.

You'll need the rayDisplace plugin to do the operation I describe below, you can get it here : displacement_maps. Actually, not, you could render a front view and remap it as we'll be dealing with perfectly flat object, it's just shameless self promotion!

However you'll need Mark Davies rayDiffuse plugin to generate the self shading maps (I think it's more or less ambient occlusion maps?). The use of normal maps is nothing new, but the use of rayDiffuse and « cubic ambient occlusion maps » adds a nice touch.

As both these nodes use raytracing, you can't bake it using Maya's « convert solid texture ». However Mark Davies great plugin includes rayBake using Tristan Salome's scanCookNode, and is a great tool to bake raytraced shading nodes to image maps : lightEngine3d

You certainly know about the way some productions or real-time application use billboards to render distant objects such as trees or signs etc... As long as the camera stays close to facing the boards they can be quite ok. Crossed billboards are often used for trees, or even a slightly more detailed « cutout » billboard so you can have it cast shadows that don't look too bad.

I was testing Bionatics NatFx ( http://www.bionatics.com ) great application for generating trees when I experimented with the shaders I'll describe here. The tree I used in the rendered exemples is one of the many tree species they can generate. They have nice options to range the resolution from a simple billboard to a full detailed tree and various in-betweens. I didn't include the tree itself in the scene files because I don't have any autorisations for this, and it's bit too heavy to post on web. So either you can go there and download the demo too (interesting stuff to see anyway), or you'll have to do with my nice make up tree I did, hope you'll like it!

As it was for a production that will likely have tight render times, I know I'll have to use a lot of billboards, so I wanted to test creating them from these trees and it worked fine. Only problem with billboards, is they're pre-lighted. If the lighting values and especially direction that were used to create the image that will be mapped on the nurbs plane don't correspond to the lighting you are setting up in your scene, you'll have to re-generate the map (if you still have the original tree somewhere).

However it's not a problem if you also use normal maps on the billboard!


General idea : using rayDisplace and rayBake I recover the color, alpha and normal maps info from the 3D tree to the simple nurbs patch so that it can be lighted and react to light direction.

Applications : these billboard are very lightweight and render fast, as long as the camera doesn't take too much angle or they're far enough to use cross billboards you can do nice background forests at cheap render cost.

If you already read my other tutorials you shouldn't have problems recovering color, alpha and normal information from the 3D tree to the board. As I said it's just a lazy convenience way, you could also do a front render, cut the render to correct size and remap it on the nurbs.

To retrieve color keep the 3D tree shaders, just make sure you use surfaceShader nodes so you get the full color value without lighting, for the alpha a 100% white shader will do fine, for the normals you can use the normals shader included in the sample scenes :

recoverColor.zip and recoverNormals.zip

To output the results as nice image maps, as usual use the great rayBake...

And you should get something like these maps :

color_normalsMaps.zip

Actually here I included the opacity map as the color map's alpha.






Now you can get rid of the 3D tree (for now) and just use both maps you just generated (normal map & color map with alpha) to create a « classic » normal map shader on the nurbs plane. I used a lambert here because we now need it to react to light.



Now you can try this scene for yourself : treeBillboardNormalMapped.zip there is an animation on the light, check how it reacts too. As you see, it's quite lightweight, uses only two RGB maps, renders fast and doesn't look too bad compared to the original tree. (Bit darker than the original huh, you can call me lazy).

Click on samples for the DIVX light animation file...


The light animation on the « reference » 3D tree


The light animation on the billboard tree



Now it's not bad at all, but a little hint of self shadowing would be nice, like this :


Is it fixe or animated, flat or volume ;)



General idea : I'll use rayDiffuse plugin to generate ambient occlusion maps for the 6 directions corresponding to the 3 world axis (+X -X, +Y -Y, +Z -Z). Then I'll recover them as two RGB maps (one channel = one direction, 2 maps = 6 directions) and use them in the shader of my flat nurbs plane. Each pixel of the plane texture will then correspond to 6 ambient occlusion information pixels, a sort of pixel based cubic ambient occlusion map.

Applications : it works quite well for large near flat surfaces where you want to reduce complexity by transforming small details to normal maps, and still have the nice ambient occlusion soft touch on top, like ornate building facades etc...

Note : I'm currently living in the delusion of having found out something original, so if this technique already exists and got a nice name, please tell me so I can show off by using it.



Recovering the directionnal occlusion information, I use rayDiffuse with the « use ray direction » parameter, a direction manipulator makes things much easier, just align it with the axis you are trying to get self shadowing information for. A direction blend parameter of 0.25 provided a nice soft look (used 16 samples each time).

You can use 3 rayDiffuse nodes and bake one map / 3 channels at a time to speed things up, check the sample scene here : treeBillboardGetShadowCubics.zip

Using the same scene, I do it twice, reversing the direction of all manipulators for the second time, thus I get my two needed RGB maps :

shadeMaps.zip




If you take a look at these 2 maps, viewing one color channel at a time, you'll see how they code ambient occlusion information for 6 directions = a cubic map



Now I need to set up a shader that will blend them according the the incident light direction. The general idea is to choose one light that will drive the shadows direction, and compute the dot product of its « lightDirection » with the 6 directions of the cubic map, then do a weighted blend of the 6 ambient occlusion maps based on these dot products (clamped at 0, negative values count as 0, that is no contribution to shading).


The shadow interpolation shader


The result on the billboard

Then I'll prepare two shaders using the same network (the classic normals maps shader shown before) except one will be lit by all lights, whereas the other will be lit by all save the main light. That black and white info will blend the 2 shaders out color to a final surfaceShader assigned to the board:



Here is the full shader. You'll have a better look in the sample scene here anyway : treeBillboardShadowedRender.zip . The final assigned surfaceShader (outlined in red) receives the input of the 2 lambert shaders (identical networks, just not lit by the same lights), mixed by the shadow interpolation network result.

I just added the gamma correction node and the setRange for fine tuning of the shadow levels.


That's it! You can take another look here to judge the final effect : treeShaded.avi

Possible improvements : the shading network making use the the cubic shade maps could be made much simpler by writing a custom node instead. It would also remove the need for the dodgy light connections I do, next thing to do...

Also the interpolation between maps could be a bit refined maybe, could be smoother than a plain weighted average. You'd mostly see the difference in animation anyway.

Olivier Renouard

January 22, 2003

olivier AT drone DOT org