Game Development Community

Normal Maps, Multipass Materials, Advanced Lighting

by Gary Hoffmann · in Torque 3D Professional · 06/25/2009 (4:49 pm) · 10 replies

I’ve found a problem with using multiple layers and normal maps with advanced lighting.

Specifically, when basic lighting is turned on I can create a material with a diffuse map and a normal map on layer 0, then I can add another diffuse map (which has a specific alpha channel so that parts of layer 0 show through) and another normal map on layer 1. Everything works great.

However, when I turn on advanced lighting, I’ve found that the normal map on layer 1 appears to be ignored and everything (regardless of layer) uses the normal map of layer 0 which causes the layer 1 parts to look totally wrong.

I’m not sure if this is an unintended consequence of how the advanced lighting works or an actual bug, but it makes it difficult to use multiple layers with anything that has a normal map.

#1
06/25/2009 (9:22 pm)
Yea... you caught something we missed... and its a hard one to solve. :(
#2
06/26/2009 (6:07 am)
@Tom: I assume the layers are rendered using multiple passes with blending in BL, no? How does it work in AL?
#3
06/26/2009 (10:15 am)
In Advanced Lighting, it lights the normal in the GBuffer. There is only one normal, and one depth value, per pixel (so translucent objects are forward shaded). The reason why this doesn't work is because there is no lighting information for the second normal. There are a few options for getting around this, and they all depend on your tolerance for pain.
#4
06/26/2009 (10:21 am)
So... in AL only the first layer outputs normals? And I assume the normal in the GBuffer is stored in a way such that blending is a no-no, right?

Couldn't the normals for the various layers be blended in the shader, before encoding and writing to the GBuffer?
#5
06/26/2009 (10:58 am)
Right now, normals can't be blended because they are stored in spherical co-ordinates and a simple lerp blend can cause errors (See image of possible Atan2 values)

Storing the normals in cartesian co-ordinates would make this possible, but would halve the resolution of the depth data. I am looking at DirectX9Ex to give us access to the depth buffer on Vista/Windows7, which would free up Blue/Alpha in the G-buffer.
#6
06/26/2009 (11:03 am)
I meant blending the normal values for all layers in a single pass before converting to spherical coordinates.
#7
06/26/2009 (11:44 am)
That is a good idea. However there are certain cases (like decals/terrain materials) we can't be assured that all normal maps can be read in one pass. Especially for decals. There are also ways around this, and the solution may just be to have a bunch of work-arounds but it is kind of a hard thing to fix globally, since there are so many cases.
#8
06/26/2009 (12:07 pm)
Hmm... one thing came to mind. Seems there's a common point with all these cases (terrain, material layers, decals): they're surfaces that are layered on other surfaces. If so, they don't need to write depth, since we already have the values we want. So, they could render their normals to a different buffer that stores normals in a blend-able format. After they are done, it would be possible to "blend" the normal buffer with the Gbuffer using a shader.
#9
06/29/2009 (11:52 am)
Logged as THREED-540
#10
06/30/2009 (6:23 pm)
I guess i left the impression that this is something we're not able to fix.

While the problem is hard... there are several possible solutions. Several suck... but one is an almost perfect fix which is the one i'm focusing on.

In the decal case or in the case of a second pass on a material we don't have to write new depth data. This means the BA channels of the 64bit Gbuffer do not need to be written to. I can then pass a blend factor into the alpha channel with color writes disabled to BA. This allows lerp blend to work on the RG channels where the spherical normal is stored.

The problem at the moment is that the spherical normal doesn't lerp blend properly. I haven't confirmed why its broken, but if its what i think it is i have an idea of how to fix it.

I just have to get thru some higher priority tasks here first.