Hi all ,I posted this thread because I’d like to share(and maybe improve) a custom terrain shader. As u can understand from the title, I’d like to achieve a terrain like battlefield 3 or udk engine. Before typing please read this topic
http://udn.epicgames.com/Three/TerrainAdvancedTextures.html
It’s really interesting, but I’d like to add normal maps to my terrain, as seen there
http://forums.epicgames.com/threads/722288-Advanced-Terrain-Texturing-downsampling?
Note the normal map(I think) :
What’s that? a normal map and how can I make one like this in unity?
ok, now I’ll post my code.
NOTE this code has not been created by me. I modified the shader so that u can have a better quality over the terrain and add a normal map to the terrain
/* Code provided by Chris Morris of Six Times Nothing (http://www.sixtimesnothing.com) */
/* Free to use and modify */
Shader "Hidden/TerrainEngine/Splatmap/Lightmap-FirstPass" {
Properties {
_Control ("Control (RGBA)", 2D) = "red" {}
_Splat3 ("Layer 3 (A)", 2D) = "white" {}
_Splat2 ("Layer 2 (B)", 2D) = "white" {}
_Splat1 ("Layer 1 (G)", 2D) = "white" {}
_Splat0 ("Layer 0 (R)", 2D) = "white" {}
// used in fallback on old cards
_MainTex ("BaseMap (RGB)", 2D) = "white" {}
_Color ("Main Color", Color) = (1,1,1,1)
}
SubShader {
Tags {
"SplatCount" = "4"
"Queue" = "Geometry-100"
"RenderType" = "Opaque"
}
CGPROGRAM
#pragma surface surf BlinnPhong vertex:vert
#pragma target 3.0
#include "UnityCG.cginc"
struct Input {
//float3 worldPos;
float2 uv_Control : TEXCOORD0;
float2 uv_Splat0 : TEXCOORD1;
float2 uv_Splat1 : TEXCOORD2;
float2 uv_Splat2 : TEXCOORD3;
float2 uv_Splat3 : TEXCOORD4;
//float2 uv_Splat4 : TEXCOORD5;
//fixed4 color : COLOR;
float2 uv_BumpMap : TEXCOORD0;
float3 viewDir;
};
// Supply the shader with tangents for the terrain
void vert (inout appdata_full v) {
// A general tangent estimation
float3 T1 = float3(1, 0, 1);
float3 Bi = cross(T1, v.normal);
float3 newTangent = cross(v.normal, Bi);
normalize(newTangent);
v.tangent.xyz = newTangent.xyz;
if (dot(cross(v.normal,newTangent),Bi) < 0)
v.tangent.w = -1.0f;
else
v.tangent.w = 1.0f;
}
sampler2D _Control, _ParallaxMap;
sampler2D _BumpMap0, _BumpMap1, _BumpMap2, _BumpMap3 , _BumpMap4, _BumpTerrain;
sampler2D _Splat0,_Splat1,_Splat2,_Splat3, _Splat4;
float _Tile0, _Tile1, _Tile2, _Tile3, _Tile4, _TerrainX, _TerrainZ, _TileX, _TileY;
void surf (Input IN, inout SurfaceOutput o) {
half4 splat_control = tex2D (_Control, IN.uv_Control);
half3 col;
half3 norm;
// first texture which is usually some kind of rock texture gets mixed with itself
// see: http://forum.unity3d.com/threads/116509-Improved-Terrain-Texture-Tiling
norm = UnpackNormal(tex2D(_BumpTerrain, float2(IN.uv_Control.x * _TileX, IN.uv_Control.y * _TileY))) * UnpackNormal(tex2D(_BumpTerrain, float2(IN.uv_Control.x * -0.5, IN.uv_Control.y * -0.5)));
col = splat_control.r * tex2D (_Splat0, IN.uv_Splat0).rgb * tex2D (_Splat0, IN.uv_Splat0 * -0.125).rgb * 3;
norm += splat_control.r * UnpackNormal(tex2D(_BumpMap0, float2(IN.uv_Control.x * (_TerrainX/_Tile0), IN.uv_Control.y * (_TerrainZ/_Tile0))));
col += splat_control.g * tex2D (_Splat1, IN.uv_Splat1).rgb * tex2D (_Splat1, IN.uv_Splat1 * -0.125).rgb * 3;
norm += splat_control.g * UnpackNormal(tex2D(_BumpMap1, float2(IN.uv_Control.x * (_TerrainX/_Tile1), IN.uv_Control.y * (_TerrainZ/_Tile1))));
col += splat_control.b * tex2D (_Splat2, IN.uv_Splat2).rgb * tex2D (_Splat2, IN.uv_Splat2 * -0.125).rgb * 1;
norm += splat_control.b * UnpackNormal(tex2D(_BumpMap2, float2(IN.uv_Control.x * (_TerrainX/_Tile2), IN.uv_Control.y * (_TerrainZ/_Tile2))));
col += splat_control.a * tex2D (_Splat3, IN.uv_Splat3).rgb * tex2D (_Splat3, IN.uv_Splat3 * -0.125).rgb * 0.9;
norm += splat_control.a * UnpackNormal(tex2D(_BumpMap3, float2(IN.uv_Control.x * (_TerrainX/_Tile3), IN.uv_Control.y * (_TerrainZ/_Tile3))));
o.Albedo = col;
o.Normal = norm;
}
ENDCG
}
// Fallback to Diffuse
Fallback "Diffuse"
}
And the script to attach to the terrain in order to add normal maps :
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class CustomTerrainScriptAtsV2 : MonoBehaviour {
public Texture2D BumpTerrain;
public float TileX;
public float TileY;
public Texture2D[] Bump;
public float[] Tile;
public float terrainSizeX;
public float terrainSizeZ;
void Update () {
//Terrain.activeTerrain.heightmapPixelError = 1;
//Terrain.activeTerrain.basemapDistance = 40000;
//Terrain.activeTerrain.detailObjectDistance = 4000;
Terrain terrainComp = (Terrain)GetComponent(typeof(Terrain));
Shader.SetGlobalTexture("_BumpTerrain" , BumpTerrain);
Shader.SetGlobalFloat("_TileX", TileX);
Shader.SetGlobalFloat("_TileY", TileY);
for (int i = 0; i < Bump.Length; i++){
Shader.SetGlobalTexture("_BumpMap"+i.ToString(), Bump[i]);
Shader.SetGlobalFloat("_Tile"+i.ToString(), Tile[i]);
}
/*
if(Bump0)
Shader.SetGlobalTexture("_BumpMap0", Bump0);
if(Bump1)
Shader.SetGlobalTexture("_BumpMap1", Bump1);
if(Bump2)
Shader.SetGlobalTexture("_BumpMap2", Bump2);
if(Bump3)
Shader.SetGlobalTexture("_BumpMap3", Bump3);
Shader.SetGlobalFloat("_Tile0", Tile0);
Shader.SetGlobalFloat("_Tile1", Tile1);
Shader.SetGlobalFloat("_Tile2", Tile2);
Shader.SetGlobalFloat("_Tile3", Tile3);
*/
terrainSizeX = terrainComp.terrainData.size.x;
terrainSizeZ = terrainComp.terrainData.size.z;
Shader.SetGlobalFloat("_TerrainX", terrainSizeX);
Shader.SetGlobalFloat("_TerrainZ", terrainSizeZ);
}
}
I hope this will be helpful to u and I’d like to have some feedback and answer.
Thanks for your time and sorry for my english