Very new to shaders so I apologize if I’m making a basic error in this.
I’m experimenting with making my own shader for procedural terrain meshes. I have it working right now as a diffuse-only shader that blends four different textures based on height and another based on slope (world normal).
I added code to do normal map blending as well, but weird stuff happens when I set o.normal. If I comment out that one line at the end and leave everything else as is, it functions perfectly.
The noted weirdnesses are 1) That certain diffuse textures are still there but others are “whited out” entirely; 2) that the diffuse blending breaks; and 3) the normal maps look weird anyway.
I appreciate any pointing in the right direction as I don’t really know how to debug this and can’t find any other shaders with similar errors. Thanks!
Shader follows:
Shader "Custom/Terrain" {
Properties{
//Diffuse maps
_Elevation1Tex("Elevation 1 Diffuse", 2D) = "white" {}
_Elevation2Tex("Elevation 2 Diffuse", 2D) = "white" {}
_Elevation3Tex("Elevation 3 Diffuse", 2D) = "white" {}
_Elevation4Tex("Elevation 4 Diffuse", 2D) = "white" {}
_SlopeTex("Slope Diffuse", 2D) = "white" {}
//Normal Maps
_Elevation1Normal("Elevation 1 Normal", 2D) = "bump" {}
_Elevation2Normal("Elevation 2 Normal", 2D) = "bump" {}
_Elevation3Normal("Elevation 3 Normal", 2D) = "bump" {}
_Elevation4Normal("Elevation 4 Normal", 2D) = "bump" {}
_SlopeNormal("Slope Normal", 2D) = "bump" {}
//For slope calculations.
_VertDir("Vertical Direction", Vector) = (0.0, 1.0, 0.0)
_SlopeIntensity("Slope Intensity", Range(0.1, 5.0)) = 2.0
_MinSlope("Minimum Slope Attenuation", Range(0.0, 2.0)) = 0.1
//Need one of each threshold + radius for (elevation maps)-1
_Elev1Level("Elevation 1 Height Threshold", Range(0.0, 1.0)) = 0.1
_Elev1Fade("Elevation 1 Attenuation Radius",Range(0.0,0.2)) = 0.05
_Elev2Level("Elevation 2 Height Threshold", Range(0.0, 1.0)) = 0.2
_TempTest("Elevation 2 Attenuation Radius",Range(0.0,0.2)) = 0.05
_Elev3Level("Elevation 3 Height Threshold", Range(0.0, 1.0)) = 0.3
_Elev3Fade("Elevation 3 Attenuation Radius",Range(0.0,0.2))= 0.05
}
SubShader{
Tags { "RenderType" = "Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
//#pragma surface surf Lambert
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 4.0
sampler2D _Elevation1Tex;
sampler2D _Elevation2Tex;
sampler2D _Elevation3Tex;
sampler2D _Elevation4Tex;
sampler2D _SlopeTex;
sampler2D _Elevation1Normal;
sampler2D _Elevation2Normal;
sampler2D _Elevation3Normal;
sampler2D _Elevation4Normal;
sampler2D _SlopeNormal;
float4 _VertDir;
float _SlopeIntensity;
float _Elev1Level;
float _Elev2Level;
float _Elev3Level;
float _Elev1Fade;
float _TempTest;
float _Elev3Fade;
float _MinSlope; //Attenuate the slope fade-in factor from here (IE underwater to beaches we may not want cliff appearance)
float minHeight;
float maxHeight;
struct Input {
float3 worldPos;
float3 worldNormal; INTERNAL_DATA //Need INTERNAL_DATA to pull normal vector since our shader writes to o.Normal
float2 uv_Elevation1Tex;
float2 uv_Elevation2Tex;
float2 uv_Elevation3Tex;
float2 uv_Elevation4Tex;
float2 uv_SlopeTex;
float2 uv_Elevation1Normal;
float2 uv_Elevation2Normal;
float2 uv_Elevation3Normal;
float2 uv_Elevation4Normal;
float2 uv_SlopeNormal;
};
float inverseLerp(float a, float b, float value) {
return saturate((value - a) / (b - a));
}
void surf(Input IN, inout SurfaceOutputStandard o) {
float heightPercent = inverseLerp(minHeight, maxHeight, IN.worldPos.y);
fixed4 elev1Tex = tex2D(_Elevation1Tex, IN.uv_Elevation1Tex);
fixed4 elev2Tex = tex2D(_Elevation2Tex, IN.uv_Elevation2Tex);
fixed4 elev3Tex = tex2D(_Elevation3Tex, IN.uv_Elevation3Tex);
fixed4 elev4Tex = tex2D(_Elevation4Tex, IN.uv_Elevation4Tex);
fixed4 slopeTex = tex2D(_SlopeTex, IN.uv_SlopeTex);
fixed4 elev1Normal = tex2D(_Elevation1Normal, IN.uv_Elevation1Normal);
fixed4 elev2Normal = tex2D(_Elevation2Normal, IN.uv_Elevation2Normal);
fixed4 elev3Normal = tex2D(_Elevation3Normal, IN.uv_Elevation3Normal);
fixed4 elev4Normal = tex2D(_Elevation4Normal, IN.uv_Elevation4Normal);
fixed4 slopeNormal = tex2D(_SlopeNormal, IN.uv_SlopeNormal);
//Default to highest
fixed4 diffuseOut = elev4Tex;
fixed4 normalOut = elev4Normal;
if (heightPercent < (_Elev1Level + _Elev1Fade)) {
if (heightPercent < (_Elev1Level - _Elev1Fade)) {
diffuseOut = elev1Tex; //Pure texture 1
normalOut = elev1Normal;
}
else {
diffuseOut = lerp(elev1Tex, elev2Tex, inverseLerp(_Elev1Level - _Elev1Fade, _Elev1Level + _Elev1Fade, heightPercent));
normalOut = lerp(elev1Normal, elev2Normal, inverseLerp(_Elev1Level - _Elev1Fade, _Elev1Level + _Elev1Fade, heightPercent));
}
}
else {
if (heightPercent < (_Elev2Level + _TempTest)) {
if (heightPercent < (_Elev2Level - _TempTest)) {
diffuseOut = elev2Tex; //Pure texture 2
normalOut = elev2Normal;
}
else {
diffuseOut = lerp(elev2Tex, elev3Tex,inverseLerp(_Elev2Level - _TempTest, _Elev2Level + _TempTest, heightPercent));
normalOut = lerp(elev2Normal, elev3Normal, inverseLerp(_Elev1Level - _Elev1Fade, _Elev1Level + _Elev1Fade, heightPercent));
}
}
else {
if (heightPercent < (_Elev3Level + _Elev3Fade)) {
if (heightPercent < (_Elev3Level - _Elev3Fade)) {
diffuseOut = elev3Tex; //Pure texture 3
normalOut = elev3Normal;
}
else {
diffuseOut = lerp(elev3Tex, elev4Tex, inverseLerp(_Elev3Level - _Elev3Fade, _Elev3Level + _Elev3Fade, heightPercent));
normalOut = lerp(elev3Normal, elev4Normal, inverseLerp(_Elev1Level - _Elev1Fade, _Elev1Level + _Elev1Fade, heightPercent));
}
}
else {
diffuseOut = elev4Tex;
normalOut = elev4Normal;
}
}
}
//Mix in the slope calculations
float slope = 1-dot(normalize(IN.worldNormal), _VertDir.xyz);
if (slope < 0) slope = 0;
slope = slope * _SlopeIntensity;
if (heightPercent < _MinSlope) {
if (heightPercent < _MinSlope - 0.1) { //For now hardcoded - 0.1 from start of attenuation, we lose slope blend effect
slope = 0;
}
else {
slope = slope * inverseLerp(_MinSlope - 0.1,_MinSlope,heightPercent);
}
}
else {
}
diffuseOut = lerp(diffuseOut, slopeTex, slope);
normalOut = lerp(normalOut, slopeNormal, slope);
o.Albedo = diffuseOut.rgb;
//o.Normal = UnpackNormal(normalOut);
//Using normals is 'whiting out' some other textures and doesn't look very good,
//so disable until we figure out the issue
}
ENDCG
}
FallBack "Diffuse"
}


