#ifndef ENKI_BILLAL_INCLUDED #define ENKI_BILLAL_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); } 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 Blend ) { 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(Blend)); 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; } void EnkiBillal_float ( float4 Color, UnityTexture2D DetailTex, float2 ScreenUV, float3 PositionWS, float3 NormalWS, float ProjectionsBlend, out float3 Output ) { // 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 = 0; ProjectionData projections = GetProjections ( positionOS, normalOS, ProjectionsBlend ); float totalMask = 0; [unroll] for (int i = 0; i < 7; i++) { float mask = projections.mask[i]; detail += SampleBombedTexture ( DetailTex, projections.uv[i] ) * mask; totalMask += mask; } detail /= max(totalMask, 1e-5); // Output Output = Color.rgb; Output = lerp(Color.rgb, Color.rgb * detail.rgb, detail.a); //Output *= shadowAtten; } #endif