Trying to port Unity shader to Godot

Godot Version

4.2.2

Question

Hello, I stupidly bought a Unity asset pack thinking it would not be too hard to convert it to Godot and I have been stuck for 3 days not even managing to properly import a single proper 3d prefab… and I am no 3d artist, had to do lots of reading to even be where I am right now.

I basically used the new Unity gltFast plugin to export them into gltf, and then import them into Godot.
Textures were all wrong in materials but that seem easy to fix as long as there are no shaders involved. But while there are not a lot of shaders in the asset pack, almost every materials is using one of them so that’s no good.

Here is a picture example, focus on the gray part. White parts I just not started to touch yet, they are using another shader. Background which is not using any shader though was easy to fix and looks exactly the same than in Unity.

Now the gray middle part, the normal seems ok to me, I got the right depth on the top horizontal bars. All the rest though is messed up…
The cube motif is coming from the “dirt roughness” texture so I am assuming the problem comes from here, and there is no albedo texture, just color, so it’s a bit special.
The dirt/wear sliders and textures are dynamically simulating scratches/weariness and that seems to work well enough.

And here is the original Unity shader code

Properties
	{
		_BaseNormal("Base Normal", 2D) = "white" {}
		_DirtRoughness("Dirt Roughness", 2D) = "white" {}
		_DetailNormal("Detail Normal", 2D) = "white" {}
		_DetailMask("Detail Mask", 2D) = "white" {}
		_BaseColor("Base Color", Color) = (0.6544118,0.6544118,0.6544118,0)
		_BaseColorOverlay("Base Color Overlay", Color) = (0.6544118,0.6544118,0.6544118,0)
		_BaseDirtColor("Base Dirt Color", Color) = (0,0,0,0)
		_DetailColor("Detail Color", Color) = (0,0,0,0)
		_BaseNormalStrength("Base Normal Strength", Range( 0 , 1)) = 0
		_BaseSmoothness("Base Smoothness", Range( 0 , 1)) = 0.5
		_BaseDirtStrength("Base Dirt Strength", Range( 0.001 , 3)) = 0
		_BaseMetallic("Base Metallic", Range( 0 , 1)) = 0
		_DetailEdgeWear("Detail Edge Wear", Range( 0 , 1)) = 0
		_DetailEdgeSmoothness("Detail Edge Smoothness", Range( 0 , 1)) = 0
		_DetailDirtStrength("Detail Dirt Strength", Range( 0 , 1)) = 0
		_DetailOcclusionStrength("Detail Occlusion Strength", Range( 0 , 1)) = 0
		[HideInInspector] _texcoord4( "", 2D ) = "white" {}
		[HideInInspector] _texcoord( "", 2D ) = "white" {}
		[HideInInspector] __dirty( "", Int ) = 1
	}

	SubShader
	{
		Tags{ "RenderType" = "Opaque"  "Queue" = "Geometry+0" }
		Cull Back
		CGPROGRAM
		#include "UnityStandardUtils.cginc"
		#pragma target 4.0
		#pragma surface surf Standard keepalpha addshadow fullforwardshadows 
		struct Input
		{
			float2 uv_texcoord;
			float2 uv4_texcoord4;
		};

		uniform sampler2D _DetailNormal;
		uniform float4 _DetailNormal_ST;
		uniform sampler2D _BaseNormal;
		uniform float4 _BaseNormal_ST;
		uniform float _BaseNormalStrength;
		uniform float4 _BaseDirtColor;
		uniform sampler2D _DirtRoughness;
		uniform float4 _DirtRoughness_ST;
		uniform float _BaseDirtStrength;
		uniform float4 _BaseColor;
		uniform float4 _BaseColorOverlay;
		uniform float4 _DetailColor;
		uniform sampler2D _DetailMask;
		uniform float4 _DetailMask_ST;
		uniform float _DetailDirtStrength;
		uniform float _DetailEdgeWear;
		uniform float _BaseMetallic;
		uniform float _BaseSmoothness;
		uniform float _DetailEdgeSmoothness;
		uniform float _DetailOcclusionStrength;

		void surf( Input i , inout SurfaceOutputStandard o )
		{
			float2 uv_DetailNormal = i.uv_texcoord * _DetailNormal_ST.xy + _DetailNormal_ST.zw;
			float3 tex2DNode3 = UnpackNormal( tex2D( _DetailNormal, uv_DetailNormal ) );
			
			float2 uv3_BaseNormal = i.uv4_texcoord4 * _BaseNormal_ST.xy + _BaseNormal_ST.zw;
			float3 lerpResult11 = lerp( float3(0,0,1) , UnpackNormal( tex2D( _BaseNormal, uv3_BaseNormal ) ) , _BaseNormalStrength);
			o.Normal = BlendNormals( tex2DNode3 , lerpResult11 );
			float2 uv3_DirtRoughness = i.uv4_texcoord4 * _DirtRoughness_ST.xy + _DirtRoughness_ST.zw;
			
			float4 tex2DNode143 = tex2D( _DirtRoughness, uv3_DirtRoughness );
			float clampResult77 = clamp( pow( tex2DNode143.g , _BaseDirtStrength ) , 0.0 , 1.0 );
			float4 lerpResult76 = lerp( _BaseDirtColor , float4( 1,1,1,0 ) , clampResult77);
			float4 lerpResult71 = lerp( _BaseColor , _BaseColorOverlay , tex2DNode143.r);
			
			float2 uv_DetailMask = i.uv_texcoord * _DetailMask_ST.xy + _DetailMask_ST.zw;
			float4 tex2DNode36 = tex2D( _DetailMask, uv_DetailMask );
			float4 lerpResult134 = lerp( lerpResult71 , _DetailColor , ceil( ( ( 1.0 - tex2DNode36.b ) + -0.95 ) ));
			
			float temp_output_120_0 = ceil( ( tex2DNode36.b + -0.8 ) );
			float4 lerpResult123 = lerp( lerpResult134 , float4( float3(1,0.95,0.9) , 0.0 ) , temp_output_120_0);
			float clampResult49 = clamp( pow( ( tex2DNode36.r + 0.55 ) , 6.0 ) , 0.0 , 1.0 );
			
			float4 lerpResult92 = lerp( lerpResult123 , ( lerpResult123 * clampResult49 ) , _DetailDirtStrength);
			float clampResult62 = clamp( ( ( tex2DNode36.r + -0.55 ) * 2.0 ) , 0.0 , 1.0 );
			float4 clampResult101 = clamp( ( clampResult62 + lerpResult92 ) , float4( 0,0,0,0 ) , float4( 1,1,1,0 ) );
			float4 lerpResult32 = lerp( lerpResult92 , clampResult101 , _DetailEdgeWear);
			
			o.Albedo = ( lerpResult76 * lerpResult32 ).rgb;
			
			
			float lerpResult94 = lerp( 0.0 , clampResult62 , _DetailEdgeWear);
			
			float clampResult97 = clamp( ( lerpResult94 + temp_output_120_0 ) , 0.0 , 1.0 );
			float clampResult145 = clamp( ( clampResult97 + _BaseMetallic ) , 0.0 , 1.0 );
			o.Metallic = clampResult145;
			float4 temp_cast_2 = (_DetailEdgeSmoothness).xxxx;
			float4 lerpResult121 = lerp( ( ( max( clampResult62 , tex2DNode143.a ) * lerpResult76 ) * _BaseSmoothness ) , temp_cast_2 , clampResult97);
			o.Smoothness = lerpResult121.r;
			float lerpResult138 = lerp( 1.0 , tex2DNode36.g , _DetailOcclusionStrength);
			o.Occlusion = lerpResult138;
			o.Alpha = 1;
		}

		ENDCG
	}
	Fallback "Diffuse"
	CustomEditor "ASEMaterialInspector"

And here is my Godot version

shader_type spatial;
render_mode blend_mix,depth_draw_always,cull_back,diffuse_burley,specular_schlick_ggx;

		group_uniforms DetailNormal;
		uniform sampler2D _DetailNormal : hint_normal,filter_linear_mipmap,repeat_enable;
		uniform vec4 _DetailNormal_ST;
		
		group_uniforms BaseNormal;
		uniform sampler2D _BaseNormal : hint_normal,filter_linear_mipmap,repeat_enable;
		uniform vec4 _BaseNormal_ST;
		uniform float _BaseNormalStrength : hint_range( 0 , 1) = 0;
		
		group_uniforms DetailMask;
		uniform sampler2D _DetailMask;
		uniform vec4 _DetailMask_ST;
		
		group_uniforms DirtRoughness;
		uniform sampler2D _DirtRoughness : hint_roughness_normal;
		uniform vec4 _DirtRoughness_ST;
		uniform float _BaseDirtStrength : hint_range( 0.001, 3) = 0;
		group_uniforms;
		
		uniform vec4 _BaseDirtColor : source_color = vec4(0,0,0,0);
		
		uniform vec4 _BaseColor : source_color = vec4(0.6544118,0.6544118,0.6544118,0);
		uniform vec4 _BaseColorOverlay : source_color = vec4(0.6544118,0.6544118,0.6544118,0);
		uniform vec4 _DetailColor : source_color = vec4(0,0,0,0);
		
		uniform float _DetailDirtStrength : hint_range( 0 , 1) = 0;
		uniform float _DetailEdgeWear : hint_range( 0 , 1) = 0;
		uniform float _BaseMetallic : hint_range( 0 , 1) = 0;
		uniform float _BaseSmoothness : hint_range( 0 , 1) = 0.5;
		uniform float _DetailEdgeSmoothness : hint_range( 0 , 1) = 0;
		uniform float _DetailOcclusionStrength : hint_range( 0 , 1) = 0;

// Those 2 functions are native to Unity but I found the code on internet to port them
vec3 blend_normals(vec3 n1, vec3 n2) {
	vec3 blendedNormal = vec3(n1.x + n2.x, n1.y + n2.y, n1.z * n2.z);
    return normalize(blendedNormal);
}

vec3 UnpackNormal(vec4 packednormal)
{
	return packednormal.xyz * 2.0 - 1.0;
//#if defined(SHADER_API_GLES)  defined(SHADER_API_MOBILE)
    //return packednormal.xyz * 2 - 1;
//#else
    //vec3 normal;
    //normal.xy = packednormal.wy * 2.0 - 1.0;
    //normal.z = sqrt(1.0 - normal.x*normal.x - normal.y * normal.y);
    //return normal;
//#endif
}

void fragment() {
	
    // Calculate the detail normal UV coordinates
    vec2 uv_DetailNormal = UV * _DetailNormal_ST.xy + _DetailNormal_ST.zw;
	
    // Sample the detail normal map and unpack it
	// vec3 tex2DNode3 = texture(_DetailNormal, uv_DetailNormal).rgb;
	vec3 tex2DNode3 = UnpackNormal(texture(_DetailNormal, uv_DetailNormal));

    // Calculate the base normal UV coordinates
    vec2 uv3_BaseNormal = UV * _BaseNormal_ST.xy + _BaseNormal_ST.zw;
    // Sample the base normal map and unpack it.
    //vec3 lerpResult11 = mix(vec3(0.0, 0.0, 1.0), texture(_BaseNormal, uv3_BaseNormal).rgb, _BaseNormalStrength);
	vec3 lerpResult11 = mix(vec3(0.0, 0.0, 1.0), UnpackNormal(texture(_BaseNormal, uv3_BaseNormal)).rgb, _BaseNormalStrength);

    // Blend the normals
    NORMAL = blend_normals(tex2DNode3, lerpResult11);
    // Calculate the dirt roughness UV coordinates
    vec2 uv3_DirtRoughness = UV * _DirtRoughness_ST.xy + _DirtRoughness_ST.zw;
    // Sample the dirt roughness map
    vec4 tex2DNode143 = texture(_DirtRoughness, uv3_DirtRoughness);

    // Calculate the base dirt color
    vec4 lerpResult76 = mix(_BaseDirtColor, vec4(1.0, 1.0, 1.0, 0.0), clamp(pow(tex2DNode143.g, _BaseDirtStrength), 0.0, 1.0));

    // Calculate the base color overlay
    vec4 lerpResult71 = mix(_BaseColor, _BaseColorOverlay, tex2DNode143.r);

    // Calculate the detail mask UV coordinates
    vec2 uv_DetailMask = UV * _DetailMask_ST.xy + _DetailMask_ST.zw;
    // Sample the detail mask
    vec4 tex2DNode36 = texture(_DetailMask, uv_DetailMask);

    // Calculate intermediate values
    vec4 lerpResult134 = mix(lerpResult71, _DetailColor, ceil((1.0 - tex2DNode36.b) + -0.95));
    float temp_output_120_0 = ceil(tex2DNode36.b + -0.8);
    vec4 lerpResult123 = mix(lerpResult134, vec4(vec3(1.0, 0.95, 0.9), 0.0), temp_output_120_0);
    float clampResult49 = clamp(pow(tex2DNode36.r + 0.55, 6.0), 0.0, 1.0);
    vec4 lerpResult92 = mix(lerpResult123, lerpResult123 * clampResult49, _DetailDirtStrength);
    float clampResult62 = clamp((tex2DNode36.r + -0.55) * 2.0, 0.0, 1.0);
    vec4 clampResult101 = clamp(clampResult62 + lerpResult92, vec4(0.0, 0.0, 0.0, 0.0), vec4(1.0, 1.0, 1.0, 0.0));
    vec4 lerpResult32 = mix(lerpResult92, clampResult101, _DetailEdgeWear);

    // Set the final albedo color
    ALBEDO = (lerpResult76 * lerpResult32).rgb;

    // Additional calculations
    float lerpResult94 = mix(0.0, clampResult62, _DetailEdgeWear);
	float clampResult97 = clamp(lerpResult94 + temp_output_120_0, 0.0, 1.0);
	float clampResult145 = clamp(clampResult97 + _BaseMetallic, 0.0, 1.0);

	METALLIC = clampResult145;

	vec4 temp_cast_2 = vec4(_DetailEdgeSmoothness, _DetailEdgeSmoothness, _DetailEdgeSmoothness, _DetailEdgeSmoothness);

	vec4 lerpResult121 = mix(
	    (max(clampResult62, tex2DNode143.a) * lerpResult76) * _BaseSmoothness,
	    temp_cast_2,
	    clampResult97
	);

        // Unity use smoothness, but godot use roughness
	ROUGHNESS = 1.0 - lerpResult121.r;

	float lerpResult138 = mix(1.0, tex2DNode36.g, _DetailOcclusionStrength);
	AO = lerpResult138;

	// Set Alpha to 1
	ALPHA = 1.0;
}

I never touched at shaders before so I am a bit lost, I am really not sure about the Unity uv3_x => Godot UV conversion, but using UV2 seems to make things even worse.
Would appreciate any pointers !

Not sure 100%, but in the shaders only UV and UV2 exist, where in Unity and Unreal, it can go up higher (Unreal to 8, can’t remember what Unity’s limit was), so you’ll need to alter the meshes to work with only two UV sets.

What parts of the model use more than 2 UV sets?

1 Like

Ooooh I didn’t even realize that there could be so many UV, I thought it was only a weird naming convention… And you are totally right it must be the (or one part of) the problem.

Unity support up to 8 UV I just checked, but thankfully all the meshes of this asset pack seems to only use 4, and maybe hopefully even only 2 UV.

Here 2 examples of the 4 UV of 2 meshes of the same prefab, to me it seems only UV0 and UV3 are used, the 2 others from my inexperienced eye seems totally… nonsensical ? Can I just assume those are dirty edits ?
I didn’t check all the meshes there are a lot of them but usually only 1 or 2 UV make sense, maybe occasionally 3.

For the first mesh they are not even referenced in the shader so… And the most important UV definitely seems UV3, so no wonder that in Godot it’s completely messed up if it was not even imported :smile:

I will try to modify the mesh tomorrow (and learn how), but if I have to do this for every mesh… and fix all the materials… and add all the non imported collisions meshes manually… I have to say that simple import is starting to become a lot more work than I thought. :sweat_smile:

1 Like

Sadly it does look like you’ll have a lot of converting to do, including splitting parts of a single mesh into other meshes as this asset set seems to be using a lot of multi-material and trim sheet setups.

This means all of the assets from the meshes, materials, shaders and textures, will be very specific to that setup, and since Godot doesn’t support more than 2 UV sets, they will all need to be converted. The UV thing might be the main issue really, but it’s so fundamental to how these shaders and textures were originally authored, converting and re-authoring everything will be inevitable.

Looking on the asset in the unity store, I imagine every single mesh uses up to 4 UV channels, but each mesh uses a different shader that accesses only what it needs, for instance there does seem to be a base setup and then some type of ‘decal’ setup they call cutout for the logos on the lockers for instance. I am thinking now that the Emission and Glass materials being the other two looking at the assets from the outside.

What I would do is, for the locker mesh(es) you are showing there in that last shot, is that 2 separate meshes, the 3 lockers on top and then the mesh decals on the bottom? If so, do they have different materials associated on them on the mesh when in the engine, even if the imported mesh has more than one Material ID?

If you know the materials and textures used on both of those models, you can figure out what each one does, and go from there to see what each UV layout is meant for. Opening up each shader and looking what UV’s each shader is pulling will help for sure, like this one is using 0 and 3 (for some reason unity goes from uv_textcoord to uv2_textcoord, uv3_textcoord and uv4_textcoord which can be confusing, as that is really UV0, UV1, UV2 and UV3).

There are tricks to making this easier, but if you really want to use these assets in Godot, converting these these fully might be in order, which I think would include completely re-writing the shader, either in visual shader setup in godot, or manually writing one. One of the reasons too is that all of the variable names are the node name in the shader editor they used, so they have little information of what they do down the line, so just renaming those do would help a lot to figure it all out, things like
tex2DNode3 and lerpResult11, etc.

You also have some sampler type issues, both normal maps look like in godot they are not being recognized as normal maps, you have the hint_normal in the shader, but in the unity shader they are doing some normal unpacking so that might need some investigation. The other one is the dirt roughness sampler looks different too, it could just be that the hint is roughness_normal, which would need some special setup on the texture resource, it just seems like you are losing the blue channel data probably due to that hint, try taking that off completely and see if it matches the unity version.

1 Like

This specific prefab is composed of 7 different meshes, each with its own material and own shader, but they are only using one each time.
The 3 decals are indeed one single mesh.

Now I thankfully found out Godot does support 8 UV, it’s just a bit hidden and not exposed in the inspector and you have to use a custom shader, which I am doing anyway.
See here and here for more information.

So using the COSTUM0.zw I was able to use what should be “UV4” for all the uv3_x Unity variables and it certainly improved things a lot, I can finally see the cube motifs so that’s good :slightly_smiling_face:

For the normal I disabled in the import settings the “Normal map” setting which is disabling the RGTC compression if I understand correctly, and I removed all the normal hint from the shaders.

I also converted the decal shader which was much simpler than this one.

Result :

Things are looking much better but there are still some problems, like the 3 lockers squares, it’s also present in Unity but much less noticeable, and on the top bar there are also 2 squares

I also notice light is really not behaving the same on the surface than in Unity, I have to use different rotations, but I don’t know how much that’s just an engine difference or if it could be a hint to the problem

Current code

shader_type spatial;
render_mode blend_mix,depth_draw_always,cull_back,diffuse_burley,specular_schlick_ggx;

		group_uniforms DetailNormal;
		//uniform sampler2D _DetailNormal : hint_normal,filter_linear_mipmap,repeat_enable;
		uniform sampler2D _DetailNormal;
		uniform vec4 _DetailNormal_ST;
		
		group_uniforms BaseNormal;
		//uniform sampler2D _BaseNormal : hint_normal,filter_linear_mipmap,repeat_enable;
		uniform sampler2D _BaseNormal;
		uniform vec4 _BaseNormal_ST;
		uniform float _BaseNormalStrength : hint_range( 0 , 1) = 0;
		
		group_uniforms DetailMask;
		uniform sampler2D _DetailMask;
		uniform vec4 _DetailMask_ST;
		
		group_uniforms DirtRoughness;
		uniform sampler2D _DirtRoughness;
		uniform vec4 _DirtRoughness_ST;
		uniform float _BaseDirtStrength : hint_range( 0.001, 3) = 0;
		group_uniforms;
		
		uniform vec4 _BaseDirtColor : source_color = vec4(0,0,0,0);
		
		uniform vec4 _BaseColor : source_color = vec4(0.6544118,0.6544118,0.6544118,0);
		uniform vec4 _BaseColorOverlay : source_color = vec4(0.6544118,0.6544118,0.6544118,0);
		uniform vec4 _DetailColor : source_color = vec4(0,0,0,0);
		
		uniform float _DetailDirtStrength : hint_range( 0 , 1) = 0;
		uniform float _DetailEdgeWear : hint_range( 0 , 1) = 0;
		uniform float _BaseMetallic : hint_range( 0 , 1) = 0;
		uniform float _BaseSmoothness : hint_range( 0 , 1) = 0.5;
		uniform float _DetailEdgeSmoothness : hint_range( 0 , 1) = 0;
		uniform float _DetailOcclusionStrength : hint_range( 0 , 1) = 0;

vec3 blend_normals(vec3 n1, vec3 n2) {
	return normalize(vec3(n1.xy + n2.xy, n1.z * n2.z));
}

vec3 UnpackNormal(vec4 packednormal)
{
	return packednormal.xyz * 2.0 - 1.0;
//#if defined(SHADER_API_GLES)  defined(SHADER_API_MOBILE)
    //return packednormal.xyz * 2 - 1;
//#else

	vec3 normal;
    normal.xy = packednormal.xy * 2.0 - 1.0;
    normal.z = sqrt(1.0 - normal.x*normal.x - normal.y * normal.y);
    return normal;
	
	
//#endif
}

varying vec4 custom0;
varying vec4 custom1;
varying vec4 custom2;
varying vec4 custom3;

void vertex()
{
	custom0 = CUSTOM0;
	custom1 = CUSTOM1;
	custom2 = CUSTOM2;
	custom3 = CUSTOM3;
}

