6-way lightmap WIP

T1: red - right
T1: green - left
T1: blue - top
T1: alpha - alpha
T2: red - bottom
T2: green - back
T2: blue - front


Thanks appreciated :slight_smile:

Hey Nate, in your material setup in the 6-way Lightmap group, what’s the second/bottom texture sample? Is that just the same flipbook rendered from the “back” of your sim?

I guess you could refer to this :slight_smile:

1 Like

Dang, thanks. Dunno how I glossed over that the first time :sleeping:

1 Like

I am very interested in this discussion and am trying to recreate what you posted, but I have to ask a sily question, what is your material’s shading model, ie lit directional or what? as I am getting no effect from my actual lights, or do you have to feed in the light direction vector using a blueprint?

1 Like

If I remember correctly the shading model is unlit. The vector for the light is fed in using AtmosphericLightVector which is the default sun/sky sun direction. I never got beyond using just that so if you wanted to use your own lights and (feed them into the shader) maybe somebody else can chime in on how to do that!

thanks for your reply, really appreciate it, I tried moving the sun/directional light direction but I couldn’t see the vector in the shader updating, I will investigate more in depth

Hey Niel, hows things…

I;ve got a version of this shader working with directional lights and 2 point lights in Unity…I can past some bits to help if your interested…


Hi Alcolepone,
I am interested in how you set this up in Unity. I’ve been playing around with this most of the day and can’t say I’ve had success.

heres the basis of the shader, bit late but hope it helps someone

		float ComputeLightMap(float3 LD, float4 lightmap, float frontMap, float  backMap)
			float hMap = (LD.r > 0.0f) ? (lightmap.x) : (lightmap.y);   // Picks the correct horizontal side.
			float vMap = (LD.g > 0.0f) ? (lightmap.z) : (lightmap.w);   // Picks the correct Vertical side.
			float dMap = (LD.b > 0.0f) ? (frontMap) : (backMap);              // Picks the correct Front/back Pseudo Map
			float lightMap = hMap*LD.r*LD.r + vMap*LD.g*LD.g + dMap*LD.b*LD.b; // Pythagoras!
			return lightMap;

		vertOutput vert (vertInput v)
			vertOutput o;
			o.texcoord = v.texcoord;
			o.texcoord2 =v.texcoord.zw;
			o.pos = UnityObjectToClipPos (v.vertex);
			o.color = v.color * _TintColor;
			o.ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
			float3 WP = mul (unity_ObjectToWorld, v.vertex).xyz;

			//particle world to tangent calculation

			float3 normalDir = UnityObjectToWorldNormal(v.normal);
			float3 tangentDir = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz);
			float3 bitangentDir = normalize(cross(normalDir, tangentDir) * v.tangent.w);
			float3x3 worldToTangent = float3x3(tangentDir, bitangentDir, normalDir);

			//directional light
			float3 lightDirection =   _WorldSpaceLightPos0.xyz;
			o.tangentlightDir1 = mul(worldToTangent, lightDirection).rgb;
			o.lightColor = _LightColor0.rgb;

			//point light 1			
			float3 lightPos = float3(unity_4LightPosX0.x, unity_4LightPosY0.x, unity_4LightPosZ0.x);
			float3 lightDirection2 = normalize(lightPos - WP.xyz); 
			o.tangentlightDir2 = mul(worldToTangent, lightDirection2);
			//o.tangentlightDir2 *= float3(1,1,-1);
			float range = (0.005 * sqrt(1000000 - unity_4LightAtten0.x)) / sqrt(unity_4LightAtten0.x);
			range =  distance(lightPos, WP.xyz) / range;
			range = saturate(1.0 / (1.0 + 25.0*range*range) * saturate((1 - range) * 5.0));			
			o.lightColor2 = unity_LightColor[0].rgb * range;

			o.normal = v.normal;
			o.blend = v.blend;


			return o;

		fixed4 frag (vertOutput IN) : COLOR
			//unity blend frames
				half4 LightMapA = tex2D(_LightmapTex, IN.texcoord);
				half4 LightMapB = tex2D(_LightmapTex, IN.texcoord2);
				half4 LightMap =  lerp(LightMapA, LightMapB, IN.blend);
			//float4 LightMap = tex2D(_LightmapTex, IN.texcoord);

				half4 AlphaMapA = tex2D(_AlphaTex, IN.texcoord);
				half4 AlphaMapB = tex2D(_AlphaTex, IN.texcoord2);
				half4 AlphaMap =  lerp(AlphaMapA, AlphaMapB, IN.blend);
			//float4 AlphaMap = tex2D(_AlphaTex, IN.texcoord);
			// If you find better approximations for front and back map using the 4channel we have… I am all ears.
			float frontMap = 0.25f * (LightMap.x+LightMap.y+LightMap.z+LightMap.w);
			frontMap = pow(frontMap, 0.55);
			float backMap =  1.0f - frontMap;
			backMap = saturate(0.25*(1.0-IN.normal.x) + 0.5*(backMap*backMap*backMap*backMap));
			//backMap *= 0.25;

			//directional light
			float3 lightDir = normalize(IN.tangentlightDir1);   //light 1
			float lightmap01 = ComputeLightMap(lightDir,LightMap,frontMap,backMap);
			//point light
			float3 lightDir2 = normalize(IN.tangentlightDir2);  //light2 
			float lightmap02 = ComputeLightMap(lightDir2,LightMap,frontMap,backMap);
			// light colors -
			float3 lightmap01rgb = float3(lightmap01, lightmap01, lightmap01)*IN.lightColor;
			float3 lightmap02rgb = float3(lightmap02, lightmap02, lightmap02)*IN.lightColor2;
			lightmap01rgb += lightmap02rgb;

			float4 heat = tex2D(_HeatGradientTex,float2((1-AlphaMap.r*IN.color.r),0));

			float4 Light = float4(lightmap01rgb,AlphaMap.g*IN.color.a);
			Light.rgb *= IN.lightColor +  IN.lightColor2;
			Light.rgb += IN.ambient;
			Light.rgb *= IN.color.ggg;
			Light.rgb += heat.rgb;
			Light.a += AlphaMap.r *IN.color.r;
			float4  d =  Light ;

did a small video about how to render those lightmaps at once in houdini:


I’m wondering: As we’re using a non-srgb texture, shouldn’t we gamma correct everything after mixing it together before sending it out to the material?

Thanks a lot for sharing! I am thinking to reproduce the shader in Unity as well. Maybe you’ve got the visual scription option? :slight_smile:

I recreated this shader, but for some reason, I found that R and G vector channels need to be multiplied to -1 to work correctly. It’s for sure some coordinate issue because I tried to swap gradients in “if” nodes and shadowing for X and Y was still upside down. However, for Z straight value from the vector node works just fine.
I’m very confused, maybe someone have an idea where problem could be?

It’s a bit hard to say why it would be backwards, the math in my original attempt was a bit dirty and I know I was having issues as well in that first shot at it. I ended up ditching all those lerps and went for a something much closer to mederics original shader, which is cleaner. So I’d defenitely recommend that over my initial version:

Am I correct to understand that this setup requires manually passing in the atmospheric sun direction vector (at least in UE4)? Does that imply that the system won’t receive dynamic shadows correctly (by ignoring them)? Or do dynamic shadows somehow come into play?

Is there a way this can be pulled off with directional normal calculations, so that the system can support any arbitrary light conditions?

a unity video about 6 way/sided lightmaps: Realistic smoke lighting with 6-way lighting in VFX Graph | Unity Blog

1 Like

it looks like in unity they can even light the particles with light probes, I am wondering if Unreal engine is supporting something like this aswell so that it doesnt look off when placed in different light situations of the level. currently it looks like all the unreal shader approachers are unlit right ?

You’re correct. The VFXGraph Unity HDRP 6-Way output is directly integrated in the HDRP Light Loop.
That means particles are receiving both Direct and indirect light contributions and that they can be lit by any numbers of lights without any shader hacks.

In all my past project as a VFX Artist, I always have been relying on Instance parameters to tweak my VFX so that they integrate better with the different lighting condition.
Then the lighting was changed and I was crying as I had to tweak again my instanced VFX.
This should enable VFX artist to make more generic VFX that can be put in different lighting condition and just work.