3.0 Terrain shader

Decided to register here to share(and test:P) a shader aimed at SM 3.0 crowd.Its a splatting shader with 3 layers,each with different spec and parallax bump map,plus a lightmap.It also has an interesting pseudo-AO effect which I’ve not seen used elsewhere(tied to the Roughness slider)

Note that if you edit the shader code and objects happen to get their normals flipped when adding lights,you must delete the object and add the material again,seems to be some bug on Unity’s side.
If you decide to try the shader,please let me know if it works as expected.

http://www.mediafire.com/file/zjjro0lzz1z/Assets.rar

pretty neat :slight_smile:

Will to test it for real once I’m back on my workstation, because I’ve my 8600M GT isn’t that happy about such bombs :wink:

puuuuuuuurty…

reupload to another host please?

Can offer to host it on my webhost if you want.
Didn’t have any prob with mediafire and unlike others they normally don’t force you to wait 1min or have an account

dreamora,please do!
I would have just attached it to my post,but my upload speed is too slow and it timed out.

Its available now at http://mirror.dreamora.net/unity/assets.rar

Should you have an update to it multivac, please let me know, through pm at best.

this doesn´t work here for some reason. Is it unity 2.5 or 2.6? It says terrain splat 0, 1 and 2 are null

Dreamora’s site seemed to be down so I mirrored it here as well. Hope it’s ok!

www.dukecg.net/Unity/SM3.0_TerrainShader_Assets.rar

link fixed.

stupid me has messed the file extension, its naturally rar, not zip (I commonly use 7z but thats OSX unfriendly especially with the 9.07 beta and lzma2 ^^)

did anyone see my comment? I can’t get it to work, it says Splat0 to 3 are null. I have an SM4 card in both my pc’s so i think it is supposed to work here…

Jan,do you have a NVIDIA card?I have an Ati so there might be some undocumented differences…

anyway,try replacing the shader with this one,it has specific texture coordinates for all three splats,might do the trick.
It also has a color slot for the pseudo-AO,so blueish indirect illumination from the sky can be faked.

Shader "Terrain/ThreeLayer Bumped" {

Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
	_Shadow ("AO shadow", Color) = (1,1,1,1)
	 _Roughness ("Roughness", Range (0.0, 1.0)) = 0.0
	 // _Burn ("Lightmap multiplier", Range (0.0, 2.0)) = 1.3
		_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
	_Shininess ("Shininess", Range (0.01, 1)) = 0.078125
	_Parallax ("Height", Range (0.005, 0.08)) = 0.02
    _MainTex ("Base (RGBA)", 2D) = "white" {}
	  _MainTex_b ("Bumpmap (RGBA)", 2D) = "bump" {}
    _MainTex2 ("Base 2 (RGBA)", 2D) = "white" {}
		  _MainTex2_b ("Bumpmap 2 (RGBA)", 2D) = "bump" {}
	_MainTex3 ("Base 3 (RGBA)", 2D) = "white" {}
		  _MainTex3_b ("Bumpmap 3 (RGBA)", 2D) = "bump" {}
		  _lightmap ("Lightmap", 2D) = "white" {}
    _Mask ("Mix Mask (RGBA)", 2D) = "gray" {}
}
 
Category {

Tags{   "RenderType"="Opaque"}
 
Blend AppSrcAdd AppDstAdd 
       
     // Cull Back
    SubShader {
	
			UsePass "Specular/BASE"

        Pass {
            Name "Blend_Layers"
            Tags { "LightMode" = "Pixel"}
			 Color [_PPLAmbient]
		  Material { Diffuse [_Color]		
  } 

                
CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile_builtin
#include "UnityCG.cginc"
#include "AutoLight.cginc"



 
struct v2f { 

    V2F_POS_FOG;
    LIGHTING_COORDS
    float3  uv[3];
	float2 uv2 ;
		float3	viewDirT;
    float3  lightDirT;

}; 
float4 _MainTex_ST,_MainTex2_ST,_MainTex3_ST,_Mask_ST; 
 uniform float _Shininess;
 
v2f vert (appdata_tan v)
{
    v2f o;
    PositionFog( v.vertex, o.pos, o.fog );
    o.uv[0].xy = 1-TRANSFORM_TEX(v.texcoord, _MainTex);
	o.uv[1].xy = 1-TRANSFORM_TEX(v.texcoord, _MainTex2);
	o.uv[2].xy = 1-TRANSFORM_TEX(v.texcoord, _MainTex3);
	o.uv[0].z = _Shininess * 128;
	o.uv2 = TRANSFORM_TEX(v.texcoord, _Mask);
    TANGENT_SPACE_ROTATION;
	o.viewDirT = mul( rotation, ObjSpaceViewDir( v.vertex ) );	
    o.lightDirT = mul( rotation, ObjSpaceLightDir( v.vertex ) );    
    TRANSFER_VERTEX_TO_FRAGMENT(o);
    return o;
}
 
uniform sampler2D _MainTex;
uniform sampler2D _MainTex2;
uniform sampler2D _MainTex3;
uniform sampler2D _MainTex_b;
uniform sampler2D _MainTex2_b;
uniform sampler2D _MainTex3_b;
uniform sampler2D _lightmap;
uniform sampler2D _Mask;
uniform float _Parallax;
uniform float _Roughness;
uniform float3 _Shadow;
//uniform float _Burn;


 
float4 frag (v2f i) : COLOR
{


   float4 mix = tex2D(_Mask,i.uv2);
								

	float n1 = tex2D(_MainTex_b, i.uv[0].xy).a  ;
	float n2 = tex2D(_MainTex2_b, i.uv[1].xy).a  ;
	float n3 = tex2D(_MainTex3_b, i.uv[2].xy).a ;

	float result=n1;
	result=((result*(1-mix.g)) + n2*(mix.g));
	result=((result*(1-mix.b))+n3*(mix.b));

	float2 offset1 = ParallaxOffset( result, -_Parallax, i.viewDirT )+i.uv[0].xy;
	float2 offset2 = ParallaxOffset( result, -_Parallax, i.viewDirT )+i.uv[1].xy;
	float2 offset3 = ParallaxOffset( result, -_Parallax, i.viewDirT )+i.uv[2].xy;
		
	float3 normal1 = tex2D(_MainTex_b, (offset1)).rgb * 2 -1;
	float3 normal2 = tex2D(_MainTex2_b, (offset2)).rgb * 2 -1;
	float3 normal3 = tex2D(_MainTex3_b, (offset3)).rgb * 2 -1;

	float3 resultn=normal1;
	resultn=  ((resultn*(1-mix.g)) + normal2*(mix.g));
	resultn=  ((resultn*(1-mix.b))+normal3*(mix.b));



	float4 col1 = tex2D(_MainTex,offset1);
    float4 col2 = tex2D(_MainTex2,offset2);
	float4 col3 = tex2D(_MainTex3,offset3);
	
	
	float3 lightmap = tex2D(_lightmap,(i.uv2)).rgb;
		
	float4 result1=col1;
	result1=  ((result1*(1-mix.g)) + col2*(mix.g));
	result1=  ((result1*(1-mix.b))+col3*(mix.b));
	result1.rgb *=lightmap*2.0;
	
	result1.rgb=lerp(result1.rgb,result1.rgb*_Shadow,((1-result)+resultn.r+resultn.g)*_Roughness);
	
	
    return SpecularLight( i.lightDirT, i.viewDirT,resultn, result1,i.uv[0].z-(result1.rgb*_Shadow), LIGHT_ATTENUATION(i) );
}
ENDCG              
        }
		}
		}
	
 
  Fallback "Diffuse", 1
 
}

I tested it on both ATI and Nvidia but when i am home i will test it!

This looks amazing and is probably the first step to having FFXIV quality terrain in unity. Can we have a webplayer?

Terrain splat 2 is null. :frowning:

Unity Pro 2.6
Windows 7

well,it seems that something about this particular shader(or unity’s SM 3.0 implementation) is unreliable.
It’s a shame,I already created a script for painting the mask in editor with different brushes and everything.

Here’s a test scene for web-player though,hold down middle mouse to try the painting feature,wasd and mouse 1 to move.

http://web.zone.ee/hover/1.unity3d

me 2, on ati hd3470

Or its just ATIs understanding of what SM3.0 includes and how it has to work

aw I get Terrain splat 0, 1 and 2 is null error :frowning:
Running Windows 7, unity Pro, GeForce 9400 GT card…

Why isn’t it working? :frowning:

I started thinking why it gives errors relating to terrain splats while I haven’t declared no such things?
Perhaps its because the shader is stored in the “hidden” terrains directory which imposes some extra stuff on the shaders within?
Could someone with the splat error remove Terrain/
from the first line of the shader?
the more i think about it,the more probable it sounds :slight_smile:
EDIT:
delete the 4layer_spec_par material and add the shader to a new material.I checked out the contents of the 4layer material in notepad and it seems it has become corrupted,having those _Splat0 and so on declared…I wonder why it happened.
actually,just try this shader on a new material.

Shader "ThreeLayer Bumped" {

Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
	_Shadow ("AO shadow", Color) = (1,1,1,1)
	 _Roughness ("Roughness", Range (0.0, 1.0)) = 0.0
	 // _Burn ("Lightmap multiplier", Range (0.0, 2.0)) = 1.3
		_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
	_Shininess ("Shininess", Range (0.01, 1)) = 0.078125
	_Parallax ("Height", Range (0.005, 0.08)) = 0.02
    _MainTex ("Base (RGBA)", 2D) = "white" {}
	  _MainTex_b ("Bumpmap (RGBA)", 2D) = "bump" {}
    _MainTex2 ("Base 2 (RGBA)", 2D) = "white" {}
		  _MainTex2_b ("Bumpmap 2 (RGBA)", 2D) = "bump" {}
	_MainTex3 ("Base 3 (RGBA)", 2D) = "white" {}
		  _MainTex3_b ("Bumpmap 3 (RGBA)", 2D) = "bump" {}
		  _lightmap ("Lightmap", 2D) = "white" {}
    _Mask ("Mix Mask (RGBA)", 2D) = "gray" {}
}
 
Category {

Tags{   "RenderType"="Opaque"}
 
Blend AppSrcAdd AppDstAdd 
       
      Cull Back
    SubShader {
	
			
UsePass "Diffuse/BASE" 
        Pass {
            Name "Blend_Layers"
            Tags { "LightMode" = "Pixel"}
			 Color [_PPLAmbient]
		  Material { Diffuse [_Color]		
  } 

                
CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile_builtin
#include "UnityCG.cginc"
#include "AutoLight.cginc"



 
struct v2f { 

    V2F_POS_FOG;
    LIGHTING_COORDS
    half3  uv;
	half2 uv2 ;
		half3	viewDirT;
   half3  lightDirT;

}; 
half4 _MainTex_ST,_Mask_ST; 
 uniform float _Shininess;
 
v2f vert (appdata_tan v)
{
    v2f o;
    PositionFog( v.vertex, o.pos, o.fog );
    o.uv.xy = 1-TRANSFORM_TEX(v.texcoord, _MainTex);
	o.uv.z = _Shininess * 128;
	o.uv2 = TRANSFORM_TEX(v.texcoord, _Mask);
    TANGENT_SPACE_ROTATION;
	o.viewDirT = mul( rotation, ObjSpaceViewDir( v.vertex ) );	
    o.lightDirT = mul( rotation, ObjSpaceLightDir( v.vertex ) );    
    TRANSFER_VERTEX_TO_FRAGMENT(o);
    return o;
}
 
uniform sampler2D _MainTex;
uniform sampler2D _MainTex2;
uniform sampler2D _MainTex3;
uniform sampler2D _MainTex_b;
uniform sampler2D _MainTex2_b;
uniform sampler2D _MainTex3_b;
uniform sampler2D _lightmap;
uniform sampler2D _Mask;
uniform half _Parallax;
uniform half _Roughness;
uniform half3 _Shadow;
//uniform half _Burn;


 
float4 frag (v2f i) : COLOR
{


   half4 mix = tex2D(_Mask,i.uv2);
								

	half n1 = tex2D(_MainTex_b, i.uv.xy).a  ;
	half n2 = tex2D(_MainTex2_b, i.uv.xy).a  ;
	half n3 = tex2D(_MainTex3_b, i.uv.xy).a ;

	half result=n1;
	result=((result*(1-mix.g)) + n2*(mix.g));
	result=((result*(1-mix.b))+n3*(mix.b));

	half2 offset = ParallaxOffset( result, -_Parallax, i.viewDirT )+i.uv.xy;

		
	half3 normal1 = tex2D(_MainTex_b, (offset)).rgb * 2 -1;
	half3 normal2 = tex2D(_MainTex2_b, (offset)).rgb * 2 -1;
	half3 normal3 = tex2D(_MainTex3_b, (offset)).rgb * 2 -1;

	half3 resultn=normal1;
	resultn=  ((resultn*(1-mix.g)) + normal2*(mix.g));
	resultn=  ((resultn*(1-mix.b))+normal3*(mix.b));



	half4 col1 = tex2D(_MainTex,offset);
    half4 col2 = tex2D(_MainTex2,offset);
	half4 col3 = tex2D(_MainTex3,offset);
	
	
	half3 lightmap = tex2D(_lightmap,(i.uv2)).rgb;
		
	half4 result1=col1;
	result1=  ((result1*(1-mix.g)) + col2*(mix.g));
	result1=  ((result1*(1-mix.b))+col3*(mix.b));

	
	result1.rgb=lerp(result1.rgb,result1.rgb*_Shadow,-((result-1)+(resultn.r+resultn.g))*_Roughness);
		result1.rgb *=1.2*lightmap;
	
    return SpecularLight( i.lightDirT, i.viewDirT,resultn, result1,i.uv.z-result1.rgb*_Shadow, LIGHT_ATTENUATION(i) );
}
ENDCG              
        }
		}
		}
	
 
  Fallback "Diffuse", 1
 
}