Im coding a unity surface shader to slowly apply a rust effect like this:
//Take 1 base color texture.
//Take 1 rust decal texture and 1 greyscale maps.
//Take 1 float range value.
Then:
//Use the range to remove from the grayscale map all the pixels that are darker than the value itself, then make theese greysclae map the rust alpha, then apply this composited rust layer over the color texture.
I managed to do this:
void surf (Input IN, inout SurfaceOutputStandard o) {
half4 C = tex2D (_MainTex, IN.uv_MainTex); //Color Texture
half4 R = tex2D (_RustTex, IN.uv_RustTex); //Rust texture
half4 RG = tex2D (_RustGuide, IN.uv_RustGuide); //Greyscale texture
//Here i need to compose the rust layer
half4 RustResult = //??? Maybe a Clip() function or what? and how?
//Here i apply the previusly composed layer over the color texture. Already tested and working.
half4 Final = lerp (C, RustResult, RustResult.a);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
So how i can complete this shader? I cant find a detailed documentation about the usable functuons in surface shaders.
EDIT: I almost get what i need using saturate(); functionlike the following
Properties {
_MainTex ("Base (RGB)", 2D) = "" {} //the color texture
_RustTex ("Rust Texture (RGB)", 2D) = "" {} //the rust texture
_RustGuide ("Rust Guide (A)", 2D) = "" {} //the rust greyscale texture
_RustAmount ("Rust Amount", range(0.0, 1.0)) = 0.0 //the rust amount float value
_RustMultiplier ("Rust Multiplier", float) = 2
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma target 3.0
#include "UnityPBSLighting.cginc"
#pragma surface surf Standard
sampler2D _MainTex;
sampler2D _RustTex;
sampler2D _RustGuide;
float _RustAmount;
float _RustMultiplier;
struct Input {
float2 uv_MainTex;
float2 uv_RustTex;
float2 uv_RustGuide;
};
void surf (Input IN, inout SurfaceOutputStandard o) {
half4 M = tex2D (_MainTex, IN.uv_MainTex);
half4 R = tex2D (_RustTex, IN.uv_RustTex);
half4 RG = tex2D (_RustGuide, IN.uv_RustGuide);
half4 RustResult;
RustResult.rgb = R.rgb;
if (_RustAmount > 0) {
RustResult.a = trunc(saturate(RG.a * _RustAmount * _RustMultiplier);
}
half4 Final = lerp (M, RustResult, RustResult.a);
o.Albedo = Final.rgb;
o.Alpha = Final.a;
}
ENDCG
}
FallBack Off
}
This makes the effect that I need. The only problem now is how i can blur the edges of the alpha?
Use the range to remove from the grayscale map all the pixels that are darker than the value itself
Can't you simply clamp the values below _RustAmount
float? Something like:
float greyScaleMapValue = tex2D(_RustGuide, IN.uv_RustGuide).a; //assuming rust guide is stored as a single channel
float clampedMap = clamp(greyScaleMapValue , _RustAmount, 1); //clamped map stores a value clamped between _RustAmount and 1 -> every pixel darker than _RustAmount are 0
half3 albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
half3 rust = tex2D (_RustTex, IN.uv_RustTex).rgb;
float3 finalCol = lerp(albedo, rust, clampedMap); // all values in the map below _RustAmount will have plain albedo value, the other will be blended with rust using the map
return float4(finalCol,1);
Note that the code above produce some abrupt transition from texture to rust (more abrupt more _RustmAmount
is higher than zero). You want eventually to remap each value higher than zero after the clamp in [0,1]
range.
If you need to smooth the transition you can remap the interval [_RustAmount,1]
into [0,1]
:
float clampedMapNormalized = (clampedMap - _RustAmount) / (1 - _RustAmount);
Hope this helps
Side note:
float3
to minimize the values to be lerped.