Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
- Shader "Custom/Merged Shader" {
- Properties {
- _Color("Main Color", Color) = (0.5,0.5,0.5,1)
- _MainTex("Top Texture", 2D) = "white" {}
- _MainTexSide("Side/Bottom Texture", 2D) = "white" {}
- _Ramp("Toon Ramp (RGB)", 2D) = "gray" {}
- _Normal("Normal/Noise", 2D) = "bump" {}
- _Scale("Top Scale", Range(-2,2)) = 1
- _SideScale("Side Scale", Range(-2,2)) = 1
- _NoiseScale("Noise Scale", Range(-2,2)) = 1
- _TopSpread("TopSpread", Range(-2,2)) = 1
- _EdgeWidth("EdgeWidth", Range(0,0.5)) = 1
- _RimPower("Rim Power", Range(-2,20)) = 1
- _RimColor("Rim Color Top", Color) = (0.5,0.5,0.5,1)
- _RimColor2("Rim Color Side/Bottom", Color) = (0.5,0.5,0.5,1)
- _MeltY("Melt Y", Float) = 0.0
- _MeltDistance("Melt Distance", Float) = 1.0
- _MeltCurve("Melt Curve", Range(1.0,10.0)) = 2.0
- _Tess("Tessellation Amount", Range( 1, 32 )) = 10
- }
- SubShader {
- Tags { "RenderType"="Opaque" }
- LOD 200
- CGPROGRAM
- // add the tessellate function here
- #pragma surface surf ToonRamp fullforwardshadows vertex:disp addshadow tessellate:tessDistance nolightmap
- // to use tessellation we must target shader model 4.6 and up
- #pragma target 4.6
- // include Unity's tessellation code
- #include "Tessellation.cginc"
- //#pragma surface surf ToonRamp
- sampler2D _Ramp;
- #pragma lighting ToonRamp exclude_path:prepass
- inline half4 LightingToonRamp(SurfaceOutput s, half3 lightDir, half atten)
- {
- #ifndef USING_DIRECTIONAL_LIGHT
- lightDir = normalize(lightDir);
- #endif
- half d = dot(s.Normal, lightDir)*0.5 + 0.5;
- half3 ramp = tex2D(_Ramp, float2(d,d)).rgb;
- half4 c;
- c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
- c.a = 0;
- return c;
- }
- sampler2D _MainTex, _MainTexSide, _Normal;
- float4 _Color, _RimColor, _RimColor2;
- float _RimPower;
- float _TopSpread, _EdgeWidth;
- float _Scale, _SideScale, _NoiseScale;
- struct Input {
- float2 uv_MainTex : TEXCOORD0;
- float3 worldPos; // world position built-in value
- float3 worldNormal; // world normal built-in value
- float3 viewDir;// view direction built-in value we're using for rimlight
- };
- //half _Glossiness;
- //half _Metallic;
- //fixed4 _Color;
- half _MeltY;
- half _MeltDistance;
- half _MeltCurve;
- float _Tess;
- struct appdata {
- float4 vertex : POSITION;
- float4 tangent : TANGENT;
- float3 normal : NORMAL;
- float2 texcoord : TEXCOORD0;
- };
- // A modified version of Unity's UnityCalcDistanceTessFactor that only adds tess verts if the vertex is in the melt range
- float MeltCalcDistanceTessFactor (float4 vertex, float minDist, float maxDist, float tess)
- {
- float3 wpos = mul(unity_ObjectToWorld,vertex).xyz;
- float dist = distance (wpos, _WorldSpaceCameraPos);
- float f = clamp(1.0 - (dist - minDist) / (maxDist - minDist), 0.01, 1.0);
- float melt = (( wpos.y - _MeltY ) / _MeltDistance);
- // calculate the melt for the world position
- // in our normal vert function we saturate this subtract it from 1 so verts near the ground are 1 and join the mesh at 0
- // we only care if the object is in the 'melt' range, so any value between 0 & 1, regardless of the sign.
- // will add a threshold too so verts near the edges are tessellated too
- if( melt < -0.1 || melt > 1.1 )
- {
- f = 0.01; // set the value to the lower end of the clamp
- }
- // move the tess multiply here for clarity
- return f * tess;
- }
- // A modified version of Unity's UnityDistanceBasedTess to run our version of TessFactor
- // Distance based tessellation:
- // Tessellation level is "tess" before "minDist" from camera, and linearly decreases to 1
- // up to "maxDist" from camera.
- float4 MeltDistanceBasedTess (float4 v0, float4 v1, float4 v2, float minDist, float maxDist, float tess)
- {
- float3 f;
- f.x = MeltCalcDistanceTessFactor (v0,minDist,maxDist,tess);
- f.y = MeltCalcDistanceTessFactor (v1,minDist,maxDist,tess);
- f.z = MeltCalcDistanceTessFactor (v2,minDist,maxDist,tess);
- return UnityCalcTriEdgeTessFactors (f);
- }
- float4 tessDistance(appdata v0, appdata v1, appdata v2)
- {
- float minDist = 10.0;
- float maxDist = 25.0;
- // this unity function scales how much tessellation based on how close the camera is
- // objects further away keep the same vert count as before
- // the last parameter is the factor of tessellation, increasing it in the material inspector increases verts created
- return MeltDistanceBasedTess(v0.vertex, v1.vertex, v2.vertex, minDist, maxDist, _Tess);
- }
- float4 getNewVertPosition( float4 objectSpacePosition, float3 objectSpaceNormal )
- {
- float4 worldSpacePosition = mul( unity_ObjectToWorld, objectSpacePosition );
- float4 worldSpaceNormal = mul( unity_ObjectToWorld, float4(objectSpaceNormal,0) );
- float melt = ( worldSpacePosition.y - _MeltY ) / _MeltDistance;
- melt = 1 - saturate( melt );
- melt = pow( melt, _MeltCurve );
- worldSpacePosition.xz += worldSpaceNormal.xz * melt;
- return mul( unity_WorldToObject, worldSpacePosition );
- }
- void disp( inout appdata v )
- {
- float4 vertPosition = getNewVertPosition( v.vertex, v.normal );
- float4 bitangent = float4( cross( v.normal, v.tangent ), 0 );
- float vertOffset = 0.01;
- float4 v1 = getNewVertPosition( v.vertex + v.tangent * vertOffset, v.normal );
- float4 v2 = getNewVertPosition( v.vertex + bitangent * vertOffset, v.normal );
- float4 newTangent = v1 - vertPosition;
- float4 newBitangent = v2 - vertPosition;
- v.normal = cross( newTangent, newBitangent );
- v.vertex = vertPosition;
- }
- void surf (Input IN, inout SurfaceOutput o) {
- // clamp (saturate) and increase(pow) the worldnormal value to use as a blend between the projected textures
- float3 blendNormal = saturate(pow(IN.worldNormal * 1.4,4));
- // normal noise triplanar for x, y, z sides
- float3 xn = tex2D(_Normal, IN.worldPos.zy * _NoiseScale);
- float3 yn = tex2D(_Normal, IN.worldPos.zx * _NoiseScale);
- float3 zn = tex2D(_Normal, IN.worldPos.xy * _NoiseScale);
- // lerped together all sides for noise texture
- float3 noisetexture = zn;
- noisetexture = lerp(noisetexture, xn, blendNormal.x);
- noisetexture = lerp(noisetexture, yn, blendNormal.y);
- // triplanar for top texture for x, y, z sides
- float3 xm = tex2D(_MainTex, IN.worldPos.zy * _Scale);
- float3 zm = tex2D(_MainTex, IN.worldPos.xy * _Scale);
- float3 ym = tex2D(_MainTex, IN.worldPos.zx * _Scale);
- // lerped together all sides for top texture
- float3 toptexture = zm;
- toptexture = lerp(toptexture, xm, blendNormal.x);
- toptexture = lerp(toptexture, ym, blendNormal.y);
- // triplanar for side and bottom texture, x,y,z sides
- float3 x = tex2D(_MainTexSide, IN.worldPos.zy * _SideScale);
- float3 y = tex2D(_MainTexSide, IN.worldPos.zx * _SideScale);
- float3 z = tex2D(_MainTexSide, IN.worldPos.xy * _SideScale);
- // lerped together all sides for side bottom texture
- float3 sidetexture = z;
- sidetexture = lerp(sidetexture, x, blendNormal.x);
- sidetexture = lerp(sidetexture, y, blendNormal.y);
- // rim light for fuzzy top texture
- half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal * noisetexture));
- // rim light for side/bottom texture
- half rim2 = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
- // dot product of world normal and surface normal + noise
- float worldNormalDotNoise = dot(o.Normal + (noisetexture.y + (noisetexture * 0.5)), IN.worldNormal.y);
- // if dot product is higher than the top spread slider, multiplied by triplanar mapped top texture
- // step is replacing an if statement to avoid branching :
- // if (worldNormalDotNoise > _TopSpread{ o.Albedo = toptexture}
- float3 topTextureResult = step(_TopSpread, worldNormalDotNoise) * toptexture;
- // if dot product is lower than the top spread slider, multiplied by triplanar mapped side/bottom texture
- float3 sideTextureResult = step(worldNormalDotNoise, _TopSpread) * sidetexture;
- // if dot product is in between the two, make the texture darker
- float3 topTextureEdgeResult = step(_TopSpread, worldNormalDotNoise) * step(worldNormalDotNoise, _TopSpread + _EdgeWidth) * -0.15;
- // final albedo color
- o.Albedo = topTextureResult + sideTextureResult + topTextureEdgeResult;
- o.Albedo *= _Color;
- // adding the fuzzy rimlight(rim) on the top texture, and the harder rimlight (rim2) on the side/bottom texture
- o.Emission = step(_TopSpread, worldNormalDotNoise) * _RimColor.rgb * pow(rim, _RimPower) + step(worldNormalDotNoise, _TopSpread) * _RimColor2.rgb * pow(rim2, _RimPower);
- }
- ENDCG
- }
- FallBack "Diffuse"
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement