#ifndef DETAILS_HLSL #define DETAILS_HLSL #include "Assets/_Content/Shaders/Include/Utilities.hlsl" void GetDetailLOD ( float Depth, float DetailSizeA, float LODJitter, out float DetailSizeAA, out float DetailSizeAB, out float LODBlend ) { const float lodRatio = 4; const float lodSize = DetailSizeA / lodRatio * 2; float dist = max(Depth, 1e-5); float lod = log(dist) / log(lodRatio) + LODJitter; // log2(dist); float lodFloor = floor(lod); float lodFrac = lod - lodFloor; LODBlend = lodFrac * lodFrac * (3 - 2 * lodFrac); DetailSizeAA = lodSize * pow(lodRatio, lodFloor); DetailSizeAB = lodSize * pow(lodRatio, lodFloor + 1); } float4 SampleBombedTexture ( UnityTexture2D Tex, float2 UV ) { const float cellBlend = 4; float2 cell = floor(UV); float2 local = frac(UV); float4 result = 0; float weightSum = 0; [unroll] for (int y = 0; y < 2; y++) { [unroll] for (int x = 0; x < 2; x++) { float2 currentCell = cell + float2(x, y); float2 randomOffset = (Hash2D(currentCell) - .5) * .35; float randomAngle = Hash1From2D(currentCell) * TWO_PI; float2 center = float2(x, y) + randomOffset; float2 delta = local - center; float weight = pow(saturate(1 - abs(delta.x)), cellBlend) * pow(saturate(1 - abs(delta.y)), cellBlend); float2 sampleUV = UV + randomOffset; sampleUV = RotateUV ( sampleUV, currentCell + .5, randomAngle ); result += Tex.tex.Sample ( Tex.samplerstate, sampleUV ) * weight; weightSum += weight; } } return result / max(weightSum, 1e-5); } struct ProjectionData { float2 uv[7]; float mask[7]; }; ProjectionData GetProjections ( float3 PositionOS, float3 NormalOS, float ProjectionBlend ) { ProjectionData data; float3 normal = normalize(NormalOS); float3 projectionNormals[7] = { normalize(float3(1, 1, 1)), normalize(float3(-1, 1, 1)), normalize(float3(1, -1, 1)), normalize(float3(-1, -1, 1)), float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1) }; float sharpness = lerp(2, 32, saturate(ProjectionBlend)); float maskSum = 0; [unroll] for (int i = 0; i < 7; i++) { float3 n = projectionNormals[i]; float d = abs(dot(normal, n)); data.mask[i] = pow(saturate(d), sharpness); maskSum += data.mask[i]; float3 up = abs(n.y) < .999 ? float3(0, 1, 0) : float3(1, 0, 0); float3 tangent = normalize(cross(up, n)); float3 bitangent = normalize(cross(n, tangent)); data.uv[i] = float2 ( dot(PositionOS, tangent), dot(PositionOS, bitangent) ); } maskSum = max(maskSum, 1e-5); [unroll] for (int i = 0; i < 7; i++) data.mask[i] /= maskSum; return data; } float4 SampleProjectedDetailLOD ( UnityTexture2D DetailTex, float3 PositionOS, float3 NormalOS, float ProjectionBlend, float DetailSizeA, float Depth ) { const float lodJitterStrength = .8; const float lodJitterSize = 1.5; float4 detail = 0; float totalMask = 0; ProjectionData projections = GetProjections ( PositionOS, NormalOS, ProjectionBlend ); [unroll] for (int i = 0; i < 7; i++) { float mask = projections.mask[i]; float lodJitter = (Hash1From2D(floor(projections.uv[i] * lodJitterSize) + i * 17.13) - .5) * lodJitterStrength; float DetailSizeAA; float DetailSizeAB; float lodBlend; GetDetailLOD ( Depth, DetailSizeA, lodJitter, DetailSizeAA, DetailSizeAB, lodBlend ); float4 detailA = SampleBombedTexture ( DetailTex, projections.uv[i] / DetailSizeAA ); float4 detailB = SampleBombedTexture ( DetailTex, projections.uv[i] / DetailSizeAB ); detail += lerp(detailA, detailB, lodBlend) * mask; totalMask += mask; } return detail / max(totalMask, 1e-5); } #endif