Material that is unlit but can catch shadows?

Hi there.

I’m doing some photogrammetry work and I need to use a material that is completely unlit but can catch shadows of other objects.

I tried to use the 0 value for diffuse, specular and metallic and having the actuali diffuse in the emmissive slot, but it does not show shadows of other objects.

Some ideas?

Thanks in advance!

Shadow is just blocked light so it’s not possible with unlit. What kind of setup you have? You may achieve same effect with post processing and custom depth.

I’m not sure, what do you mean with setup?
I use a standard lit material with 0 value in diffuse, specular and metallic, then I use the color texture in emission.

What I need is something simiular to a matte shadow material that shows the diffuse texture without lighting it but catches shadows from other objects on it.

Cheers and thanks for the help!

Well, if you use stationary or dynamic lights, they would cast shadows from movable actors onto you mesh with until material.

Afaik unlit material won’t “catch” baked shadows.

If your photogrammetry texture includes lighting already then you will not be able to integrate it into another scene properly. When Epic made the photogrammetry assets for the Kite demo they used a technique where they rendered the lighting so that they could approximately remove it from the textures which allows the lighting system in the engine to work properly with the assets.

You can - sort of - do what you are asking.

If you put a ‘lit’ version of your photogrammetry texture bake in the ‘color’ slot, and an ‘unlit’ version in the ‘emissive’ slot, you can create a pre-baked material that can also (sort of) receive shadows.

You can test the technique by taking your photogrammetry output texture, multiply it by 0.75, and plugging it into the ‘color’ slot. Then take the same texture, multiply it by 0.25, and plug it into the ‘emissive’ slot. Add a moveable light source, and something to cast shadows, and see if it’s going to do what you want.

Ok, let’s rephrase the case, I need the photogrammetry to include lighting, this is a must, it’s a whole enviroment recreated in photogrammetry :slight_smile:

The thing is that this is already done in the shader used in Unity for “The Lab” demo for the HTC Vive, the “Secret Room” uses that shader, it does not receive any light but it does receive shadows, you can check it’s description here:

Also you can check how it works here:

Check the Vive controller shadow in the left part of the screen at time 1:57.

So in the end, I don’t have the posibility to have an unlit version of the photogrammetry, more or less what I need is the same as a Matte material in Vray or mental ray, but in Unreal.

Cheers and thanks! :slight_smile:

To get correct lighting you need to have the lighting separate from the albedo of the scene, otherwise you get shadows on top of shadows and it can’t blend them together. For that one, most likely they just have a regular material with a light in the scene, it’s not correct but it’ll look OK when you cast shadows on areas that don’t have shadow.

Nope, they use an specific matte shadow shared, it’s explained in the pdf:

Valve VR Photogrammetry Shader
This shader is optimized for content that is unlit but still needs to receive real-time shadows.
The primary use case is photogrammetry scenes where the lighting is baked into the texture maps, but we also want dynamic objects to cast shadows onto that geometry.

And that is the shader I’m asking for, it basically a matte shadow shader that only receive diret shadows, just real time shadows, not baked ones.
There is no way to reproduce it?+

The code is freely distributed with the lab renderer, so I hope it’s ok to put it here in case it helps to reproduce this material:

// Copyright (c) Valve Corporation, All rights reserved. ======================================================================================================

