//Stylized Water 2 //Staggart Creations (http://staggart.xyz) //Copyright protected under Unity Asset Store EULA #if defined(SHADER_API_XBOXONE) || defined(SHADER_API_PSSL) // AMD recommends this value for GCN http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/05/GCNPerformanceTweets.pdf #define MAX_TESSELLATION_FACTORS 15.0 #else #define MAX_TESSELLATION_FACTORS 64.0 #endif #if defined(SHADER_API_GLES2) #warning Current graphics API does not support tessellation, falling back to non-tessellated shader automatically. #else #define UNITY_CAN_COMPILE_TESSELLATION #endif struct Attributes { float4 positionOS : POSITION; float4 normalOS : NORMAL; float4 tangentOS : TANGENT; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { half fogFactor : TEXCOORD1; //wPos.x in w-component float4 normalWS : NORMAL; //wPos.y in w-component float4 tangent : TANGENT; //wPos.z in w-component float4 bitangent : TEXCOORD4; float4 positionNDC : TEXCOORD5; float4 positionCS : SV_POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct TessellationFactors { float edge[3] : SV_TessFactor; float inside : SV_InsideTessFactor; }; struct VertexControl { float4 positionOS : INTERNALTESSPOS; float4 normalOS : NORMAL; float4 tangentOS : TANGENT; UNITY_VERTEX_INPUT_INSTANCE_ID }; VertexControl VertexTessellation(Attributes input) { VertexControl output; UNITY_SETUP_INSTANCE_ID(input); UNITY_TRANSFER_INSTANCE_ID(input, output); output.positionOS = input.positionOS; output.normalOS = input.normalOS; output.tangentOS = input.tangentOS; return output; } float CalcDistanceTessFactor(float4 positionOS, float minDist, float maxDist, float tess) { float3 positionWS = TransformObjectToWorld(positionOS.xyz).xyz; float dist = distance(positionWS, GetCurrentViewPosition()); float f = (1.0-saturate((dist - minDist) / (maxDist - minDist)) + 0.001) * tess; return f; } float4 CalcTriEdgeTessFactors (float3 triVertexFactors) { float4 tess; tess.x = 0.5 * (triVertexFactors.y + triVertexFactors.z); tess.y = 0.5 * (triVertexFactors.x + triVertexFactors.z); tess.z = 0.5 * (triVertexFactors.x + triVertexFactors.y); tess.w = (triVertexFactors.x + triVertexFactors.y + triVertexFactors.z) / 3.0f; return tess; } float4 DistanceBasedTess(float4 v0, float4 v1, float4 v2, float tess, float minDist, float maxDist) { float3 f; f.x = CalcDistanceTessFactor(v0, minDist, maxDist, tess); f.y = CalcDistanceTessFactor(v1, minDist, maxDist, tess); f.z = CalcDistanceTessFactor(v2, minDist, maxDist, tess); //Don't use the Core RP version, creates cracks on edges return CalcTriEdgeTessFactors(f); } TessellationFactors HullConstant(InputPatch patch) { TessellationFactors output; float4 tf = DistanceBasedTess(patch[0].positionOS, patch[1].positionOS, patch[2].positionOS, _TessValue, _TessMin, _TessMax); UNITY_SETUP_INSTANCE_ID(patch[0]); output.edge[0] = tf.x; output.edge[1] = tf.y; output.edge[2] = tf.z; output.inside = tf.w; return output; } [maxtessfactor(MAX_TESSELLATION_FACTORS)] [domain("tri")] [partitioning("fractional_odd")] [outputtopology("triangle_cw")] [patchconstantfunc("HullConstant")] [outputcontrolpoints(3)] VertexControl Hull(InputPatch input, uint id : SV_OutputControlPointID) { return input[id]; } #define TESSELLATION_INTERPOLATE_BARY_URP(name, bary) IN.name = input[0].name * bary.x + input[1].name * bary.y + input[2].name * bary.z [domain("tri")] Varyings Domain(TessellationFactors factors, OutputPatch input, float3 baryCoords : SV_DomainLocation) { Attributes IN = (Attributes)0; Varyings output = (Varyings)0; TESSELLATION_INTERPOLATE_BARY_URP(positionOS, baryCoords); TESSELLATION_INTERPOLATE_BARY_URP(normalOS, baryCoords); TESSELLATION_INTERPOLATE_BARY_URP(tangentOS, baryCoords); //Tessellation does not work entirely correct with GPU instancing UNITY_TRANSFER_INSTANCE_ID(input[0], output); VertexNormalInputs normalInput = GetVertexNormalInputs(IN.normalOS.xyz, IN.tangentOS); float3 positionWS = TransformObjectToWorld(IN.positionOS.xyz); WaveInfo waves = GetWaveInfo(positionWS.xz, TIME_VERTEX * _WaveSpeed, _WaveHeight, 1, _WaveFadeDistance.x, _WaveFadeDistance.y); positionWS += waves.position; float4 positionCS = TransformWorldToHClip(positionWS); output.positionCS = positionCS; float4 ndc = positionCS * 0.5f; ndc.xy = float2(ndc.x, ndc.y * _ProjectionParams.x) + ndc.w; ndc.zw = positionCS.zw; output.positionNDC = ndc; output.normalWS = float4(waves.normal, positionWS.x); output.tangent = float4(normalInput.tangentWS, positionWS.y); output.bitangent = float4(normalInput.bitangentWS, positionWS.z); output.fogFactor = ComputeFogFactor(positionCS.z); return output; }