A truly lightmap shader !

Well, this is, for some one who interest in baking art and wonder about the weakness of lightmapper, that the fact is black multiply texture.

This is the issue of current lightmapper

Well, we lose the glow/exposure point that make scene really dull.

So I decide to make a mod to current lightmapper shader, add a exposure control texture. You will see the different here

New Lightmapper

Shader "Lightmapped/DiffuseMod" {
	Properties {
		_Color ("Main Color", Color) = (1,1,1,1)
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_LightMap ("Lightmap (RGB)", 2D) = "black" {}
		_LightMap2 ("Exposure map (RGB)", 2D) = "black" {}			
	}
	SubShader {
		UsePass "Lightmapped/VertexLitMod/BASE"
		UsePass "Diffuse/PPL"
	}
	FallBack "Lightmapped/VertexLit", 1
}

New lightmapper Dependency

Shader "Lightmapped/VertexLitMod" {
Properties {
	_Color ("Main Color", Color) = (1,1,1,1)
	_SpecColor ("Spec Color", Color) = (1,1,1,1)
	_Shininess ("Shininess", Range (0.01, 1)) = 0.7
	_MainTex ("Base (RGB)", 2D) = "white" {}
	_LightMap ("Lightmap (RGB)", 2D) = "black" {}
	_LightMap2 ("Lightmap (RGB)", 2D) = "black" {}		
}

// ------------------------------------------------------------------
// Three texture cards (Radeons, GeForce3/4Ti and up)

SubShader {
	Blend AppSrcAdd AppDstAdd
	Fog { Color [_AddFog] }

	// Ambient pass
	Pass {
		Name "BASE"
		Tags {"LightMode" = "PixelOrNone"}
		Color [_PPLAmbient]
		BindChannels {
			Bind "Vertex", vertex
			Bind "normal", normal
			Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
			Bind "texcoord", texcoord1 // lightmap uses 2nd uv			
			Bind "texcoord1", texcoord2 // main uses 1st uv
		}
		
	
		SetTexture [_LightMap] {
			constantColor [_Color]
			combine texture * constant
		}
		
		SetTexture [_MainTex] {
			constantColor [_Color]
			combine texture * previous
		}
		
		SetTexture [_LightMap2] {
			constantColor [_Color]
			combine texture + previous
		}		
	}
	
	// Vertex lights
	Pass {
		Name "BASE"
		Tags {"LightMode" = "Vertex"}
		Material {
			Diffuse [_Color]
			Shininess [_Shininess]
			Specular [_SpecColor]
		}

		Lighting On
		SeparateSpecular On

		BindChannels {
			Bind "Vertex", vertex
			Bind "normal", normal
			Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
			Bind "texcoord1", texcoord1 // lightmap uses 2nd uv
			Bind "texcoord", texcoord2 // main uses 1st uv
		}
		
		SetTexture [_LightMap] {
			constantColor [_Color]
			combine texture * constant
		}
		SetTexture [_LightMap] {
			constantColor (0.5,0.5,0.5,0.5)
			combine previous * constant + primary
		}
		SetTexture [_MainTex] {
			combine texture * previous DOUBLE, texture * primary
		}
	}
}

// ------------------------------------------------------------------
// Dual texture cards - draw in two passes

SubShader {
	Blend AppSrcAdd AppDstAdd
	Fog { Color [_AddFog] }

	// Always drawn base pass: texture * lightmap
	Pass {
		Name "BASE"
		Tags {"LightMode" = "Always"}
		Color [_PPLAmbient]
		BindChannels {
			Bind "Vertex", vertex
			Bind "normal", normal
			Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
			Bind "texcoord", texcoord1 // main uses 1st uv
		}
		SetTexture [_LightMap] {
			constantColor [_Color]
			combine texture * constant
		}
		SetTexture [_MainTex] {
			combine texture * previous, texture * primary
		}
	}
	
	// Vertex lights: add lighting on top of base pass
	Pass {
		Name "BASE"
		Tags {"LightMode" = "Vertex"}
		Material {
			Diffuse [_Color]
			Shininess [_Shininess]
			Specular [_SpecColor]
		}

		Lighting On
		SeparateSpecular On
		
		ColorMask RGB

		SetTexture [_MainTex] {
			combine texture * primary DOUBLE, texture
		}
	}
}

// ------------------------------------------------------------------
// Single texture cards - lightmap and texture in two passes; no lighting

SubShader {
	Blend AppSrcAdd AppDstAdd
	Fog { Color [_AddFog] }

	// Base pass: lightmap
	Pass {
		Name "BASE"
		Tags {"LightMode" = "Always"}
		BindChannels {
			Bind "Vertex", vertex
			Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
		}
		SetTexture [_LightMap] { constantColor [_Color] combine texture * constant }
	}
	
	// Second pass: modulate with texture
	Pass {
		Name "BASE"
		Tags {"LightMode" = "Always"}
		BindChannels {
			Bind "Vertex", vertex
			Bind "texcoord", texcoord0 // main uses 1st uv
		}
		Blend Zero SrcColor
		SetTexture [_MainTex] { combine texture }
	}
}

Fallback "VertexLit", 1

}

And this is texture sample for lightmap and exposure slot

Now I think I can not do anything more because of lacking knowledge. :sweat_smile: :? :frowning: . These thing need to be done:

  1. Add a control brightness and contrast for exposure texture. This will save tone of time open back and forth PS for editing picture. However, If, this affect much to FPS ?
  2. Fix code with the following
    Vertex lights
    Dual texture cards - draw in two passes
    Single texture cards - lightmap and texture in two passes; no lighting
  3. A simpler work flow for generate these kind of texture !!!

You could maybe also try playing with the blendmodes instead of using an extra exposure map.
A mod x 2 blend should be easily doable in Unity and would let your lightmaps look like they do in the 3D tool (if exposure is set up correctly in the 3D package) because they can also brighten up the base texture and not just darken it like with multiply blending.
I haven’t played with it in Unity yet, but use the blend-style in other engines (NF, OGRE, Blitz3D) all the time for lightmaps. Will try around in Unity when I get home tonight.
Don’t hurt me if I am wrong, I am a Unity newbie.

Yeah, built-in Lightmapped shaders do multiplication (that is, lightmap can only darken the base texture).

Another approach, like you outlined, is to have lightmaps that can both darken and lighten the texture.

I think doing “combine texture * previous double” when combining the lightmap the main texture is the most efficient way (that way, gray color in the lightmap would do nothing; darker colors would darken and lighter colors would brighten).

I understand the way re-use of lightmap to an “add” mode. However, problem is, data inside lightmap is not enough for the exposure enhancement in most case. The black and white data inside lightmap CAN NOT stand for all exposure data that texture should have after lighting

So In theory, we usually talk about re-add lightmap to gain exposure, but that doesnot bring the reality and the mood we have when rendering, especially If we are working with GI engine like MR or VR, that really sensitive in exposure data.

I have finishing develop a toolkit to solve all matter come out with this method, from baking to transfering data into Unity. However It will need a little time of testing before I release to community :lol: :lol: :smile:

I really don’t understand the problem with Aras’ solution, or what you’re trying to accomplish beyond getting a brighter result out of light maps.

In Unity, dynamic lights add texturelightColor2, which allows the overbright effect you’re talking about. Unity 2 added an intensity value for lights that gets multiplied in as well, allowing users to get new extremes of brightness.

The lightmap shaders that come with Unity only add texture*lightmapColor, which results in the purely darkening effect you see.

Aras’ solution would give you texturelightmapColor2, which results in the same magnitudes as lights of intensity 1.

If that’s still not bright enough for you, you could quadruple the result while still keeping everything in fixed function.

Here, I implemented Aras’ suggestion:

Shader "Lightmapped*2/VertexLit" {
Properties {
	_Color ("Main Color", Color) = (1,1,1,1)
	_SpecColor ("Spec Color", Color) = (1,1,1,1)
	_Shininess ("Shininess", Range (0.01, 1)) = 0.7
	_MainTex ("Base (RGB)", 2D) = "white" {}
	_LightMap ("Lightmap (RGB)", 2D) = "black" {}
}

// ------------------------------------------------------------------
// Three texture cards (Radeons, GeForce3/4Ti and up)

SubShader {
	Blend AppSrcAdd AppDstAdd
	Fog { Color [_AddFog] }

	// Ambient pass
	Pass {
		Name "BASE"
		Tags {"LightMode" = "PixelOrNone"}
		Color [_PPLAmbient]
		BindChannels {
			Bind "Vertex", vertex
			Bind "normal", normal
			Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
			Bind "texcoord", texcoord1 // main uses 1st uv
		}
		SetTexture [_LightMap] {
			constantColor [_Color]
			combine texture * constant DOUBLE
		}
		SetTexture [_MainTex] {
			constantColor [_Color]
			combine texture * previous, texture * constant
		}
	}
	
	// Vertex lights
	Pass {
		Name "BASE"
		Tags {"LightMode" = "Vertex"}
		Material {
			Diffuse [_Color]
			Shininess [_Shininess]
			Specular [_SpecColor]
		}

		Lighting On
		SeparateSpecular On

		BindChannels {
			Bind "Vertex", vertex
			Bind "normal", normal
			Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
			Bind "texcoord1", texcoord1 // lightmap uses 2nd uv
			Bind "texcoord", texcoord2 // main uses 1st uv
		}
		
		SetTexture [_LightMap] {
			constantColor [_Color]
			combine texture * constant
		}
		SetTexture [_LightMap] {
			combine previous + primary
		}
		SetTexture [_MainTex] {
			combine texture * previous DOUBLE, texture * primary
		}
	}
}

// ------------------------------------------------------------------
// Dual texture cards - draw in two passes

SubShader {
	Blend AppSrcAdd AppDstAdd
	Fog { Color [_AddFog] }

	// Always drawn base pass: texture * lightmap
	Pass {
		Name "BASE"
		Tags {"LightMode" = "Always"}
		Color [_PPLAmbient]
		BindChannels {
			Bind "Vertex", vertex
			Bind "normal", normal
			Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
			Bind "texcoord", texcoord1 // main uses 1st uv
		}
		SetTexture [_LightMap] {
			constantColor [_Color]
			combine texture * constant DOUBLE
		}
		SetTexture [_MainTex] {
			combine texture * previous, texture * primary
		}
	}
	
	// Vertex lights: add lighting on top of base pass
	Pass {
		Name "BASE"
		Tags {"LightMode" = "Vertex"}
		Material {
			Diffuse [_Color]
			Shininess [_Shininess]
			Specular [_SpecColor]
		}

		Lighting On
		SeparateSpecular On
		
		ColorMask RGB

		SetTexture [_MainTex] {
			combine texture * primary DOUBLE, texture
		}
	}
}

// ------------------------------------------------------------------
// Single texture cards - lightmap and texture in two passes; no lighting

SubShader {
	Blend AppSrcAdd AppDstAdd
	Fog { Color [_AddFog] }

	// Base pass: lightmap
	Pass {
		Name "BASE"
		Tags {"LightMode" = "Always"}
		BindChannels {
			Bind "Vertex", vertex
			Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
		}
		SetTexture [_LightMap] { constantColor [_Color] combine texture * constant DOUBLE}
	}
	
	// Second pass: modulate with texture
	Pass {
		Name "BASE"
		Tags {"LightMode" = "Always"}
		BindChannels {
			Bind "Vertex", vertex
			Bind "texcoord", texcoord0 // main uses 1st uv
		}
		Blend Zero SrcColor
		SetTexture [_MainTex] { combine texture }
	}
}

Fallback "VertexLit", 1

}

As I said, the data inside lightmap is not enough for exposure It will “mass” exposure your result because of vast area in lightmap is white, or grey, that will bring the wrong result. We do not need exposure WHERE data is white! White color does not stand for that area should be gain EXPOSURE. It just points out that area is fully LIT, no thing more !!!

Okie I will show more thing about what lightmap bring if we use it to gain exposure

First, this is the lightmap


Now result with only lightmap multiplied

And now I use your method, lightmap also a “exposure map” (my own term:o )

So well, now we have a fully exposure model. But that TOTALLY WRONG! all white data is exposured without concerning if it is exposured in rendering or not!!! Model, in just case is call “burning” and if we make a scene with “burning model” like this, that will elimiated all the development of Rendering field for tonemapping and exposure control over years.
:lol: :lol:

Now I show you the exposure map, only area appear in map is OVER EXPOSURE. That mean bring the reality and a good MOOD for model.

Now you see exposure data is quite sensitive, only area where sun hit in a direct way gain exposure

You could understand why exposure data need to be seperated from Lightmap :slight_smile:

If you use my shader with a normal light map texture, it will be twice as bright as the built-in lightmap shader.

If all you’re doing is summing your “exposure” texture with the existing, non-doubled lightmap, there is no reason why you can’t combine your exposure and light map textures beforehand:

doubleLightmap = exposure0.5 + lightmap0.5

Then you can accomplish the same effect without a second texture.

Sorry I dont get all what you mean :sweat_smile: …So you mean after rendering out exposure map and lightmap, you use a composite apps to combine them into one map? Then what method we use to add this to our model ? :roll:

Your method uses three textures:

• Diffuse: base colour
• Lightmap: a regular light map
• “Exposure” map: a selectively darkened version of the diffuse map

and applies them like this:

result = diffuse*lightmap + exposure

Because the exposure map is just a selectively darkened diffuse map, the equation can be expanded as follows:

result = diffuse*lightmap + diffuse*selectiveDarkening
result = diffuse*(lightmap + selectiveDarkening)
result = 2*diffuse*(0.5*lightmap + 0.5*selectiveDarkening)

The coefficients added in the last step are necessary because (lightmap+selectivedarkening) will have values ranging from 0-2, which cannot be encoded in a regular texture. Thus we use a half-brightness version of this result, and double it in the shader.
This means that you need to use my shader with a combined light map created in the following way:

  1. Make a half-brightness version of your regular light map
  2. Make a half-brightness version of whatever you used to darken your exposure map
  3. Sum the two
    The part I don’t really know about is 2, because I’m not sure what method you use to darken the diffuse map. Whatever that method is, do it to a full white image instead of the diffuse map. Reduce the brightness of the result by half, and you’ll have what you need from step 2.

Thanks, I will try your method. :roll: If that go really well I will use imagemagik to combine 2 image into one and make the final lightmap texture. That will save a lot of space in graphic card, especially when it s a giant scene! :o

Hi

After alot of testing I must assume It s really hard to control the workflow because of produce a texture that suit to double modulate is very very difficult!

I will continue to stuck to current workflow, until we find a new way to store “exposure data” :cry: :cry:

How do you produce your exposure texture?

There are two way you could use

I am using Vray, so It has an option to control contrast and brighness for output images, so I write script to batch bake and post-process them

If you are using another renderer (Mray or any else), I advice to use imagemagik to post-process. Create a bat file after rendering image and we get the result.

And I see you are having some misundestanding with exposure map (sorry if I wrong). It is not an darken version of diffuse, but It is the render result, mean we have lite the diffuse, and then darken it so only exposure area remain on texture

The “darkened diffuse” was just a guess. The point is that your exposure texture incorporates the diffuse colour. This means that it’s not strictly lighting, because it’s been pre-multiplied, which is why you can get away with just adding it to the lightmap result in your shader.

I guess my question is this: if you took the base colour out of the exposure map, what would be left? Is it just a representation of the parts of the light map that are over-exposed?

Yes :wink:

The fact area are marked on exposure map IS over-exposed area in lightmap. Because we have no way to store these floating data to lightmap, I make a seperate map for it. :roll:

Ok. In that case, is it possible to just render the light map component of your exposure map, without the diffuse colour multiplied in? If you can get that, you should be able to combine it with the regular range light map, and use it with my version of the light map shader.

It will not be a problem…So you mean we get exposure map without diffuse color and then make half brightness of it, add blending with half brightness lightmap and use your method? :?: :roll:

There are one thing I want to ask too about 0.5 brightness thing. You mean we control exposure (mean Value in HSV color space) in a floating image, or just half brightness of a texture 8bit/channel

Yeah, I think you’ve got it. The end result (the average of the exposure and lightmap textures) will be a “full-range” light map, wherein any value over 127 will produce that over-exposed look that regular light maps don’t get you.

I’m keen to see the results!