Created
December 14, 2018 19:33
-
-
Save unitycoder/9cc7b09a2bb54827454ea555238d4f56 to your computer and use it in GitHub Desktop.
Terrain Shader Tesselation Diffuse
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Author: Przemyslaw Zaworski | |
// Modified version of original: | |
// https://github.com/przemyslawzaworski/Unity3D-CG-programming/blob/master/terrain_shader_tessellation_diffuse.shader | |
// Shader supports maximum four splat textures (Splat and Normal maps) with triangle tessellation. | |
// Works seamlessly with built-in Terrain Component. Lambert light model (directional) with shadow casting and receiving. | |
// https://forum.unity.com/threads/how-to-dynamically-tessellate-a-mesh.597469/#post-3997999 | |
Shader "Terrain Shader Tessellation Diffuse" | |
{ | |
Properties | |
{ | |
[HideInInspector] _Control ("Control (RGBA)", 2D) = "red" {} | |
[HideInInspector] _Splat3 ("Layer 3 (A)", 2D) = "white" {} | |
[HideInInspector] _Splat2 ("Layer 2 (B)", 2D) = "white" {} | |
[HideInInspector] _Splat1 ("Layer 1 (G)", 2D) = "white" {} | |
[HideInInspector] _Splat0 ("Layer 0 (R)", 2D) = "white" {} | |
[HideInInspector] _Normal3 ("Normal 3 (A)", 2D) = "bump" {} | |
[HideInInspector] _Normal2 ("Normal 2 (B)", 2D) = "bump" {} | |
[HideInInspector] _Normal1 ("Normal 1 (G)", 2D) = "bump" {} | |
[HideInInspector] _Normal0 ("Normal 0 (R)", 2D) = "bump" {} | |
_TessellationMap ("Tessellation Map", 2D) = "black" {} | |
} | |
SubShader | |
{ | |
Tags {"RenderType" = "Opaque"} | |
Pass | |
{ | |
Tags {"LightMode" = "ForwardBase" "SplatCount" = "4" "Queue" = "Geometry-100"} | |
CGPROGRAM | |
#pragma vertex vertex_shader | |
#pragma hull hull_shader | |
#pragma domain domain_shader | |
#pragma fragment pixel_shader | |
#pragma target 5.0 | |
#pragma multi_compile_fwdbase | |
#include "AutoLight.cginc" | |
sampler2D _Control; | |
float4 _Control_ST; | |
sampler2D _Splat0; | |
sampler2D _Splat1; | |
sampler2D _Splat2; | |
sampler2D _Splat3; | |
float4 _Splat0_ST; | |
float4 _Splat1_ST; | |
float4 _Splat2_ST; | |
float4 _Splat3_ST; | |
float4 _LightColor0; | |
sampler2D _TessellationMap; | |
sampler2D _Normal0, _Normal1, _Normal2, _Normal3; | |
struct APPDATA | |
{ | |
float2 tc_Control: COLOR; | |
float4 vertex : POSITION; | |
float3 normal : NORMAL; | |
float2 uv_Splat0 : TEXCOORD0; | |
float2 uv_Splat1 : TEXCOORD1; | |
float2 uv_Splat2 : TEXCOORD2; | |
float2 uv_Splat3 : TEXCOORD3; | |
}; | |
struct VS_CONTROL_POINT_OUTPUT | |
{ | |
float4 position : SV_POSITION; | |
float3 normal : NORMAL; | |
float2 uv_Splat0 : TEXCOORD0; | |
float2 uv_Splat1 : TEXCOORD1; | |
float2 uv_Splat2 : TEXCOORD2; | |
float2 uv_Splat3 : TEXCOORD3; | |
float2 tc_Control : COLOR; | |
float4 _ShadowCoord : TEXCOORD4; | |
}; | |
struct HS_CONSTANT_DATA_OUTPUT | |
{ | |
float edge[3] : SV_TessFactor; | |
float inside : SV_InsideTessFactor; | |
}; | |
float4 ComputeScreenPos (float4 p) | |
{ | |
float4 o = p * 0.5; | |
o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w; | |
o.zw = p.zw; | |
return o; | |
} | |
VS_CONTROL_POINT_OUTPUT vertex_shader (APPDATA i) | |
{ | |
VS_CONTROL_POINT_OUTPUT vs; | |
vs.position = i.vertex; | |
vs.normal = i.normal; | |
vs.uv_Splat0 = i.uv_Splat0; | |
vs.uv_Splat1 = i.uv_Splat1; | |
vs.uv_Splat2 = i.uv_Splat2; | |
vs.uv_Splat3 = i.uv_Splat3; | |
vs.tc_Control = i.tc_Control; | |
vs._ShadowCoord = ComputeScreenPos(vs.position); | |
return vs; | |
} | |
HS_CONSTANT_DATA_OUTPUT constantsHS (InputPatch<VS_CONTROL_POINT_OUTPUT,3> V, uint PatchID : SV_PrimitiveID) | |
{ | |
HS_CONSTANT_DATA_OUTPUT output = (HS_CONSTANT_DATA_OUTPUT)0; | |
// float2 uv = (V[0].uv_Splat0 + V[1].uv_Splat0 + V[2].uv_Splat0) / 3.0; | |
float2 uv = V[0].uv_Splat0; | |
float factor = tex2Dlod(_TessellationMap,float4(uv,0,0)).r ; | |
output.edge[0] = output.edge[1] = output.edge[2] = lerp(1.0,64.0,factor); | |
output.inside = lerp(1.0,64.0,factor); | |
return output; | |
} | |
[domain("tri")] | |
[partitioning("integer")] | |
[outputtopology("triangle_cw")] | |
[patchconstantfunc("constantsHS")] | |
[outputcontrolpoints(3)] | |
VS_CONTROL_POINT_OUTPUT hull_shader (InputPatch<VS_CONTROL_POINT_OUTPUT,3> V, uint ID : SV_OutputControlPointID) | |
{ | |
return V[ID]; | |
} | |
[domain("tri")] | |
VS_CONTROL_POINT_OUTPUT domain_shader (HS_CONSTANT_DATA_OUTPUT input, const OutputPatch<VS_CONTROL_POINT_OUTPUT,3> P, float3 K : SV_DomainLocation) | |
{ | |
APPDATA ds; | |
ds.vertex = UnityObjectToClipPos(P[0].position*K.x + P[1].position*K.y + P[2].position*K.z); | |
ds.normal = (P[0].normal*K.x + P[1].normal*K.y + P[2].normal*K.z); | |
ds.uv_Splat0 = (P[0].uv_Splat0*K.x + P[1].uv_Splat0*K.y + P[2].uv_Splat0*K.z)*_Splat0_ST.xy+_Splat0_ST.zw; | |
ds.uv_Splat1 = (P[0].uv_Splat1*K.x + P[1].uv_Splat1*K.y + P[2].uv_Splat1*K.z)*_Splat1_ST.xy+_Splat1_ST.zw; | |
ds.uv_Splat2 = (P[0].uv_Splat2*K.x + P[1].uv_Splat2*K.y + P[2].uv_Splat2*K.z)*_Splat2_ST.xy+_Splat2_ST.zw; | |
ds.uv_Splat3 = (P[0].uv_Splat3*K.x + P[1].uv_Splat3*K.y + P[2].uv_Splat3*K.z)*_Splat3_ST.xy+_Splat3_ST.zw; | |
ds.tc_Control = (P[0].uv_Splat0*K.x + P[1].uv_Splat0*K.y + P[2].uv_Splat0*K.z)*_Control_ST.xy+_Control_ST.zw; | |
return vertex_shader(ds); | |
} | |
float4 pixel_shader (VS_CONTROL_POINT_OUTPUT ps) : SV_Target | |
{ | |
float3 normal = normalize(mul((float3x3)unity_ObjectToWorld,ps.normal)); | |
float4 tangent = float4 (cross(ps.normal, float3(0,0,1)),-1); | |
tangent.xyz = normalize(mul((float3x3)unity_ObjectToWorld,tangent.xyz)); | |
float3 binormal = normalize(cross(normal,tangent)*tangent.w); | |
float4 splat_control = tex2D (_Control, ps.tc_Control); | |
float weight = dot(splat_control, half4(1,1,1,1)); | |
clip(weight == 0.0f ? -1 : 1); | |
splat_control /= (weight + 1e-3f); | |
float3 color = splat_control.r * tex2D (_Splat0, ps.uv_Splat0).rgb; | |
color += splat_control.g * tex2D (_Splat1, ps.uv_Splat1).rgb; | |
color += splat_control.b * tex2D (_Splat2, ps.uv_Splat2).rgb; | |
color += splat_control.a * tex2D (_Splat3, ps.uv_Splat3).rgb; | |
float4 nrm = splat_control.r * tex2D(_Normal0, ps.uv_Splat0); | |
nrm += splat_control.g * tex2D(_Normal1, ps.uv_Splat1); | |
nrm += splat_control.b * tex2D(_Normal2, ps.uv_Splat2); | |
nrm += splat_control.a * tex2D(_Normal3, ps.uv_Splat3); | |
nrm.rgb = float3(2.0*nrm.ag-1.0, 0.0); | |
nrm.b = sqrt(1.0 - dot(nrm.rgb,nrm.rgb)); | |
float3x3 tbn = float3x3(tangent.xyz,binormal,normal); | |
float attenuation = SHADOW_ATTENUATION(ps); | |
float3 AmbientLight = UNITY_LIGHTMODEL_AMBIENT; | |
float3 LightDirection = normalize(_WorldSpaceLightPos0.xyz); | |
float3 LightColor = _LightColor0.xyz*attenuation; | |
float3 NormalDirection = normalize(mul(nrm.rgb, tbn)); | |
float3 diffuse = max(dot(LightDirection, NormalDirection),0.0) * LightColor + AmbientLight; | |
return float4(color*weight*diffuse,1.0); | |
} | |
ENDCG | |
} | |
} | |
FallBack "Diffuse" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment