Thank you, it works perfectly now. For anyone in the future that finds this thread and needs something similar, here’s the final shader:
edit: It works fine so long as you don’t rotate the model in question. If anyone can figure out how to fix that, please do share.
Shader "Custom/Trim sheets"
{
Properties
{
_MainTex ("Base Color", 2D) = "white" {}
[Normal]_MainNorm ("Base Normal", 2D) = "bump" {}
_MainR ("Base Roughness", 2D) = "grey" {}
_MainM ("Base Metalic", 2D) = "black" {}
_Trim ("Trim Color", 2D) = "black" {}
[Normal]_TrimNorm ("Trim Normal", 2D) = "bump" {}
_TrimR ("Trim Roughness", 2D) = "grey" {}
_TrimM ("Trim Metalic", 2D) = "black" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "PerformanceChecks"="False"}
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows vertex:vert
// Use shader model 3.5 target, because otherwise there won't be enough texture space.
#pragma target 3.5
#include "UnityStandardUtils.cginc"
sampler2D _MainTex;
sampler2D _MainNorm;
sampler2D _MainR;
sampler2D _MainM;
sampler2D _Trim;
sampler2D _TrimNorm;
sampler2D _TrimR;
sampler2D _TrimM;
struct Input
{
float2 uv_MainTex : TEXCOORD0;
float2 uv3_Trim : TEXCOORD2;
float3 pos;
float3 norm;
float3 worldNormal;
INTERNAL_DATA
};
float3 WorldToTangentNormalVector(Input IN, float3 normal) {
float3 t2w0 = WorldNormalVector(IN, float3(1,0,0));
float3 t2w1 = WorldNormalVector(IN, float3(0,1,0));
float3 t2w2 = WorldNormalVector(IN, float3(0,0,1));
float3x3 t2w = float3x3(t2w0, t2w1, t2w2);
return normalize(mul(t2w, normal));
}
void vert (inout appdata_full v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input,o);
o.norm = v.normal;
o.pos = mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1)).xyz - _WorldSpaceCameraPos;
}
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
void surf (Input IN, inout SurfaceOutputStandard o)
{
IN.worldNormal = WorldNormalVector(IN, float3(0,0,1));
fixed4 c;
float4 trim = tex2D (_Trim, IN.uv3_Trim);
//if you need to use a different normal map, switch the IN.uv variable
float3 dp1 = ddx( IN.pos );
float3 dp2 = ddy( IN.pos ) * _ProjectionParams.x;
float2 duv1 = ddx( IN.uv3_Trim );
float2 duv2 = ddy( IN.uv3_Trim ) * _ProjectionParams.x;
// solve the linear system
float3 dp2perp = cross( dp2, IN.norm );
float3 dp1perp = cross( IN.norm, dp1 );
float3 T = dp2perp * duv1.x + dp1perp * duv2.x;
float3 B = dp2perp * duv1.y + dp1perp * duv2.y;
// construct a scale-invariant frame
float invmax = rsqrt( max( dot(T,T), dot(B,B) ) );
float3x3 cotangent_frame = transpose(float3x3( T * invmax, B * invmax, IN.norm ));
float3 twonorm = tex2D (_TrimNorm, IN.uv3_Trim);
twonorm*=2;
twonorm-=1;
float3 Norm2 =normalize(mul(cotangent_frame,twonorm));
o.Normal=normalize(lerp(UnpackNormal(tex2D(_MainNorm, IN.uv_MainTex)),WorldToTangentNormalVector(IN, Norm2),trim.a));
c = lerp( tex2D (_MainTex, IN.uv_MainTex),trim.rgba,trim.a);
o.Smoothness = 1-lerp( tex2D (_MainR, IN.uv_MainTex), tex2D (_TrimR, IN.uv3_Trim),trim.a);
o.Metallic = lerp( tex2D (_MainM, IN.uv_MainTex), tex2D (_TrimM, IN.uv3_Trim),trim.a);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}