- Home /
How to add Bump/Normal Map to surface shader? (CG)
Hi dear community. I am trying to get a normal map texture working with a custom terrain shader I got from following a tutorial series by Sebastian Lague. I have currently tried this:
`Shader "Custom/Terrain" {
Properties {
// Textures and Scale-Slot
testTexture("Texture", 2D) = "white"{}
testScale("Scale", Float) = 1
_NormalMap ("Normal Map", 2D) = "bump" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
// SHADER-Language = CG
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
const static int maxLayerCount = 8; // Max Amount of colors the terrain can have
const static float epsilon = 1E-4;
int layerCount;
float3 baseColours[maxLayerCount];
float baseStartHeights[maxLayerCount]; // ZONES FOR COLORS OF TERRAIN
float baseBlends[maxLayerCount]; // BLENDS FoR COLORS/TEXTUREN
float baseColourStrength[maxLayerCount];
float baseTextureScales[maxLayerCount]; // Texture size
float minHeight; //min. Hight of Map
float maxHeight; //max. Hight of Map
sampler2D testTexture; // Textur Slot
float testScale; // Scale of the texture
sampler2D _NormalMap;
UNITY_DECLARE_TEX2DARRAY(baseTextures); // Texture-Array from TextureData(another Script) definieren
struct Input {
float3 worldPos; // Position on Map
float3 worldNormal; // Normales of Map
float2 uv_Diffuse;
INTERNAL_DATA
};
float inverseLerp(float a, float b, float value) // a = min.value, b = max.value, value = surrent value
{
return saturate((value - a)/(b-a));
}
// --> TRIPLANAR MAPPING
float3 triplanar (float3 worldPos, float scale, float3 blendAxes, int textureIndex)
{
float3 scaledWorldPos = worldPos/ scale;
float3 xProjection = UNITY_SAMPLE_TEX2DARRAY(baseTextures, float3(scaledWorldPos.y,scaledWorldPos.z, textureIndex)) * blendAxes.x;
float3 yProjection = UNITY_SAMPLE_TEX2DARRAY(baseTextures, float3(scaledWorldPos.x,scaledWorldPos.z, textureIndex)) * blendAxes.y;
float3 zProjection = UNITY_SAMPLE_TEX2DARRAY(baseTextures, float3(scaledWorldPos.x,scaledWorldPos.y, textureIndex)) * blendAxes.z;
return xProjection + yProjection + zProjection; // Mix textures
}
// 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_CBUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_CBUFFER_END
void surf (Input IN, inout SurfaceOutputStandard o) {
float heightPercent = inverseLerp(minHeight, maxHeight, IN.worldPos.y);
float3 blendAxes = abs(IN.worldNormal);
blendAxes /= blendAxes.x + blendAxes.y + blendAxes.z;
for (int i = 0; i < layerCount; i++)
{
float drawStrenght = inverseLerp(-baseBlends[i]/2 - epsilon, baseBlends[i]/2, heightPercent - baseStartHeights[i]);
float3 baseColour = baseColours[i] * baseColourStrength[i];
// Textur
float3 textureColour = triplanar(IN.worldPos, baseTextureScales[i], blendAxes, i) * (1-baseColourStrength[i]);
o.Albedo = o.Albedo * (1 - drawStrenght) + (baseColour + textureColour) * drawStrenght;
o.Normal = UnpackNormal( tex2D(_NormalMap, IN.uv_Diffuse));
}
}
ENDCG
}
FallBack "Diffuse"}`
This currently gets me to the point of having a black terrain (instead of the original triplanar mapped main texture) and looks like this:
This is the set up in the Unity inspector:
my question is: How can I achieve having the terrain with the bump map on it? Thx to everyone who helps out!
You might wanna see what Unity does normally with their terrain shading. check out the "built-in" shaders:
thx @inso$$anonymous$$x I know at least now (after trying out stuff for hours) that the issue is there because I have multiple layers of textures. These "o.Albedos" get set up in the for-loop:
for (int i = 0; i < layerCount; i++)
{ float drawStrenght = inverseLerp(-baseBlends[i]/2 - epsilon, baseBlends[i]/2, heightPercent - baseStartHeights[i]); float3 baseColour = baseColours[i] baseColourStrength[i]; // Textur float3 textureColour = triplanar(IN.worldPos, baseTextureScales[i], blendAxes, i) (1-baseColourStrength[i]); o.Albedo = o.Albedo (1 - drawStrenght) + (baseColour + textureColour) drawStrenght; o.Normal = UnpackNormal( tex2D(_Normal$$anonymous$$ap, IN.uv_Diffuse)); }
When I don't use " o.Normal = UnpackNormal( tex2D(_Normal$$anonymous$$ap, IN.uv_Diffuse));" in here it works fine. I need to figure out how and where exactly the normal map is applied?
Your answer
Follow this Question
Related Questions
Surface Shader World Normal 0 Answers
Spherical Hamonics - ShadeSH9 and Surface Shader issue 0 Answers
Shader - Object Depth 0 Answers
Shader that renders fragment behind 0 Answers
Prevent ColorMask obscuring parts of an object's mesh 0 Answers