Shader "Hidden/HDRP/Sky/HDRISky" { HLSLINCLUDE #pragma vertex Vert #pragma editor_sync_compilation #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch #define LIGHTLOOP_DISABLE_TILE_AND_CLUSTER #pragma multi_compile_local _ SKY_MOTION #pragma multi_compile_local _ USE_FLOWMAP #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile SHADOW_LOW SHADOW_MEDIUM SHADOW_HIGH #pragma multi_compile USE_FPTL_LIGHTLIST USE_CLUSTERED_LIGHTLIST #define ATTRIBUTES_NEED_NORMAL #define ATTRIBUTES_NEED_TANGENT #define VARYINGS_NEED_POSITION_WS #define VARYINGS_NEED_TANGENT_TO_WORLD #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl" #define SHADERPASS SHADERPASS_FORWARD_UNLIT #define HAS_LIGHTLOOP #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonLighting.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyUtils.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/SDF2D.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesFunctions.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/HDShadow.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoopDef.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/PunctualLightCommon.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/HDShadowLoop.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/NormalBuffer.hlsl" TEXTURECUBE(_Cubemap); SAMPLER(sampler_Cubemap); TEXTURE2D(_Flowmap); SAMPLER(sampler_Flowmap); float4 _SkyParam; // x exposure, y multiplier, zw rotation (cosPhi and sinPhi) float4 _BackplateParameters0; // xy: scale, z: groundLevel, w: projectionDistance float4 _BackplateParameters1; // x: BackplateType, y: BlendAmount, zw: backplate rotation (cosPhi_plate, sinPhi_plate) float4 _BackplateParameters2; // xy: BackplateTextureRotation (cos/sin), zw: Backplate Texture Offset float3 _BackplateShadowTint; // xyz: ShadowTint uint _BackplateShadowFilter; float4 _FlowmapParam; // x upper hemisphere only, y scroll factor, zw scroll direction (cosPhi and sinPhi) #define _Intensity _SkyParam.x #define _CosPhi _SkyParam.z #define _SinPhi _SkyParam.w #define _CosSinPhi _SkyParam.zw #define _Scales _BackplateParameters0.xy #define _ScaleX _BackplateParameters0.x #define _ScaleY _BackplateParameters0.y #define _GroundLevel _BackplateParameters0.z #define _ProjectionDistance _BackplateParameters0.w #define _BackplateType _BackplateParameters1.x #define _BlendAmount _BackplateParameters1.y #define _CosPhiPlate _BackplateParameters1.z #define _SinPhiPlate _BackplateParameters1.w #define _CosSinPhiPlate _BackplateParameters1.zw #define _CosPhiPlateTex _BackplateParameters2.x #define _SinPhiPlateTex _BackplateParameters2.y #define _CosSinPhiPlateTex _BackplateParameters2.xy #define _OffsetTexX _BackplateParameters2.z #define _OffsetTexY _BackplateParameters2.w #define _OffsetTex _BackplateParameters2.zw #define _ShadowTint _BackplateShadowTint.rgb #define _ShadowFilter _BackplateShadowFilter #define _UpperHemisphere _FlowmapParam.x #define _ScrollFactor _FlowmapParam.y #define _ScrollDirection _FlowmapParam.zw struct Attributes { uint vertexID : SV_VertexID; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; UNITY_VERTEX_OUTPUT_STEREO }; Varyings Vert(Attributes input) { Varyings output; UNITY_SETUP_INSTANCE_ID(input); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID, UNITY_RAW_FAR_CLIP_VALUE); return output; } float3 RotationUp(float3 p, float2 cos_sin) { float3 rotDirX = float3(cos_sin.x, 0, -cos_sin.y); float3 rotDirY = float3(cos_sin.y, 0, cos_sin.x); return float3(dot(rotDirX, p), p.y, dot(rotDirY, p)); } // TODO: cf. dir.y == 0 float3 GetPositionOnInfinitePlane(float3 dir) { const float alpha = (_GroundLevel - _WorldSpaceCameraPos.y)/dir.y; return _WorldSpaceCameraPos + alpha*dir; } float GetSDF(out float scale, float2 position) { position = RotationUp(float3(position.x, 0.0f, position.y), _CosSinPhiPlate).xz; if (_BackplateType == 0) // Circle { scale = _ScaleX; return CircleSDF(position, _ScaleX); } else if (_BackplateType == 1) // Rectangle { scale = min(_ScaleX, _ScaleY); return RectangleSDF(position, _Scales); } else if (_BackplateType == 2) // Ellipse { scale = min(_ScaleX, _ScaleY); return EllipseSDF(position, _Scales); } else //if (_BackplateType == 3) // Infinite backplate { scale = FLT_MAX; return CircleSDF(position, scale); } } void IsBackplateCommon(out float sdf, out float localScale, out float3 positionOnBackplatePlane, float3 dir) { positionOnBackplatePlane = GetPositionOnInfinitePlane(dir); sdf = GetSDF(localScale, positionOnBackplatePlane.xz); } bool IsHit(float sdf, float dirY) { return sdf < 0.0f && dirY < 0.0f && _WorldSpaceCameraPos.y > _GroundLevel; } bool IsBackplateHit(out float3 positionOnBackplatePlane, float3 dir) { float sdf; float localScale; IsBackplateCommon(sdf, localScale, positionOnBackplatePlane, dir); return IsHit(sdf, dir.y); } bool IsBackplateHitWithBlend(out float3 positionOnBackplatePlane, out float blend, float3 dir) { float sdf; float localScale; IsBackplateCommon(sdf, localScale, positionOnBackplatePlane, dir); blend = smoothstep(0.0f, localScale*_BlendAmount, max(-sdf, 0)); return IsHit(sdf, dir.y); } float3 GetSkyColor(float3 dir) { #if SKY_MOTION if (dir.y >= 0 || !_UpperHemisphere) { float2 alpha = frac(float2(_ScrollFactor, _ScrollFactor + 0.5)) - 0.5; #ifdef USE_FLOWMAP float3 tangent = normalize(cross(dir, float3(0.0, 1.0, 0.0))); float3 bitangent = cross(tangent, dir); float3 windDir = RotationUp(dir, _ScrollDirection); float2 flow = SAMPLE_TEXTURE2D_LOD(_Flowmap, sampler_Flowmap, GetLatLongCoords(windDir, _UpperHemisphere), 0).rg * 2.0 - 1.0; float3 dd = flow.x * tangent + flow.y * bitangent; #else float3 windDir = RotationUp(float3(0, 0, 1), _ScrollDirection); windDir.x *= -1.0; float3 dd = windDir*sin(dir.y*PI*0.5); #endif // Sample twice float3 color1 = SAMPLE_TEXTURECUBE_LOD(_Cubemap, sampler_Cubemap, dir - alpha.x*dd, 0).rgb; float3 color2 = SAMPLE_TEXTURECUBE_LOD(_Cubemap, sampler_Cubemap, dir - alpha.y*dd, 0).rgb; // Blend color samples return lerp(color1, color2, abs(2.0 * alpha.x)); } else #endif return SAMPLE_TEXTURECUBE_LOD(_Cubemap, sampler_Cubemap, dir, 0).rgb; } float4 GetColorWithRotation(float3 dir, float exposure, float2 cos_sin) { dir = RotationUp(dir, cos_sin); float3 skyColor = GetSkyColor(dir)*_Intensity*exposure; skyColor = ClampToFloat16Max(skyColor); return float4(skyColor, 1.0); } float4 RenderSky(Varyings input, float exposure) { float3 viewDirWS = GetSkyViewDirWS(input.positionCS.xy); // Reverse it to point into the scene float3 dir = -viewDirWS; return GetColorWithRotation(dir, exposure, _CosSinPhi); } float3 GetScreenSpaceAmbientOcclusionForBackplate(float2 positionSS, float NdotV, float perceptualRoughness) { float indirectAmbientOcclusion = 1.0 - LOAD_TEXTURE2D_X(_AmbientOcclusionTexture, positionSS).x; float directAmbientOcclusion = lerp(1.0, indirectAmbientOcclusion, _AmbientOcclusionParam.w); return lerp(_AmbientOcclusionParam.rgb, 1.0, directAmbientOcclusion); } float4 RenderSkyWithBackplate(Varyings input, float3 positionOnBackplate, float exposure, float3 originalDir, float blend, float depth) { // Reverse it to point into the scene float3 offset = RotationUp(float3(_OffsetTexX, 0.0, _OffsetTexY), _CosSinPhiPlate); float3 dir = positionOnBackplate - float3(0.0, _ProjectionDistance + _GroundLevel, 0.0) + offset; // No need for normalization PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw, depth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V); HDShadowContext shadowContext = InitShadowContext(); float shadow; // Use uniform directly - The float need to be cast to uint (as unity don't support to set a uint as uniform) uint renderingLayers = GetMeshRenderingLightLayer(); float3 shadow3; ShadowLoopMin(shadowContext, posInput, float3(0.0, 1.0, 0.0), _ShadowFilter, renderingLayers, shadow3); shadow = dot(shadow3, float3(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); float3 shadowColor = ComputeShadowColor(shadow, _ShadowTint, 0.0); float3 output = lerp( GetColorWithRotation(originalDir, exposure, _CosSinPhi).rgb, shadowColor * GetColorWithRotation(RotationUp(dir, _CosSinPhiPlateTex), exposure, _CosSinPhi).rgb, blend); float3 ao = GetScreenSpaceAmbientOcclusionForBackplate(posInput.positionSS, originalDir.z, 1.0); return float4(ao * output, exposure); } float4 FragBaking(Varyings input) : SV_Target { return RenderSky(input, 1.0); } float4 FragRender(Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); return RenderSky(input, GetCurrentExposureMultiplier()); } float4 RenderBackplate(Varyings input, float exposure) { float3 viewDirWS = -GetSkyViewDirWS(input.positionCS.xy); float3 finalPos; float depth; float blend; if (IsBackplateHitWithBlend(finalPos, blend, viewDirWS)) { depth = ComputeNormalizedDeviceCoordinatesWithZ(finalPos - _WorldSpaceCameraPos, UNITY_MATRIX_VP).z; } else { depth = UNITY_RAW_FAR_CLIP_VALUE; } float curDepth = LoadCameraDepth(input.positionCS.xy); if (curDepth > depth) discard; float4 results = 0; // Warning if (curDepth == UNITY_RAW_FAR_CLIP_VALUE) results = RenderSky(input, exposure); else if (curDepth <= depth) results = RenderSkyWithBackplate(input, finalPos, exposure, viewDirWS, blend, depth); return results; } float4 FragRenderBackplate(Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); return RenderBackplate(input, GetCurrentExposureMultiplier()); } float GetDepthWithBackplate(Varyings input) { float3 viewDirWS = -GetSkyViewDirWS(input.positionCS.xy); float3 finalPos; float depth; if (IsBackplateHit(finalPos, viewDirWS)) { depth = ComputeNormalizedDeviceCoordinatesWithZ(finalPos - _WorldSpaceCameraPos, UNITY_MATRIX_VP).z; } else { depth = UNITY_RAW_FAR_CLIP_VALUE; } return depth; } float4 FragRenderBackplateDepth(Varyings input, out float depth : SV_Depth) : SV_Target0 { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); depth = GetDepthWithBackplate(input); NormalData normalData; normalData.normalWS = float3(0, 1, 0); normalData.perceptualRoughness = 1.0f; float4 gbufferNormal = 0; if (depth != UNITY_RAW_FAR_CLIP_VALUE) EncodeIntoNormalBuffer(normalData, gbufferNormal); return gbufferNormal; } ENDHLSL SubShader { // Regular HDRI Sky // For cubemap Pass { ZWrite Off ZTest Always Blend Off Cull Off HLSLPROGRAM #pragma fragment FragBaking ENDHLSL } // For fullscreen Sky Pass { ZWrite Off ZTest LEqual Blend Off Cull Off HLSLPROGRAM #pragma fragment FragRender ENDHLSL } // For fullscreen Sky with Backplate Pass { ZWrite Off ZTest Always Blend Off Cull Off HLSLPROGRAM #pragma fragment FragRenderBackplate ENDHLSL } // DepthOnly For fullscreen Sky with Backplate Pass { ZWrite On ZTest LEqual Blend Off Cull Off HLSLPROGRAM #pragma fragment FragRenderBackplateDepth ENDHLSL } } Fallback Off }