Shader "Valve/vr_photogrammetry"
		_Color( "Color", Color ) = ( 1, 1, 1, 1 )
		_MainTex( "Albedo", 2D ) = "white" {}
		//_DetailTex( "Detail Albedo x2", 2D ) = "gray" {}

		Tags { "RenderType" = "Photogrammetry" "PerformanceChecks" = "False" }
		LOD 300

		// Base forward pass (directional light, emission, lightmaps, ...)
			Name "FORWARD"
			Tags { "LightMode" = "ForwardBase" }

			Blend SrcAlpha OneMinusSrcAlpha
			//ZWrite [_ZWrite]

				#pragma target 5.0
				#pragma only_renderers d3d11
				#pragma exclude_renderers gles

				#pragma multi_compile _ D_VALVE_FOG

				#pragma skip_variants SHADOWS_SOFT

				#pragma vertex MainVs
				#pragma fragment MainPs

				// Includes -------------------------------------------------------------------------------------------------------------------------------------------------
				#include "UnityCG.cginc"
				#include "UnityLightingCommon.cginc"
				#include "UnityStandardUtils.cginc"
				#include "UnityStandardInput.cginc"
				#include "vr_utils.cginc"
				#include "vr_lighting.cginc"
				#include "vr_fog.cginc"

				// Structs --------------------------------------------------------------------------------------------------------------------------------------------------
				struct VS_INPUT
					float4 vPositionOs : POSITION;
					float2 vTexCoord0 : TEXCOORD0;

				struct PS_INPUT
					float4 vPositionPs : SV_Position;
					float3 vPositionWs : TEXCOORD0;
					float4 vTextureCoords : TEXCOORD1;

					#if ( D_VALVE_FOG )
						float2 vFogCoords : TEXCOORD6;

				// Vars -----------------------------------------------------------------------------------------------------------------------------------------------------
				float g_flValveGlobalVertexScale = 1.0; // Used to "hide" all valve materials for debugging
				float3 g_vShadowColor;
				float4 _Detail_ST;
				float3 g_vPhotogrammetryShadowColor;

				#define g_vColorTint _Color
				#define g_tColor _MainTex
				#define g_tDetail2x _DetailTex

				// MainVs ---------------------------------------------------------------------------------------------------------------------------------------------------
				PS_INPUT MainVs( VS_INPUT i )
					PS_INPUT o = ( PS_INPUT )0;

					// Position
					i.vPositionOs.xyzw *= g_flValveGlobalVertexScale; // Used to "hide" all valve materials for debugging = mul( unity_ObjectToWorld, i.vPositionOs.xyzw ).xyz;
					o.vPositionPs.xyzw = mul( UNITY_MATRIX_MVP, i.vPositionOs.xyzw );

					// Texture coordinates
					o.vTextureCoords.xy = TRANSFORM_TEX( i.vTexCoord0.xy, _MainTex ); = TRANSFORM_TEX( i.vTexCoord0.xy, _Detail );

					#if ( D_VALVE_FOG )
						o.vFogCoords.xy = CalculateFogCoords( );

					return o;

				// MainPs ---------------------------------------------------------------------------------------------------------------------------------------------------
				struct PS_OUTPUT
					float4 vColor : SV_Target0;

				PS_OUTPUT MainPs( PS_INPUT i )
					PS_OUTPUT o = ( PS_OUTPUT )0;

					float4 vColorTexel = tex2D( g_tColor, i.vTextureCoords.xy );

					float4 vDetailTexel = tex2D( g_tColor, );

					float flShadowScalarTotal = 1.0;
					 loop ] for ( int j = 0; j < g_nNumLights; j++ )
						if ( g_vLightShadowIndex_vLightParams j ].x != 0.0 )
							float flShadowScalar = ComputeShadow_PCF_3x3_Gaussian(, g_matWorldToShadow j ], g_vShadowMinMaxUv j ] );
							flShadowScalarTotal = min( flShadowScalarTotal, flShadowScalar );

					// Output color
					o.vColor.rgba = vColorTexel.rgba;
					//o.vColor.rgb *= 2.0 * vDetailTexel.rgb; // FIXME: How to do mod2x correctly in Unity?
					o.vColor.rgb = lerp( g_vPhotogrammetryShadowColor.rgb * o.vColor.rgb, o.vColor.rgb, flShadowScalarTotal );

					// Fog
					#if ( D_VALVE_FOG )
						o.vColor.rgb = ApplyFog( o.vColor.rgb, i.vFogCoords.xy );

					// Dither to fix banding artifacts
					o.vColor.rgb += ScreenSpaceDither( i.vPositionPs.xy );

					return o;

		// Shadow rendering pass
		//	Name "ShadowCaster"
		//	Tags { "LightMode" = "ShadowCaster" }
		//	ZWrite On ZTest LEqual
		//		#pragma target 5.0
		//		// TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
		//		#pragma exclude_renderers gles
		//		// -------------------------------------
		//		#pragma multi_compile_shadowcaster
		//		#pragma vertex vertShadowCaster
		//		#pragma fragment fragShadowCaster
		//		#include "UnityStandardShadow.cginc"
		//	ENDCG

		// Extracts information for lightmapping, GI (emission, albedo, ...)
		// This pass it not used during regular rendering.
			Name "META" 
			Tags { "LightMode"="Meta" }
			Cull Off
				#pragma only_renderers d3d11

				#pragma vertex vert_meta
				#pragma fragment frag_meta
				#pragma shader_feature _EMISSION
				#pragma shader_feature _METALLICGLOSSMAP
				#pragma shader_feature ___ _DETAIL_MULX2
				#include "UnityStandardMeta.cginc"

Hope this helps a bit :slight_smile:


If you’re able to multiply the shadows onto the material then it can do that, most likely what that shader does.

I’m just saying it won’t look correct, since it can’t blend with the shadows in the texture, top is what will happen vs. bottom what you would want:

Yes, you are totally right, it wont look perfect, but I have to live with that problem :slight_smile:
but how can I multiply the shadows over an unlit material?


You can’t, afaik Unreal does not allow you that flexibility. You would have to edit USF files.

I had to revive this thread since i am working on a project that requires this.

Is there any way this can be achieved inside UE4 with forward rendering?

I was able to create this effect inside unity 3d using node based material through shader forge and make it work just fine, in my scene my sunlight or any other light source can cast shadows onto the entire unlit surfaces from unlit moving objects. I can also control the shadow’s density and color to match the baked one, as well as have additive reflections onto the unlit objects, which work very well. This can be very flexible.

How can this be achieved inside UE4?

In Forward Shading? Maybe. Check out this link:
Perhaps you can apply that technique to single out shadows.
Otherwise you’d have to use a SceneCapture2D to capture a depth map and do shadows manually that way.

Is this still not possible?