#ifndef ENKI_BILAL_INCLUDED #define ENKI_BILAL_INCLUDED #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" #include "Assets/_Content/Shaders/Include/Noises.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/AmbientOcclusion.hlsl" float2 RotateUV(float2 UV, float2 Pivot, float Angle) { float s = sin(Angle); float c = cos(Angle); UV -= Pivot; float2 rotated = float2( UV.x * c - UV.y * s, UV.x * s + UV.y * c ); return rotated + Pivot; } float3 GetScale(float3 PivotWS) { return float3 ( length(TransformObjectToWorld(float3(1, 0, 0)) - PivotWS), length(TransformObjectToWorld(float3(0, 1, 0)) - PivotWS), length(TransformObjectToWorld(float3(0, 0, 1)) - PivotWS) ); } float GetShadow(float3 PositionWS) { float4 shadowCoord = TransformWorldToShadowCoord(PositionWS); Light mainLight = GetMainLight(shadowCoord); float shadow = 1 - mainLight.shadowAttenuation; #if defined(_ADDITIONAL_LIGHTS) uint lightsCount = GetAdditionalLightsCount(); [loop] for (uint i = 0; i < lightsCount; i++) { Light light = GetAdditionalLight(i, PositionWS); shadow = max(shadow, 1 - light.shadowAttenuation); } #endif return saturate(shadow); } void GetDetailLOD ( float Depth, float DetailSize, float LODJitter, out float DetailSizeA, out float DetailSizeB, out float LODBlend ) { const float lodRatio = 4; const float lodSize = DetailSize / 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); DetailSizeA = lodSize * pow(lodRatio, lodFloor); DetailSizeB = 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 DetailSize, 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 detailSizeA; float detailSizeB; float lodBlend; GetDetailLOD ( Depth, DetailSize, lodJitter, detailSizeA, detailSizeB, lodBlend ); float4 detailA = SampleBombedTexture ( DetailTex, projections.uv[i] / detailSizeA ); float4 detailB = SampleBombedTexture ( DetailTex, projections.uv[i] / detailSizeB ); detail += lerp(detailA, detailB, lodBlend) * mask; totalMask += mask; } return detail / max(totalMask, 1e-5); } void EnkiBillal_float ( float4 Color, UnityTexture2D DetailTex, float2 ScreenUV, float3 PositionWS, float3 NormalWS, float ProjectionsBlend, float DetailSize, uint FogUse, float4 FogColor, float FogMin, float FogMax, out float3 Output, out float Alpha ) { // Common float depth = length(PositionWS - _WorldSpaceCameraPos.xyz); float3 pivotWS = TransformObjectToWorld(float3(0, 0, 0)); float3 scale = GetScale(pivotWS); float3 positionOS = TransformWorldToObject(PositionWS) * scale; float3 normalOS = normalize(TransformWorldToObjectDir(NormalWS)); //float ao = GetScreenSpaceAmbientOcclusion(ScreenUV).directAmbientOcclusion; // Shadow float shadow = GetShadow(PositionWS); float shadowAtten = Remap(1, 0, .6, 1, shadow); // Detail float4 detail = SampleProjectedDetailLOD ( DetailTex, positionOS, normalOS, ProjectionsBlend, DetailSize, depth ); float detailMask = smoothstep(0, .8, detail.a); // Fog // Output Output = Color.rgb; Output = lerp(Output.rgb, detail.rgb, detailMask); if (FogUse) { Output = lerp(Output.rgb, FogColor.rgb, smoothstep(FogMin, FogMax, depth) * FogColor.a); } Alpha = Color.a; } #endif