Custom lightmapping shader

Hey, guys. I’m trying to write a custom shader that reads and displays lightmaps generated in Unity. The shader is almost working but I still need to access the light map texture matrix in the shader to get correct lightmap UVs.I know I need this because currently the UVs are not entirely correct, but if I manually copy the offset and tilling from the lightmapping->object>atlas to the material texture properties in the inspector the UVs become fine. So, how can I make Unity feed the shader with the appropriate lightmap texture matrices?

As you can see in the code, I’m already applying the texture matrix of the light map to the UVs with “o.uv2 = TRANSFORM_TEX (v.texcoord1, _LightMap);” but it has no effect, it seems that the matrix is empty.

Shader "Warsoup/Lighting" {
Properties {
    _Color ("Base Color", Color) = (1,1,1,0.5)
    DiffuseTexture ("Diffuse Texture", 2D) = "white" { }
	_LightMap ("LightMap", 2D) = "white" {}
}
SubShader {
    Pass {

		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag

		#include "UnityCG.cginc"

		float4		_Color;
		sampler2D	DiffuseTexture;
		sampler2D	_LightMap;
		
		float4 DiffuseTexture_ST;
		float4 _LightMap_ST;

		struct v2f {
			float4	pos : SV_POSITION;
			float2	uv1;
			float2	uv2;
		};

		struct InputVS {
			float4 vertex : POSITION;
			float4 tangent : TANGENT;
			float3 normal : NORMAL;
			float4 texcoord : TEXCOORD0;
			float4 texcoord1 : TEXCOORD1;
		};
		
		v2f vert (InputVS v)
		{
			v2f o;
			o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
			o.uv1 = TRANSFORM_TEX (v.texcoord, DiffuseTexture);
			o.uv2 = TRANSFORM_TEX (v.texcoord1, _LightMap);
			return o;
		}

		half4 frag (v2f i) : COLOR
		{
			half4 texcol = tex2D (DiffuseTexture, i.uv1);
			half4 lightmap = tex2D (_LightMap, i.uv2);
			return texcol*lightmap;
		}
		ENDCG

    }
}
Fallback "VertexLit"
}

your shaderlab part is missing the channel bindings so I’m unsure UV2 is even fed in correctly

I believe shader bindings are not necessary when you use a Cg shader.
Nevertheless, the UV2 is feed correctly because I can render the lightmaps if I feed the texture matrix by hand. So, now I only need that matrix to be fed correctly.

Here is the solution in case any one needs it.

Input Data:

sampler2D unity_Lightmap; //Far lightmap.
sampler2D unity_LightmapInd; //Near lightmap (indirect lighting only).
float4 unity_LightmapST; //Lightmap atlasing data.

In the vertex shader, apply the atlasing data like this:

o.lightmapUV = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;

PS: thanks to Aras for the solution.

1 Like

sweet, thanks for sharing

Hey thanks a lot for that information!

However, I am trying to realize the same effect as a fixed function effect, but have troubles with the texture coordinates of the lightmap again.
This is what my code looks like:

SubShader
	{
		Pass
		{
			BindChannels
			{
				Bind "Vertex", vertex
				Bind "texcoord", texcoord0
				Bind "texcoord1", texcoord1
			}
			 
			Tags {"LightMode" = "Always"}
			SetTexture [_MainTex]
			SetTexture [unity_Lightmap]
			{
				combine previous*texture
			}
		}
	}

Any ideas on how to solve that would be really great!
Is it possible to set the texture transformation matrix directly from within the .shader file?
Like: matrix (unity_LightmapST.x, 0.0, 0.0, unity_LightmapST.z, 0.0, unity_LightmapST.y, 0.0, unity_LightmapST.w, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) How to do something like this correctly, or doesn´t it work at all?

1 Like

best thing to do is take a shader with lightmapping, add the debug pragma and let it compile and see what unity adds for lightmapping in the FFP case

Thanks, although, it was already enough to just look at one of the built in shaders…
Strange, I thought that I already looked there :).

hehe :slight_smile:

Hi!

(Diggin up an old post but this is really relevant.)

I’m doing the same thing, using the lightmaps only as ambient occlusion. It works great when there’s baked lighting but when it isn’t the lightmap texture obviously doesn’t exist. And it doesn’t look good. What I want to do is use the LIGHTMAP_ON ifdef to detect if there are lightmaps for this object but since #pragma nolightmap sets every pass to LIGHTMAP_OFF I can’t.

Does any of you know how I can detect if there are lightmaps for an object and only apply them if they exists?