void fragment() {
	vec2 UV4 = custom0.zw;
	
    // Calculate the detail normal UV coordinates
    vec2 uv_DetailNormal = UV * _DetailNormal_ST.xy + _DetailNormal_ST.zw;
	
    // Sample the detail normal map and unpack it
	//vec3 tex2DNode3 = texture(_DetailNormal, uv_DetailNormal).rga;
	vec3 tex2DNode3 = UnpackNormal(texture(_DetailNormal, uv_DetailNormal));

    // Calculate the base normal UV coordinates
    vec2 uv3_BaseNormal = UV4 * _BaseNormal_ST.xy + _BaseNormal_ST.zw;
	
    // Sample the base normal map and unpack it
    //vec3 lerpResult11 = mix(vec3(0.0, 0.0, 1.0), texture(_BaseNormal, uv3_BaseNormal).rga, _BaseNormalStrength);
	vec3 lerpResult11 = mix(vec3(0.0, 0.0, 1.0), UnpackNormal(texture(_BaseNormal, uv3_BaseNormal)).rgb, _BaseNormalStrength);

    // Blend the normals
    NORMAL_MAP = blend_normals(tex2DNode3, lerpResult11);
    // Calculate the dirt roughness UV coordinates
    vec2 uv3_DirtRoughness = UV4 * _DirtRoughness_ST.xy + _DirtRoughness_ST.zw;
	
    // Sample the dirt roughness map
    vec4 tex2DNode143 = texture(_DirtRoughness, uv3_DirtRoughness);

    // Calculate the base dirt color
    vec4 lerpResult76 = mix(_BaseDirtColor, vec4(1.0, 1.0, 1.0, 0.0), clamp(pow(tex2DNode143.g, _BaseDirtStrength), 0.0, 1.0));

    // Calculate the base color overlay
    vec4 lerpResult71 = mix(_BaseColor, _BaseColorOverlay, tex2DNode143.r);

    // Calculate the detail mask UV coordinates
    vec2 uv_DetailMask = UV * _DetailMask_ST.xy + _DetailMask_ST.zw;
    // Sample the detail mask
    vec4 tex2DNode36 = texture(_DetailMask, uv_DetailMask);

    // Calculate intermediate values
    vec4 lerpResult134 = mix(lerpResult71, _DetailColor, ceil((1.0 - tex2DNode36.b) + -0.95));
    float temp_output_120_0 = ceil(tex2DNode36.b + -0.8);
    vec4 lerpResult123 = mix(lerpResult134, vec4(vec3(1.0, 0.95, 0.9), 0.0), temp_output_120_0);
    float clampResult49 = clamp(pow(tex2DNode36.r + 0.55, 6.0), 0.0, 1.0);
    vec4 lerpResult92 = mix(lerpResult123, lerpResult123 * clampResult49, _DetailDirtStrength);
    float clampResult62 = clamp((tex2DNode36.r + -0.55) * 2.0, 0.0, 1.0);
    vec4 clampResult101 = clamp(clampResult62 + lerpResult92, vec4(0.0, 0.0, 0.0, 0.0), vec4(1.0, 1.0, 1.0, 0.0));
    vec4 lerpResult32 = mix(lerpResult92, clampResult101, _DetailEdgeWear);

    // Set the final albedo color
    ALBEDO = (lerpResult76 * lerpResult32).rgb;

    // Additional calculations (if needed)
    float lerpResult94 = mix(0.0, clampResult62, _DetailEdgeWear);
	
	// Calculate clampResult97
	float clampResult97 = clamp(lerpResult94 + temp_output_120_0, 0.0, 1.0);

	// Calculate clampResult144
	float clampResult144 = clamp(clampResult97 + _BaseMetallic, 0.0, 1.0);
	METALLIC = clampResult144;

	// Create a temporary vec4 variable
	vec4 temp_cast_2 = vec4(_DetailEdgeSmoothness, _DetailEdgeSmoothness, _DetailEdgeSmoothness, _DetailEdgeSmoothness);

	// Calculate lerpResult121
	vec4 lerpResult121 = mix(
	    (max(clampResult62, tex2DNode143.a) * lerpResult76) * _BaseSmoothness,
	    temp_cast_2,
	    clampResult97
	);
	ROUGHNESS = 1.0 - lerpResult121.r;

	// Calculate lerpResult138
	float lerpResult138 = mix(1.0, tex2DNode36.g, _DetailOcclusionStrength);
	AO = lerpResult138;

	// Set Alpha to 1
	ALPHA = 1.0;
}

Yeah, it looks like the base normal map, at least on the lockers, either isn’t the right one, or you might still need hint_normal. What I would do is make a much simpler test shader that only imports the base normal map and draws it on the locker mesh with like a mid to lighter grey color, see if maybe another part the material is needing some update, or if it’s the source assets.

Can you either show the base normal map in a larger screenshot too, or if you are comfortable send the mesh and the normal map (or any others) and I’ll take a look.

What are these UV shifts doing?

Sent you the required files, thank you !

The shifting is basically the Unity “Tiling” and “Offset” settings, I tried messing with them but that donesn’t solve the problem, (1,1,0,0) or even (1,1,1,1) seems correct.

I don’t know what it means exactly, but I noticed in the Unity “UV Checker” tab, when looking at the mesh, I got a checkerboard motif (for transparency?) on UV0 exactly at the location of the squares.
Same for the top bar.

So to close this and for the people interested, I was able to fully fix this specific mesh with the big help of roc4u1000

The biggest problem was the UV3 explained above, I also had to remove all the UnpackNormal, no unpacking take place, and change this specific line

vec3 lerpResult11 = mix(vec3(0.0, 0.0, 1.0), texture(_BaseNormal, uv3_BaseNormal)).rgb, _BaseNormalStrength);

To this

vec3 lerpResult11 = mix(vec3(0.5, 0.5, 1.0),texture(_BaseNormal, uv3_BaseNormal)).rgb, _BaseNormalStrength);

Because the “zero” vector is not the same in this specific setup.

I also had to do the srgb conversion myself for the albedo color after all the lerping.

1 Like