diff --git a/Content/Editor/Camera/M_Camera.flax b/Content/Editor/Camera/M_Camera.flax index 7dc7ae92d..96a7cfe6f 100644 --- a/Content/Editor/Camera/M_Camera.flax +++ b/Content/Editor/Camera/M_Camera.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e3719d6696fc99d392e692c5a33c3513194ea9b0dcbe4b912d1fd03ff6806de8 -size 29740 +oid sha256:f74c9fbe0a662098539cce65d1f3d0d4804344a49d78682f073596deb6cbcfbe +size 30376 diff --git a/Content/Editor/CubeTexturePreviewMaterial.flax b/Content/Editor/CubeTexturePreviewMaterial.flax index c16e7b2c2..0e20158a6 100644 --- a/Content/Editor/CubeTexturePreviewMaterial.flax +++ b/Content/Editor/CubeTexturePreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:251f631a68805a22eb485c75e23d292ca340e1c231e0b9cc2d2beb1996c39334 -size 31293 +oid sha256:ceae144560a19ab5d71296f75918719619f4d4069a96b2bc46e54dc0cb71c7db +size 31929 diff --git a/Content/Editor/DebugMaterials/DDGIDebugProbes.flax b/Content/Editor/DebugMaterials/DDGIDebugProbes.flax index dd9c206d9..60c62fba3 100644 --- a/Content/Editor/DebugMaterials/DDGIDebugProbes.flax +++ b/Content/Editor/DebugMaterials/DDGIDebugProbes.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac0e118b9cb0fe9fdcaed25a141ff036441959dcb75435d4d436d51dc5ec9dd9 -size 41695 +oid sha256:a57f6ae32a6b5b67540914583757752fee027ce187b2ff5655e1de774cdac3fb +size 41699 diff --git a/Content/Editor/DebugMaterials/SingleColor/Particle.flax b/Content/Editor/DebugMaterials/SingleColor/Particle.flax index 2e64844ee..afd40c5ef 100644 --- a/Content/Editor/DebugMaterials/SingleColor/Particle.flax +++ b/Content/Editor/DebugMaterials/SingleColor/Particle.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:90a2465be9b88b4bdd1964c33583fce00583d393e9e13135fd44533072e6efe3 -size 31900 +oid sha256:4e43c8be4f61fcb229f36663d2fe96085369d61a6cee62715bb7396e8db666b2 +size 32611 diff --git a/Content/Editor/DebugMaterials/SingleColor/Surface.flax b/Content/Editor/DebugMaterials/SingleColor/Surface.flax index 857f328a7..57be70ca1 100644 --- a/Content/Editor/DebugMaterials/SingleColor/Surface.flax +++ b/Content/Editor/DebugMaterials/SingleColor/Surface.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a8e018c5451c59c0d51005afb368267f9a37f7af02f20e2da4043298ab694c02 -size 29636 +oid sha256:5bbb29da2c223cf952b3de6c13a3001f6b0594077a19ba484f0141472fcd5929 +size 30272 diff --git a/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax b/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax index cc0df4ad4..4918d4cb0 100644 --- a/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax +++ b/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f17088e79d90261b8f630807173c4544a35558956ad4cb6ef0854f8749b5504 -size 31432 +oid sha256:50682179fbdcbfaffe882cb20c988538985a658b8080742c95316e029eafc54e +size 32068 diff --git a/Content/Editor/DefaultFontMaterial.flax b/Content/Editor/DefaultFontMaterial.flax index 7305b03a3..b63adfc39 100644 --- a/Content/Editor/DefaultFontMaterial.flax +++ b/Content/Editor/DefaultFontMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:583f8fc1103a204c64742c370e65fe9b012f03379c36b0f8fb1ed56a89c7a9ba -size 29815 +oid sha256:c018f5ec479f05333b997abad26f1bb9f633dacef883eecf69a907413f45a971 +size 30451 diff --git a/Content/Editor/Gizmo/FoliageBrushMaterial.flax b/Content/Editor/Gizmo/FoliageBrushMaterial.flax index 7be601ae2..7184acd1b 100644 --- a/Content/Editor/Gizmo/FoliageBrushMaterial.flax +++ b/Content/Editor/Gizmo/FoliageBrushMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eba32bfcb4daf4103f78ef0da45af03a39b7524609b77fc0abcf77da0a46b052 -size 35450 +oid sha256:bc20821469f9f6daad085ed8015b4ae2c096923b885ecfc45a5aa3a379957e6b +size 36086 diff --git a/Content/Editor/Gizmo/Material.flax b/Content/Editor/Gizmo/Material.flax index de6af6bf6..5375afa49 100644 --- a/Content/Editor/Gizmo/Material.flax +++ b/Content/Editor/Gizmo/Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5a38dff84bb7567a36681da8f49cdb42c2983716c9ce22066041e01981b6f38f -size 31970 +oid sha256:c7922ca3c520f573b61e4381971c4780395b897f5e170190b7c958c34bc82cc6 +size 32606 diff --git a/Content/Editor/Gizmo/MaterialWire.flax b/Content/Editor/Gizmo/MaterialWire.flax index 697c75f67..68df95b84 100644 --- a/Content/Editor/Gizmo/MaterialWire.flax +++ b/Content/Editor/Gizmo/MaterialWire.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:089c20c734028de1d6e377c1128d37af340772daee835920e0b7f2a47277306a -size 31183 +oid sha256:e7c775989c659d19d415bd739adea83f3d2e0f4ba31ffee1bbfb4a952b611a77 +size 31819 diff --git a/Content/Editor/Gizmo/SelectionOutlineMaterial.flax b/Content/Editor/Gizmo/SelectionOutlineMaterial.flax index 343b9d359..29dbc3ace 100644 --- a/Content/Editor/Gizmo/SelectionOutlineMaterial.flax +++ b/Content/Editor/Gizmo/SelectionOutlineMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2e659db97079c9e4c12ed202f8f3121ed54bc72d666ee8e26012525bf6c47952 -size 15979 +oid sha256:abeacff17a677e6559fdddc464027eae7773f48384aecfb706c2c33aac1df18d +size 15899 diff --git a/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax b/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax index 609b91ac6..7bf1d0f0c 100644 --- a/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax +++ b/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08e51480d1e5a58d89537fecc9897a32c1f641081e0ca0e53991dc431fbafd18 -size 30749 +oid sha256:903de465290b59884856eb169496b5aa76018b46af84c19a49ae491eb174eac7 +size 31385 diff --git a/Content/Editor/Highlight Material.flax b/Content/Editor/Highlight Material.flax index 21da6298d..f781fc603 100644 --- a/Content/Editor/Highlight Material.flax +++ b/Content/Editor/Highlight Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78c1b74d0c7ca3729e918ebd071b141f816792a539c1fe0a637163bba9f7de45 -size 29782 +oid sha256:deaccd404be601e04bd6e9e06c46d69016067b3e0bb310a13f0ebeda2da0a138 +size 30418 diff --git a/Content/Editor/Icons/IconsMaterial.flax b/Content/Editor/Icons/IconsMaterial.flax index fd49b5205..4f247ff1d 100644 --- a/Content/Editor/Icons/IconsMaterial.flax +++ b/Content/Editor/Icons/IconsMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b4ebf0e6605a5afb03cd3efbf1a35a8ee2d921d343a59c68c4e207ea1d37c974 -size 29710 +oid sha256:63eefd35f042a8266a7096d4b91dd22a9f066e443c862782c741f166ef7c95e2 +size 30346 diff --git a/Content/Editor/IesProfilePreviewMaterial.flax b/Content/Editor/IesProfilePreviewMaterial.flax index 3c2a05761..3e4f62c7c 100644 --- a/Content/Editor/IesProfilePreviewMaterial.flax +++ b/Content/Editor/IesProfilePreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7f011ee46428e752f6c719ab548971ae527c6536e1bf1e5de5b7cda7f901bea6 -size 18254 +oid sha256:da8bf8669e1cc74900dc4970702dfa3e096bf290ca4098080ba75e303a2f93db +size 18477 diff --git a/Content/Editor/MaterialTemplates/Surface.shader b/Content/Editor/MaterialTemplates/Surface.shader index ff88f1b40..ebf020597 100644 --- a/Content/Editor/MaterialTemplates/Surface.shader +++ b/Content/Editor/MaterialTemplates/Surface.shader @@ -617,14 +617,14 @@ void PS_Depth(PixelInput input) #if _PS_QuadOverdraw -#include "./Flax/Editor/QuadOverdraw.hlsl" +//#include "./Flax/Editor/QuadOverdraw.hlsl" // Pixel Shader function for Quad Overdraw Pass (editor-only) [earlydepthstencil] META_PS(USE_EDITOR, FEATURE_LEVEL_SM5) void PS_QuadOverdraw(float4 svPos : SV_Position, uint primId : SV_PrimitiveID) { - DoQuadOverdraw(svPos, primId); + //DoQuadOverdraw(svPos, primId); } #endif diff --git a/Content/Editor/Particles/Particle Material Color.flax b/Content/Editor/Particles/Particle Material Color.flax index afb352921..651e15f8f 100644 --- a/Content/Editor/Particles/Particle Material Color.flax +++ b/Content/Editor/Particles/Particle Material Color.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:240cf4a974876cf7d912fa13ccce11f8e2127690709cc8375dcb39019acf3d1d -size 30092 +oid sha256:f11e69104e806add833006570dc621b0746c53c430faea896b3a7badb080e8a6 +size 30803 diff --git a/Content/Editor/Particles/Smoke Material.flax b/Content/Editor/Particles/Smoke Material.flax index 66dad0416..248da9ba5 100644 --- a/Content/Editor/Particles/Smoke Material.flax +++ b/Content/Editor/Particles/Smoke Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:404950e170fecb6bdd772ca06724f11e2ae3afc737c3ae6f6d72f3cae25615ce -size 36203 +oid sha256:2aea33c284ec7e73d68fe767bcef5ff8b89590e3c96d93e6265ecfd18a23832c +size 36914 diff --git a/Content/Editor/Particles/Smoke.flax b/Content/Editor/Particles/Smoke.flax index e68821034..3450f64e4 100644 --- a/Content/Editor/Particles/Smoke.flax +++ b/Content/Editor/Particles/Smoke.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84c4ea742b6b4775bc518731ecb56d7fe202302b3bdb61f1dcdf8727ade94353 -size 16019 +oid sha256:eacbc2471d622eb8a483036f01bbbbdde25cd3ab5f9e7b3ca1ec52634e9795f6 +size 16157 diff --git a/Content/Editor/Particles/Sparks.flax b/Content/Editor/Particles/Sparks.flax index 8b076afdc..73b73b304 100644 --- a/Content/Editor/Particles/Sparks.flax +++ b/Content/Editor/Particles/Sparks.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a6dc75b65f0eb1a66b12fbe4e20091b55aed9143a8574e7a9dfc000413eb2f6 -size 15081 +oid sha256:fab2f2ed2faec08c4c834e10dc730064baa2d92142f3bd06c243a44d36dbec63 +size 15275 diff --git a/Content/Editor/SpriteMaterial.flax b/Content/Editor/SpriteMaterial.flax index 639e047a3..518dac15e 100644 --- a/Content/Editor/SpriteMaterial.flax +++ b/Content/Editor/SpriteMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:903d85af5a3f78da2ced6896d274c954fa01361f3c3b612a23834c5a6f00d3b3 -size 30828 +oid sha256:7ae78cb3278f3363b23ec5a2fbae387afbd7ecbcce1829966cfffefac5449300 +size 31464 diff --git a/Content/Editor/TexturePreviewMaterial.flax b/Content/Editor/TexturePreviewMaterial.flax index cf603fc6a..9d86a708e 100644 --- a/Content/Editor/TexturePreviewMaterial.flax +++ b/Content/Editor/TexturePreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:50c530e40174d835aa0daa1d2a0a6cc06975c173e6aa2672238891c580a4ad52 -size 10413 +oid sha256:ec2f3b0fc4bc04f965159675e45e82a7ff0c6f2ac3625636b0f0b745ef19fde4 +size 10673 diff --git a/Content/Editor/Wires Debug Material.flax b/Content/Editor/Wires Debug Material.flax index fb4722aa9..c9a30f2f0 100644 --- a/Content/Editor/Wires Debug Material.flax +++ b/Content/Editor/Wires Debug Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c99e922203b5bad2e85747216ba53790bcd8ae97fe97a575aeacfe327001a815 -size 29782 +oid sha256:eb5552c4a20c9c11a5a6733c8dfdea8f8931eccd8f4014f847884c2983b951ae +size 30418 diff --git a/Content/Engine/DefaultDeformableMaterial.flax b/Content/Engine/DefaultDeformableMaterial.flax index 7dad19bdc..48018f511 100644 --- a/Content/Engine/DefaultDeformableMaterial.flax +++ b/Content/Engine/DefaultDeformableMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:16fdcea1d354ccd230bbc25ced1763e53e51c9cd24876d2a9dcf2e448fc7d800 -size 19140 +oid sha256:71d41fd76f1366700d32d9f7c5d3f18fa75d6ba5e859f723c36e41ac2b46f69e +size 19131 diff --git a/Content/Engine/DefaultMaterial.flax b/Content/Engine/DefaultMaterial.flax index dcf11c4d9..3c2476654 100644 --- a/Content/Engine/DefaultMaterial.flax +++ b/Content/Engine/DefaultMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:54f3db43dd7c475d8f2ac439e4df0d119ebfe06f32430bb52515383b7defbc1b -size 31528 +oid sha256:476755a18369bc6a56792f56f3dfcf1b7c9c1e4b999881af86423ad778875b74 +size 32155 diff --git a/Content/Engine/DefaultTerrainMaterial.flax b/Content/Engine/DefaultTerrainMaterial.flax index c4d0b0039..f7720e532 100644 --- a/Content/Engine/DefaultTerrainMaterial.flax +++ b/Content/Engine/DefaultTerrainMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:702f071488e43af1c317f7b7b0d192b8e97f45379c24d90e8ec6f7def7294891 -size 23633 +oid sha256:7a2d8f9c7c4739de1de26b996e590bd8600a626e950770c948ec93fde0788c6f +size 23624 diff --git a/Content/Engine/SingleColorMaterial.flax b/Content/Engine/SingleColorMaterial.flax index 8dcda00ba..ee147cea2 100644 --- a/Content/Engine/SingleColorMaterial.flax +++ b/Content/Engine/SingleColorMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2cb8ff6c5c7376790725d9b9ffb698244f7977a4aa490546c2ee16e5cf6c1cfb -size 29837 +oid sha256:f1ef17a46abb31f26374c8750bd01105cb43b6bfb9cd95089ae8113856a26149 +size 30473 diff --git a/Content/Engine/SkyboxMaterial.flax b/Content/Engine/SkyboxMaterial.flax index c191813df..d7c495f6a 100644 --- a/Content/Engine/SkyboxMaterial.flax +++ b/Content/Engine/SkyboxMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2e030a81391a5b7e6d9e57d2fdb9a7402f76979df03b6e1207dbba7b316f80c7 -size 31035 +oid sha256:4e7cdcdbe88a895d76a6076f5309c4795c5119d2cca0a3c5d603cdc2834b963e +size 31671 diff --git a/Content/Shaders/GI/DDGI.flax b/Content/Shaders/GI/DDGI.flax index 1982e532e..5fea80f23 100644 --- a/Content/Shaders/GI/DDGI.flax +++ b/Content/Shaders/GI/DDGI.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f53f603799652bb3cfba5b25388fa0c7bad4745c1128d891c61ccff5bac70fb6 -size 19937 +oid sha256:220cdb9a73d181fb2dccf59de1169e57d42537b8aaf9deba495dc753fd19c8b6 +size 22031 diff --git a/Content/Shaders/GI/GlobalSurfaceAtlas.flax b/Content/Shaders/GI/GlobalSurfaceAtlas.flax index 73cdb345d..dedc2d667 100644 --- a/Content/Shaders/GI/GlobalSurfaceAtlas.flax +++ b/Content/Shaders/GI/GlobalSurfaceAtlas.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d102890fcf25252144222b53cd049d2534ce552a951daedd57afbe6ebe13398b -size 11847 +oid sha256:cd43051dd43bb23828e1f2f2001d9a2b008ebad085df44f1188a0e482f6f7e34 +size 12851 diff --git a/Content/Shaders/VolumetricFog.flax b/Content/Shaders/VolumetricFog.flax index f8e613b46..cb7fe197b 100644 --- a/Content/Shaders/VolumetricFog.flax +++ b/Content/Shaders/VolumetricFog.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b38c74ccf0bdeb69ea20b3a495df1e2b53e584982d85e5053a57c8573e65c2e6 -size 14237 +oid sha256:820a1dcf3ed2631677201e633aa759615f6afb9abcd25e99c5aa78c4d975895d +size 14257 diff --git a/Source/Shaders/Atmosphere.hlsl b/Source/Shaders/Atmosphere.hlsl index 8e1050bdb..751a2b480 100644 --- a/Source/Shaders/Atmosphere.hlsl +++ b/Source/Shaders/Atmosphere.hlsl @@ -37,7 +37,7 @@ const static float3 BetaRayleighScattering = float3(5.8e-3, 1.35e-2, 3.31e-2); / const static float HeightScaleMie = 1.2f; // 1.2 km, for Mie scattering const static float3 BetaMieScattering = float3(4e-3f, 4e-3f, 4e-3f); // Equation 4 const static float BetaRatio = 0.9f; // Figure 6, BetaMScattering/BetaMExtinction = 0.9 -const static float3 BetaMieExtinction = BetaMieScattering / BetaRatio.rrr; +const static float3 BetaMieExtinction = BetaMieScattering / BetaRatio.rrr; const static float MieG = 0.8f; // Equation 4 const static float RadiusScale = 1; @@ -83,16 +83,16 @@ Texture2D AtmosphereIrradianceTexture : register(t4); Texture3D AtmosphereInscatterTexture : register(t5); #else Texture2D AtmosphereTransmittanceTexture : register(t0); -Texture2D AtmosphereIrradianceTexture : register(t1); -Texture3D AtmosphereInscatterTexture : register(t2); +Texture2D AtmosphereIrradianceTexture : register(t1); +Texture3D AtmosphereInscatterTexture : register(t2); #endif -float2 GetTransmittanceUV(float radius, float Mu) +float2 GetTransmittanceUV(float radius, float Mu) { float u, v; #if TRANSMITTANCE_NON_LINEAR - v = sqrt((radius - RadiusGround) / (RadiusAtmosphere - RadiusGround)); - u = atan((Mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5; + v = sqrt((radius - RadiusGround) / (RadiusAtmosphere - RadiusGround)); + u = atan((Mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5; #else v = (radius - RadiusGround) / (RadiusAtmosphere - RadiusGround); u = (Mu + 0.15) / (1.0 + 0.15); @@ -100,7 +100,7 @@ float2 GetTransmittanceUV(float radius, float Mu) return float2(u, v); } -void GetTransmittanceRMuS(float2 uv, out float radius, out float MuS) +void GetTransmittanceRMuS(float2 uv, out float radius, out float MuS) { radius = uv.y; MuS = uv.x; @@ -113,14 +113,14 @@ void GetTransmittanceRMuS(float2 uv, out float radius, out float MuS) #endif } -float2 GetIrradianceUV(float radius, float MuS) +float2 GetIrradianceUV(float radius, float MuS) { float v = (radius - RadiusGround) / (RadiusAtmosphere - RadiusGround); float u = (MuS + 0.2) / (1.0 + 0.2); return float2(u, v); } -void GetIrradianceRMuS(float2 uv, out float radius, out float MuS) +void GetIrradianceRMuS(float2 uv, out float radius, out float MuS) { radius = RadiusGround + (uv.y * float(IrradianceTexHeight) - 0.5) / (float(IrradianceTexHeight) - 1.0) * (RadiusAtmosphere - RadiusGround); MuS = -0.2 + (uv.x * float(IrradianceTexWidth) - 0.5) / (float(IrradianceTexWidth) - 1.0) * (1.0 + 0.2); @@ -128,47 +128,47 @@ void GetIrradianceRMuS(float2 uv, out float radius, out float MuS) float4 Texture4DSample(Texture3D tex, float radius, float Mu, float MuS, float Nu) { - float H = sqrt(RadiusAtmosphere * RadiusAtmosphere - RadiusGround * RadiusGround); - float Rho = sqrt(radius * radius - RadiusGround * RadiusGround); + float H = sqrt(RadiusAtmosphere * RadiusAtmosphere - RadiusGround * RadiusGround); + float Rho = sqrt(radius * radius - RadiusGround * RadiusGround); #if INSCATTER_NON_LINEAR - float RMu = radius * Mu; - float Delta = RMu * RMu - radius * radius + RadiusGround * RadiusGround; - float4 TexOffset = RMu < 0.0 && Delta > 0.0 ? float4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(InscatterMuNum)) : float4(-1.0, H * H, H, 0.5 + 0.5 / float(InscatterMuNum)); - float MuR = 0.5 / float(AtmosphericFogInscatterAltitudeSampleNum) + Rho / H * (1.0 - 1.0 / float(AtmosphericFogInscatterAltitudeSampleNum)); - float MuMu = TexOffset.w + (RMu * TexOffset.x + sqrt(Delta + TexOffset.y)) / (Rho + TexOffset.z) * (0.5 - 1.0 / float(InscatterMuNum)); - float MuMuS = 0.5 / float(InscatterMuSNum) + (atan(max(MuS, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5 * (1.0 - 1.0 / float(InscatterMuSNum)); + float RMu = radius * Mu; + float Delta = RMu * RMu - radius * radius + RadiusGround * RadiusGround; + float4 TexOffset = RMu < 0.0 && Delta > 0.0 ? float4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(InscatterMuNum)) : float4(-1.0, H * H, H, 0.5 + 0.5 / float(InscatterMuNum)); + float MuR = 0.5 / float(AtmosphericFogInscatterAltitudeSampleNum) + Rho / H * (1.0 - 1.0 / float(AtmosphericFogInscatterAltitudeSampleNum)); + float MuMu = TexOffset.w + (RMu * TexOffset.x + sqrt(Delta + TexOffset.y)) / (Rho + TexOffset.z) * (0.5 - 1.0 / float(InscatterMuNum)); + float MuMuS = 0.5 / float(InscatterMuSNum) + (atan(max(MuS, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5 * (1.0 - 1.0 / float(InscatterMuSNum)); #else float MuR = 0.5 / float(AtmosphericFogInscatterAltitudeSampleNum) + Rho / H * (1.0 - 1.0 / float(AtmosphericFogInscatterAltitudeSampleNum)); float MuMu = 0.5 / float(InscatterMuNum) + (Mu + 1.0) * 0.5f * (1.0 - 1.0 / float(InscatterMuNum)); float MuMuS = 0.5 / float(InscatterMuSNum) + max(MuS + 0.2, 0.0) / 1.2 * (1.0 - 1.0 / float(InscatterMuSNum)); #endif - float LerpValue = (Nu + 1.0) * 0.5f * (float(InscatterNuNum) - 1.0); - float MuNu = floor(LerpValue); - LerpValue = LerpValue - MuNu; + float LerpValue = (Nu + 1.0) * 0.5f * (float(InscatterNuNum) - 1.0); + float MuNu = floor(LerpValue); + LerpValue = LerpValue - MuNu; - return tex.SampleLevel(SamplerLinearClamp, float3((MuNu + MuMuS) / float(InscatterNuNum), MuMu, MuR), 0) * (1.0 - LerpValue) - + tex.SampleLevel(SamplerLinearClamp, float3((MuNu + MuMuS + 1.0) / float(InscatterNuNum), MuMu, MuR), 0) * LerpValue; + return tex.SampleLevel(SamplerLinearClamp, float3((MuNu + MuMuS) / float(InscatterNuNum), MuMu, MuR), 0) * (1.0 - LerpValue) + + tex.SampleLevel(SamplerLinearClamp, float3((MuNu + MuMuS + 1.0) / float(InscatterNuNum), MuMu, MuR), 0) * LerpValue; } float Mod(float x, float y) { - return x - y * floor(x / y); + return x - y * floor(x / y); } -void GetMuMuSNu(float2 uv, float radius, float4 DhdH, out float Mu, out float MuS, out float Nu) +void GetMuMuSNu(float2 uv, float radius, float4 DhdH, out float Mu, out float MuS, out float Nu) { float x = uv.x * float(InscatterMuSNum * InscatterNuNum) - 0.5; float y = uv.y * float(InscatterMuNum) - 0.5; #if INSCATTER_NON_LINEAR - if (y < float(InscatterMuNum) * 0.5f) - { + if (y < float(InscatterMuNum) * 0.5f) + { float d = 1.0 - y / (float(InscatterMuNum) * 0.5f - 1.0); d = min(max(DhdH.z, d * DhdH.w), DhdH.w * 0.999); Mu = (RadiusGround * RadiusGround - radius * radius - d * d) / (2.0 * radius * d); Mu = min(Mu, -sqrt(1.0 - (RadiusGround / radius) * (RadiusGround / radius)) - 0.001); } - else - { + else + { float d = (y - float(InscatterMuNum) * 0.5f) / (float(InscatterMuNum) * 0.5f - 1.0); d = min(max(DhdH.x, d * DhdH.y), DhdH.y * 0.999); Mu = (RadiusAtmosphere * RadiusAtmosphere - radius * radius - d * d) / (2.0 * radius * d); @@ -185,15 +185,15 @@ void GetMuMuSNu(float2 uv, float radius, float4 DhdH, out float Mu, out float Mu } // Nearest intersection of ray r,mu with ground or top atmosphere boundary, mu=cos(ray zenith angle at ray origin) -float Limit(float radius, float Mu) +float Limit(float radius, float Mu) { float Dout = -radius * Mu + sqrt(radius * radius * (Mu * Mu - 1.0) + RadiusLimit * RadiusLimit); float Delta2 = radius * radius * (Mu * Mu - 1.0) + RadiusGround * RadiusGround; - if (Delta2 >= 0.0) - { + if (Delta2 >= 0.0) + { float Din = -radius * Mu - sqrt(Delta2); - if (Din >= 0.0) - { + if (Din >= 0.0) + { Dout = min(Dout, Din); } } @@ -201,90 +201,90 @@ float Limit(float radius, float Mu) } // Transmittance(=transparency) of atmosphere for infinite ray (r,mu) (mu=cos(view zenith angle)), intersections with ground ignored -float3 Transmittance(float radius, float Mu) +float3 Transmittance(float radius, float Mu) { - float2 uv = GetTransmittanceUV(radius, Mu); - return AtmosphereTransmittanceTexture.SampleLevel(SamplerLinearClamp, uv, 0).rgb; + float2 uv = GetTransmittanceUV(radius, Mu); + return AtmosphereTransmittanceTexture.SampleLevel(SamplerLinearClamp, uv, 0).rgb; } // Transmittance(=transparency) of atmosphere for infinite ray (r,mu) (mu=cos(view zenith angle)), or zero if ray intersects ground -float3 TransmittanceWithShadow(float radius, float Mu) +float3 TransmittanceWithShadow(float radius, float Mu) { - return Transmittance(radius, Mu); + return Transmittance(radius, Mu); } //Transmittance(=transparency) of atmosphere between x and x0. Assume segment x,x0 not intersecting ground. D = Distance between x and x0, mu=cos(zenith angle of [x,x0) ray at x) -float3 TransmittanceWithDistance(float radius, float Mu, float D) +float3 TransmittanceWithDistance(float radius, float Mu, float D) { float3 result; float R1 = sqrt(radius * radius + D * D + 2.0 * radius * Mu * D); float Mu1 = (radius * Mu + D) / R1; - if (Mu > 0.0) - { + if (Mu > 0.0) + { result = min(Transmittance(radius, Mu) / Transmittance(R1, Mu1), 1.0); } - else - { + else + { result = min(Transmittance(R1, -Mu1) / Transmittance(radius, -Mu), 1.0); } return result; } // Transmittance(=transparency) of atmosphere between x and x0. Assume segment x,x0 not intersecting ground radius=||x||, Mu=cos(zenith angle of [x,x0) ray at x), v=unit direction vector of [x,x0) ray -float3 TransmittanceWithDistance(float radius, float Mu, float3 V, float3 X0) +float3 TransmittanceWithDistance(float radius, float Mu, float3 V, float3 X0) { float3 result; float d1 = length(X0); float Mu1 = dot(X0, V) / radius; - if (Mu > 0.0) + if (Mu > 0.0) result = min(Transmittance(radius, Mu) / Transmittance(d1, Mu1), 1.0); - else + else result = min(Transmittance(d1, -Mu1) / Transmittance(radius, -Mu), 1.0); return result; } // Optical depth for ray (r,mu) of length d, using analytic formula (mu=cos(view zenith angle)), intersections with ground ignored H=height scale of exponential density function -float OpticalDepthWithDistance(float H, float radius, float Mu, float D) +float OpticalDepthWithDistance(float H, float radius, float Mu, float D) { - float particleDensity = 6.2831; // REK 04, Table 2 + float particleDensity = 6.2831; // REK 04, Table 2 float a = sqrt(0.5 / H * radius); float2 A01 = a * float2(Mu, Mu + D / radius); float2 A01Sign = sign(A01); - float2 A01Squared = A01*A01; + float2 A01Squared = A01 * A01; float x = A01Sign.y > A01Sign.x ? exp(A01Squared.x) : 0.0; - float2 y = A01Sign / (2.3193 * abs(A01) + sqrt(1.52 * A01Squared + 4.0)) * float2(1.0, exp(-D / H*(D / (2.0 * radius) + Mu))); - return sqrt((particleDensity * H)*radius) * exp((RadiusGround - radius) / H) * (x + dot(y, float2(1.0, -1.0))); + float2 y = A01Sign / (2.3193 * abs(A01) + sqrt(1.52 * A01Squared + 4.0)) * float2(1.0, exp(-D / H * (D / (2.0 * radius) + Mu))); + return sqrt((particleDensity * H) * radius) * exp((RadiusGround - radius) / H) * (x + dot(y, float2(1.0, -1.0))); } // Transmittance(=transparency) of atmosphere for ray (r,mu) of length d (mu=cos(view zenith angle)), intersections with ground ignored uses analytic formula instead of transmittance texture, REK 04, Atmospheric Transparency -float3 AnalyticTransmittance(float R, float Mu, float D) +float3 AnalyticTransmittance(float R, float Mu, float D) { return exp(- BetaRayleighScattering * OpticalDepthWithDistance(HeightScaleRayleigh, R, Mu, D) - BetaMieExtinction * OpticalDepthWithDistance(HeightScaleMie, R, Mu, D)); } -float3 Irradiance(Texture2D tex, float r, float muS) +float3 Irradiance(Texture2D tex, float r, float muS) { float2 uv = GetIrradianceUV(r, muS); - return tex.SampleLevel(SamplerLinearClamp, uv, 0).rgb; + return tex.SampleLevel(SamplerLinearClamp, uv, 0).rgb; } // Rayleigh phase function -float PhaseFunctionR(float Mu) +float PhaseFunctionR(float Mu) { return (3.0 / (16.0 * PI)) * (1.0 + Mu * Mu); } // Mie phase function -float PhaseFunctionM(float Mu) +float PhaseFunctionM(float Mu) { - return 1.5 * 1.0 / (4.0 * PI) * (1.0 - MieG * MieG) * pow(1.0 + (MieG * MieG) - 2.0 * MieG * Mu, -3.0/2.0) * (1.0 + Mu * Mu) / (2.0 + MieG * MieG); + return 1.5 * 1.0 / (4.0 * PI) * (1.0 - MieG * MieG) * pow(1.0 + (MieG * MieG) - 2.0 * MieG * Mu, -3.0 / 2.0) * (1.0 + Mu * Mu) / (2.0 + MieG * MieG); } // Approximated single Mie scattering (cf. approximate Cm in paragraph "Angular precision") -float3 GetMie(float4 RayMie) -{ - // RayMie.rgb=C*, RayMie.w=Cm,r - return RayMie.rgb * RayMie.w / max(RayMie.r, 1e-4) * (BetaRayleighScattering.rrr / BetaRayleighScattering.rgb); +float3 GetMie(float4 RayMie) +{ + // RayMie.rgb=C*, RayMie.w=Cm,r + return RayMie.rgb * RayMie.w / max(RayMie.r, 1e-4) * (BetaRayleighScattering.rrr / BetaRayleighScattering.rgb); } #endif diff --git a/Source/Shaders/AtmosphereFog.hlsl b/Source/Shaders/AtmosphereFog.hlsl index 45e000e11..ae60a25ef 100644 --- a/Source/Shaders/AtmosphereFog.hlsl +++ b/Source/Shaders/AtmosphereFog.hlsl @@ -27,222 +27,221 @@ static const float HeightOffset = 0.01f; // inscattered light along ray x+tv, when sun in direction s (=S[L]-T(x,x0)S[L]|x0) float3 GetInscatterColor(float fogDepth, float3 X, float T, float3 V, float3 S, float radius, float Mu, out float3 attenuation, bool isSceneGeometry) { - float3 result = float3(0.0f, 0.0f, 0.0f); - attenuation = float3(1.0f, 1.0f, 1.0f); + float3 result = float3(0.0f, 0.0f, 0.0f); + attenuation = float3(1.0f, 1.0f, 1.0f); - float d = -radius * Mu - sqrt(radius * radius * (Mu * Mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere); - if (d > 0.0f) - { - // if X in space and ray intersects atmosphere - // move X to nearest intersection of ray with top atmosphere boundary - X += d * V; - T -= d; - Mu = (radius * Mu + d) / RadiusAtmosphere; - radius = RadiusAtmosphere; - } + float d = -radius * Mu - sqrt(radius * radius * (Mu * Mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere); + if (d > 0.0f) + { + // if X in space and ray intersects atmosphere + // move X to nearest intersection of ray with top atmosphere boundary + X += d * V; + T -= d; + Mu = (radius * Mu + d) / RadiusAtmosphere; + radius = RadiusAtmosphere; + } - float epsilon = 0.005f; + float epsilon = 0.005f; - if (radius < RadiusGround + HeightOffset + epsilon) - { - float diff = (RadiusGround + HeightOffset + epsilon) - radius; - X -= diff * V; - T -= diff; - radius = RadiusGround + HeightOffset + epsilon; - Mu = dot(X, V) / radius; - } + if (radius < RadiusGround + HeightOffset + epsilon) + { + float diff = (RadiusGround + HeightOffset + epsilon) - radius; + X -= diff * V; + T -= diff; + radius = RadiusGround + HeightOffset + epsilon; + Mu = dot(X, V) / radius; + } - if (radius <= RadiusAtmosphere && fogDepth > 0.0f) - { - float3 X0 = X + T * V; - float R0 = length(X0); - float Nu = dot(V, S); - float MuS = dot(X, S) / radius; + if (radius <= RadiusAtmosphere && fogDepth > 0.0f) + { + float3 X0 = X + T * V; + float R0 = length(X0); + float Nu = dot(V, S); + float MuS = dot(X, S) / radius; - float MuHorizon = -sqrt(1.0 - (RadiusGround / radius) * (RadiusGround / radius)); + float MuHorizon = -sqrt(1.0 - (RadiusGround / radius) * (RadiusGround / radius)); - if (isSceneGeometry) - { - Mu = max(Mu, MuHorizon + epsilon + 0.15f); - } - else - { - Mu = max(Mu, MuHorizon + epsilon); - } + if (isSceneGeometry) + { + Mu = max(Mu, MuHorizon + epsilon + 0.15f); + } + else + { + Mu = max(Mu, MuHorizon + epsilon); + } - float MuOriginal = Mu; - float blendRatio = 0.0f; + float MuOriginal = Mu; + float blendRatio = 0.0f; - if (isSceneGeometry) - { - blendRatio = saturate(exp(-V.z) - 0.5); - if (blendRatio < 1.0) - { - V.z = max(V.z, 0.15); - V = normalize(V); - float3 x1 = X + T * V; - Mu = dot(x1, V) / length(x1); - } - } + if (isSceneGeometry) + { + blendRatio = saturate(exp(-V.z) - 0.5); + if (blendRatio < 1.0) + { + V.z = max(V.z, 0.15); + V = normalize(V); + float3 x1 = X + T * V; + Mu = dot(x1, V) / length(x1); + } + } - float phaseR = PhaseFunctionR(Nu); - float phaseM = PhaseFunctionM(Nu); - float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu), 0.0); + float phaseR = PhaseFunctionR(Nu); + float phaseM = PhaseFunctionM(Nu); + float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu), 0.0); - if (T > 0.0) - { - attenuation = AnalyticTransmittance(radius, Mu, T); - float Mu0 = dot(X0, V) / R0; - float MuS0 = dot(X0, S) / R0; - if (isSceneGeometry) - { - R0 = max(R0, radius); - } + if (T > 0.0) + { + attenuation = AnalyticTransmittance(radius, Mu, T); + float Mu0 = dot(X0, V) / R0; + float MuS0 = dot(X0, S) / R0; + if (isSceneGeometry) + { + R0 = max(R0, radius); + } - if (R0 > RadiusGround + HeightOffset) - { - if (blendRatio < 1.0) - { - inscatter = max(inscatter - attenuation.rgbr * Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu), 0.0); - if (!isSceneGeometry) - { - if (abs(Mu - MuHorizon) < epsilon) - { - Mu = MuHorizon - epsilon; - R0 = sqrt(radius * radius + T * T + 2.0 * radius * T * Mu); - Mu0 = (radius * Mu + T) / R0; + if (R0 > RadiusGround + HeightOffset) + { + if (blendRatio < 1.0) + { + inscatter = max(inscatter - attenuation.rgbr * Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu), 0.0); + if (!isSceneGeometry) + { + if (abs(Mu - MuHorizon) < epsilon) + { + Mu = MuHorizon - epsilon; + R0 = sqrt(radius * radius + T * T + 2.0 * radius * T * Mu); + Mu0 = (radius * Mu + T) / R0; - Mu0 = max(MuHorizon + epsilon, Mu0); - float4 inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu); - float4 inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu); - float4 inscatterA = max(inscatter0 - attenuation.rgbr * inscatter1, 0.0); + Mu0 = max(MuHorizon + epsilon, Mu0); + float4 inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu); + float4 inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu); + float4 inscatterA = max(inscatter0 - attenuation.rgbr * inscatter1, 0.0); - Mu = MuHorizon + epsilon; - R0 = sqrt(radius * radius + T * T + 2.0 * radius * T * Mu); + Mu = MuHorizon + epsilon; + R0 = sqrt(radius * radius + T * T + 2.0 * radius * T * Mu); - Mu0 = (radius * Mu + T) / R0; - Mu0 = max(MuHorizon + epsilon, Mu0); - inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu); - inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu); - float4 inscatterB = max(inscatter1 - attenuation.rgbr * inscatter1, 0.0); + Mu0 = (radius * Mu + T) / R0; + Mu0 = max(MuHorizon + epsilon, Mu0); + inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu); + inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu); + float4 inscatterB = max(inscatter1 - attenuation.rgbr * inscatter1, 0.0); - float alpha = ((Mu - MuHorizon) + epsilon) * 0.5f / epsilon; - inscatter = lerp(inscatterA, inscatterB, alpha); - } - } - else if (blendRatio > 0.0) - { - inscatter = lerp(inscatter, (1.0 - attenuation.rgbr) * max(Texture4DSample(AtmosphereInscatterTexture, radius, MuOriginal, MuS, Nu), 0.0), blendRatio); - } - } - else - { - inscatter = (1.0 - attenuation.rgbr) * inscatter; - } - } - } + float alpha = ((Mu - MuHorizon) + epsilon) * 0.5f / epsilon; + inscatter = lerp(inscatterA, inscatterB, alpha); + } + } + else if (blendRatio > 0.0) + { + inscatter = lerp(inscatter, (1.0 - attenuation.rgbr) * max(Texture4DSample(AtmosphereInscatterTexture, radius, MuOriginal, MuS, Nu), 0.0), blendRatio); + } + } + else + { + inscatter = (1.0 - attenuation.rgbr) * inscatter; + } + } + } - inscatter.w *= smoothstep(0.00, 0.02, MuS); - result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0); - } + inscatter.w *= smoothstep(0.00, 0.02, MuS); + result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0); + } - return result; + return result; } // Ground radiance at end of ray x+tv, when sun in direction s attenuated between ground and viewer (=R[L0]+R[L*]) float3 GetGroundColor(float4 sceneColor, float3 X, float T, float3 V, float3 S, float radius, float3 attenuation, bool isSceneGeometry) { - float3 result = float3(0.0f, 0.0f, 0.0f); - if (T > 0.0f) - { - // if ray hits ground surface - // ground Reflectance at end of ray, X0 - float3 X0 = X + T * V; - float R0 = length(X0); - float3 N = X0 / R0; - sceneColor.xyz = saturate(sceneColor.xyz + 0.05); + float3 result = float3(0.0f, 0.0f, 0.0f); + if (T > 0.0f) + { + // if ray hits ground surface + // ground Reflectance at end of ray, X0 + float3 X0 = X + T * V; + float R0 = length(X0); + float3 N = X0 / R0; + sceneColor.xyz = saturate(sceneColor.xyz + 0.05); - float4 reflectance = sceneColor * float4(0.2, 0.2, 0.2, 1.0); + float4 reflectance = sceneColor * float4(0.2, 0.2, 0.2, 1.0); - // direct sun light (radiance) reaching X0 - float MuS = dot(N, S); - float3 sunLight = isSceneGeometry ? float3(0.f, 0.f, 0.f) : TransmittanceWithShadow(R0, MuS); + // direct sun light (radiance) reaching X0 + float MuS = dot(N, S); + float3 sunLight = isSceneGeometry ? float3(0.f, 0.f, 0.f) : TransmittanceWithShadow(R0, MuS); - // precomputed sky light (irradiance) (=E[L*]) at X0 - float3 groundSkyLight = Irradiance(AtmosphereIrradianceTexture, R0, MuS); + // precomputed sky light (irradiance) (=E[L*]) at X0 + float3 groundSkyLight = Irradiance(AtmosphereIrradianceTexture, R0, MuS); - // light reflected at X0 (=(R[L0]+R[L*])/T(X,X0)) - float3 groundColor = reflectance.rgb * ((max(MuS, 0.0) * sunLight + groundSkyLight) / PI); + // light reflected at X0 (=(R[L0]+R[L*])/T(X,X0)) + float3 groundColor = reflectance.rgb * ((max(MuS, 0.0) * sunLight + groundSkyLight) / PI); - // water specular color due to SunLight - if (!isSceneGeometry && reflectance.w > 0.0) - { - float3 H = normalize(S - V); - float fresnel = 0.02 + 0.98 * pow(1.0 - dot(-V, H), 5.0); - float waterBrdf = fresnel * pow(max(dot(H, N), 0.0), 150.0); - groundColor += reflectance.w * max(waterBrdf, 0.0) * sunLight; - } + // water specular color due to SunLight + if (!isSceneGeometry && reflectance.w > 0.0) + { + float3 H = normalize(S - V); + float fresnel = 0.02 + 0.98 * pow(1.0 - dot(-V, H), 5.0); + float waterBrdf = fresnel * pow(max(dot(H, N), 0.0), 150.0); + groundColor += reflectance.w * max(waterBrdf, 0.0) * sunLight; + } - result = attenuation * groundColor; //=R[L0]+R[L*] - } - return result; + result = attenuation * groundColor; //=R[L0]+R[L*] + } + return result; } // Direct sun light for ray x+tv, when sun in direction s (=L0) float3 GetSunColor(AtmosphericFogData atmosphericFog, float3 X, float T, float3 V, float3 S, float radius, float Mu) { - if (T > 0.0) - return float3(0.0f, 0.0f, 0.0f); + if (T > 0.0) + return float3(0.0f, 0.0f, 0.0f); - float3 transmittance = radius <= RadiusAtmosphere ? TransmittanceWithShadow(radius, Mu) : float3(1.0, 1.0, 1.0); // T(X,xo) - float sunIntensity = step(cos(PI * atmosphericFog.AtmosphericFogSunDiscScale / 180.0), dot(V, S)); // Lsun - return transmittance * sunIntensity; // Eq (9) + float3 transmittance = radius <= RadiusAtmosphere ? TransmittanceWithShadow(radius, Mu) : float3(1.0, 1.0, 1.0); // T(X,xo) + float sunIntensity = step(cos(PI * atmosphericFog.AtmosphericFogSunDiscScale / 180.0), dot(V, S)); // Lsun + return transmittance * sunIntensity; // Eq (9) } float3 inscatter(inout float3 x, inout float t, float3 v, float3 s, out float r, out float mu, out float3 attenuation) { - float3 result = 0; - r = length(x); - mu = dot(x, v) / r; - float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere); + float3 result = 0; + r = length(x); + mu = dot(x, v) / r; + float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere); - // if x in space and ray intersects atmosphere - if (d > 0.0) - { - // move x to nearest intersection of ray with top atmosphere boundary - x += d * v; - t -= d; - mu = (r * mu + d) / RadiusAtmosphere; - r = RadiusAtmosphere; - } + // if x in space and ray intersects atmosphere + if (d > 0.0) + { + // move x to nearest intersection of ray with top atmosphere boundary + x += d * v; + t -= d; + mu = (r * mu + d) / RadiusAtmosphere; + r = RadiusAtmosphere; + } - float epsilon = 0.0045f; + float epsilon = 0.0045f; - // if ray intersects atmosphere - if (r <= RadiusAtmosphere) - { - float nu = dot(v, s); - float muS = dot(x, s) / r; - float phaseR = PhaseFunctionR(nu); - float phaseM = PhaseFunctionM(nu); - float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, r, mu, muS, nu), 0.0); + // if ray intersects atmosphere + if (r <= RadiusAtmosphere) + { + float nu = dot(v, s); + float muS = dot(x, s) / r; + float phaseR = PhaseFunctionR(nu); + float phaseM = PhaseFunctionM(nu); + float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, r, mu, muS, nu), 0.0); - if (t > 0.0) - { - float3 x0 = x + t * v; - float r0 = length(x0); - float rMu0 = dot(x0, v); - float mu0 = rMu0 / r0; - float muS0 = dot(x0, s) / r0; + if (t > 0.0) + { + float3 x0 = x + t * v; + float r0 = length(x0); + float rMu0 = dot(x0, v); + float mu0 = rMu0 / r0; + float muS0 = dot(x0, s) / r0; attenuation = AnalyticTransmittance(r, mu, t); - if (r0 > RadiusGround + 0.01) - { - // computes S[L]-T(x,x0)S[L]|x0 - inscatter = max(inscatter - attenuation.rgbr * Texture4DSample(AtmosphereInscatterTexture, r0, mu0, muS0, nu), 0.0); + if (r0 > RadiusGround + 0.01) + { + // computes S[L]-T(x,x0)S[L]|x0 + inscatter = max(inscatter - attenuation.rgbr * Texture4DSample(AtmosphereInscatterTexture, r0, mu0, muS0, nu), 0.0); float muHoriz = -sqrt(1.0 - (RadiusGround / r) * (RadiusGround / r)); if (abs(mu - muHoriz) < epsilon) - { - + { mu = muHoriz - epsilon; r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); mu0 = (r * mu + t) / r0; @@ -256,18 +255,18 @@ float3 inscatter(inout float3 x, inout float t, float3 v, float3 s, out float r, inScatter0 = Texture4DSample(AtmosphereInscatterTexture, r, mu, muS, nu); inScatter1 = Texture4DSample(AtmosphereInscatterTexture, r0, mu0, muS0, nu); float4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); - + float alpha = ((mu - muHoriz) + epsilon) / (2.0 * epsilon); inscatter = lerp(inScatterA, inScatterB, alpha); } - } - } + } + } inscatter.w *= smoothstep(0.00, 0.02, muS); - result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0); - } + result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0); + } - return result; + return result; } static const float EPSILON_ATMOSPHERE = 0.002f; @@ -280,40 +279,40 @@ static const float EPSILON_INSCATTER = 0.004f; // output - return value: intersection occurred true/false bool intersectAtmosphere(in float3 viewPosition, in float3 d, out float offset, out float maxPathLength) { - offset = 0.0f; - maxPathLength = 0.0f; + offset = 0.0f; + maxPathLength = 0.0f; - // vector from ray origin to center of the sphere - float3 l = -viewPosition; - float l2 = dot(l, l); - float s = dot(l, d); + // vector from ray origin to center of the sphere + float3 l = -viewPosition; + float l2 = dot(l, l); + float s = dot(l, d); - // adjust top atmosphere boundary by small epsilon to prevent artifacts - float r = Rt - EPSILON_ATMOSPHERE; - float r2 = r * r; - if (l2 <= r2) - { - // ray origin inside sphere, hit is ensured - float m2 = l2 - (s * s); - float q = sqrt(r2 - m2); - maxPathLength = s + q; - return true; - } - else if (s >= 0) - { - // ray starts outside in front of sphere, hit is possible - float m2 = l2 - (s * s); - if (m2 <= r2) - { - // ray hits atmosphere definitely - float q = sqrt(r2 - m2); - offset = s - q; - maxPathLength = (s + q) - offset; - return true; - } - } + // adjust top atmosphere boundary by small epsilon to prevent artifacts + float r = Rt - EPSILON_ATMOSPHERE; + float r2 = r * r; + if (l2 <= r2) + { + // ray origin inside sphere, hit is ensured + float m2 = l2 - (s * s); + float q = sqrt(r2 - m2); + maxPathLength = s + q; + return true; + } + if (s >= 0) + { + // ray starts outside in front of sphere, hit is possible + float m2 = l2 - (s * s); + if (m2 <= r2) + { + // ray hits atmosphere definitely + float q = sqrt(r2 - m2); + offset = s - q; + maxPathLength = (s + q) - offset; + return true; + } + } - return false; + return false; } // input - surfacePos: reconstructed position of current pixel @@ -323,105 +322,105 @@ bool intersectAtmosphere(in float3 viewPosition, in float3 d, out float offset, // output - return value: total in-scattered light float3 GetInscatteredLight(AtmosphericFogData atmosphericFog, in float3 viewPosition, in float3 surfacePos, in float3 viewDir, in out float3 attenuation, in out float irradianceFactor) { - float3 inscatteredLight = float3(0.0f, 0.0f, 0.0f); - float offset; - float maxPathLength; + float3 inscatteredLight = float3(0.0f, 0.0f, 0.0f); + float offset; + float maxPathLength; - if (intersectAtmosphere(viewPosition, viewDir, offset, maxPathLength)) - { - return float3(offset / 10, 0, 0); + if (intersectAtmosphere(viewPosition, viewDir, offset, maxPathLength)) + { + return float3(offset / 10, 0, 0); - float pathLength = distance(viewPosition, surfacePos); - //return pathLength.xxx; + float pathLength = distance(viewPosition, surfacePos); + //return pathLength.xxx; - // check if object occludes atmosphere - if (pathLength > offset) - { - //return float3(1,0,0); + // check if object occludes atmosphere + if (pathLength > offset) + { + //return float3(1,0,0); - // offsetting camera - float3 startPos = viewPosition + offset * viewDir; - float startPosHeight = length(startPos); - pathLength -= offset; + // offsetting camera + float3 startPos = viewPosition + offset * viewDir; + float startPosHeight = length(startPos); + pathLength -= offset; - // starting position of path is now ensured to be inside atmosphere - // was either originally there or has been moved to top boundary - float muStartPos = dot(startPos, viewDir) / startPosHeight; - float nuStartPos = dot(viewDir, atmosphericFog.AtmosphericFogSunDirection); - float musStartPos = dot(startPos, atmosphericFog.AtmosphericFogSunDirection) / startPosHeight; + // starting position of path is now ensured to be inside atmosphere + // was either originally there or has been moved to top boundary + float muStartPos = dot(startPos, viewDir) / startPosHeight; + float nuStartPos = dot(viewDir, atmosphericFog.AtmosphericFogSunDirection); + float musStartPos = dot(startPos, atmosphericFog.AtmosphericFogSunDirection) / startPosHeight; - // in-scattering for infinite ray (light in-scattered when - // no surface hit or object behind atmosphere) - float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, startPosHeight, muStartPos, musStartPos, nuStartPos), 0.0f); - float surfacePosHeight = length(surfacePos); - float musEndPos = dot(surfacePos, atmosphericFog.AtmosphericFogSunDirection) / surfacePosHeight; - //return float3(muStartPos, 0, 0); + // in-scattering for infinite ray (light in-scattered when + // no surface hit or object behind atmosphere) + float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, startPosHeight, muStartPos, musStartPos, nuStartPos), 0.0f); + float surfacePosHeight = length(surfacePos); + float musEndPos = dot(surfacePos, atmosphericFog.AtmosphericFogSunDirection) / surfacePosHeight; + //return float3(muStartPos, 0, 0); - // check if object hit is inside atmosphere - if (pathLength < maxPathLength) - { - //return float3(1,0,0); + // check if object hit is inside atmosphere + if (pathLength < maxPathLength) + { + //return float3(1,0,0); - // reduce total in-scattered light when surface hit - // within atmosphere - // fíx described in chapter 5.1.1 - attenuation = AnalyticTransmittance(startPosHeight, muStartPos, pathLength); // TODO: optimize this!! here - float muEndPos = dot(surfacePos, viewDir) / surfacePosHeight; - float4 inscatterSurface = Texture4DSample(AtmosphereInscatterTexture, surfacePosHeight, muEndPos, musEndPos, nuStartPos); - inscatter = max(inscatter - attenuation.rgbr * inscatterSurface, 0.0f); - irradianceFactor = 1.0f; - } - else - { - //return float3(1,0,0); + // reduce total in-scattered light when surface hit + // within atmosphere + // fíx described in chapter 5.1.1 + attenuation = AnalyticTransmittance(startPosHeight, muStartPos, pathLength); // TODO: optimize this!! here + float muEndPos = dot(surfacePos, viewDir) / surfacePosHeight; + float4 inscatterSurface = Texture4DSample(AtmosphereInscatterTexture, surfacePosHeight, muEndPos, musEndPos, nuStartPos); + inscatter = max(inscatter - attenuation.rgbr * inscatterSurface, 0.0f); + irradianceFactor = 1.0f; + } + else + { + //return float3(1,0,0); - // retrieve extinction factor for inifinte ray - // fíx described in chapter 5.1.1 - attenuation = AnalyticTransmittance(startPosHeight, muStartPos, pathLength); // TODO: optimize this! and here - } - /* - // avoids imprecision problems near horizon by interpolating between - // two points above and below horizon - // fíx described in chapter 5.1.2 - float muHorizon = -sqrt(1.0 - (g_Rg / startPosHeight) * (g_Rg / startPosHeight)); - if (abs(muStartPos - muHorizon) < EPSILON_INSCATTER) - { - float mu = muHorizon - EPSILON_INSCATTER; - float samplePosHeight = sqrt(startPosHeight*startPosHeight + pathLength * pathLength + 2.0f * startPosHeight * pathLength*mu); - float muSamplePos = (startPosHeight * mu + pathLength) / samplePosHeight; - float4 inScatter0 = Texture4DSample(AtmosphereInscatterTexture, startPosHeight, mu, musStartPos, nuStartPos); - float4 inScatter1 = Texture4DSample(AtmosphereInscatterTexture, samplePosHeight, muSamplePos, musEndPos, nuStartPos); - float4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); - mu = muHorizon + EPSILON_INSCATTER; - samplePosHeight = sqrt(startPosHeight * startPosHeight + pathLength * pathLength + 2.0f * startPosHeight * pathLength * mu); - muSamplePos = (startPosHeight * mu + pathLength) / samplePosHeight; - inScatter0 = Texture4DSample(AtmosphereInscatterTexture, startPosHeight, mu, musStartPos, nuStartPos); - inScatter1 = Texture4DSample(AtmosphereInscatterTexture, samplePosHeight, muSamplePos, musEndPos, nuStartPos); - float4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0f); - float t = ((muStartPos - muHorizon) + EPSILON_INSCATTER) / (2.0 * EPSILON_INSCATTER); - inscatter = lerp(inScatterA, inScatterB, t); - } - */ + // retrieve extinction factor for inifinte ray + // fíx described in chapter 5.1.1 + attenuation = AnalyticTransmittance(startPosHeight, muStartPos, pathLength); // TODO: optimize this! and here + } + /* + // avoids imprecision problems near horizon by interpolating between + // two points above and below horizon + // fíx described in chapter 5.1.2 + float muHorizon = -sqrt(1.0 - (g_Rg / startPosHeight) * (g_Rg / startPosHeight)); + if (abs(muStartPos - muHorizon) < EPSILON_INSCATTER) + { + float mu = muHorizon - EPSILON_INSCATTER; + float samplePosHeight = sqrt(startPosHeight*startPosHeight + pathLength * pathLength + 2.0f * startPosHeight * pathLength*mu); + float muSamplePos = (startPosHeight * mu + pathLength) / samplePosHeight; + float4 inScatter0 = Texture4DSample(AtmosphereInscatterTexture, startPosHeight, mu, musStartPos, nuStartPos); + float4 inScatter1 = Texture4DSample(AtmosphereInscatterTexture, samplePosHeight, muSamplePos, musEndPos, nuStartPos); + float4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); + mu = muHorizon + EPSILON_INSCATTER; + samplePosHeight = sqrt(startPosHeight * startPosHeight + pathLength * pathLength + 2.0f * startPosHeight * pathLength * mu); + muSamplePos = (startPosHeight * mu + pathLength) / samplePosHeight; + inScatter0 = Texture4DSample(AtmosphereInscatterTexture, startPosHeight, mu, musStartPos, nuStartPos); + inScatter1 = Texture4DSample(AtmosphereInscatterTexture, samplePosHeight, muSamplePos, musEndPos, nuStartPos); + float4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0f); + float t = ((muStartPos - muHorizon) + EPSILON_INSCATTER) / (2.0 * EPSILON_INSCATTER); + inscatter = lerp(inScatterA, inScatterB, t); + } + */ - // avoids imprecision problems in Mie scattering when sun is below - //horizon - // fíx described in chapter 5.1.3 - inscatter.w *= smoothstep(0.00, 0.02, musStartPos); - float phaseR = PhaseFunctionR(nuStartPos); - float phaseM = PhaseFunctionM(nuStartPos); - inscatteredLight = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0f); + // avoids imprecision problems in Mie scattering when sun is below + //horizon + // fíx described in chapter 5.1.3 + inscatter.w *= smoothstep(0.00, 0.02, musStartPos); + float phaseR = PhaseFunctionR(nuStartPos); + float phaseM = PhaseFunctionM(nuStartPos); + inscatteredLight = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0f); - float sunIntensity = 10; - inscatteredLight *= sunIntensity; - } - } + float sunIntensity = 10; + inscatteredLight *= sunIntensity; + } + } - return inscatteredLight; + return inscatteredLight; } float4 GetAtmosphericFog(AtmosphericFogData atmosphericFog, float viewFar, float3 viewPosition, float3 viewVector, float sceneDepth, float3 sceneColor) { - float4 result = float4(1, 0, 0, 1); + float4 result = float4(1, 0, 0, 1); #if 0 @@ -455,96 +454,96 @@ float4 GetAtmosphericFog(AtmosphericFogData atmosphericFog, float viewFar, float #if 1 - // TODO: scale viewPosition from cm to km + // TODO: scale viewPosition from cm to km - float scale = 0.0001f * atmosphericFog.AtmosphericFogDistanceScale; - viewPosition.y = (viewPosition.y - atmosphericFog.AtmosphericFogGroundOffset) * atmosphericFog.AtmosphericFogAltitudeScale; - //viewPosition *= atmosphericFog.AtmosphericFogDistanceScale; - viewPosition *= scale; - //viewPosition.xz *= 0.00001f; + float scale = 0.0001f * atmosphericFog.AtmosphericFogDistanceScale; + viewPosition.y = (viewPosition.y - atmosphericFog.AtmosphericFogGroundOffset) * atmosphericFog.AtmosphericFogAltitudeScale; + //viewPosition *= atmosphericFog.AtmosphericFogDistanceScale; + viewPosition *= scale; + //viewPosition.xz *= 0.00001f; - //viewPosition *= scale; - viewPosition.y += RadiusGround + HeightOffset; + //viewPosition *= scale; + viewPosition.y += RadiusGround + HeightOffset; - //viewPosition.y -= atmosphericFog.AtmosphericFogGroundOffset; - //worldPosition - float Radius = length(viewPosition); - float3 V = normalize(viewVector); - float Mu = dot(viewPosition, V) / Radius; - float T = -Radius * Mu - sqrt(Radius * Radius * (Mu * Mu - 1.0) + RadiusGround * RadiusGround); + //viewPosition.y -= atmosphericFog.AtmosphericFogGroundOffset; + //worldPosition + float Radius = length(viewPosition); + float3 V = normalize(viewVector); + float Mu = dot(viewPosition, V) / Radius; + float T = -Radius * Mu - sqrt(Radius * Radius * (Mu * Mu - 1.0) + RadiusGround * RadiusGround); - //-Radius * Mu > sqrt(Radius * Radius * (Mu * Mu - 1.0) + RadiusGround * RadiusGround) - /* - float3 g = viewPosition - float3(0.0, 0.0, RadiusGround + 10.0); - float a = V.x * V.x + V.y * V.y - V.z * V.z; - float b = 2.0 * (g.x * V.x + g.y * V.y - g.z * V.z); - float c = g.x * g.x + g.y * g.y - g.z * g.z; - float d = -(b + sqrt(b * b - 4.0 * a * c)) / (2.0 * a); - bool cone = d > 0.0 && abs(viewPosition.z + d * V.z - RadiusGround) <= 10.0; - - if (T > 0.0) - { - if (cone && d < T) - T = d; - //return float4(1,0,0,1); - } - else if (cone) - { - T = d; - //return float4(0,0,1,1); - } - */ - //return float4(V, 1); + //-Radius * Mu > sqrt(Radius * Radius * (Mu * Mu - 1.0) + RadiusGround * RadiusGround) + /* + float3 g = viewPosition - float3(0.0, 0.0, RadiusGround + 10.0); + float a = V.x * V.x + V.y * V.y - V.z * V.z; + float b = 2.0 * (g.x * V.x + g.y * V.y - g.z * V.z); + float c = g.x * g.x + g.y * g.y - g.z * g.z; + float d = -(b + sqrt(b * b - 4.0 * a * c)) / (2.0 * a); + bool cone = d > 0.0 && abs(viewPosition.z + d * V.z - RadiusGround) <= 10.0; + + if (T > 0.0) + { + if (cone && d < T) + T = d; + //return float4(1,0,0,1); + } + else if (cone) + { + T = d; + //return float4(0,0,1,1); + } + */ + //return float4(V, 1); - // TODO: create uniform param for that depth limit - float depthThreshold = min(100.0f * atmosphericFog.AtmosphericFogDistanceScale, (viewFar * 0.997f) * scale); // 100km limit or far plane - sceneDepth *= scale; + // TODO: create uniform param for that depth limit + float depthThreshold = min(100.0f * atmosphericFog.AtmosphericFogDistanceScale, (viewFar * 0.997f) * scale); // 100km limit or far plane + sceneDepth *= scale; - float fogDepth = max(0.0f, sceneDepth - atmosphericFog.AtmosphericFogStartDistance); - float shadowFactor = 1.0f; - float DistanceRatio = min(fogDepth * 0.1f / atmosphericFog.AtmosphericFogStartDistance, 1.0f); - bool isSceneGeometry = (sceneDepth < depthThreshold); // Assume as scene geometry - //isSceneGeometry = false; - if (isSceneGeometry) - { - shadowFactor = DistanceRatio * atmosphericFog.AtmosphericFogPower; - T = max(sceneDepth + atmosphericFog.AtmosphericFogDistanceOffset, 1.0f); + float fogDepth = max(0.0f, sceneDepth - atmosphericFog.AtmosphericFogStartDistance); + float shadowFactor = 1.0f; + float DistanceRatio = min(fogDepth * 0.1f / atmosphericFog.AtmosphericFogStartDistance, 1.0f); + bool isSceneGeometry = (sceneDepth < depthThreshold); // Assume as scene geometry + //isSceneGeometry = false; + if (isSceneGeometry) + { + shadowFactor = DistanceRatio * atmosphericFog.AtmosphericFogPower; + T = max(sceneDepth + atmosphericFog.AtmosphericFogDistanceOffset, 1.0f); - // TODO: fog for scene objects - return 0; - //return float4(0, 1, 0, 1); - } + // TODO: fog for scene objects + return 0; + //return float4(0, 1, 0, 1); + } - float3 attenuation; - float3 inscatterColor = GetInscatterColor(fogDepth, viewPosition, T, V, atmosphericFog.AtmosphericFogSunDirection, Radius, Mu, attenuation, isSceneGeometry); //S[L]-T(viewPosition,xs)S[l]|xs - //float3 inscatterColor = inscatter(viewPosition, T, V, atmosphericFog.AtmosphericFogSunDirection, Radius, Mu, attenuation); //S[L]-T(viewPosition,xs)S[l]|xs - //float3 groundColor = 0; - float3 groundColor = GetGroundColor(float4(sceneColor.rgb, 1.f), viewPosition, T, V, atmosphericFog.AtmosphericFogSunDirection, Radius, attenuation, isSceneGeometry); //R[L0]+R[L*] - float3 sun = GetSunColor(atmosphericFog, viewPosition, T, V, atmosphericFog.AtmosphericFogSunDirection, Radius, Mu); //L0 + float3 attenuation; + float3 inscatterColor = GetInscatterColor(fogDepth, viewPosition, T, V, atmosphericFog.AtmosphericFogSunDirection, Radius, Mu, attenuation, isSceneGeometry); //S[L]-T(viewPosition,xs)S[l]|xs + //float3 inscatterColor = inscatter(viewPosition, T, V, atmosphericFog.AtmosphericFogSunDirection, Radius, Mu, attenuation); //S[L]-T(viewPosition,xs)S[l]|xs + //float3 groundColor = 0; + float3 groundColor = GetGroundColor(float4(sceneColor.rgb, 1.f), viewPosition, T, V, atmosphericFog.AtmosphericFogSunDirection, Radius, attenuation, isSceneGeometry); //R[L0]+R[L*] + float3 sun = GetSunColor(atmosphericFog, viewPosition, T, V, atmosphericFog.AtmosphericFogSunDirection, Radius, Mu); //L0 - float3 color = (atmosphericFog.AtmosphericFogSunPower) * (sun + groundColor + inscatterColor) * atmosphericFog.AtmosphericFogSunColor.rgb; - //return float4(color, lerp(saturate(attenuation.r * atmosphericFog.AtmosphericFogDensityScale - atmosphericFog.AtmosphericFogDensityOffset), 1.0f, (1.0f - DistanceRatio)) ); - //return lerp(saturate(attenuation.r * atmosphericFog.AtmosphericFogDensityScale - atmosphericFog.AtmosphericFogDensityOffset), 1.0f, (1.0f - DistanceRatio)); - //color *= lerp(saturate(attenuation.r * atmosphericFog.AtmosphericFogDensityScale - atmosphericFog.AtmosphericFogDensityOffset), 1.0f, (1.0f - DistanceRatio)); + float3 color = (atmosphericFog.AtmosphericFogSunPower) * (sun + groundColor + inscatterColor) * atmosphericFog.AtmosphericFogSunColor.rgb; + //return float4(color, lerp(saturate(attenuation.r * atmosphericFog.AtmosphericFogDensityScale - atmosphericFog.AtmosphericFogDensityOffset), 1.0f, (1.0f - DistanceRatio)) ); + //return lerp(saturate(attenuation.r * atmosphericFog.AtmosphericFogDensityScale - atmosphericFog.AtmosphericFogDensityOffset), 1.0f, (1.0f - DistanceRatio)); + //color *= lerp(saturate(attenuation.r * atmosphericFog.AtmosphericFogDensityScale - atmosphericFog.AtmosphericFogDensityOffset), 1.0f, (1.0f - DistanceRatio)); - //return attenuation.bbbb; + //return attenuation.bbbb; - return float4(color, 1); + return float4(color, 1); - //return float4(sun, 1); - //return float4(inscatterColor + sun, 1); - //return float4(sun + groundColor, 1); - //return float4(sun + groundColor + inscatterColor, 1); + //return float4(sun, 1); + //return float4(inscatterColor + sun, 1); + //return float4(sun + groundColor, 1); + //return float4(sun + groundColor + inscatterColor, 1); #endif - return result; + return result; } float4 GetAtmosphericFog(AtmosphericFogData atmosphericFog, float viewFar, float3 worldPosition, float3 cameraPosition) { - float3 viewVector = worldPosition - cameraPosition; - return GetAtmosphericFog(atmosphericFog, viewFar, cameraPosition, viewVector, length(viewVector), float3(0, 0, 0)); + float3 viewVector = worldPosition - cameraPosition; + return GetAtmosphericFog(atmosphericFog, viewFar, cameraPosition, viewVector, length(viewVector), float3(0, 0, 0)); } #endif diff --git a/Source/Shaders/BRDF.hlsl b/Source/Shaders/BRDF.hlsl index 7247dd6d0..739682e3e 100644 --- a/Source/Shaders/BRDF.hlsl +++ b/Source/Shaders/BRDF.hlsl @@ -7,55 +7,55 @@ float3 Diffuse_Lambert(float3 diffuseColor) { - return diffuseColor * (1 / PI); + return diffuseColor * (1 / PI); } // GGX / Trowbridge-Reitz // [Walter et al. 2007, "Microfacet models for refraction through rough surfaces"] float D_GGX(float roughness, float NoH) { - float a = roughness * roughness; - float a2 = a * a; - float d = (NoH * a2 - NoH) * NoH + 1; - return a2 / (PI * d * d); + float a = roughness * roughness; + float a2 = a * a; + float d = (NoH * a2 - NoH) * NoH + 1; + return a2 / (PI * d * d); } // Tuned to match behavior of Vis_Smith // [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"] float Vis_Schlick(float roughness, float NoV, float NoL) { - float k = Square(roughness) * 0.5; - float visSchlickV = NoV * (1 - k) + k; - float visSchlickL = NoL * (1 - k) + k; - return 0.25 / (visSchlickV * visSchlickL); + float k = Square(roughness) * 0.5; + float visSchlickV = NoV * (1 - k) + k; + float visSchlickL = NoL * (1 - k) + k; + return 0.25 / (visSchlickV * visSchlickL); } // Smith term for GGX // [Smith 1967, "Geometrical shadowing of a random rough surface"] float Vis_Smith(float roughness, float NoV, float NoL) { - float a = Square(roughness); - float a2 = a * a; - float visSmithV = NoV + sqrt(NoV * (NoV - NoV * a2) + a2); - float visSmithL = NoL + sqrt(NoL * (NoL - NoL * a2) + a2); - return rcp(visSmithV * visSmithL); + float a = Square(roughness); + float a2 = a * a; + float visSmithV = NoV + sqrt(NoV * (NoV - NoV * a2) + a2); + float visSmithL = NoL + sqrt(NoL * (NoL - NoL * a2) + a2); + return rcp(visSmithV * visSmithL); } // Appoximation of joint Smith term for GGX // [Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"] float Vis_SmithJointApprox(float roughness, float NoV, float NoL) { - float a = Square(roughness); - float visSmithV = NoL * (NoV * (1 - a) + a); - float visSmithL = NoV * (NoL * (1 - a) + a); - return 0.5 * rcp(visSmithV + visSmithL); + float a = Square(roughness); + float visSmithV = NoL * (NoV * (1 - a) + a); + float visSmithL = NoV * (NoL * (1 - a) + a); + return 0.5 * rcp(visSmithV + visSmithL); } // [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"] float3 F_Schlick(float3 specularColor, float VoH) { - float fc = Pow5(1 - VoH); - return saturate(50.0 * specularColor.g) * fc + (1 - fc) * specularColor; + float fc = Pow5(1 - VoH); + return saturate(50.0 * specularColor.g) * fc + (1 - fc) * specularColor; } #define REFLECTION_CAPTURE_NUM_MIPS 7 @@ -64,44 +64,44 @@ float3 F_Schlick(float3 specularColor, float VoH) half ProbeMipFromRoughness(half roughness) { - half mip1px = REFLECTION_CAPTURE_ROUGHEST_MIP - REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE * log2(roughness); - return REFLECTION_CAPTURE_NUM_MIPS - 1 - mip1px; + half mip1px = REFLECTION_CAPTURE_ROUGHEST_MIP - REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE * log2(roughness); + return REFLECTION_CAPTURE_NUM_MIPS - 1 - mip1px; } half SSRMipFromRoughness(half roughness) { - half mip1px = 4 - REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE * log2(roughness); - return max(1, 10 - mip1px); + half mip1px = 4 - REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE * log2(roughness); + return max(1, 10 - mip1px); } float ProbeRoughnessFromMip(float mip) { - float mip1px = REFLECTION_CAPTURE_NUM_MIPS - 1 - mip; - return exp2((REFLECTION_CAPTURE_ROUGHEST_MIP - mip1px) / REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE); + float mip1px = REFLECTION_CAPTURE_NUM_MIPS - 1 - mip; + return exp2((REFLECTION_CAPTURE_ROUGHEST_MIP - mip1px) / REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE); } // [Lazarov 2013, "Getting More Physical in Call of Duty: Black Ops II"] float3 EnvBRDFApprox(float3 specularColor, float roughness, float NoV) { - // Approximate version, base for pre integrated version - const half4 c0 = { -1, -0.0275, -0.572, 0.022 }; - const half4 c1 = { 1, 0.0425, 1.04, -0.04 }; - half4 r = roughness * c0 + c1; - half a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; - half2 ab = half2(-1.04, 1.04) * a004 + r.zw; - return specularColor * ab.x + saturate(50.0 * specularColor.g) * ab.y; + // Approximate version, base for pre integrated version + const half4 c0 = { -1, -0.0275, -0.572, 0.022 }; + const half4 c1 = { 1, 0.0425, 1.04, -0.04 }; + half4 r = roughness * c0 + c1; + half a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; + half2 ab = half2(-1.04, 1.04) * a004 + r.zw; + return specularColor * ab.x + saturate(50.0 * specularColor.g) * ab.y; } // Importance sampled preintegrated G * F float3 EnvBRDF(Texture2D preIntegratedGF, float3 specularColor, float roughness, float NoV) { - float2 ab = preIntegratedGF.SampleLevel(SamplerLinearClamp, float2(NoV, roughness), 0).rg; - return specularColor * ab.x + saturate(50.0 * specularColor.g) * ab.y; + float2 ab = preIntegratedGF.SampleLevel(SamplerLinearClamp, float2(NoV, roughness), 0).rg; + return specularColor * ab.x + saturate(50.0 * specularColor.g) * ab.y; } float RoughnessToSpecularPower(float roughness) { - return pow(2, 13 * (1 - roughness)); + return pow(2, 13 * (1 - roughness)); } #endif diff --git a/Source/Shaders/Collisions.hlsl b/Source/Shaders/Collisions.hlsl index 4a62aebc4..6794bc6fe 100644 --- a/Source/Shaders/Collisions.hlsl +++ b/Source/Shaders/Collisions.hlsl @@ -5,17 +5,17 @@ bool RayHitSphere(float3 r, float3 sphereCenter, float sphereRadius) { - float3 closestPointOnRay = max(0, dot(sphereCenter, r)) * r; - float3 centerToRay = closestPointOnRay - sphereCenter; - return dot(centerToRay, centerToRay) <= (sphereRadius * sphereRadius); + float3 closestPointOnRay = max(0, dot(sphereCenter, r)) * r; + float3 centerToRay = closestPointOnRay - sphereCenter; + return dot(centerToRay, centerToRay) <= (sphereRadius * sphereRadius); } bool RayHitRect(float3 r, float3 rectCenter, float3 rectX, float3 rectY, float3 rectZ, float rectExtentX, float rectExtentY) { - float3 pointOnPlane = r * max(0, dot(rectZ, rectCenter) / dot(rectZ, r)); - bool inExtentX = abs(dot(rectX, pointOnPlane - rectCenter)) <= rectExtentX; - bool inExtentY = abs(dot(rectY, pointOnPlane - rectCenter)) <= rectExtentY; - return inExtentX && inExtentY; + float3 pointOnPlane = r * max(0, dot(rectZ, rectCenter) / dot(rectZ, r)); + bool inExtentX = abs(dot(rectX, pointOnPlane - rectCenter)) <= rectExtentX; + bool inExtentY = abs(dot(rectY, pointOnPlane - rectCenter)) <= rectExtentY; + return inExtentX && inExtentY; } // Hits axis-aligned box (boxMin, boxMax) with a line (lineStart, lineEnd). @@ -24,21 +24,21 @@ bool RayHitRect(float3 r, float3 rectCenter, float3 rectX, float3 rectY, float3 // Hit point is: hitPoint = lineStart + (lineEnd - lineStart) * intersections.x/y. float2 LineHitBox(float3 lineStart, float3 lineEnd, float3 boxMin, float3 boxMax) { - float3 invDirection = 1.0f / (lineEnd - lineStart); - float3 enterIntersection = (boxMin - lineStart) * invDirection; - float3 exitIntersection = (boxMax - lineStart) * invDirection; - float3 minIntersections = min(enterIntersection, exitIntersection); - float3 maxIntersections = max(enterIntersection, exitIntersection); - float2 intersections; - intersections.x = max(minIntersections.x, max(minIntersections.y, minIntersections.z)); - intersections.y = min(maxIntersections.x, min(maxIntersections.y, maxIntersections.z)); - return saturate(intersections); + float3 invDirection = 1.0f / (lineEnd - lineStart); + float3 enterIntersection = (boxMin - lineStart) * invDirection; + float3 exitIntersection = (boxMax - lineStart) * invDirection; + float3 minIntersections = min(enterIntersection, exitIntersection); + float3 maxIntersections = max(enterIntersection, exitIntersection); + float2 intersections; + intersections.x = max(minIntersections.x, max(minIntersections.y, minIntersections.z)); + intersections.y = min(maxIntersections.x, min(maxIntersections.y, maxIntersections.z)); + return saturate(intersections); } // Determines whether there is an intersection between a box and a sphere. bool BoxIntersectsSphere(float3 boxMin, float3 boxMax, float3 sphereCenter, float sphereRadius) { - const float3 clampedCenter = clamp(sphereCenter, boxMin, boxMax); + const float3 clampedCenter = clamp(sphereCenter, boxMin, boxMax); return distance(sphereCenter, clampedCenter) <= sphereRadius; } diff --git a/Source/Shaders/Common.hlsl b/Source/Shaders/Common.hlsl index fd5fc19f4..1bc9e718c 100644 --- a/Source/Shaders/Common.hlsl +++ b/Source/Shaders/Common.hlsl @@ -134,12 +134,12 @@ SamplerComparisonState ShadowSamplerPCF : register(s5); // Structure that contains information about GBuffer struct GBufferData { - float4 ViewInfo; // x-1/Projection[0,0] y-1/Projection[1,1] z-(Far / (Far - Near) w-(-Far * Near) / (Far - Near) / Far) - float4 ScreenSize; // x-Width y-Height z-1/Width w-1/Height - float3 ViewPos; // view position (in world space) - float ViewFar; // view far plane distance (in world space) - float4x4 InvViewMatrix; // inverse view matrix (4 rows by 4 columns) - float4x4 InvProjectionMatrix; // inverse projection matrix (4 rows by 4 columns) + float4 ViewInfo; // x-1/Projection[0,0], y-1/Projection[1,1], z-(Far / (Far - Near), w-(-Far * Near) / (Far - Near) / Far) + float4 ScreenSize; // x-Width, y-Height, z-1/Width, w-1/Height + float3 ViewPos; // view position (in world space) + float ViewFar; // view far plane distance (in world space) + float4x4 InvViewMatrix; // inverse view matrix (4 rows by 4 columns) + float4x4 InvProjectionMatrix; // inverse projection matrix (4 rows by 4 columns) }; #ifdef PLATFORM_ANDROID @@ -152,28 +152,28 @@ struct GBufferData // Structure that contains information about atmosphere fog struct AtmosphericFogData { - float AtmosphericFogDensityScale; - float AtmosphericFogSunDiscScale; - float AtmosphericFogDistanceScale; - float AtmosphericFogGroundOffset; + float AtmosphericFogDensityScale; + float AtmosphericFogSunDiscScale; + float AtmosphericFogDistanceScale; + float AtmosphericFogGroundOffset; - float AtmosphericFogAltitudeScale; - float AtmosphericFogStartDistance; - float AtmosphericFogPower; - float AtmosphericFogDistanceOffset; + float AtmosphericFogAltitudeScale; + float AtmosphericFogStartDistance; + float AtmosphericFogPower; + float AtmosphericFogDistanceOffset; - float3 AtmosphericFogSunDirection; - float AtmosphericFogSunPower; + float3 AtmosphericFogSunDirection; + float AtmosphericFogSunPower; - float3 AtmosphericFogSunColor; - float AtmosphericFogDensityOffset; + float3 AtmosphericFogSunColor; + float AtmosphericFogDensityOffset; }; // Packed env probe data struct ProbeData { - float4 Data0; // x - Position.x, y - Position.y, z - Position.z, w - unused - float4 Data1; // x - Radius , y - 1 / Radius, z - Brightness, w - unused + float4 Data0; // x - Position.x, y - Position.y, z - Position.z, w - unused + float4 Data1; // x - Radius , y - 1 / Radius, z - Brightness, w - unused }; #define ProbePos Data0.xyz @@ -183,25 +183,25 @@ struct ProbeData struct Quad_VS2PS { - float4 Position : SV_Position; - noperspective float2 TexCoord : TEXCOORD0; + float4 Position : SV_Position; + noperspective float2 TexCoord : TEXCOORD0; }; struct Quad_VS2GS { - Quad_VS2PS Vertex; - uint LayerIndex : TEXCOORD1; + Quad_VS2PS Vertex; + uint LayerIndex : TEXCOORD1; }; struct Quad_GS2PS { - Quad_VS2PS Vertex; - uint LayerIndex : SV_RenderTargetArrayIndex; + Quad_VS2PS Vertex; + uint LayerIndex : SV_RenderTargetArrayIndex; }; float Luminance(float3 color) { - return dot(color, float3(0.299f, 0.587f, 0.114f)); + return dot(color, float3(0.299f, 0.587f, 0.114f)); } // Quaternion multiplication (http://mathworld.wolfram.com/Quaternion.html) @@ -220,13 +220,13 @@ float3 QuatRotateVector(float4 q, float3 v) // Samples the unwrapped 3D texture (eg. volume texture of size 16x16x16 would be unwrapped to 256x16) float4 SampleUnwrappedTexture3D(Texture2D tex, SamplerState s, float3 uvw, float size) { - float intW = floor(uvw.z * size - 0.5); - half fracW = uvw.z * size - 0.5 - intW; - float u = (uvw.x + intW) / size; - float v = uvw.y; - float4 rg0 = tex.Sample(s, float2(u, v)); - float4 rg1 = tex.Sample(s, float2(u + 1.0f / size, v)); - return lerp(rg0, rg1, fracW); + float intW = floor(uvw.z * size - 0.5); + half fracW = uvw.z * size - 0.5 - intW; + float u = (uvw.x + intW) / size; + float v = uvw.y; + float4 rg0 = tex.Sample(s, float2(u, v)); + float4 rg1 = tex.Sample(s, float2(u + 1.0f / size, v)); + return lerp(rg0, rg1, fracW); } #endif diff --git a/Source/Shaders/Editor/QuadOverdraw.hlsl b/Source/Shaders/Editor/QuadOverdraw.hlsl index 12e9ba9a5..acb411108 100644 --- a/Source/Shaders/Editor/QuadOverdraw.hlsl +++ b/Source/Shaders/Editor/QuadOverdraw.hlsl @@ -3,46 +3,46 @@ #define __QUAD_OVERDRAW__ RWTexture2D lockUAV : register(u0); -RWTexture2D overdrawUAV : register(u1); +RWTexture2D overdrawUAV : register(u1); RWTexture2D liveCountUAV : register(u2); void DoQuadOverdraw(float4 svPos, uint primId) { - uint2 quad = svPos.xy * 0.5; - uint prevID; - uint unlockedID = 0xffffffff; - bool processed = false; - int lockCount = 0; - int pixelCount = 0; + uint2 quad = svPos.xy * 0.5; + uint prevID; + uint unlockedID = 0xffffffff; + bool processed = false; + int lockCount = 0; + int pixelCount = 0; - for (int i = 0; i < 64; i++) - { - if (!processed) - InterlockedCompareExchange(lockUAV[quad], unlockedID, primId, prevID); - [branch] - if (prevID == unlockedID) - { - if (++lockCount == 4) - { - // Retrieve live pixel count (minus 1) in quad - InterlockedAnd(liveCountUAV[quad], 0, pixelCount); + for (int i = 0; i < 64; i++) + { + if (!processed) + InterlockedCompareExchange(lockUAV[quad], unlockedID, primId, prevID); + [branch] + if (prevID == unlockedID) + { + if (++lockCount == 4) + { + // Retrieve live pixel count (minus 1) in quad + InterlockedAnd(liveCountUAV[quad], 0, pixelCount); - // Unlock for other quads - InterlockedExchange(lockUAV[quad], unlockedID, prevID); - } - processed = true; - } - if (prevID == primId && !processed) - { - InterlockedAdd(liveCountUAV[quad], 1); - processed = true; - } - } + // Unlock for other quads + InterlockedExchange(lockUAV[quad], unlockedID, prevID); + } + processed = true; + } + if (prevID == primId && !processed) + { + InterlockedAdd(liveCountUAV[quad], 1); + processed = true; + } + } - if (lockCount) - { - InterlockedAdd(overdrawUAV[quad], 1); - } + if (lockCount) + { + InterlockedAdd(overdrawUAV[quad], 1); + } } #endif diff --git a/Source/Shaders/ExponentialHeightFog.hlsl b/Source/Shaders/ExponentialHeightFog.hlsl index d3008857e..d94ef5e0c 100644 --- a/Source/Shaders/ExponentialHeightFog.hlsl +++ b/Source/Shaders/ExponentialHeightFog.hlsl @@ -9,82 +9,82 @@ // Structure that contains information about exponential height fog struct ExponentialHeightFogData { - float3 FogInscatteringColor; - float FogMinOpacity; + float3 FogInscatteringColor; + float FogMinOpacity; - float FogDensity; - float FogHeight; - float FogHeightFalloff; - float FogAtViewPosition; + float FogDensity; + float FogHeight; + float FogHeightFalloff; + float FogAtViewPosition; - float3 InscatteringLightDirection; - float ApplyDirectionalInscattering; + float3 InscatteringLightDirection; + float ApplyDirectionalInscattering; - float3 DirectionalInscatteringColor; - float DirectionalInscatteringExponent; + float3 DirectionalInscatteringColor; + float DirectionalInscatteringExponent; - float FogCutoffDistance; - float VolumetricFogMaxDistance; - float DirectionalInscatteringStartDistance; - float StartDistance; + float FogCutoffDistance; + float VolumetricFogMaxDistance; + float DirectionalInscatteringStartDistance; + float StartDistance; }; float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 posWS, float3 camWS, float skipDistance) { - float3 cameraToPos = posWS - camWS; - float cameraToPosSqr = dot(cameraToPos, cameraToPos); - float cameraToPosLenInv = rsqrt(cameraToPosSqr); - float cameraToPosLen = cameraToPosSqr * cameraToPosLenInv; - float3 cameraToReceiverNorm = cameraToPos * cameraToPosLenInv; + float3 cameraToPos = posWS - camWS; + float cameraToPosSqr = dot(cameraToPos, cameraToPos); + float cameraToPosLenInv = rsqrt(cameraToPosSqr); + float cameraToPosLen = cameraToPosSqr * cameraToPosLenInv; + float3 cameraToReceiverNorm = cameraToPos * cameraToPosLenInv; - float rayOriginTerms = exponentialHeightFog.FogAtViewPosition; - float rayLength = cameraToPosLen; - float rayDirectionY = cameraToPos.y; + float rayOriginTerms = exponentialHeightFog.FogAtViewPosition; + float rayLength = cameraToPosLen; + float rayDirectionY = cameraToPos.y; - // Apply start distance offset - skipDistance = max(skipDistance, exponentialHeightFog.StartDistance); - if (skipDistance > 0) - { - float excludeIntersectionTime = skipDistance * cameraToPosLenInv; - float cameraToExclusionIntersectionY = excludeIntersectionTime * cameraToPos.y; - float exclusionIntersectionY = camWS.y + cameraToExclusionIntersectionY; - rayLength = (1.0f - excludeIntersectionTime) * cameraToPosLen; - rayDirectionY = cameraToPos.y - cameraToExclusionIntersectionY; - float exponent = exponentialHeightFog.FogHeightFalloff * (exclusionIntersectionY - exponentialHeightFog.FogHeight); - rayOriginTerms = exponentialHeightFog.FogDensity * exp2(-exponent); - } + // Apply start distance offset + skipDistance = max(skipDistance, exponentialHeightFog.StartDistance); + if (skipDistance > 0) + { + float excludeIntersectionTime = skipDistance * cameraToPosLenInv; + float cameraToExclusionIntersectionY = excludeIntersectionTime * cameraToPos.y; + float exclusionIntersectionY = camWS.y + cameraToExclusionIntersectionY; + rayLength = (1.0f - excludeIntersectionTime) * cameraToPosLen; + rayDirectionY = cameraToPos.y - cameraToExclusionIntersectionY; + float exponent = exponentialHeightFog.FogHeightFalloff * (exclusionIntersectionY - exponentialHeightFog.FogHeight); + rayOriginTerms = exponentialHeightFog.FogDensity * exp2(-exponent); + } - // Calculate the integral of the ray starting from the view to the object position with the fog density function - float falloff = max(-127.0f, exponentialHeightFog.FogHeightFalloff * rayDirectionY); - float lineIntegral = (1.0f - exp2(-falloff)) / falloff; - float lineIntegralTaylor = log(2.0f) - (0.5f * Pow2(log(2.0f))) * falloff; - float exponentialHeightLineIntegralCalc = rayOriginTerms * (abs(falloff) > 0.01f ? lineIntegral : lineIntegralTaylor); - float exponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * rayLength; + // Calculate the integral of the ray starting from the view to the object position with the fog density function + float falloff = max(-127.0f, exponentialHeightFog.FogHeightFalloff * rayDirectionY); + float lineIntegral = (1.0f - exp2(-falloff)) / falloff; + float lineIntegralTaylor = log(2.0f) - (0.5f * Pow2(log(2.0f))) * falloff; + float exponentialHeightLineIntegralCalc = rayOriginTerms * (abs(falloff) > 0.01f ? lineIntegral : lineIntegralTaylor); + float exponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * rayLength; - // Calculate the light that went through the fog - float expFogFactor = max(saturate(exp2(-exponentialHeightLineIntegral)), exponentialHeightFog.FogMinOpacity); + // Calculate the light that went through the fog + float expFogFactor = max(saturate(exp2(-exponentialHeightLineIntegral)), exponentialHeightFog.FogMinOpacity); - // Calculate the directional light inscattering - float3 inscatteringColor = exponentialHeightFog.FogInscatteringColor; - float3 directionalInscattering = 0; - BRANCH - if (exponentialHeightFog.ApplyDirectionalInscattering > 0) - { - float3 directionalLightInscattering = exponentialHeightFog.DirectionalInscatteringColor * pow(saturate(dot(cameraToReceiverNorm, exponentialHeightFog.InscatteringLightDirection)), exponentialHeightFog.DirectionalInscatteringExponent); - float dirExponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * max(rayLength - exponentialHeightFog.DirectionalInscatteringStartDistance, 0.0f); - float directionalInscatteringFogFactor = saturate(exp2(-dirExponentialHeightLineIntegral)); - directionalInscattering = directionalLightInscattering * (1.0f - directionalInscatteringFogFactor); - } + // Calculate the directional light inscattering + float3 inscatteringColor = exponentialHeightFog.FogInscatteringColor; + float3 directionalInscattering = 0; + BRANCH + if (exponentialHeightFog.ApplyDirectionalInscattering > 0) + { + float3 directionalLightInscattering = exponentialHeightFog.DirectionalInscatteringColor * pow(saturate(dot(cameraToReceiverNorm, exponentialHeightFog.InscatteringLightDirection)), exponentialHeightFog.DirectionalInscatteringExponent); + float dirExponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * max(rayLength - exponentialHeightFog.DirectionalInscatteringStartDistance, 0.0f); + float directionalInscatteringFogFactor = saturate(exp2(-dirExponentialHeightLineIntegral)); + directionalInscattering = directionalLightInscattering * (1.0f - directionalInscatteringFogFactor); + } - // Disable fog after a certain distance - FLATTEN - if (exponentialHeightFog.FogCutoffDistance > 0 && cameraToPosLen > exponentialHeightFog.FogCutoffDistance) - { - expFogFactor = 1; - directionalInscattering = 0; - } + // Disable fog after a certain distance + FLATTEN + if (exponentialHeightFog.FogCutoffDistance > 0 && cameraToPosLen > exponentialHeightFog.FogCutoffDistance) + { + expFogFactor = 1; + directionalInscattering = 0; + } - return float4(inscatteringColor * (1.0f - expFogFactor) + directionalInscattering, expFogFactor); + return float4(inscatteringColor * (1.0f - expFogFactor) + directionalInscattering, expFogFactor); } #endif diff --git a/Source/Shaders/GBuffer.hlsl b/Source/Shaders/GBuffer.hlsl index 9ec390135..9288ab8a6 100644 --- a/Source/Shaders/GBuffer.hlsl +++ b/Source/Shaders/GBuffer.hlsl @@ -11,7 +11,7 @@ Texture2D GBuffer0 : register(t0); Texture2D GBuffer1 : register(t1); Texture2D GBuffer2 : register(t2); -Texture2D Depth : register(t3); +Texture2D Depth : register(t3); #if defined(USE_GBUFFER_CUSTOM_DATA) Texture2D GBuffer3 : register(t4); #endif @@ -27,28 +27,28 @@ Texture2D GBuffer3 : register(t4); // Linearize raw device depth float LinearizeZ(GBufferData gBuffer, float depth) { - return gBuffer.ViewInfo.w / (depth - gBuffer.ViewInfo.z); + return gBuffer.ViewInfo.w / (depth - gBuffer.ViewInfo.z); } // Convert linear depth to device depth float LinearZ2DeviceDepth(GBufferData gBuffer, float linearDepth) { - return (gBuffer.ViewInfo.w / linearDepth) + gBuffer.ViewInfo.z; + return (gBuffer.ViewInfo.w / linearDepth) + gBuffer.ViewInfo.z; } // Get view space position at given pixel coordinate with given device depth float3 GetViewPos(GBufferData gBuffer, float2 uv, float deviceDepth) { - float4 clipPos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), deviceDepth, 1.0); - float4 viewPos = mul(clipPos, gBuffer.InvProjectionMatrix); - return viewPos.xyz / viewPos.w; + float4 clipPos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), deviceDepth, 1.0); + float4 viewPos = mul(clipPos, gBuffer.InvProjectionMatrix); + return viewPos.xyz / viewPos.w; } // Get world space position at given pixel coordinate with given device depth float3 GetWorldPos(GBufferData gBuffer, float2 uv, float deviceDepth) { - float3 viewPos = GetViewPos(gBuffer, uv, deviceDepth); - return mul(float4(viewPos, 1), gBuffer.InvViewMatrix).xyz; + float3 viewPos = GetViewPos(gBuffer, uv, deviceDepth); + return mul(float4(viewPos, 1), gBuffer.InvViewMatrix).xyz; } #if !defined(NO_GBUFFER_SAMPLING) @@ -56,92 +56,92 @@ float3 GetWorldPos(GBufferData gBuffer, float2 uv, float deviceDepth) // Sample raw device depth buffer float SampleZ(float2 uv) { - return SAMPLE_RT(Depth, uv).r; + return SAMPLE_RT(Depth, uv).r; } // Sample linear depth float SampleDepth(GBufferData gBuffer, float2 uv) { - float deviceDepth = SampleZ(uv); - return LinearizeZ(gBuffer, deviceDepth); + float deviceDepth = SampleZ(uv); + return LinearizeZ(gBuffer, deviceDepth); } // Get view space position at given pixel coordinate float3 GetViewPos(GBufferData gBuffer, float2 uv) { - float deviceDepth = SampleZ(uv); - return GetViewPos(gBuffer, uv, deviceDepth); + float deviceDepth = SampleZ(uv); + return GetViewPos(gBuffer, uv, deviceDepth); } // Get world space position at given pixel coordinate float3 GetWorldPos(GBufferData gBuffer, float2 uv) { - float deviceDepth = SampleZ(uv); - return GetWorldPos(gBuffer, uv, deviceDepth); + float deviceDepth = SampleZ(uv); + return GetWorldPos(gBuffer, uv, deviceDepth); } // Sample normal vector with pixel shading model float3 SampleNormal(float2 uv, out int shadingModel) { - // Sample GBuffer - float4 gBuffer1 = SAMPLE_RT(GBuffer1, uv); + // Sample GBuffer + float4 gBuffer1 = SAMPLE_RT(GBuffer1, uv); - // Decode normal and shading model - shadingModel = (int)(gBuffer1.a * 3.999); - return DecodeNormal(gBuffer1.rgb); + // Decode normal and shading model + shadingModel = (int)(gBuffer1.a * 3.999); + return DecodeNormal(gBuffer1.rgb); } // Sample GBuffer GBufferSample SampleGBuffer(GBufferData gBuffer, float2 uv) { - GBufferSample result; + GBufferSample result; - // Sample GBuffer - float4 gBuffer0 = SAMPLE_RT(GBuffer0, uv); - float4 gBuffer1 = SAMPLE_RT(GBuffer1, uv); - float4 gBuffer2 = SAMPLE_RT(GBuffer2, uv); + // Sample GBuffer + float4 gBuffer0 = SAMPLE_RT(GBuffer0, uv); + float4 gBuffer1 = SAMPLE_RT(GBuffer1, uv); + float4 gBuffer2 = SAMPLE_RT(GBuffer2, uv); #if defined(USE_GBUFFER_CUSTOM_DATA) float4 gBuffer3 = SAMPLE_RT(GBuffer3, uv); #endif - // Decode normal and shading model - result.Normal = DecodeNormal(gBuffer1.rgb); - result.ShadingModel = (int)(gBuffer1.a * 3.999); + // Decode normal and shading model + result.Normal = DecodeNormal(gBuffer1.rgb); + result.ShadingModel = (int)(gBuffer1.a * 3.999); - // Calculate view space and world space positions - result.ViewPos = GetViewPos(gBuffer, uv); - result.WorldPos = mul(float4(result.ViewPos, 1), gBuffer.InvViewMatrix).xyz; + // Calculate view space and world space positions + result.ViewPos = GetViewPos(gBuffer, uv); + result.WorldPos = mul(float4(result.ViewPos, 1), gBuffer.InvViewMatrix).xyz; - // Decode GBuffer data - result.Color = gBuffer0.rgb; - result.AO = gBuffer0.a; - result.Roughness = gBuffer2.r; - result.Metalness = gBuffer2.g; - result.Specular = gBuffer2.b; + // Decode GBuffer data + result.Color = gBuffer0.rgb; + result.AO = gBuffer0.a; + result.Roughness = gBuffer2.r; + result.Metalness = gBuffer2.g; + result.Specular = gBuffer2.b; #if defined(USE_GBUFFER_CUSTOM_DATA) result.CustomData = gBuffer3; #endif - return result; + return result; } // Sample GBuffer (fast - only few parameters are being sampled) GBufferSample SampleGBufferFast(GBufferData gBuffer, float2 uv) { - GBufferSample result; + GBufferSample result; - // Sample GBuffer - float4 gBuffer1 = SAMPLE_RT(GBuffer1, uv); + // Sample GBuffer + float4 gBuffer1 = SAMPLE_RT(GBuffer1, uv); - // Decode normal and shading model - result.Normal = DecodeNormal(gBuffer1.rgb); - result.ShadingModel = (int)(gBuffer1.a * 3.999); + // Decode normal and shading model + result.Normal = DecodeNormal(gBuffer1.rgb); + result.ShadingModel = (int)(gBuffer1.a * 3.999); - // Calculate view space position - result.ViewPos = GetViewPos(gBuffer, uv); - result.WorldPos = mul(float4(result.ViewPos, 1), gBuffer.InvViewMatrix).xyz; + // Calculate view space position + result.ViewPos = GetViewPos(gBuffer, uv); + result.WorldPos = mul(float4(result.ViewPos, 1), gBuffer.InvViewMatrix).xyz; - return result; + return result; } #if defined(USE_GBUFFER_CUSTOM_DATA) diff --git a/Source/Shaders/GBufferCommon.hlsl b/Source/Shaders/GBufferCommon.hlsl index e78fec549..ebeeaefde 100644 --- a/Source/Shaders/GBufferCommon.hlsl +++ b/Source/Shaders/GBufferCommon.hlsl @@ -8,15 +8,15 @@ // GBuffer sample data structure struct GBufferSample { - float3 Normal; - float Roughness; - float3 WorldPos; - float Metalness; - float3 Color; - float Specular; - float3 ViewPos; - float AO; - int ShadingModel; + float3 Normal; + float Roughness; + float3 WorldPos; + float Metalness; + float3 Color; + float Specular; + float3 ViewPos; + float AO; + int ShadingModel; #if defined(USE_GBUFFER_CUSTOM_DATA) float4 CustomData; #endif @@ -24,45 +24,45 @@ struct GBufferSample bool IsSubsurfaceMode(int shadingModel) { - return shadingModel == SHADING_MODEL_SUBSURFACE || shadingModel == SHADING_MODEL_FOLIAGE; + return shadingModel == SHADING_MODEL_SUBSURFACE || shadingModel == SHADING_MODEL_FOLIAGE; } float3 GetDiffuseColor(in float3 color, in float metalness) { - return color - color * metalness; + return color - color * metalness; } float3 GetSpecularColor(in float3 color, in float specular, in float metalness) { - return lerp(0.08 * specular.xxx, color.rgb, metalness.xxx); + return lerp(0.08 * specular.xxx, color.rgb, metalness.xxx); } // Calculate material diffuse color float3 GetDiffuseColor(in GBufferSample gBuffer) { - return gBuffer.Color - gBuffer.Color * gBuffer.Metalness; + return gBuffer.Color - gBuffer.Color * gBuffer.Metalness; } // Calculate material specular color float3 GetSpecularColor(in GBufferSample gBuffer) { - return lerp(0.08 * gBuffer.Specular.xxx, gBuffer.Color.rgb, gBuffer.Metalness.xxx); + return lerp(0.08 * gBuffer.Specular.xxx, gBuffer.Color.rgb, gBuffer.Metalness.xxx); } // Compact Normal Storage for Small G-Buffers // [Aras Pranckevièius 2010, http://aras-p.info/texts/CompactNormalStorage.html] float3 EncodeNormal(float3 n) { - // Pack to [0;1] range - return n * 0.5 + 0.5; + // Pack to [0;1] range + return n * 0.5 + 0.5; } // Compact Normal Storage for Small G-Buffers // [Aras Pranckevièius 2010, http://aras-p.info/texts/CompactNormalStorage.html] float3 DecodeNormal(float3 enc) { - // Unpack from [0;1] range - return normalize(enc * 2 - 1); + // Unpack from [0;1] range + return normalize(enc * 2 - 1); } #endif diff --git a/Source/Shaders/GI/DDGI.hlsl b/Source/Shaders/GI/DDGI.hlsl index 9b5101c6a..78a11bb2c 100644 --- a/Source/Shaders/GI/DDGI.hlsl +++ b/Source/Shaders/GI/DDGI.hlsl @@ -158,7 +158,7 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D probesState, } if (cascadeIndex == data.CascadesCount) return data.FallbackIrradiance; - + float probesSpacing = data.ProbesOriginAndSpacing[cascadeIndex].w; float3 probesOrigin = data.ProbesScrollOffsets[cascadeIndex].xyz * probesSpacing + data.ProbesOriginAndSpacing[cascadeIndex].xyz; float3 probesExtent = (data.ProbesCounts - 1) * (probesSpacing * 0.5f); @@ -196,7 +196,7 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D probesState, // Smooth backface test float weight = Square(dot(worldPosToProbe, worldNormal) * 0.5f + 0.5f); - + // Sample distance texture float2 octahedralCoords = GetOctahedralCoords(-biasedPosToProbe); float2 uv = GetDDGIProbeUV(data, cascadeIndex, probeIndex, octahedralCoords, DDGI_PROBE_RESOLUTION_DISTANCE); diff --git a/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl b/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl index 6545257ff..30c963d85 100644 --- a/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl +++ b/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl @@ -14,114 +14,114 @@ struct GlobalSurfaceTile { - float4 AtlasRectUV; - float4x4 WorldToLocal; - float3 ViewBoundsSize; + float4 AtlasRectUV; + float4x4 WorldToLocal; + float3 ViewBoundsSize; }; struct GlobalSurfaceObject { - float3 BoundsPosition; - float BoundsRadius; - float4x4 WorldToLocal; - float3 Extent; + float3 BoundsPosition; + float BoundsRadius; + float4x4 WorldToLocal; + float3 Extent; bool UseVisibility; - uint TileOffsets[6]; - uint DataSize; // count of float4s for object+tiles + uint TileOffsets[6]; + uint DataSize; // count of float4s for object+tiles }; float4 LoadGlobalSurfaceAtlasObjectBounds(Buffer objects, uint objectAddress) { - // This must match C++ - return objects.Load(objectAddress + 0); + // This must match C++ + return objects.Load(objectAddress + 0); } uint LoadGlobalSurfaceAtlasObjectDataSize(Buffer objects, uint objectAddress) { - // This must match C++ - return asuint(objects.Load(objectAddress + 1).w); + // This must match C++ + return asuint(objects.Load(objectAddress + 1).w); } GlobalSurfaceObject LoadGlobalSurfaceAtlasObject(Buffer objects, uint objectAddress) { - // This must match C++ - float4 vector0 = objects.Load(objectAddress + 0); - float4 vector1 = objects.Load(objectAddress + 1); - float4 vector2 = objects.Load(objectAddress + 2); - float4 vector3 = objects.Load(objectAddress + 3); - float4 vector4 = objects.Load(objectAddress + 4); - float4 vector5 = objects.Load(objectAddress + 5); - GlobalSurfaceObject object = (GlobalSurfaceObject)0; - object.BoundsPosition = vector0.xyz; - object.BoundsRadius = vector0.w; - object.WorldToLocal[0] = float4(vector2.xyz, 0.0f); - object.WorldToLocal[1] = float4(vector3.xyz, 0.0f); - object.WorldToLocal[2] = float4(vector4.xyz, 0.0f); - object.WorldToLocal[3] = float4(vector2.w, vector3.w, vector4.w, 1.0f); - object.Extent = vector5.xyz; - object.UseVisibility = vector5.w > 0.5f; - uint vector1x = asuint(vector1.x); - uint vector1y = asuint(vector1.y); - uint vector1z = asuint(vector1.z); - object.DataSize = asuint(vector1.w); - object.TileOffsets[0] = vector1x & 0xffff; - object.TileOffsets[1] = vector1x >> 16; - object.TileOffsets[2] = vector1y & 0xffff; - object.TileOffsets[3] = vector1y >> 16; - object.TileOffsets[4] = vector1z & 0xffff; - object.TileOffsets[5] = vector1z >> 16; - return object; + // This must match C++ + float4 vector0 = objects.Load(objectAddress + 0); + float4 vector1 = objects.Load(objectAddress + 1); + float4 vector2 = objects.Load(objectAddress + 2); + float4 vector3 = objects.Load(objectAddress + 3); + float4 vector4 = objects.Load(objectAddress + 4); + float4 vector5 = objects.Load(objectAddress + 5); + GlobalSurfaceObject object = (GlobalSurfaceObject)0; + object.BoundsPosition = vector0.xyz; + object.BoundsRadius = vector0.w; + object.WorldToLocal[0] = float4(vector2.xyz, 0.0f); + object.WorldToLocal[1] = float4(vector3.xyz, 0.0f); + object.WorldToLocal[2] = float4(vector4.xyz, 0.0f); + object.WorldToLocal[3] = float4(vector2.w, vector3.w, vector4.w, 1.0f); + object.Extent = vector5.xyz; + object.UseVisibility = vector5.w > 0.5f; + uint vector1x = asuint(vector1.x); + uint vector1y = asuint(vector1.y); + uint vector1z = asuint(vector1.z); + object.DataSize = asuint(vector1.w); + object.TileOffsets[0] = vector1x & 0xffff; + object.TileOffsets[1] = vector1x >> 16; + object.TileOffsets[2] = vector1y & 0xffff; + object.TileOffsets[3] = vector1y >> 16; + object.TileOffsets[4] = vector1z & 0xffff; + object.TileOffsets[5] = vector1z >> 16; + return object; } GlobalSurfaceTile LoadGlobalSurfaceAtlasTile(Buffer objects, uint tileAddress) { - // This must match C++ - float4 vector0 = objects.Load(tileAddress + 0); - float4 vector1 = objects.Load(tileAddress + 1); - float4 vector2 = objects.Load(tileAddress + 2); - float4 vector3 = objects.Load(tileAddress + 3); - float4 vector4 = objects.Load(tileAddress + 4); // w unused - GlobalSurfaceTile tile = (GlobalSurfaceTile)0; - tile.AtlasRectUV = vector0.xyzw; - tile.WorldToLocal[0] = float4(vector1.xyz, 0.0f); - tile.WorldToLocal[1] = float4(vector2.xyz, 0.0f); - tile.WorldToLocal[2] = float4(vector3.xyz, 0.0f); - tile.WorldToLocal[3] = float4(vector1.w, vector2.w, vector3.w, 1.0f); - tile.ViewBoundsSize = vector4.xyz; - return tile; + // This must match C++ + float4 vector0 = objects.Load(tileAddress + 0); + float4 vector1 = objects.Load(tileAddress + 1); + float4 vector2 = objects.Load(tileAddress + 2); + float4 vector3 = objects.Load(tileAddress + 3); + float4 vector4 = objects.Load(tileAddress + 4); // w unused + GlobalSurfaceTile tile = (GlobalSurfaceTile)0; + tile.AtlasRectUV = vector0.xyzw; + tile.WorldToLocal[0] = float4(vector1.xyz, 0.0f); + tile.WorldToLocal[1] = float4(vector2.xyz, 0.0f); + tile.WorldToLocal[2] = float4(vector3.xyz, 0.0f); + tile.WorldToLocal[3] = float4(vector1.w, vector2.w, vector3.w, 1.0f); + tile.ViewBoundsSize = vector4.xyz; + return tile; } // Global Surface Atlas data for a constant buffer struct GlobalSurfaceAtlasData { - float3 ViewPos; - float Padding0; - float Padding1; - float Resolution; - float ChunkSize; - uint ObjectsCount; + float3 ViewPos; + float Padding0; + float Padding1; + float Resolution; + float ChunkSize; + uint ObjectsCount; }; float3 SampleGlobalSurfaceAtlasTex(Texture2D atlas, float2 atlasUV, float4 bilinearWeights) { - float4 sampleX = atlas.GatherRed(SamplerLinearClamp, atlasUV); - float4 sampleY = atlas.GatherGreen(SamplerLinearClamp, atlasUV); - float4 sampleZ = atlas.GatherBlue(SamplerLinearClamp, atlasUV); - return float3(dot(sampleX, bilinearWeights), dot(sampleY, bilinearWeights), dot(sampleZ, bilinearWeights)); + float4 sampleX = atlas.GatherRed(SamplerLinearClamp, atlasUV); + float4 sampleY = atlas.GatherGreen(SamplerLinearClamp, atlasUV); + float4 sampleZ = atlas.GatherBlue(SamplerLinearClamp, atlasUV); + return float3(dot(sampleX, bilinearWeights), dot(sampleY, bilinearWeights), dot(sampleZ, bilinearWeights)); } float4 SampleGlobalSurfaceAtlasTile(const GlobalSurfaceAtlasData data, GlobalSurfaceObject object, GlobalSurfaceTile tile, Texture2D depth, Texture2D atlas, float3 worldPosition, float3 worldNormal, float surfaceThreshold) { #if GLOBAL_SURFACE_ATLAS_TILE_NORMAL_WEIGHT_ENABLED - // Tile normal weight based on the sampling angle - float3 tileNormal = normalize(mul(worldNormal, (float3x3)tile.WorldToLocal)); - float normalWeight = saturate(dot(float3(0, 0, -1), tileNormal)); - normalWeight = (normalWeight - GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD) / (1.0f - GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD); - if (normalWeight <= 0.0f && object.UseVisibility) - return 0; + // Tile normal weight based on the sampling angle + float3 tileNormal = normalize(mul(worldNormal, (float3x3)tile.WorldToLocal)); + float normalWeight = saturate(dot(float3(0, 0, -1), tileNormal)); + normalWeight = (normalWeight - GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD) / (1.0f - GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD); + if (normalWeight <= 0.0f && object.UseVisibility) + return 0; #endif - // Get tile UV and depth at the world position + // Get tile UV and depth at the world position float3 tilePosition = mul(float4(worldPosition, 1), tile.WorldToLocal).xyz; float tileDepth = tilePosition.z / tile.ViewBoundsSize.z; float2 tileUV = saturate((tilePosition.xy / tile.ViewBoundsSize.xy) + 0.5f); @@ -129,15 +129,15 @@ float4 SampleGlobalSurfaceAtlasTile(const GlobalSurfaceAtlasData data, GlobalSur tileUV = min(tileUV, 0.999999f); float2 atlasUV = tileUV * tile.AtlasRectUV.zw + tile.AtlasRectUV.xy; - // Calculate bilinear weights - float2 bilinearWeightsUV = frac(atlasUV * data.Resolution + 0.5f); - float4 bilinearWeights; - bilinearWeights.x = (1.0 - bilinearWeightsUV.x) * (bilinearWeightsUV.y); - bilinearWeights.y = (bilinearWeightsUV.x) * (bilinearWeightsUV.y); - bilinearWeights.z = (bilinearWeightsUV.x) * (1 - bilinearWeightsUV.y); - bilinearWeights.w = (1 - bilinearWeightsUV.x) * (1 - bilinearWeightsUV.y); + // Calculate bilinear weights + float2 bilinearWeightsUV = frac(atlasUV * data.Resolution + 0.5f); + float4 bilinearWeights; + bilinearWeights.x = (1.0 - bilinearWeightsUV.x) * (bilinearWeightsUV.y); + bilinearWeights.y = (bilinearWeightsUV.x) * (bilinearWeightsUV.y); + bilinearWeights.z = (bilinearWeightsUV.x) * (1 - bilinearWeightsUV.y); + bilinearWeights.w = (1 - bilinearWeightsUV.x) * (1 - bilinearWeightsUV.y); - // Tile depth weight based on sample position occlusion + // Tile depth weight based on sample position occlusion float4 tileZ = depth.Gather(SamplerLinearClamp, atlasUV, 0.0f); float depthThreshold = 2.0f * surfaceThreshold / tile.ViewBoundsSize.z; float4 depthVisibility = 1.0f; @@ -150,74 +150,74 @@ float4 SampleGlobalSurfaceAtlasTile(const GlobalSurfaceAtlasData data, GlobalSur } float sampleWeight = dot(depthVisibility, bilinearWeights); #if GLOBAL_SURFACE_ATLAS_TILE_NORMAL_WEIGHT_ENABLED - if (object.UseVisibility) + if (object.UseVisibility) sampleWeight *= normalWeight; #endif if (sampleWeight <= 0.0f) return 0; - bilinearWeights *= depthVisibility; - //bilinearWeights = normalize(bilinearWeights); + bilinearWeights *= depthVisibility; + //bilinearWeights = normalize(bilinearWeights); - // Sample atlas texture - float3 sampleColor = SampleGlobalSurfaceAtlasTex(atlas, atlasUV, bilinearWeights); + // Sample atlas texture + float3 sampleColor = SampleGlobalSurfaceAtlasTex(atlas, atlasUV, bilinearWeights); - //return float4(sampleWeight.xxx, sampleWeight); - return float4(sampleColor.rgb * sampleWeight, sampleWeight); - //return float4(normalWeight.xxx, sampleWeight); + //return float4(sampleWeight.xxx, sampleWeight); + return float4(sampleColor.rgb * sampleWeight, sampleWeight); + //return float4(normalWeight.xxx, sampleWeight); } // Samples the Global Surface Atlas and returns the lighting (with opacity) at the given world location (and direction). // surfaceThreshold - Additional threshold (in world-units) between object or tile size compared with input data (error due to SDF or LOD incorrect appearance) float4 SampleGlobalSurfaceAtlas(const GlobalSurfaceAtlasData data, ByteAddressBuffer chunks, ByteAddressBuffer culledObjects, Buffer objects, Texture2D depth, Texture2D atlas, float3 worldPosition, float3 worldNormal, float surfaceThreshold = 20.0f) { - float4 result = float4(0, 0, 0, 0); + float4 result = float4(0, 0, 0, 0); - // Snap to the closest chunk to get culled objects - uint3 chunkCoord = (uint3)clamp(floor((worldPosition - data.ViewPos) / data.ChunkSize + (GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION * 0.5f)), 0, GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION - 1); - uint chunkAddress = (chunkCoord.z * (GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION * GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION) + chunkCoord.y * GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION + chunkCoord.x) * 4; - uint objectsStart = chunks.Load(chunkAddress); - if (objectsStart == 0) - { - // Empty chunk - return result; - } + // Snap to the closest chunk to get culled objects + uint3 chunkCoord = (uint3)clamp(floor((worldPosition - data.ViewPos) / data.ChunkSize + (GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION * 0.5f)), 0, GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION - 1); + uint chunkAddress = (chunkCoord.z * (GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION * GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION) + chunkCoord.y * GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION + chunkCoord.x) * 4; + uint objectsStart = chunks.Load(chunkAddress); + if (objectsStart == 0) + { + // Empty chunk + return result; + } - // Read objects counter - uint objectsCount = culledObjects.Load(objectsStart * 4); - if (objectsCount > data.ObjectsCount) // Prevents crashing - don't know why the data is invalid here (rare issue when moving fast though scene with terrain) - return result; - objectsStart++; + // Read objects counter + uint objectsCount = culledObjects.Load(objectsStart * 4); + if (objectsCount > data.ObjectsCount) // Prevents crashing - don't know why the data is invalid here (rare issue when moving fast though scene with terrain) + return result; + objectsStart++; - // Loop over culled objects inside the chunk - LOOP - for (uint objectIndex = 0; objectIndex < objectsCount; objectIndex++) - { - // Cull point vs sphere - uint objectAddress = culledObjects.Load(objectsStart * 4); - objectsStart++; - float4 objectBounds = LoadGlobalSurfaceAtlasObjectBounds(objects, objectAddress); - if (distance(objectBounds.xyz, worldPosition) > objectBounds.w) - continue; - GlobalSurfaceObject object = LoadGlobalSurfaceAtlasObject(objects, objectAddress); - float3 localPosition = mul(float4(worldPosition, 1), object.WorldToLocal).xyz; - float3 localExtent = object.Extent + surfaceThreshold; - if (any(localPosition > localExtent) || any(localPosition < -localExtent)) - continue; + // Loop over culled objects inside the chunk + LOOP + for (uint objectIndex = 0; objectIndex < objectsCount; objectIndex++) + { + // Cull point vs sphere + uint objectAddress = culledObjects.Load(objectsStart * 4); + objectsStart++; + float4 objectBounds = LoadGlobalSurfaceAtlasObjectBounds(objects, objectAddress); + if (distance(objectBounds.xyz, worldPosition) > objectBounds.w) + continue; + GlobalSurfaceObject object = LoadGlobalSurfaceAtlasObject(objects, objectAddress); + float3 localPosition = mul(float4(worldPosition, 1), object.WorldToLocal).xyz; + float3 localExtent = object.Extent + surfaceThreshold; + if (any(localPosition > localExtent) || any(localPosition < -localExtent)) + continue; - // Remove the scale vector from the transformation matrix - float3x3 worldToLocal = (float3x3)object.WorldToLocal; - float scaleX = length(worldToLocal[0]); - float scaleY = length(worldToLocal[1]); - float scaleZ = length(worldToLocal[2]); - float3 invScale = float3( - scaleX > 0.00001f ? 1.0f / scaleX : 0.0f, - scaleY > 0.00001f ? 1.0f / scaleY : 0.0f, - scaleZ > 0.00001f ? 1.0f / scaleZ : 0.0f); - worldToLocal[0] *= invScale.x; - worldToLocal[1] *= invScale.y; - worldToLocal[2] *= invScale.z; + // Remove the scale vector from the transformation matrix + float3x3 worldToLocal = (float3x3)object.WorldToLocal; + float scaleX = length(worldToLocal[0]); + float scaleY = length(worldToLocal[1]); + float scaleZ = length(worldToLocal[2]); + float3 invScale = float3( + scaleX > 0.00001f ? 1.0f / scaleX : 0.0f, + scaleY > 0.00001f ? 1.0f / scaleY : 0.0f, + scaleZ > 0.00001f ? 1.0f / scaleZ : 0.0f); + worldToLocal[0] *= invScale.x; + worldToLocal[1] *= invScale.y; + worldToLocal[2] *= invScale.z; - // Sample tiles based on the directionality + // Sample tiles based on the directionality #if GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD_ENABLED float3 localNormal = normalize(mul(worldNormal, worldToLocal)); float3 localNormalSq = localNormal * localNormal; @@ -240,47 +240,47 @@ float4 SampleGlobalSurfaceAtlas(const GlobalSurfaceAtlasData data, ByteAddressBu result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); } #else - uint tileOffset = object.TileOffsets[0]; - if (tileOffset != 0) - { - GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); - result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); - } - tileOffset = object.TileOffsets[1]; - if (tileOffset != 0) - { - GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); - result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); - } - tileOffset = object.TileOffsets[2]; - if (tileOffset != 0) - { - GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); - result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); - } - tileOffset = object.TileOffsets[3]; - if (tileOffset != 0) - { - GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); - result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); - } - tileOffset = object.TileOffsets[4]; - if (tileOffset != 0) - { - GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); - result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); - } - tileOffset = object.TileOffsets[5]; - if (tileOffset != 0) - { - GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); - result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); - } + uint tileOffset = object.TileOffsets[0]; + if (tileOffset != 0) + { + GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); + result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); + } + tileOffset = object.TileOffsets[1]; + if (tileOffset != 0) + { + GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); + result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); + } + tileOffset = object.TileOffsets[2]; + if (tileOffset != 0) + { + GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); + result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); + } + tileOffset = object.TileOffsets[3]; + if (tileOffset != 0) + { + GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); + result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); + } + tileOffset = object.TileOffsets[4]; + if (tileOffset != 0) + { + GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); + result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); + } + tileOffset = object.TileOffsets[5]; + if (tileOffset != 0) + { + GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); + result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); + } #endif - } + } - // Normalize result - result.rgb /= max(result.a, 0.0001f); + // Normalize result + result.rgb /= max(result.a, 0.0001f); - return result; + return result; } diff --git a/Source/Shaders/GUICommon.hlsl b/Source/Shaders/GUICommon.hlsl index d19c3e783..1f8ef377b 100644 --- a/Source/Shaders/GUICommon.hlsl +++ b/Source/Shaders/GUICommon.hlsl @@ -9,53 +9,53 @@ struct Render2DVertex { - float2 Position : POSITION0; - float2 TexCoord : TEXCOORD0; - float4 Color : COLOR0; - float4 CustomDataAndClipOrigin : TEXCOORD1; // x-per-geometry type, y-features mask, zw-clip origin - float4 ClipExtents : TEXCOORD2; + float2 Position : POSITION0; + float2 TexCoord : TEXCOORD0; + float4 Color : COLOR0; + float4 CustomDataAndClipOrigin : TEXCOORD1; // x-per-geometry type, y-features mask, zw-clip origin + float4 ClipExtents : TEXCOORD2; }; struct VS2PS { - float4 Position : SV_Position; - float4 Color : COLOR0; - float2 TexCoord : TEXCOORD0; - float2 CustomData : TEXCOORD1; - float4 ClipExtents : TEXCOORD2; - float4 ClipOriginAndPos : TEXCOORD3; + float4 Position : SV_Position; + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; + float2 CustomData : TEXCOORD1; + float4 ClipExtents : TEXCOORD2; + float4 ClipOriginAndPos : TEXCOORD3; }; float cross2(float2 a, float2 b) { - return a.x * b.y - a.y * b.x; + return a.x * b.y - a.y * b.x; } // Given a point p and a parallelogram defined by point a and vectors b and c, determines in p is inside the parallelogram. Returns a 4-vector that can be used with the clip instruction. float4 PointInParallelogram(float2 p, float2 a, float4 bc) { - float2 o = p - a; - float invD = 1 / cross2(bc.xy, bc.zw); - float2 t = (o.x * bc.yw - o.y * bc.xz) * float2(-invD, invD); - return float4(t, float2(1, 1) - t); + float2 o = p - a; + float invD = 1 / cross2(bc.xy, bc.zw); + float2 t = (o.x * bc.yw - o.y * bc.xz) * float2(-invD, invD); + return float4(t, float2(1, 1) - t); } void PerformClipping(float2 clipOrigin, float2 windowPos, float4 clipExtents) { #if CLIPPING_ENABLE - // Clip pixels which are outside of the clipping rect - float4 clipTest = PointInParallelogram(windowPos, clipOrigin, clipExtents); + // Clip pixels which are outside of the clipping rect + float4 clipTest = PointInParallelogram(windowPos, clipOrigin, clipExtents); - // Clip pixels which are outside of the clipping rect - clip(clipTest); + // Clip pixels which are outside of the clipping rect + clip(clipTest); #endif } void PerformClipping(VS2PS input) { - PerformClipping(input.ClipOriginAndPos.xy, input.ClipOriginAndPos.zw, input.ClipExtents); + PerformClipping(input.ClipOriginAndPos.xy, input.ClipOriginAndPos.zw, input.ClipExtents); } #endif diff --git a/Source/Shaders/GammaCorrectionCommon.hlsl b/Source/Shaders/GammaCorrectionCommon.hlsl index a5ca4d53d..5681616ed 100644 --- a/Source/Shaders/GammaCorrectionCommon.hlsl +++ b/Source/Shaders/GammaCorrectionCommon.hlsl @@ -9,69 +9,69 @@ // http://gpuopen.com/optimized-reversible-tonemapper-for-resolve/ float3 FastTonemap(float3 c) { - return c * rcp(max(max(c.r, c.g), c.b) + 1.0); + return c * rcp(max(max(c.r, c.g), c.b) + 1.0); } float4 FastTonemap(float4 c) { - return float4(FastTonemap(c.rgb), c.a); + return float4(FastTonemap(c.rgb), c.a); } float3 FastTonemap(float3 c, float w) { - return c * (w * rcp(max(max(c.r, c.g), c.b) + 1.0)); + return c * (w * rcp(max(max(c.r, c.g), c.b) + 1.0)); } float4 FastTonemap(float4 c, float w) { - return float4(FastTonemap(c.rgb, w), c.a); + return float4(FastTonemap(c.rgb, w), c.a); } float3 FastTonemapInvert(float3 c) { - return c * rcp(1.0 - max(max(c.r, c.g), c.b)); + return c * rcp(1.0 - max(max(c.r, c.g), c.b)); } float4 FastTonemapInvert(float4 c) { - return float4(FastTonemapInvert(c.rgb), c.a); + return float4(FastTonemapInvert(c.rgb), c.a); } float LinearToSrgbChannel(float linearColor) { - if (linearColor < 0.00313067) - return linearColor * 12.92; - return pow(linearColor, (1.0 / 2.4)) * 1.055 - 0.055; + if (linearColor < 0.00313067) + return linearColor * 12.92; + return pow(linearColor, (1.0 / 2.4)) * 1.055 - 0.055; } float3 LinearToSrgb(float3 linearColor) { - return float3( - LinearToSrgbChannel(linearColor.r), - LinearToSrgbChannel(linearColor.g), - LinearToSrgbChannel(linearColor.b)); + return float3( + LinearToSrgbChannel(linearColor.r), + LinearToSrgbChannel(linearColor.g), + LinearToSrgbChannel(linearColor.b)); } float3 sRGBToLinear(float3 color) { - color = max(6.10352e-5, color); - return color > 0.04045 ? pow(color * (1.0 / 1.055) + 0.0521327, 2.4) : color * (1.0 / 12.92); + color = max(6.10352e-5, color); + return color > 0.04045 ? pow(color * (1.0 / 1.055) + 0.0521327, 2.4) : color * (1.0 / 12.92); } float3 LogToLinear(float3 logColor) { - const float linearRange = 14.0f; - const float linearGrey = 0.18f; - const float exposureGrey = 444.0f; - return exp2((logColor - exposureGrey / 1023.0) * linearRange) * linearGrey; + const float linearRange = 14.0f; + const float linearGrey = 0.18f; + const float exposureGrey = 444.0f; + return exp2((logColor - exposureGrey / 1023.0) * linearRange) * linearGrey; } float3 LinearToLog(float3 linearColor) { - const float linearRange = 14.0f; - const float linearGrey = 0.18f; - const float exposureGrey = 444.0f; - return saturate(log2(linearColor) / linearRange - log2(linearGrey) / linearRange + exposureGrey / 1023.0f); + const float linearRange = 14.0f; + const float linearGrey = 0.18f; + const float exposureGrey = 444.0f; + return saturate(log2(linearColor) / linearRange - log2(linearGrey) / linearRange + exposureGrey / 1023.0f); } #endif diff --git a/Source/Shaders/Gather.hlsl b/Source/Shaders/Gather.hlsl index f2e0e7124..f6540fe86 100644 --- a/Source/Shaders/Gather.hlsl +++ b/Source/Shaders/Gather.hlsl @@ -10,11 +10,11 @@ float4 TextureGatherRed(Texture2D tex, SamplerState sam, float2 uv) #if CAN_USE_GATHER return tex.GatherRed(sam, uv); #else - float x = tex.Sample(sam, uv, int2(0, 1)).x; - float y = tex.Sample(sam, uv, int2(1, 1)).x; - float z = tex.Sample(sam, uv, int2(1, 0)).x; - float w = tex.Sample(sam, uv, int2(0, 0)).x; - return float4(x, y, z, w); + float x = tex.Sample(sam, uv, int2(0, 1)).x; + float y = tex.Sample(sam, uv, int2(1, 1)).x; + float z = tex.Sample(sam, uv, int2(1, 0)).x; + float w = tex.Sample(sam, uv, int2(0, 0)).x; + return float4(x, y, z, w); #endif } @@ -23,11 +23,11 @@ float4 TextureGatherRed(Texture2DArray tex, SamplerState sam, float3 uv) #if CAN_USE_GATHER return tex.GatherRed(sam, uv); #else - float x = tex.Sample(sam, uv, int2(0, 1)).x; - float y = tex.Sample(sam, uv, int2(1, 1)).x; - float z = tex.Sample(sam, uv, int2(1, 0)).x; - float w = tex.Sample(sam, uv, int2(0, 0)).x; - return float4(x, y, z, w); + float x = tex.Sample(sam, uv, int2(0, 1)).x; + float y = tex.Sample(sam, uv, int2(1, 1)).x; + float z = tex.Sample(sam, uv, int2(1, 0)).x; + float w = tex.Sample(sam, uv, int2(0, 0)).x; + return float4(x, y, z, w); #endif } @@ -36,11 +36,11 @@ float4 TextureGatherRed(Texture2D tex, SamplerState sam, float2 uv, int2 offset) #if CAN_USE_GATHER return tex.GatherRed(sam, uv, offset); #else - float x = tex.Sample(sam, uv, offset + int2(0, 1)).x; - float y = tex.Sample(sam, uv, offset + int2(1, 1)).x; - float z = tex.Sample(sam, uv, offset + int2(1, 0)).x; - float w = tex.Sample(sam, uv, offset + int2(0, 0)).x; - return float4(x, y, z, w); + float x = tex.Sample(sam, uv, offset + int2(0, 1)).x; + float y = tex.Sample(sam, uv, offset + int2(1, 1)).x; + float z = tex.Sample(sam, uv, offset + int2(1, 0)).x; + float w = tex.Sample(sam, uv, offset + int2(0, 0)).x; + return float4(x, y, z, w); #endif } @@ -49,11 +49,11 @@ float4 TextureGatherRed(Texture2D tex, SamplerState sam, float2 uv) #if CAN_USE_GATHER return tex.GatherRed(sam, uv); #else - float x = tex.Sample(sam, uv, int2(0, 1)).x; - float y = tex.Sample(sam, uv, int2(1, 1)).x; - float z = tex.Sample(sam, uv, int2(1, 0)).x; - float w = tex.Sample(sam, uv, int2(0, 0)).x; - return float4(x, y, z, w); + float x = tex.Sample(sam, uv, int2(0, 1)).x; + float y = tex.Sample(sam, uv, int2(1, 1)).x; + float z = tex.Sample(sam, uv, int2(1, 0)).x; + float w = tex.Sample(sam, uv, int2(0, 0)).x; + return float4(x, y, z, w); #endif } @@ -62,11 +62,11 @@ float4 TextureGatherRed(Texture2D tex, SamplerState sam, float2 uv, int2 #if CAN_USE_GATHER return tex.GatherRed(sam, uv, offset); #else - float x = tex.Sample(sam, uv, offset + int2(0, 1)).x; - float y = tex.Sample(sam, uv, offset + int2(1, 1)).x; - float z = tex.Sample(sam, uv, offset + int2(1, 0)).x; - float w = tex.Sample(sam, uv, offset + int2(0, 0)).x; - return float4(x, y, z, w); + float x = tex.Sample(sam, uv, offset + int2(0, 1)).x; + float y = tex.Sample(sam, uv, offset + int2(1, 1)).x; + float z = tex.Sample(sam, uv, offset + int2(1, 0)).x; + float w = tex.Sample(sam, uv, offset + int2(0, 0)).x; + return float4(x, y, z, w); #endif } diff --git a/Source/Shaders/GlobalSignDistanceField.hlsl b/Source/Shaders/GlobalSignDistanceField.hlsl index 6a7044e10..6022ea20f 100644 --- a/Source/Shaders/GlobalSignDistanceField.hlsl +++ b/Source/Shaders/GlobalSignDistanceField.hlsl @@ -11,52 +11,52 @@ // Global SDF data for a constant buffer struct GlobalSDFData { - float4 CascadePosDistance[4]; - float4 CascadeVoxelSize; - float2 Padding; + float4 CascadePosDistance[4]; + float4 CascadeVoxelSize; + float2 Padding; uint CascadesCount; - float Resolution; + float Resolution; }; // Global SDF ray trace settings. struct GlobalSDFTrace { - float3 WorldPosition; - float MinDistance; - float3 WorldDirection; - float MaxDistance; - float StepScale; - bool NeedsHitNormal; + float3 WorldPosition; + float MinDistance; + float3 WorldDirection; + float MaxDistance; + float StepScale; + bool NeedsHitNormal; - void Init(float3 worldPosition, float3 worldDirection, float minDistance, float maxDistance, float stepScale = 1.0f) - { - WorldPosition = worldPosition; - WorldDirection = worldDirection; - MinDistance = minDistance; - MaxDistance = maxDistance; - StepScale = stepScale; - NeedsHitNormal = false; - } + void Init(float3 worldPosition, float3 worldDirection, float minDistance, float maxDistance, float stepScale = 1.0f) + { + WorldPosition = worldPosition; + WorldDirection = worldDirection; + MinDistance = minDistance; + MaxDistance = maxDistance; + StepScale = stepScale; + NeedsHitNormal = false; + } }; // Global SDF ray trace hit information. struct GlobalSDFHit { - float3 HitNormal; - float HitTime; - uint HitCascade; - uint StepsCount; - float HitSDF; + float3 HitNormal; + float HitTime; + uint HitCascade; + uint StepsCount; + float HitSDF; - bool IsHit() - { - return HitTime >= 0.0f; - } + bool IsHit() + { + return HitTime >= 0.0f; + } - float3 GetHitPosition(const GlobalSDFTrace trace) - { - return trace.WorldPosition + trace.WorldDirection * HitTime; - } + float3 GetHitPosition(const GlobalSDFTrace trace) + { + return trace.WorldPosition + trace.WorldDirection * HitTime; + } }; void GetGlobalSDFCascadeUV(const GlobalSDFData data, uint cascade, float3 worldPosition, out float cascadeMaxDistance, out float3 cascadeUV, out float3 textureUV) @@ -71,182 +71,182 @@ void GetGlobalSDFCascadeUV(const GlobalSDFData data, uint cascade, float3 worldP // Samples the Global SDF and returns the distance to the closest surface (in world units) at the given world location. float SampleGlobalSDF(const GlobalSDFData data, Texture3D tex, float3 worldPosition) { - float distance = data.CascadePosDistance[3].w * 2.0f; - if (distance <= 0.0f) - return GLOBAL_SDF_WORLD_SIZE; - for (uint cascade = 0; cascade < data.CascadesCount; cascade++) - { - float cascadeMaxDistance; - float3 cascadeUV, textureUV; - GetGlobalSDFCascadeUV(data, cascade, worldPosition, cascadeMaxDistance, cascadeUV, textureUV); - float cascadeDistance = tex.SampleLevel(SamplerLinearClamp, textureUV, 0); - if (cascadeDistance < 1.0f && !any(cascadeUV < 0) && !any(cascadeUV > 1)) - { - distance = cascadeDistance * cascadeMaxDistance; - break; - } - } - return distance; + float distance = data.CascadePosDistance[3].w * 2.0f; + if (distance <= 0.0f) + return GLOBAL_SDF_WORLD_SIZE; + for (uint cascade = 0; cascade < data.CascadesCount; cascade++) + { + float cascadeMaxDistance; + float3 cascadeUV, textureUV; + GetGlobalSDFCascadeUV(data, cascade, worldPosition, cascadeMaxDistance, cascadeUV, textureUV); + float cascadeDistance = tex.SampleLevel(SamplerLinearClamp, textureUV, 0); + if (cascadeDistance < 1.0f && !any(cascadeUV < 0) && !any(cascadeUV > 1)) + { + distance = cascadeDistance * cascadeMaxDistance; + break; + } + } + return distance; } // Samples the Global SDF and returns the gradient vector (derivative) at the given world location. Normalize it to get normal vector. float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D tex, float3 worldPosition, out float distance) { - float3 gradient = float3(0, 0.00001f, 0); - distance = GLOBAL_SDF_WORLD_SIZE; - if (data.CascadePosDistance[3].w <= 0.0f) - return gradient; - for (uint cascade = 0; cascade < data.CascadesCount; cascade++) - { - float cascadeMaxDistance; - float3 cascadeUV, textureUV; - GetGlobalSDFCascadeUV(data, cascade, worldPosition, cascadeMaxDistance, cascadeUV, textureUV); - float cascadeDistance = tex.SampleLevel(SamplerLinearClamp, textureUV, 0); - if (cascadeDistance < 0.9f && !any(cascadeUV < 0) && !any(cascadeUV > 1)) - { - float texelOffset = 1.0f / data.Resolution; - float xp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x + texelOffset, textureUV.y, textureUV.z), 0).x; - float xn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x - texelOffset, textureUV.y, textureUV.z), 0).x; - float yp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y + texelOffset, textureUV.z), 0).x; - float yn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y - texelOffset, textureUV.z), 0).x; - float zp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z + texelOffset), 0).x; - float zn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z - texelOffset), 0).x; - gradient = float3(xp - xn, yp - yn, zp - zn) * cascadeMaxDistance; - distance = cascadeDistance * cascadeMaxDistance; - break; - } - } - return gradient; + float3 gradient = float3(0, 0.00001f, 0); + distance = GLOBAL_SDF_WORLD_SIZE; + if (data.CascadePosDistance[3].w <= 0.0f) + return gradient; + for (uint cascade = 0; cascade < data.CascadesCount; cascade++) + { + float cascadeMaxDistance; + float3 cascadeUV, textureUV; + GetGlobalSDFCascadeUV(data, cascade, worldPosition, cascadeMaxDistance, cascadeUV, textureUV); + float cascadeDistance = tex.SampleLevel(SamplerLinearClamp, textureUV, 0); + if (cascadeDistance < 0.9f && !any(cascadeUV < 0) && !any(cascadeUV > 1)) + { + float texelOffset = 1.0f / data.Resolution; + float xp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x + texelOffset, textureUV.y, textureUV.z), 0).x; + float xn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x - texelOffset, textureUV.y, textureUV.z), 0).x; + float yp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y + texelOffset, textureUV.z), 0).x; + float yn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y - texelOffset, textureUV.z), 0).x; + float zp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z + texelOffset), 0).x; + float zn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z - texelOffset), 0).x; + gradient = float3(xp - xn, yp - yn, zp - zn) * cascadeMaxDistance; + distance = cascadeDistance * cascadeMaxDistance; + break; + } + } + return gradient; } // Samples the Global SDF and returns the gradient vector (derivative) at the given world location. Normalize it to get normal vector. float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D tex, Texture3D mip, float3 worldPosition, out float distance) { - float3 gradient = float3(0, 0.00001f, 0); - distance = GLOBAL_SDF_WORLD_SIZE; - if (data.CascadePosDistance[3].w <= 0.0f) - return gradient; - float chunkSizeDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_SIZE / data.Resolution; // Size of the chunk in SDF distance (0-1) - float chunkMarginDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN / data.Resolution; // Size of the chunk margin in SDF distance (0-1) - for (uint cascade = 0; cascade < data.CascadesCount; cascade++) - { - float cascadeMaxDistance; - float3 cascadeUV, textureUV; - GetGlobalSDFCascadeUV(data, cascade, worldPosition, cascadeMaxDistance, cascadeUV, textureUV); - float cascadeDistance = mip.SampleLevel(SamplerLinearClamp, textureUV, 0); - if (cascadeDistance < chunkSizeDistance && !any(cascadeUV < 0) && !any(cascadeUV > 1)) - { - float cascadeDistanceTex = tex.SampleLevel(SamplerLinearClamp, textureUV, 0); - if (cascadeDistanceTex < chunkMarginDistance * 2) - { - cascadeDistance = cascadeDistanceTex; - } - float texelOffset = 1.0f / data.Resolution; - float xp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x + texelOffset, textureUV.y, textureUV.z), 0).x; - float xn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x - texelOffset, textureUV.y, textureUV.z), 0).x; - float yp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y + texelOffset, textureUV.z), 0).x; - float yn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y - texelOffset, textureUV.z), 0).x; - float zp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z + texelOffset), 0).x; - float zn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z - texelOffset), 0).x; - gradient = float3(xp - xn, yp - yn, zp - zn) * cascadeMaxDistance; - distance = cascadeDistance * cascadeMaxDistance; - break; - } - } - return gradient; + float3 gradient = float3(0, 0.00001f, 0); + distance = GLOBAL_SDF_WORLD_SIZE; + if (data.CascadePosDistance[3].w <= 0.0f) + return gradient; + float chunkSizeDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_SIZE / data.Resolution; // Size of the chunk in SDF distance (0-1) + float chunkMarginDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN / data.Resolution; // Size of the chunk margin in SDF distance (0-1) + for (uint cascade = 0; cascade < data.CascadesCount; cascade++) + { + float cascadeMaxDistance; + float3 cascadeUV, textureUV; + GetGlobalSDFCascadeUV(data, cascade, worldPosition, cascadeMaxDistance, cascadeUV, textureUV); + float cascadeDistance = mip.SampleLevel(SamplerLinearClamp, textureUV, 0); + if (cascadeDistance < chunkSizeDistance && !any(cascadeUV < 0) && !any(cascadeUV > 1)) + { + float cascadeDistanceTex = tex.SampleLevel(SamplerLinearClamp, textureUV, 0); + if (cascadeDistanceTex < chunkMarginDistance * 2) + { + cascadeDistance = cascadeDistanceTex; + } + float texelOffset = 1.0f / data.Resolution; + float xp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x + texelOffset, textureUV.y, textureUV.z), 0).x; + float xn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x - texelOffset, textureUV.y, textureUV.z), 0).x; + float yp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y + texelOffset, textureUV.z), 0).x; + float yn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y - texelOffset, textureUV.z), 0).x; + float zp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z + texelOffset), 0).x; + float zn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z - texelOffset), 0).x; + gradient = float3(xp - xn, yp - yn, zp - zn) * cascadeMaxDistance; + distance = cascadeDistance * cascadeMaxDistance; + break; + } + } + return gradient; } // Ray traces the Global SDF. // cascadeTraceStartBias - scales the trace start position offset (along the trace direction) by cascade voxel size (reduces artifacts on far cascades). Use it for shadow rays to prevent self-occlusion when tracing from object surface that looses quality in far cascades. GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D tex, Texture3D mip, const GlobalSDFTrace trace, float cascadeTraceStartBias = 0.0f) { - GlobalSDFHit hit = (GlobalSDFHit)0; - hit.HitTime = -1.0f; - float chunkSizeDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_SIZE / data.Resolution; // Size of the chunk in SDF distance (0-1) - float chunkMarginDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN / data.Resolution; // Size of the chunk margin in SDF distance (0-1) - float nextIntersectionStart = 0.0f; - float traceMaxDistance = min(trace.MaxDistance, data.CascadePosDistance[3].w * 2); - float3 traceEndPosition = trace.WorldPosition + trace.WorldDirection * traceMaxDistance; - for (uint cascade = 0; cascade < data.CascadesCount && hit.HitTime < 0.0f; cascade++) - { - float4 cascadePosDistance = data.CascadePosDistance[cascade]; - float voxelSize = data.CascadeVoxelSize[cascade]; - float voxelExtent = voxelSize * 0.5f; - float cascadeMinStep = voxelSize; - float3 worldPosition = trace.WorldPosition + trace.WorldDirection * (voxelSize * cascadeTraceStartBias); + GlobalSDFHit hit = (GlobalSDFHit)0; + hit.HitTime = -1.0f; + float chunkSizeDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_SIZE / data.Resolution; // Size of the chunk in SDF distance (0-1) + float chunkMarginDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN / data.Resolution; // Size of the chunk margin in SDF distance (0-1) + float nextIntersectionStart = 0.0f; + float traceMaxDistance = min(trace.MaxDistance, data.CascadePosDistance[3].w * 2); + float3 traceEndPosition = trace.WorldPosition + trace.WorldDirection * traceMaxDistance; + for (uint cascade = 0; cascade < data.CascadesCount && hit.HitTime < 0.0f; cascade++) + { + float4 cascadePosDistance = data.CascadePosDistance[cascade]; + float voxelSize = data.CascadeVoxelSize[cascade]; + float voxelExtent = voxelSize * 0.5f; + float cascadeMinStep = voxelSize; + float3 worldPosition = trace.WorldPosition + trace.WorldDirection * (voxelSize * cascadeTraceStartBias); - // Hit the cascade bounds to find the intersection points - float2 intersections = LineHitBox(worldPosition, traceEndPosition, cascadePosDistance.xyz - cascadePosDistance.www, cascadePosDistance.xyz + cascadePosDistance.www); - intersections.xy *= traceMaxDistance; - intersections.x = max(intersections.x, nextIntersectionStart); - float stepTime = intersections.x; - if (intersections.x >= intersections.y) - { - // Skip the current cascade if the ray starts outside it - stepTime = intersections.y; - } - else - { - // Skip the current cascade tracing on the next cascade - nextIntersectionStart = intersections.y; - } + // Hit the cascade bounds to find the intersection points + float2 intersections = LineHitBox(worldPosition, traceEndPosition, cascadePosDistance.xyz - cascadePosDistance.www, cascadePosDistance.xyz + cascadePosDistance.www); + intersections.xy *= traceMaxDistance; + intersections.x = max(intersections.x, nextIntersectionStart); + float stepTime = intersections.x; + if (intersections.x >= intersections.y) + { + // Skip the current cascade if the ray starts outside it + stepTime = intersections.y; + } + else + { + // Skip the current cascade tracing on the next cascade + nextIntersectionStart = intersections.y; + } - // Walk over the cascade SDF - uint step = 0; - LOOP - for (; step < 250 && stepTime < intersections.y; step++) - { - float3 stepPosition = worldPosition + trace.WorldDirection * stepTime; + // Walk over the cascade SDF + uint step = 0; + LOOP + for (; step < 250 && stepTime < intersections.y; step++) + { + float3 stepPosition = worldPosition + trace.WorldDirection * stepTime; - // Sample SDF - float cascadeMaxDistance; - float3 cascadeUV, textureUV; - GetGlobalSDFCascadeUV(data, cascade, stepPosition, cascadeMaxDistance, cascadeUV, textureUV); - float stepDistance = mip.SampleLevel(SamplerLinearClamp, textureUV, 0); - if (stepDistance < chunkSizeDistance) - { - float stepDistanceTex = tex.SampleLevel(SamplerLinearClamp, textureUV, 0); - if (stepDistanceTex < chunkMarginDistance * 2) - { - stepDistance = stepDistanceTex; - } - } - else - { - // Assume no SDF nearby so perform a jump - stepDistance = chunkSizeDistance; - } - stepDistance *= cascadeMaxDistance; + // Sample SDF + float cascadeMaxDistance; + float3 cascadeUV, textureUV; + GetGlobalSDFCascadeUV(data, cascade, stepPosition, cascadeMaxDistance, cascadeUV, textureUV); + float stepDistance = mip.SampleLevel(SamplerLinearClamp, textureUV, 0); + if (stepDistance < chunkSizeDistance) + { + float stepDistanceTex = tex.SampleLevel(SamplerLinearClamp, textureUV, 0); + if (stepDistanceTex < chunkMarginDistance * 2) + { + stepDistance = stepDistanceTex; + } + } + else + { + // Assume no SDF nearby so perform a jump + stepDistance = chunkSizeDistance; + } + stepDistance *= cascadeMaxDistance; - // Detect surface hit - float minSurfaceThickness = voxelExtent * saturate(stepTime / (voxelExtent * 2.0f)); - if (stepDistance < minSurfaceThickness) - { - // Surface hit - hit.HitTime = max(stepTime + stepDistance - minSurfaceThickness, 0.0f); - hit.HitCascade = cascade; - hit.HitSDF = stepDistance; - if (trace.NeedsHitNormal) - { - // Calculate hit normal from SDF gradient - float texelOffset = 1.0f / data.Resolution; - float xp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x + texelOffset, textureUV.y, textureUV.z), 0).x; - float xn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x - texelOffset, textureUV.y, textureUV.z), 0).x; - float yp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y + texelOffset, textureUV.z), 0).x; - float yn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y - texelOffset, textureUV.z), 0).x; - float zp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z + texelOffset), 0).x; - float zn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z - texelOffset), 0).x; - hit.HitNormal = normalize(float3(xp - xn, yp - yn, zp - zn)); - } - break; - } + // Detect surface hit + float minSurfaceThickness = voxelExtent * saturate(stepTime / (voxelExtent * 2.0f)); + if (stepDistance < minSurfaceThickness) + { + // Surface hit + hit.HitTime = max(stepTime + stepDistance - minSurfaceThickness, 0.0f); + hit.HitCascade = cascade; + hit.HitSDF = stepDistance; + if (trace.NeedsHitNormal) + { + // Calculate hit normal from SDF gradient + float texelOffset = 1.0f / data.Resolution; + float xp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x + texelOffset, textureUV.y, textureUV.z), 0).x; + float xn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x - texelOffset, textureUV.y, textureUV.z), 0).x; + float yp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y + texelOffset, textureUV.z), 0).x; + float yn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y - texelOffset, textureUV.z), 0).x; + float zp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z + texelOffset), 0).x; + float zn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z - texelOffset), 0).x; + hit.HitNormal = normalize(float3(xp - xn, yp - yn, zp - zn)); + } + break; + } - // Move forward - stepTime += max(stepDistance * trace.StepScale, cascadeMinStep); - } - hit.StepsCount += step; - } - return hit; + // Move forward + stepTime += max(stepDistance * trace.StepScale, cascadeMinStep); + } + hit.StepsCount += step; + } + return hit; } // Calculates the surface threshold for Global Surface Atlas sampling which matches the Global SDF trace to reduce artifacts diff --git a/Source/Shaders/IESProfile.hlsl b/Source/Shaders/IESProfile.hlsl index 53c53542d..c7351e275 100644 --- a/Source/Shaders/IESProfile.hlsl +++ b/Source/Shaders/IESProfile.hlsl @@ -6,10 +6,10 @@ // Calculate IES light profile from 1D texture float ComputeLightProfileMultiplier(Texture2D tex, float3 worldPosition, float3 lightPosition, float3 lightDirection) { - float3 l = normalize(worldPosition - lightPosition); - float d = dot(lightPosition, lightDirection); - float angle = asin(d) / PI + 0.5f; - return tex.SampleLevel(SamplerLinearClamp, float2(angle, 0), 0).r; + float3 l = normalize(worldPosition - lightPosition); + float d = dot(lightPosition, lightDirection); + float angle = asin(d) / PI + 0.5f; + return tex.SampleLevel(SamplerLinearClamp, float2(angle, 0), 0).r; } #endif diff --git a/Source/Shaders/Lighting.hlsl b/Source/Shaders/Lighting.hlsl index 9984d638a..af1b193a0 100644 --- a/Source/Shaders/Lighting.hlsl +++ b/Source/Shaders/Lighting.hlsl @@ -11,150 +11,150 @@ ShadowData GetShadow(LightData lightData, GBufferSample gBuffer, float4 shadowMask) { - ShadowData shadow; - shadow.SurfaceShadow = gBuffer.AO * shadowMask.r; - shadow.TransmissionShadow = shadowMask.g; - return shadow; + ShadowData shadow; + shadow.SurfaceShadow = gBuffer.AO * shadowMask.r; + shadow.TransmissionShadow = shadowMask.g; + return shadow; } LightingData StandardShading(GBufferSample gBuffer, float energy, float3 L, float3 V, half3 N) { - float3 diffuseColor = GetDiffuseColor(gBuffer); - float3 H = normalize(V + L); - float NoL = saturate(dot(N, L)); - float NoV = max(dot(N, V), 1e-5); - float NoH = saturate(dot(N, H)); - float VoH = saturate(dot(V, H)); + float3 diffuseColor = GetDiffuseColor(gBuffer); + float3 H = normalize(V + L); + float NoL = saturate(dot(N, L)); + float NoV = max(dot(N, V), 1e-5); + float NoH = saturate(dot(N, H)); + float VoH = saturate(dot(V, H)); - LightingData lighting; - lighting.Diffuse = Diffuse_Lambert(diffuseColor); + LightingData lighting; + lighting.Diffuse = Diffuse_Lambert(diffuseColor); #if NO_SPECULAR - lighting.Specular = 0; + lighting.Specular = 0; #else - float3 specularColor = GetSpecularColor(gBuffer); - float3 F = F_Schlick(specularColor, VoH); - float D = D_GGX(gBuffer.Roughness, NoH) * energy; - float Vis = Vis_SmithJointApprox(gBuffer.Roughness, NoV, NoL); - lighting.Specular = (D * Vis) * F; + float3 specularColor = GetSpecularColor(gBuffer); + float3 F = F_Schlick(specularColor, VoH); + float D = D_GGX(gBuffer.Roughness, NoH) * energy; + float Vis = Vis_SmithJointApprox(gBuffer.Roughness, NoV, NoL); + lighting.Specular = (D * Vis) * F; #endif - lighting.Transmission = 0; - return lighting; + lighting.Transmission = 0; + return lighting; } LightingData SubsurfaceShading(GBufferSample gBuffer, float energy, float3 L, float3 V, half3 N) { - LightingData lighting = StandardShading(gBuffer, energy, L, V, N); + LightingData lighting = StandardShading(gBuffer, energy, L, V, N); #if defined(USE_GBUFFER_CUSTOM_DATA) - // Fake effect of the light going through the material - float3 subsurfaceColor = gBuffer.CustomData.rgb; - float opacity = gBuffer.CustomData.a; - float3 H = normalize(V + L); - float inscatter = pow(saturate(dot(L, -V)), 12.1f) * lerp(3, 0.1f, opacity); - float normalContribution = saturate(dot(N, H) * opacity + 1.0f - opacity); - float backScatter = gBuffer.AO * normalContribution / (PI * 2.0f); - lighting.Transmission = lerp(backScatter, 1, inscatter) * subsurfaceColor; + // Fake effect of the light going through the material + float3 subsurfaceColor = gBuffer.CustomData.rgb; + float opacity = gBuffer.CustomData.a; + float3 H = normalize(V + L); + float inscatter = pow(saturate(dot(L, -V)), 12.1f) * lerp(3, 0.1f, opacity); + float normalContribution = saturate(dot(N, H) * opacity + 1.0f - opacity); + float backScatter = gBuffer.AO * normalContribution / (PI * 2.0f); + lighting.Transmission = lerp(backScatter, 1, inscatter) * subsurfaceColor; #endif - return lighting; + return lighting; } LightingData FoliageShading(GBufferSample gBuffer, float energy, float3 L, float3 V, half3 N) { - LightingData lighting = StandardShading(gBuffer, energy, L, V, N); + LightingData lighting = StandardShading(gBuffer, energy, L, V, N); #if defined(USE_GBUFFER_CUSTOM_DATA) - // Fake effect of the light going through the thin foliage - float3 subsurfaceColor = gBuffer.CustomData.rgb; - float wrapNoL = saturate((-dot(N, L) + 0.5f) / 2.25); - float VoL = dot(V, L); - float scatter = D_GGX(0.36, saturate(-VoL)); - lighting.Transmission = subsurfaceColor * (wrapNoL * scatter); + // Fake effect of the light going through the thin foliage + float3 subsurfaceColor = gBuffer.CustomData.rgb; + float wrapNoL = saturate((-dot(N, L) + 0.5f) / 2.25); + float VoL = dot(V, L); + float scatter = D_GGX(0.36, saturate(-VoL)); + lighting.Transmission = subsurfaceColor * (wrapNoL * scatter); #endif - return lighting; + return lighting; } LightingData SurfaceShading(GBufferSample gBuffer, float energy, float3 L, float3 V, half3 N) { - switch (gBuffer.ShadingModel) - { - case SHADING_MODEL_UNLIT: - case SHADING_MODEL_LIT: - return StandardShading(gBuffer, energy, L, V, N); - case SHADING_MODEL_SUBSURFACE: - return SubsurfaceShading(gBuffer, energy, L, V, N); - case SHADING_MODEL_FOLIAGE: - return FoliageShading(gBuffer, energy, L, V, N); - default: - return (LightingData)0; - } + switch (gBuffer.ShadingModel) + { + case SHADING_MODEL_UNLIT: + case SHADING_MODEL_LIT: + return StandardShading(gBuffer, energy, L, V, N); + case SHADING_MODEL_SUBSURFACE: + return SubsurfaceShading(gBuffer, energy, L, V, N); + case SHADING_MODEL_FOLIAGE: + return FoliageShading(gBuffer, energy, L, V, N); + default: + return (LightingData)0; + } } float4 GetSkyLightLighting(LightData lightData, GBufferSample gBuffer, TextureCube ibl) { - // Get material diffuse color - float3 diffuseColor = GetDiffuseColor(gBuffer); + // Get material diffuse color + float3 diffuseColor = GetDiffuseColor(gBuffer); - // Compute the preconvolved incoming lighting with the normal direction (apply ambient color) - // Some data is packed, see C++ RendererSkyLightData::SetupLightData - float mip = lightData.SourceLength; - float3 diffuseLookup = ibl.SampleLevel(SamplerLinearClamp, gBuffer.Normal, mip).rgb * lightData.Color.rgb; - diffuseLookup += float3(lightData.SpotAngles.rg, lightData.SourceRadius); + // Compute the preconvolved incoming lighting with the normal direction (apply ambient color) + // Some data is packed, see C++ RendererSkyLightData::SetupLightData + float mip = lightData.SourceLength; + float3 diffuseLookup = ibl.SampleLevel(SamplerLinearClamp, gBuffer.Normal, mip).rgb * lightData.Color.rgb; + diffuseLookup += float3(lightData.SpotAngles.rg, lightData.SourceRadius); - // Fade out based on distance to capture - float3 captureVector = gBuffer.WorldPos - lightData.Position; - float captureVectorLength = length(captureVector); - float normalizedDistanceToCapture = saturate(captureVectorLength / lightData.Radius); - float distanceAlpha = 1.0 - smoothstep(0.6, 1, normalizedDistanceToCapture); + // Fade out based on distance to capture + float3 captureVector = gBuffer.WorldPos - lightData.Position; + float captureVectorLength = length(captureVector); + float normalizedDistanceToCapture = saturate(captureVectorLength / lightData.Radius); + float distanceAlpha = 1.0 - smoothstep(0.6, 1, normalizedDistanceToCapture); - // Calculate final light - float3 color = diffuseLookup * diffuseColor; - float luminance = Luminance(diffuseLookup); - return float4(color, luminance) * (distanceAlpha * gBuffer.AO); + // Calculate final light + float3 color = diffuseLookup * diffuseColor; + float luminance = Luminance(diffuseLookup); + return float4(color, luminance) * (distanceAlpha * gBuffer.AO); } float4 GetLighting(float3 viewPos, LightData lightData, GBufferSample gBuffer, float4 shadowMask, bool isRadial, bool isSpotLight) { - float4 result = 0; - float3 V = normalize(viewPos - gBuffer.WorldPos); - float3 N = gBuffer.Normal; - float3 L = lightData.Direction; // no need to normalize - float NoL = saturate(dot(N, L)); - float distanceAttenuation = 1; - float lightRadiusMask = 1; - float spotAttenuation = 1; - float3 toLight = lightData.Direction; + float4 result = 0; + float3 V = normalize(viewPos - gBuffer.WorldPos); + float3 N = gBuffer.Normal; + float3 L = lightData.Direction; // no need to normalize + float NoL = saturate(dot(N, L)); + float distanceAttenuation = 1; + float lightRadiusMask = 1; + float spotAttenuation = 1; + float3 toLight = lightData.Direction; - // Calculate attenuation - if (isRadial) - { - toLight = lightData.Position - gBuffer.WorldPos; - float distanceSqr = dot(toLight, toLight); - L = toLight * rsqrt(distanceSqr); - GetRadialLightAttenuation(lightData, isSpotLight, N, distanceSqr, 1, toLight, L, NoL, distanceAttenuation, lightRadiusMask, spotAttenuation); - } - float attenuation = distanceAttenuation * lightRadiusMask * spotAttenuation; + // Calculate attenuation + if (isRadial) + { + toLight = lightData.Position - gBuffer.WorldPos; + float distanceSqr = dot(toLight, toLight); + L = toLight * rsqrt(distanceSqr); + GetRadialLightAttenuation(lightData, isSpotLight, N, distanceSqr, 1, toLight, L, NoL, distanceAttenuation, lightRadiusMask, spotAttenuation); + } + float attenuation = distanceAttenuation * lightRadiusMask * spotAttenuation; - // Calculate shadow - ShadowData shadow = GetShadow(lightData, gBuffer, shadowMask); + // Calculate shadow + ShadowData shadow = GetShadow(lightData, gBuffer, shadowMask); - // Reduce shadow mapping artifacts - shadow.SurfaceShadow *= saturate(NoL * 6.0f - 0.2f); + // Reduce shadow mapping artifacts + shadow.SurfaceShadow *= saturate(NoL * 6.0f - 0.2f); - BRANCH - if (shadow.SurfaceShadow + shadow.TransmissionShadow > 0) - { - gBuffer.Roughness = max(gBuffer.Roughness, lightData.MinRoughness); - float energy = AreaLightSpecular(lightData, gBuffer.Roughness, toLight, L, V, N); + BRANCH + if (shadow.SurfaceShadow + shadow.TransmissionShadow > 0) + { + gBuffer.Roughness = max(gBuffer.Roughness, lightData.MinRoughness); + float energy = AreaLightSpecular(lightData, gBuffer.Roughness, toLight, L, V, N); - // Calculate direct lighting - LightingData lighting = SurfaceShading(gBuffer, energy, L, V, N); + // Calculate direct lighting + LightingData lighting = SurfaceShading(gBuffer, energy, L, V, N); - // Calculate final light color - float3 surfaceLight = (lighting.Diffuse + lighting.Specular) * (NoL * attenuation * shadow.SurfaceShadow); - float3 subsurfaceLight = lighting.Transmission * (attenuation * shadow.TransmissionShadow); - result.rgb = lightData.Color * (surfaceLight + subsurfaceLight); - result.a = 1; - } + // Calculate final light color + float3 surfaceLight = (lighting.Diffuse + lighting.Specular) * (NoL * attenuation * shadow.SurfaceShadow); + float3 subsurfaceLight = lighting.Transmission * (attenuation * shadow.TransmissionShadow); + result.rgb = lightData.Color * (surfaceLight + subsurfaceLight); + result.a = 1; + } - return result; + return result; } #endif diff --git a/Source/Shaders/LightingCommon.hlsl b/Source/Shaders/LightingCommon.hlsl index 6666f0951..1015cf536 100644 --- a/Source/Shaders/LightingCommon.hlsl +++ b/Source/Shaders/LightingCommon.hlsl @@ -9,126 +9,126 @@ // Structure that contains information about light struct LightData { - float2 SpotAngles; - float SourceRadius; - float SourceLength; + float2 SpotAngles; + float SourceRadius; + float SourceLength; - float3 Color; - float MinRoughness; + float3 Color; + float MinRoughness; - float3 Position; - float CastShadows; + float3 Position; + float CastShadows; - float3 Direction; - float Radius; + float3 Direction; + float Radius; - float FalloffExponent; - float InverseSquared; - float Dummy0; - float RadiusInv; + float FalloffExponent; + float InverseSquared; + float Dummy0; + float RadiusInv; }; // Structure that contains information about shadow struct ShadowData { - float SurfaceShadow; - float TransmissionShadow; + float SurfaceShadow; + float TransmissionShadow; }; // Structure that contains information about direct lighting calculations result struct LightingData { - float3 Diffuse; - float3 Specular; - float3 Transmission; + float3 Diffuse; + float3 Specular; + float3 Transmission; }; // Calculates radial light (point or spot) attenuation factors (distance, spot and radius mask) void GetRadialLightAttenuation( - LightData lightData, - bool isSpotLight, - float3 N, - float distanceSqr, - float distanceBiasSqr, - float3 toLight, - float3 L, - inout float NoL, - inout float distanceAttenuation, - inout float lightRadiusMask, - inout float spotAttenuation) + LightData lightData, + bool isSpotLight, + float3 N, + float distanceSqr, + float distanceBiasSqr, + float3 toLight, + float3 L, + inout float NoL, + inout float distanceAttenuation, + inout float lightRadiusMask, + inout float spotAttenuation) { - if (lightData.InverseSquared) - { - BRANCH - if (lightData.SourceLength > 0) - { - float3 l01 = lightData.Direction * lightData.SourceLength; - float3 l0 = toLight - 0.5 * l01; - float3 l1 = toLight + 0.5 * l01; - float lengthL0 = length(l0); - float lengthL1 = length(l1); - distanceAttenuation = rcp((lengthL0 * lengthL1 + dot(l0, l1)) * 0.5 + distanceBiasSqr); - NoL = saturate(0.5 * (dot(N, l0) / lengthL0 + dot(N, l1) / lengthL1)); - } - else - { - distanceAttenuation = rcp(distanceSqr + distanceBiasSqr); - NoL = saturate(dot(N, L)); - } - lightRadiusMask = Square(saturate(1 - Square(distanceSqr * Square(lightData.RadiusInv)))); - } - else - { - distanceAttenuation = 1; - NoL = saturate(dot(N, L)); - float3 worldLightVector = toLight * lightData.RadiusInv; - float t = dot(worldLightVector, worldLightVector); - lightRadiusMask = pow(1.0f - saturate(t), lightData.FalloffExponent); - } + if (lightData.InverseSquared) + { + BRANCH + if (lightData.SourceLength > 0) + { + float3 l01 = lightData.Direction * lightData.SourceLength; + float3 l0 = toLight - 0.5 * l01; + float3 l1 = toLight + 0.5 * l01; + float lengthL0 = length(l0); + float lengthL1 = length(l1); + distanceAttenuation = rcp((lengthL0 * lengthL1 + dot(l0, l1)) * 0.5 + distanceBiasSqr); + NoL = saturate(0.5 * (dot(N, l0) / lengthL0 + dot(N, l1) / lengthL1)); + } + else + { + distanceAttenuation = rcp(distanceSqr + distanceBiasSqr); + NoL = saturate(dot(N, L)); + } + lightRadiusMask = Square(saturate(1 - Square(distanceSqr * Square(lightData.RadiusInv)))); + } + else + { + distanceAttenuation = 1; + NoL = saturate(dot(N, L)); + float3 worldLightVector = toLight * lightData.RadiusInv; + float t = dot(worldLightVector, worldLightVector); + lightRadiusMask = pow(1.0f - saturate(t), lightData.FalloffExponent); + } - if (isSpotLight) - { - // SpotAngles.x is CosOuterCone, SpotAngles.y is InvCosConeDifference - spotAttenuation = Square(saturate((dot(normalize(-L), lightData.Direction) - lightData.SpotAngles.x) * lightData.SpotAngles.y)); - } + if (isSpotLight) + { + // SpotAngles.x is CosOuterCone, SpotAngles.y is InvCosConeDifference + spotAttenuation = Square(saturate((dot(normalize(-L), lightData.Direction) - lightData.SpotAngles.x) * lightData.SpotAngles.y)); + } } // Find representative incoming light direction and energy modification float AreaLightSpecular(LightData lightData, float roughness, inout float3 toLight, inout float3 L, float3 V, half3 N) { - float energy = 1; + float energy = 1; - float m = roughness * roughness; - float3 r = reflect(-V, N); - float invDistToLight = rsqrt(dot(toLight, toLight)); + float m = roughness * roughness; + float3 r = reflect(-V, N); + float invDistToLight = rsqrt(dot(toLight, toLight)); - BRANCH - if (lightData.SourceLength > 0) - { - float lineAngle = saturate(lightData.SourceLength * invDistToLight); - energy *= m / saturate(m + 0.5 * lineAngle); - float3 l01 = lightData.Direction * lightData.SourceLength; - float3 l0 = toLight - 0.5 * l01; - float a = Square(lightData.SourceLength); - float b = dot(r, l01); - float t = saturate(dot(l0, b * r - l01) / (a - b * b)); - toLight = l0 + t * l01; - } + BRANCH + if (lightData.SourceLength > 0) + { + float lineAngle = saturate(lightData.SourceLength * invDistToLight); + energy *= m / saturate(m + 0.5 * lineAngle); + float3 l01 = lightData.Direction * lightData.SourceLength; + float3 l0 = toLight - 0.5 * l01; + float a = Square(lightData.SourceLength); + float b = dot(r, l01); + float t = saturate(dot(l0, b * r - l01) / (a - b * b)); + toLight = l0 + t * l01; + } - BRANCH - if (lightData.SourceRadius > 0) - { - float sphereAngle = saturate(lightData.SourceRadius * invDistToLight); - energy *= Square(m / saturate(m + 0.5 * sphereAngle)); - float3 closestPointOnRay = dot(toLight, r) * r; - float3 centerToRay = closestPointOnRay - toLight; - float3 closestPointOnSphere = toLight + centerToRay * saturate(lightData.SourceRadius * rsqrt(dot(centerToRay, centerToRay))); - toLight = closestPointOnSphere; - } + BRANCH + if (lightData.SourceRadius > 0) + { + float sphereAngle = saturate(lightData.SourceRadius * invDistToLight); + energy *= Square(m / saturate(m + 0.5 * sphereAngle)); + float3 closestPointOnRay = dot(toLight, r) * r; + float3 centerToRay = closestPointOnRay - toLight; + float3 closestPointOnSphere = toLight + centerToRay * saturate(lightData.SourceRadius * rsqrt(dot(centerToRay, centerToRay))); + toLight = closestPointOnSphere; + } - L = normalize(toLight); + L = normalize(toLight); - return energy; + return energy; } #endif diff --git a/Source/Shaders/MaterialCommon.hlsl b/Source/Shaders/MaterialCommon.hlsl index a18e29f81..60ba7e298 100644 --- a/Source/Shaders/MaterialCommon.hlsl +++ b/Source/Shaders/MaterialCommon.hlsl @@ -20,69 +20,69 @@ // Validate inputs #ifndef MATERIAL - #define MATERIAL 0 +#define MATERIAL 0 #endif #ifndef MATERIAL_DOMAIN - #define MATERIAL_DOMAIN MATERIAL_DOMAIN_SURFACE +#define MATERIAL_DOMAIN MATERIAL_DOMAIN_SURFACE #endif #ifndef MATERIAL_BLEND - #define MATERIAL_BLEND MATERIAL_BLEND_OPAQUE +#define MATERIAL_BLEND MATERIAL_BLEND_OPAQUE #endif #ifndef MATERIAL_SHADING_MODEL - #define MATERIAL_SHADING_MODEL SHADING_MODEL_LIT +#define MATERIAL_SHADING_MODEL SHADING_MODEL_LIT #endif #ifndef USE_INSTANCING - #define USE_INSTANCING 0 +#define USE_INSTANCING 0 #endif #ifndef USE_SKINNING - #define USE_SKINNING 0 +#define USE_SKINNING 0 #endif #ifndef USE_LIGHTMAP - #define USE_LIGHTMAP 0 +#define USE_LIGHTMAP 0 #endif #ifndef USE_POSITION_OFFSET - #define USE_POSITION_OFFSET 0 +#define USE_POSITION_OFFSET 0 #endif #ifndef USE_VERTEX_COLOR - #define USE_VERTEX_COLOR 0 +#define USE_VERTEX_COLOR 0 #endif #ifndef USE_DISPLACEMENT - #define USE_DISPLACEMENT 0 +#define USE_DISPLACEMENT 0 #endif #ifndef USE_TESSELLATION - #define USE_TESSELLATION 0 +#define USE_TESSELLATION 0 #endif #ifndef USE_DITHERED_LOD_TRANSITION - #define USE_DITHERED_LOD_TRANSITION 0 +#define USE_DITHERED_LOD_TRANSITION 0 #endif #ifndef MATERIAL_TESSELLATION - #define MATERIAL_TESSELLATION MATERIAL_TESSELLATION_NONE +#define MATERIAL_TESSELLATION MATERIAL_TESSELLATION_NONE #endif #ifndef MAX_TESSELLATION_FACTOR - #define MAX_TESSELLATION_FACTOR 15 +#define MAX_TESSELLATION_FACTOR 15 #endif #ifndef PER_BONE_MOTION_BLUR - #define PER_BONE_MOTION_BLUR 0 +#define PER_BONE_MOTION_BLUR 0 #endif // Material properties struct Material { - float3 Emissive; - float Roughness; - float3 Color; - float AO; - float3 WorldNormal; - float Metalness; - float3 TangentNormal; - float Specular; - float3 PositionOffset; - float Opacity; - float3 SubsurfaceColor; - float Refraction; - float Mask; - float TessellationMultiplier; - float3 WorldDisplacement; + float3 Emissive; + float Roughness; + float3 Color; + float AO; + float3 WorldNormal; + float Metalness; + float3 TangentNormal; + float Specular; + float3 PositionOffset; + float Opacity; + float3 SubsurfaceColor; + float Refraction; + float Mask; + float TessellationMultiplier; + float3 WorldDisplacement; #if USE_CUSTOM_VERTEX_INTERPOLATORS float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT]; #endif @@ -90,11 +90,11 @@ struct Material struct ModelInput { - float3 Position : POSITION; - float2 TexCoord : TEXCOORD0; - float4 Normal : NORMAL; - float4 Tangent : TANGENT; - float2 LightmapUV : TEXCOORD1; + float3 Position : POSITION; + float2 TexCoord : TEXCOORD0; + float4 Normal : NORMAL; + float4 Tangent : TANGENT; + float2 LightmapUV : TEXCOORD1; #if USE_VERTEX_COLOR half4 Color : COLOR; #endif @@ -109,7 +109,7 @@ struct ModelInput struct ModelInput_PosOnly { - float3 Position : POSITION; + float3 Position : POSITION; #if USE_INSTANCING float4 InstanceOrigin : ATTRIBUTE0; // .w contains PerInstanceRandom float4 InstanceTransform1 : ATTRIBUTE1; // .w contains LODDitherFactor @@ -121,12 +121,12 @@ struct ModelInput_PosOnly struct ModelInput_Skinned { - float3 Position : POSITION; - float2 TexCoord : TEXCOORD0; - float4 Normal : NORMAL; - float4 Tangent : TANGENT; - uint4 BlendIndices : BLENDINDICES; - float4 BlendWeights : BLENDWEIGHT; + float3 Position : POSITION; + float2 TexCoord : TEXCOORD0; + float4 Normal : NORMAL; + float4 Tangent : TANGENT; + uint4 BlendIndices : BLENDINDICES; + float4 BlendWeights : BLENDWEIGHT; #if USE_INSTANCING float4 InstanceOrigin : ATTRIBUTE0; // .w contains PerInstanceRandom float4 InstanceTransform1 : ATTRIBUTE1; // .w contains LODDitherFactor @@ -138,55 +138,55 @@ struct ModelInput_Skinned struct Model_VS2PS { - float4 Position : SV_Position; - float4 ScreenPos : TEXCOORD0; + float4 Position : SV_Position; + float4 ScreenPos : TEXCOORD0; }; struct GBufferOutput { - float4 Light : SV_Target0; - float4 RT0 : SV_Target1; - float4 RT1 : SV_Target2; - float4 RT2 : SV_Target3; - float4 RT3 : SV_Target4; + float4 Light : SV_Target0; + float4 RT0 : SV_Target1; + float4 RT1 : SV_Target2; + float4 RT2 : SV_Target3; + float4 RT3 : SV_Target4; }; float3x3 CalcTangentBasis(float3 normal, float3 pos, float2 uv) { - // References: - // http://www.thetenthplanet.de/archives/1180 - // https://zhangdoa.com/posts/normal-and-normal-mapping - float3 dp1 = ddx(pos); - float3 dp2 = ddy(pos); - float2 duv1 = ddx(uv); - float2 duv2 = ddy(uv); - float3 dp2perp = cross(dp2, normal); - float3 dp1perp = cross(normal, dp1); - float3 tangent = normalize(dp2perp * duv1.x + dp1perp * duv2.x); - float3 bitangent = normalize(dp2perp * duv1.y + dp1perp * duv2.y); - return float3x3(tangent, bitangent, normal); + // References: + // http://www.thetenthplanet.de/archives/1180 + // https://zhangdoa.com/posts/normal-and-normal-mapping + float3 dp1 = ddx(pos); + float3 dp2 = ddy(pos); + float2 duv1 = ddx(uv); + float2 duv2 = ddy(uv); + float3 dp2perp = cross(dp2, normal); + float3 dp1perp = cross(normal, dp1); + float3 tangent = normalize(dp2perp * duv1.x + dp1perp * duv2.x); + float3 bitangent = normalize(dp2perp * duv1.y + dp1perp * duv2.y); + return float3x3(tangent, bitangent, normal); } float3x3 CalcTangentBasisFromWorldNormal(float3 normal) { - float3 tangent = cross(normal, float3(1, 0, 0)); - float3 bitangent = cross(normal, tangent); - return float3x3(tangent, bitangent, normal); + float3 tangent = cross(normal, float3(1, 0, 0)); + float3 bitangent = cross(normal, tangent); + return float3x3(tangent, bitangent, normal); } float3x3 CalcTangentBasis(float3 normal, float4 tangent) { - float3 bitangent = cross(normal, tangent.xyz) * tangent.w; - return float3x3(tangent.xyz, bitangent, normal); + float3 bitangent = cross(normal, tangent.xyz) * tangent.w; + return float3x3(tangent.xyz, bitangent, normal); } // [Jimenez et al. 2016, "Practical Realtime Strategies for Accurate Indirect Occlusion"] float3 AOMultiBounce(float visibility, float3 albedo) { - float3 a = 2.0404 * albedo - 0.3324; - float3 b = -4.7951 * albedo + 0.6417; - float3 c = 2.7552 * albedo + 0.6903; - return max(visibility, ((visibility * a + b) * visibility + c) * visibility); + float3 a = 2.0404 * albedo - 0.3324; + float3 b = -4.7951 * albedo + 0.6417; + float3 c = 2.7552 * albedo + 0.6903; + return max(visibility, ((visibility * a + b) * visibility + c) * visibility); } #endif diff --git a/Source/Shaders/Math.hlsl b/Source/Shaders/Math.hlsl index 037efccba..16a4ff549 100644 --- a/Source/Shaders/Math.hlsl +++ b/Source/Shaders/Math.hlsl @@ -5,254 +5,254 @@ uint NextPow2(uint value) { - uint mask = (1 << firstbithigh(value)) - 1; - return (value + mask) & ~mask; + uint mask = (1 << firstbithigh(value)) - 1; + return (value + mask) & ~mask; } float3 SafeNormalize(float3 v) { - return v / sqrt(max(dot(v, v), 0.01)); + return v / sqrt(max(dot(v, v), 0.01)); } float3 ExtractLargestComponent(float3 v) { - float3 a = abs(v); - if (a.x > a.y) - { - if (a.x > a.z) - { - return float3(v.x > 0 ? 1 : -1, 0, 0); - } - } - else - { - if (a.y > a.z) - { - return float3(0, v.y > 0 ? 1 : -1, 0); - } - } - return float3(0, 0, v.z > 0 ? 1 : -1); + float3 a = abs(v); + if (a.x > a.y) + { + if (a.x > a.z) + { + return float3(v.x > 0 ? 1 : -1, 0, 0); + } + } + else + { + if (a.y > a.z) + { + return float3(0, v.y > 0 ? 1 : -1, 0); + } + } + return float3(0, 0, v.z > 0 ? 1 : -1); } float Square(float x) { - return x * x; + return x * x; } float2 Square(float2 x) { - return x * x; + return x * x; } float3 Square(float3 x) { - return x * x; + return x * x; } float4 Square(float4 x) { - return x * x; + return x * x; } float Min2(float2 x) { - return min(x.x, x.y); + return min(x.x, x.y); } float Min3(float3 x) { - return min(x.x, min(x.y, x.z)); + return min(x.x, min(x.y, x.z)); } float Min4(float4 x) { - return min(x.x, min(x.y, min(x.z, x.w))); + return min(x.x, min(x.y, min(x.z, x.w))); } float Max2(float2 x) { - return max(x.x, x.y); + return max(x.x, x.y); } float Max3(float3 x) { - return max(x.x, max(x.y, x.z)); + return max(x.x, max(x.y, x.z)); } float Max4(float4 x) { - return max(x.x, max(x.y, max(x.z, x.w))); + return max(x.x, max(x.y, max(x.z, x.w))); } float Pow2(float x) { - return x * x; + return x * x; } float2 Pow2(float2 x) { - return x * x; + return x * x; } float3 Pow2(float3 x) { - return x * x; + return x * x; } float4 Pow2(float4 x) { - return x * x; + return x * x; } float Pow3(float x) { - return x * x * x; + return x * x * x; } float2 Pow3(float2 x) { - return x * x * x; + return x * x * x; } float3 Pow3(float3 x) { - return x * x * x; + return x * x * x; } float4 Pow3(float4 x) { - return x * x * x; + return x * x * x; } float Pow4(float x) { - float xx = x * x; - return xx * xx; + float xx = x * x; + return xx * xx; } float2 Pow4(float2 x) { - float2 xx = x * x; - return xx * xx; + float2 xx = x * x; + return xx * xx; } float3 Pow4(float3 x) { - float3 xx = x * x; - return xx * xx; + float3 xx = x * x; + return xx * xx; } float4 Pow4(float4 x) { - float4 xx = x * x; - return xx * xx; + float4 xx = x * x; + return xx * xx; } float Pow5(float x) { - float xx = x * x; - return xx * xx * x; + float xx = x * x; + return xx * xx * x; } float2 Pow5(float2 x) { - float2 xx = x * x; - return xx * xx * x; + float2 xx = x * x; + return xx * xx * x; } float3 Pow5(float3 x) { - float3 xx = x * x; - return xx * xx * x; + float3 xx = x * x; + return xx * xx * x; } float4 Pow5(float4 x) { - float4 xx = x * x; - return xx * xx * x; + float4 xx = x * x; + return xx * xx * x; } float Pow6(float x) { - float xx = x * x; - return xx * xx * xx; + float xx = x * x; + return xx * xx * xx; } float2 Pow6(float2 x) { - float2 xx = x * x; - return xx * xx * xx; + float2 xx = x * x; + return xx * xx * xx; } float3 Pow6(float3 x) { - float3 xx = x * x; - return xx * xx * xx; + float3 xx = x * x; + return xx * xx * xx; } float4 Pow6(float4 x) { - float4 xx = x * x; - return xx * xx * xx; + float4 xx = x * x; + return xx * xx * xx; } float ClampedPow(float x, float y) { - return pow(max(abs(x), 0.000001f), y); + return pow(max(abs(x), 0.000001f), y); } float2 ClampedPow(float2 x, float2 y) { - return pow(max(abs(x), float2(0.000001f, 0.000001f)), y); + return pow(max(abs(x), float2(0.000001f, 0.000001f)), y); } float3 ClampedPow(float3 x, float3 y) { - return pow(max(abs(x), float3(0.000001f, 0.000001f, 0.000001f)), y); + return pow(max(abs(x), float3(0.000001f, 0.000001f, 0.000001f)), y); } float4 ClampedPow(float4 x, float4 y) { - return pow(max(abs(x), float4(0.000001f, 0.000001f, 0.000001f, 0.000001f)), y); + return pow(max(abs(x), float4(0.000001f, 0.000001f, 0.000001f, 0.000001f)), y); } float4 FindQuatBetween(float3 from, float3 to) { - float normAB = 1.0f; - float w = normAB + dot(from, to); - float4 result; + float normAB = 1.0f; + float w = normAB + dot(from, to); + float4 result; - if (w >= 1e-6f * normAB) - { - result = float4 - ( - from.y * to.z - from.z * to.y, - from.z * to.x - from.x * to.z, - from.x * to.y - from.y * to.x, - w - ); - } - else - { - w = 0.f; - result = abs(from.x) > abs(from.y) - ? float4(-from.z, 0.f, from.x, w) - : float4(0.f, -from.z, from.y, w); - } + if (w >= 1e-6f * normAB) + { + result = float4 + ( + from.y * to.z - from.z * to.y, + from.z * to.x - from.x * to.z, + from.x * to.y - from.y * to.x, + w + ); + } + else + { + w = 0.f; + result = abs(from.x) > abs(from.y) + ? float4(-from.z, 0.f, from.x, w) + : float4(0.f, -from.z, from.y, w); + } - return normalize(result); + return normalize(result); } // Rotates Position about the given axis by the given angle, in radians, and returns the offset to position float3 RotateAboutAxis(float4 normalizedRotationAxisAndAngle, float3 positionOnAxis, float3 position) { - float3 pointOnAxis = positionOnAxis + normalizedRotationAxisAndAngle.xyz * dot(normalizedRotationAxisAndAngle.xyz, position - positionOnAxis); - float3 axisU = position - pointOnAxis; - float3 axisV = cross(normalizedRotationAxisAndAngle.xyz, axisU); - float cosAngle, sinAngle; - sincos(normalizedRotationAxisAndAngle.w, sinAngle, cosAngle); - float3 rotation = axisU * cosAngle + axisV * sinAngle; - return pointOnAxis + rotation - position; + float3 pointOnAxis = positionOnAxis + normalizedRotationAxisAndAngle.xyz * dot(normalizedRotationAxisAndAngle.xyz, position - positionOnAxis); + float3 axisU = position - pointOnAxis; + float3 axisV = cross(normalizedRotationAxisAndAngle.xyz, axisU); + float cosAngle, sinAngle; + sincos(normalizedRotationAxisAndAngle.w, sinAngle, cosAngle); + float3 rotation = axisU * cosAngle + axisV * sinAngle; + return pointOnAxis + rotation - position; } #endif diff --git a/Source/Shaders/Matrix.hlsl b/Source/Shaders/Matrix.hlsl index ec611d93c..c1f379e43 100644 --- a/Source/Shaders/Matrix.hlsl +++ b/Source/Shaders/Matrix.hlsl @@ -49,26 +49,26 @@ float3x3 EulerMatrix(float3 angles) { float3 s, c; sincos(angles, s, c); - return float3x3(c.y * c.z + s.x * s.y * s.z, c.z * s.x * s.y - c.y * s.z, c.x * s.y, - c.x * s.z, c.x * c.z, -s.x, - -c.z * s.y + c.y * s.x * s.z, c.y * c.z * s.x + s.y * s.z, c.x * c.y); + return float3x3(c.y * c.z + s.x * s.y * s.z, c.z * s.x * s.y - c.y * s.z, c.x * s.y, c.x * s.z, c.x * c.z, -s.x, -c.z * s.y + c.y * s.x * s.z, c.y * c.z * s.x + s.y * s.z, c.x * c.y); } float4x4 QuaternionToMatrix(float4 q) { - float x2 = q.x + q.x; float y2 = q.y + q.y; float z2 = q.z + q.z; - float xx = q.x * x2; float xy = q.x * y2; float xz = q.x * z2; - float yy = q.y * y2; float yz = q.y * z2; float zz = q.z * z2; - float wx = q.w * x2; float wy = q.w * y2; float wz = q.w * z2; - - float4x4 result = - { - 1.0f - (yy + zz), xy - wz, xz + wy, 0.0f, - xy + wz, 1.0f - (xx + zz), yz - wx, 0.0f, - xz - wy, yz + wx, 1.0f - (xx + yy), 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }; - return result; + // @formatter:off + float x2 = q.x + q.x; float y2 = q.y + q.y; float z2 = q.z + q.z; + float xx = q.x * x2; float xy = q.x * y2; float xz = q.x * z2; + float yy = q.y * y2; float yz = q.y * z2; float zz = q.z * z2; + float wx = q.w * x2; float wy = q.w * y2; float wz = q.w * z2; + + float4x4 result = + { + 1.0f - (yy + zz), xy - wz, xz + wy, 0.0f, + xy + wz, 1.0f - (xx + zz), yz - wx, 0.0f, + xz - wy, yz + wx, 1.0f - (xx + yy), 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + return result; + // @formatter:on } #endif diff --git a/Source/Shaders/MonteCarlo.hlsl b/Source/Shaders/MonteCarlo.hlsl index b11410957..aefc866cf 100644 --- a/Source/Shaders/MonteCarlo.hlsl +++ b/Source/Shaders/MonteCarlo.hlsl @@ -5,16 +5,16 @@ float3 TangentToWorld(float3 vec, float3 tangentZ) { - float3 upVector = abs(tangentZ.z) < 0.999 ? float3(0,0,1) : float3(1,0,0); - float3 tangentX = normalize(cross(upVector, tangentZ)); - float3 tangentY = cross(tangentZ, tangentX); - return tangentX * vec.x + tangentY * vec.y + tangentZ * vec.z; + float3 upVector = abs(tangentZ.z) < 0.999 ? float3(0, 0, 1) : float3(1, 0, 0); + float3 tangentX = normalize(cross(upVector, tangentZ)); + float3 tangentY = cross(tangentZ, tangentX); + return tangentX * vec.x + tangentY * vec.y + tangentZ * vec.z; } uint ReverseBits32(uint bits) { #if FEATURE_LEVEL >= FEATURE_LEVEL_SM5 - return reversebits(bits); + return reversebits(bits); #else bits = ( bits << 16) | ( bits >> 16); bits = ( (bits & 0x00ff00ff) << 8 ) | ( (bits & 0xff00ff00) >> 8 ); @@ -27,117 +27,117 @@ uint ReverseBits32(uint bits) float2 Hammersley(uint index, uint numSamples, uint2 random) { - float e1 = frac((float)index / numSamples + float(random.x & 0xffff) / (1 << 16)); - float e2 = float(ReverseBits32(index) ^ random.y) * 2.3283064365386963e-10; - return float2(e1, e2); + float e1 = frac((float)index / numSamples + float(random.x & 0xffff) / (1 << 16)); + float e2 = float(ReverseBits32(index) ^ random.y) * 2.3283064365386963e-10; + return float2(e1, e2); } float4 UniformSampleSphere(float2 e) { - float phi = 2 * PI * e.x; - float cosTheta = 1 - 2 * e.y; - float sinTheta = sqrt(1 - cosTheta * cosTheta); + float phi = 2 * PI * e.x; + float cosTheta = 1 - 2 * e.y; + float sinTheta = sqrt(1 - cosTheta * cosTheta); - float3 h; - h.x = sinTheta * cos(phi); - h.y = sinTheta * sin(phi); - h.z = cosTheta; + float3 h; + h.x = sinTheta * cos(phi); + h.y = sinTheta * sin(phi); + h.z = cosTheta; - float pdf = 1.0 / (4 * PI); - return float4(h, pdf); + float pdf = 1.0 / (4 * PI); + return float4(h, pdf); } float4 UniformSampleHemisphere(float2 e) { - float phi = 2 * PI * e.x; - float cosTheta = e.y; - float sinTheta = sqrt(1 - cosTheta * cosTheta); + float phi = 2 * PI * e.x; + float cosTheta = e.y; + float sinTheta = sqrt(1 - cosTheta * cosTheta); - float3 h; - h.x = sinTheta * cos(phi); - h.y = sinTheta * sin(phi); - h.z = cosTheta; + float3 h; + h.x = sinTheta * cos(phi); + h.y = sinTheta * sin(phi); + h.z = cosTheta; - float pdf = 1.0 / (2 * PI); - return float4(h, pdf); + float pdf = 1.0 / (2 * PI); + return float4(h, pdf); } float4 CosineSampleHemisphere(float2 e) { - float phi = 2 * PI * e.x; - float cosTheta = sqrt(e.y); - float sinTheta = sqrt(1 - cosTheta * cosTheta); + float phi = 2 * PI * e.x; + float cosTheta = sqrt(e.y); + float sinTheta = sqrt(1 - cosTheta * cosTheta); - float3 h; - h.x = sinTheta * cos(phi); - h.y = sinTheta * sin(phi); - h.z = cosTheta; + float3 h; + h.x = sinTheta * cos(phi); + h.y = sinTheta * sin(phi); + h.z = cosTheta; - float pdf = cosTheta / PI; - return float4(h, pdf); + float pdf = cosTheta / PI; + return float4(h, pdf); } float4 UniformSampleCone(float2 e, float cosThetaMax) { - float phi = 2 * PI * e.x; - float cosTheta = lerp(cosThetaMax, 1, e.y); - float sinTheta = sqrt(1 - cosTheta * cosTheta); + float phi = 2 * PI * e.x; + float cosTheta = lerp(cosThetaMax, 1, e.y); + float sinTheta = sqrt(1 - cosTheta * cosTheta); - float3 l; - l.x = sinTheta * cos(phi); - l.y = sinTheta * sin(phi); - l.z = cosTheta; + float3 l; + l.x = sinTheta * cos(phi); + l.y = sinTheta * sin(phi); + l.z = cosTheta; - float pdf = 1.0 / (2 * PI * (1 - cosThetaMax)); - return float4(l, pdf); + float pdf = 1.0 / (2 * PI * (1 - cosThetaMax)); + return float4(l, pdf); } float4 ImportanceSampleBlinn(float2 e, float roughness) { - float m = roughness * roughness; - float n = 2 / (m * m) - 2; + float m = roughness * roughness; + float n = 2 / (m * m) - 2; - float phi = 2 * PI * e.x; - float cosTheta = ClampedPow(e.y, 1 / (n + 1)); - float sinTheta = sqrt(1 - cosTheta * cosTheta); + float phi = 2 * PI * e.x; + float cosTheta = ClampedPow(e.y, 1 / (n + 1)); + float sinTheta = sqrt(1 - cosTheta * cosTheta); - float3 h; - h.x = sinTheta * cos(phi); - h.y = sinTheta * sin(phi); - h.z = cosTheta; + float3 h; + h.x = sinTheta * cos(phi); + h.y = sinTheta * sin(phi); + h.z = cosTheta; - float d = (n + 2)/ (2 * PI) * ClampedPow(cosTheta, n); - float pdf = d * cosTheta; - return float4(h, pdf); + float d = (n + 2) / (2 * PI) * ClampedPow(cosTheta, n); + float pdf = d * cosTheta; + return float4(h, pdf); } float4 ImportanceSampleGGX(float2 e, float roughness) { - float m = roughness * roughness; - float m2 = m * m; + float m = roughness * roughness; + float m2 = m * m; - float phi = 2 * PI * e.x; - float cosTheta = sqrt((1 - e.y) / (1 + (m2 - 1) * e.y)); - float sinTheta = sqrt(1 - cosTheta * cosTheta); + float phi = 2 * PI * e.x; + float cosTheta = sqrt((1 - e.y) / (1 + (m2 - 1) * e.y)); + float sinTheta = sqrt(1 - cosTheta * cosTheta); - float3 h; - h.x = sinTheta * cos(phi); - h.y = sinTheta * sin(phi); - h.z = cosTheta; - - float r = (cosTheta * m2 - cosTheta) * cosTheta + 1; - float d = m2 / (PI * r * r); - float pdf = d * cosTheta; - return float4(h, pdf); + float3 h; + h.x = sinTheta * cos(phi); + h.y = sinTheta * sin(phi); + h.z = cosTheta; + + float r = (cosTheta * m2 - cosTheta) * cosTheta + 1; + float d = m2 / (PI * r * r); + float pdf = d * cosTheta; + return float4(h, pdf); } // Multiple importance sampling power heuristic of two functions with a power of two. // [Veach 1997, "Robust Monte Carlo Methods for Light Transport Simulation"] float MISWeight(uint number, float PDF, uint otherNumber, float otherPDF) { - float weight = number * PDF; - float otherWeight = otherNumber * otherPDF; - return weight * weight / (weight * weight + otherWeight * otherWeight); + float weight = number * PDF; + float otherWeight = otherNumber * otherPDF; + return weight * weight / (weight * weight + otherWeight * otherWeight); } #endif diff --git a/Source/Shaders/Quaternion.hlsl b/Source/Shaders/Quaternion.hlsl index 09b5c49b3..1247c48fe 100644 --- a/Source/Shaders/Quaternion.hlsl +++ b/Source/Shaders/Quaternion.hlsl @@ -5,14 +5,14 @@ float4 QuaternionMultiply(float4 q1, float4 q2) { - return float4(q2.xyz * q1.w + q1.xyz * q2.w + cross(q1.xyz, q2.xyz), q1.w * q2.w - dot(q1.xyz, q2.xyz)); + return float4(q2.xyz * q1.w + q1.xyz * q2.w + cross(q1.xyz, q2.xyz), q1.w * q2.w - dot(q1.xyz, q2.xyz)); } float3 QuaternionRotate(float4 q, float3 v) { - float3 b = q.xyz; - float b2 = dot(b, b); - return (v * (q.w * q.w - b2) + b * (dot(v, b) * 2.f) + cross(b, v) * (q.w * 2.f)); + float3 b = q.xyz; + float b2 = dot(b, b); + return (v * (q.w * q.w - b2) + b * (dot(v, b) * 2.f) + cross(b, v) * (q.w * 2.f)); } #endif diff --git a/Source/Shaders/Random.hlsl b/Source/Shaders/Random.hlsl index 33aa3cbb4..0c48b0eaa 100644 --- a/Source/Shaders/Random.hlsl +++ b/Source/Shaders/Random.hlsl @@ -5,8 +5,8 @@ float PseudoRandom(float2 xy) { - float2 p = frac(xy / 128.0f) * 128.0f + float2(-64.340622f, -72.465622f); - return frac(dot(p.xyx * p.xyy, float3(20.390625f, 60.703125f, 2.4281209f))); + float2 p = frac(xy / 128.0f) * 128.0f + float2(-64.340622f, -72.465622f); + return frac(dot(p.xyx * p.xyy, float3(20.390625f, 60.703125f, 2.4281209f))); } // Generic noise (1-component) @@ -23,33 +23,33 @@ float2 RandN2(float2 n) void FindBestAxisVectors(float3 input, out float3 axis1, out float3 axis2) { - const float3 a = abs(input); - if (a.z > a.x && a.z > a.y) - axis1 = float3(1, 0, 0); - else - axis1 = float3(0, 0, 1); - axis1 = normalize(axis1 - input * dot(axis1, input)); - axis2 = cross(axis1, input); + const float3 a = abs(input); + if (a.z > a.x && a.z > a.y) + axis1 = float3(1, 0, 0); + else + axis1 = float3(0, 0, 1); + axis1 = normalize(axis1 - input * dot(axis1, input)); + axis2 = cross(axis1, input); } float PerlinRamp(in float t) { - return t * t * t * (t * (t * 6 - 15) + 10); + return t * t * t * (t * (t * 6 - 15) + 10); } float2 PerlinRamp(in float2 t) { - return t * t * t * (t * (t * 6 - 15) + 10); + return t * t * t * (t * (t * 6 - 15) + 10); } float3 PerlinRamp(in float3 t) { - return t * t * t * (t * (t * 6 - 15) + 10); + return t * t * t * (t * (t * 6 - 15) + 10); } float4 PerlinRamp(in float4 t) { - return t * t * t * (t * (t * 6 - 15) + 10); + return t * t * t * (t * (t * 6 - 15) + 10); } #endif diff --git a/Source/Shaders/ReflectionsCommon.hlsl b/Source/Shaders/ReflectionsCommon.hlsl index cd4695095..f6e4aafa1 100644 --- a/Source/Shaders/ReflectionsCommon.hlsl +++ b/Source/Shaders/ReflectionsCommon.hlsl @@ -7,48 +7,48 @@ float GetSpecularOcclusion(float NoV, float roughnessSq, float ao) { - return saturate(pow(NoV + ao, roughnessSq) - 1 + ao); + return saturate(pow(NoV + ao, roughnessSq) - 1 + ao); } float4 SampleReflectionProbe(float3 viewPos, TextureCube probe, ProbeData data, float3 positionWS, float3 normal, float roughness) { - // Calculate distance from probe to the pixel - float3 captureVector = positionWS - data.ProbePos; - float captureVectorLength = length(captureVector); - - // Check if cannot light pixel - // TODO: maybe remove this check?? - test it out with dozens of probes - BRANCH - if (captureVectorLength >= data.ProbeRadius) - { - // End - return 0; - } + // Calculate distance from probe to the pixel + float3 captureVector = positionWS - data.ProbePos; + float captureVectorLength = length(captureVector); - // Fade out based on distance to capture - float normalizedDistanceToCapture = saturate(captureVectorLength * data.ProbeInvRadius); - float distanceAlpha = 1.0 - smoothstep(0.7, 1, normalizedDistanceToCapture); - float fade = distanceAlpha * data.ProbeBrightness; + // Check if cannot light pixel + // TODO: maybe remove this check?? - test it out with dozens of probes + BRANCH + if (captureVectorLength >= data.ProbeRadius) + { + // End + return 0; + } - // Calculate reflection vector - float3 V = normalize(positionWS - viewPos); - float3 R = reflect(V, normal); - float3 D = data.ProbeInvRadius * captureVector + R; + // Fade out based on distance to capture + float normalizedDistanceToCapture = saturate(captureVectorLength * data.ProbeInvRadius); + float distanceAlpha = 1.0 - smoothstep(0.7, 1, normalizedDistanceToCapture); + float fade = distanceAlpha * data.ProbeBrightness; - // Sample probe at valid mip level based on surface roughness value - half mip = ProbeMipFromRoughness(roughness); - float4 probeSample = probe.SampleLevel(SamplerLinearClamp, D, mip); + // Calculate reflection vector + float3 V = normalize(positionWS - viewPos); + float3 R = reflect(V, normal); + float3 D = data.ProbeInvRadius * captureVector + R; - return probeSample * fade; + // Sample probe at valid mip level based on surface roughness value + half mip = ProbeMipFromRoughness(roughness); + float4 probeSample = probe.SampleLevel(SamplerLinearClamp, D, mip); + + return probeSample * fade; } // Calculates the reflective environment lighting to multiply the raw reflection color for the specular light (eg. from Env Probe or SSR). float3 GetReflectionSpecularLighting(float3 viewPos, GBufferSample gBuffer) { - float3 specularColor = GetSpecularColor(gBuffer); - float3 V = normalize(viewPos - gBuffer.WorldPos); - float NoV = saturate(dot(gBuffer.Normal, V)); - return EnvBRDFApprox(specularColor, gBuffer.Roughness, NoV); + float3 specularColor = GetSpecularColor(gBuffer); + float3 V = normalize(viewPos - gBuffer.WorldPos); + float NoV = saturate(dot(gBuffer.Normal, V)); + return EnvBRDFApprox(specularColor, gBuffer.Roughness, NoV); } #endif diff --git a/Source/Shaders/SH.hlsl b/Source/Shaders/SH.hlsl index d4d38d0fe..93712af03 100644 --- a/Source/Shaders/SH.hlsl +++ b/Source/Shaders/SH.hlsl @@ -6,34 +6,34 @@ // The SH coefficients for the projection of a function that maps directions to scalar values struct ThreeBandSHVector { - half4 V0; - half4 V1; - half V2; + half4 V0; + half4 V1; + half V2; }; ThreeBandSHVector SHBasisFunction3(half3 v) { - ThreeBandSHVector result; + ThreeBandSHVector result; - result.V0.x = 0.282095f; - result.V0.y = -0.488603f * v.y; - result.V0.z = 0.488603f * v.z; - result.V0.w = -0.488603f * v.x; + result.V0.x = 0.282095f; + result.V0.y = -0.488603f * v.y; + result.V0.z = 0.488603f * v.z; + result.V0.w = -0.488603f * v.x; - result.V1.x = 1.092548f * v.x * v.y; - result.V1.y = -1.092548f * v.y * v.z; - result.V1.z = 0.315392f * (3.0f * v.z - 1.0f); - result.V1.w = -1.092548f * v.x * v.z; - result.V2 = 0.546274f * (v.x - v.y); + result.V1.x = 1.092548f * v.x * v.y; + result.V1.y = -1.092548f * v.y * v.z; + result.V1.z = 0.315392f * (3.0f * v.z - 1.0f); + result.V1.w = -1.092548f * v.x * v.z; + result.V2 = 0.546274f * (v.x - v.y); - return result; + return result; } // Projects a direction onto SH and convolves with a cosine kernel to compute irradiance void ProjectOntoSH3(in float3 n, in float3 color, out float3 sh[9]) { - // Cosine kernel - const float A0 = 3.141593f; + // Cosine kernel + const float A0 = 3.141593f; const float A1 = 2.095395f; const float A2 = 0.785398f; @@ -57,27 +57,28 @@ void ProjectOntoSH3(in float3 n, in float3 color, out float3 sh[9]) // [Ralf Habel and Michael Wimmer, "Efficient Irradiance Normal Mapping"] void ConvertSH3ToHBasis(in float3 sh[9], out float3 hBasis[4]) { - const float rt2 = sqrt(2.0f); - const float rt32 = sqrt(3.0f / 2.0f); - const float rt52 = sqrt(5.0f / 2.0f); - const float rt152 = sqrt(15.0f / 2.0f); - const float convMatrix[4*9] = - { - 1.0f / rt2, 0, 0.5f * rt32, 0, 0, 0, 0, 0, 0, - 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0, 0, 0, - 0, 0, 1.0f / (2.0f * rt2), 0, 0, 0, 0.25f * rt152, 0, 0, - 0, 0, 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0 - }; + const float rt2 = sqrt(2.0f); + const float rt32 = sqrt(3.0f / 2.0f); + const float rt52 = sqrt(5.0f / 2.0f); + const float rt152 = sqrt(15.0f / 2.0f); + const float convMatrix[4 * 9] = + { + // @formatter:off + 1.0f / rt2, 0, 0.5f * rt32, 0, 0, 0, 0, 0, 0, + 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0, 0, 0, + 0, 0, 1.0f / (2.0f * rt2), 0, 0, 0, 0.25f * rt152, 0, 0, + 0, 0, 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0 + // @formatter:on + }; - UNROLL - for (uint row = 0; row < 4; row++) - { - hBasis[row] = 0.0f; - - UNROLL - for (uint col = 0; col < 9; col++) - hBasis[row] += convMatrix[row * 9 + col] * sh[col]; - } + UNROLL + for (uint row = 0; row < 4; row++) + { + hBasis[row] = 0.0f; + UNROLL + for (uint col = 0; col < 9; col++) + hBasis[row] += convMatrix[row * 9 + col] * sh[col]; + } } #endif diff --git a/Source/Shaders/SSR.hlsl b/Source/Shaders/SSR.hlsl index ccb2b1e89..41c1ccfd5 100644 --- a/Source/Shaders/SSR.hlsl +++ b/Source/Shaders/SSR.hlsl @@ -9,137 +9,134 @@ // 1:-1 to 0:1 float2 ClipToUv(float2 clipPos) { - return clipPos * float2(0.5, -0.5) + float2(0.5, 0.5); + return clipPos * float2(0.5, -0.5) + float2(0.5, 0.5); } // go into clip space (-1:1 from bottom/left to up/right) float3 ProjectWorldToClip(float3 wsPos, float4x4 viewProjectionMatrix) { - float4 clipPos = mul(float4(wsPos, 1), viewProjectionMatrix); - return clipPos.xyz / clipPos.w; + float4 clipPos = mul(float4(wsPos, 1), viewProjectionMatrix); + return clipPos.xyz / clipPos.w; } // go into UV space. (0:1 from top/left to bottom/right) float3 ProjectWorldToUv(float3 wsPos, float4x4 viewProjectionMatrix) { - float3 clipPos = ProjectWorldToClip(wsPos, viewProjectionMatrix); - return float3(ClipToUv(clipPos.xy), clipPos.z); + float3 clipPos = ProjectWorldToClip(wsPos, viewProjectionMatrix); + return float3(ClipToUv(clipPos.xy), clipPos.z); } float3 TangentToWorld(float3 N, float4 H) { - float3 upVector = abs(N.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0); - float3 T = normalize(cross(upVector, N)); - float3 B = cross(N, T); - return float3((T * H.x) + (B * H.y) + (N * H.z)); + float3 upVector = abs(N.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0); + float3 T = normalize(cross(upVector, N)); + float3 B = cross(N, T); + return float3((T * H.x) + (B * H.y) + (N * H.z)); } float RayAttenBorder(float2 pos, float value) { - float borderDist = min(1.0 - max(pos.x, pos.y), min(pos.x, pos.y)); - return saturate(borderDist > value ? 1.0 : borderDist / value); + float borderDist = min(1.0 - max(pos.x, pos.y), min(pos.x, pos.y)); + return saturate(borderDist > value ? 1.0 : borderDist / value); } // Screen Space Reflection ray tracing utility. // Returns: xy: hitUV, z: hitMask, where hitUV is the result UV of hit pixel, hitMask is the normalized sample weight (0 if no hit). float3 TraceSceenSpaceReflection(float2 uv, GBufferSample gBuffer, Texture2D depthBuffer, float3 viewPos, float4x4 viewMatrix, float4x4 viewProjectionMatrix, float stepSize, float maxSamples = 20, bool temporal = false, float temporalTime = 0.0f, float worldAntiSelfOcclusionBias = 0.1f, float brdfBias = 0.82f, float drawDistance = 5000.0f, float roughnessThreshold = 0.4f, float edgeFade = 0.1f) { - // Reject invalid pixels - if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT || gBuffer.Roughness > roughnessThreshold || gBuffer.ViewPos.z > drawDistance) - return 0; + // Reject invalid pixels + if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT || gBuffer.Roughness > roughnessThreshold || gBuffer.ViewPos.z > drawDistance) + return 0; - // Calculate view space normal vector - float3 normalVS = mul(gBuffer.Normal, (float3x3)viewMatrix); + // Calculate view space normal vector + float3 normalVS = mul(gBuffer.Normal, (float3x3)viewMatrix); - // Randomize it a little - float2 jitter = RandN2(uv + temporalTime); - float2 Xi = jitter; - Xi.y = lerp(Xi.y, 0.0, brdfBias); - float3 H = temporal ? TangentToWorld(gBuffer.Normal, ImportanceSampleGGX(Xi, gBuffer.Roughness)) : gBuffer.Normal; + // Randomize it a little + float2 jitter = RandN2(uv + temporalTime); + float2 Xi = jitter; + Xi.y = lerp(Xi.y, 0.0, brdfBias); + float3 H = temporal ? TangentToWorld(gBuffer.Normal, ImportanceSampleGGX(Xi, gBuffer.Roughness)) : gBuffer.Normal; - // Calculate normalized view space reflection vector - float3 reflectVS = normalize(reflect(gBuffer.ViewPos, normalVS)); - if (gBuffer.ViewPos.z < 1.0 && reflectVS.z < 0.4) - return 0; + // Calculate normalized view space reflection vector + float3 reflectVS = normalize(reflect(gBuffer.ViewPos, normalVS)); + if (gBuffer.ViewPos.z < 1.0 && reflectVS.z < 0.4) + return 0; - float3 viewWS = normalize(gBuffer.WorldPos - viewPos); - float3 reflectWS = reflect(viewWS, H.xyz); + float3 viewWS = normalize(gBuffer.WorldPos - viewPos); + float3 reflectWS = reflect(viewWS, H.xyz); - float3 startWS = gBuffer.WorldPos + gBuffer.Normal * worldAntiSelfOcclusionBias; - float3 startUV = ProjectWorldToUv(startWS, viewProjectionMatrix); - float3 endUV = ProjectWorldToUv(startWS + reflectWS, viewProjectionMatrix); + float3 startWS = gBuffer.WorldPos + gBuffer.Normal * worldAntiSelfOcclusionBias; + float3 startUV = ProjectWorldToUv(startWS, viewProjectionMatrix); + float3 endUV = ProjectWorldToUv(startWS + reflectWS, viewProjectionMatrix); - float3 rayUV = endUV - startUV; + float3 rayUV = endUV - startUV; float2 rayUVAbs = abs(rayUV.xy); - rayUV *= stepSize / max(rayUVAbs.x, rayUVAbs.y); - float3 startUv = startUV + rayUV * 2; + rayUV *= stepSize / max(rayUVAbs.x, rayUVAbs.y); + float3 startUv = startUV + rayUV * 2; - float3 currOffset = startUv; - float3 rayStep = rayUV * 2; + float3 currOffset = startUv; + float3 rayStep = rayUV * 2; - // Calculate number of samples - float3 samplesToEdge = ((sign(rayStep.xyz) * 0.5 + 0.5) - currOffset.xyz) / rayStep.xyz; - samplesToEdge.x = min(samplesToEdge.x, min(samplesToEdge.y, samplesToEdge.z)) * 1.05f; - float numSamples = min(maxSamples, samplesToEdge.x); - rayStep *= samplesToEdge.x / numSamples; + // Calculate number of samples + float3 samplesToEdge = ((sign(rayStep.xyz) * 0.5 + 0.5) - currOffset.xyz) / rayStep.xyz; + samplesToEdge.x = min(samplesToEdge.x, min(samplesToEdge.y, samplesToEdge.z)) * 1.05f; + float numSamples = min(maxSamples, samplesToEdge.x); + rayStep *= samplesToEdge.x / numSamples; - // Calculate depth difference error - float depthDiffError = 1.3f * abs(rayStep.z); + // Calculate depth difference error + float depthDiffError = 1.3f * abs(rayStep.z); - // Ray trace - float currSampleIndex = 0; - float currSample, depthDiff; - LOOP - while (currSampleIndex < numSamples) - { - // Sample depth buffer and calculate depth difference - currSample = SAMPLE_RT(depthBuffer, currOffset.xy).r; - depthDiff = currOffset.z - currSample; + // Ray trace + float currSampleIndex = 0; + float currSample, depthDiff; + LOOP + while (currSampleIndex < numSamples) + { + // Sample depth buffer and calculate depth difference + currSample = SAMPLE_RT(depthBuffer, currOffset.xy).r; + depthDiff = currOffset.z - currSample; - // Check intersection - if (depthDiff >= 0) - { - if (depthDiff < depthDiffError) - { - break; - } - else - { - currOffset -= rayStep; - rayStep *= 0.5; - } - } + // Check intersection + if (depthDiff >= 0) + { + if (depthDiff < depthDiffError) + { + break; + } + currOffset -= rayStep; + rayStep *= 0.5; + } - // Move forward - currOffset += rayStep; - currSampleIndex++; - } + // Move forward + currOffset += rayStep; + currSampleIndex++; + } - // Check if has valid result after ray tracing - if (currSampleIndex >= numSamples) - { - // All samples done but no result - return 0; - } + // Check if has valid result after ray tracing + if (currSampleIndex >= numSamples) + { + // All samples done but no result + return 0; + } - float2 hitUV = currOffset.xy; + float2 hitUV = currOffset.xy; - // Fade rays close to screen edge - const float fadeStart = 0.9f; - const float fadeEnd = 1.0f; - const float fadeDiffRcp = 1.0f / (fadeEnd - fadeStart); - float2 boundary = abs(hitUV - float2(0.5f, 0.5f)) * 2.0f; - float fadeOnBorder = 1.0f - saturate((boundary.x - fadeStart) * fadeDiffRcp); - fadeOnBorder *= 1.0f - saturate((boundary.y - fadeStart) * fadeDiffRcp); - fadeOnBorder = smoothstep(0.0f, 1.0f, fadeOnBorder); - fadeOnBorder *= RayAttenBorder(hitUV, edgeFade); + // Fade rays close to screen edge + const float fadeStart = 0.9f; + const float fadeEnd = 1.0f; + const float fadeDiffRcp = 1.0f / (fadeEnd - fadeStart); + float2 boundary = abs(hitUV - float2(0.5f, 0.5f)) * 2.0f; + float fadeOnBorder = 1.0f - saturate((boundary.x - fadeStart) * fadeDiffRcp); + fadeOnBorder *= 1.0f - saturate((boundary.y - fadeStart) * fadeDiffRcp); + fadeOnBorder = smoothstep(0.0f, 1.0f, fadeOnBorder); + fadeOnBorder *= RayAttenBorder(hitUV, edgeFade); - // Fade rays on high roughness - float roughnessFade = saturate((roughnessThreshold - gBuffer.Roughness) * 20); + // Fade rays on high roughness + float roughnessFade = saturate((roughnessThreshold - gBuffer.Roughness) * 20); - // Fade on distance - float distanceFade = saturate((drawDistance - gBuffer.ViewPos.z) / drawDistance); + // Fade on distance + float distanceFade = saturate((drawDistance - gBuffer.ViewPos.z) / drawDistance); - // Output: xy: hitUV, z: hitMask - return float3(hitUV, fadeOnBorder * roughnessFade * distanceFade); + // Output: xy: hitUV, z: hitMask + return float3(hitUV, fadeOnBorder * roughnessFade * distanceFade); } diff --git a/Source/Shaders/ShadowsCommon.hlsl b/Source/Shaders/ShadowsCommon.hlsl index 56764937b..c06b16654 100644 --- a/Source/Shaders/ShadowsCommon.hlsl +++ b/Source/Shaders/ShadowsCommon.hlsl @@ -10,26 +10,26 @@ // Set default macros if not provided #ifndef SHADOWS_QUALITY - #define SHADOWS_QUALITY 0 +#define SHADOWS_QUALITY 0 #endif #ifndef CSM_BLENDING - #define CSM_BLENDING 0 +#define CSM_BLENDING 0 #endif // Structure that contains information about light struct LightShadowData { - float2 ShadowMapSize; - float Sharpness; - float Fade; + float2 ShadowMapSize; + float Sharpness; + float Fade; - float NormalOffsetScale; - float Bias; - float FadeDistance; - uint NumCascades; + float NormalOffsetScale; + float Bias; + float FadeDistance; + uint NumCascades; - float4 CascadeSplits; - float4x4 ShadowVP[6]; + float4 CascadeSplits; + float4x4 ShadowVP[6]; }; #ifdef PLATFORM_ANDROID @@ -41,15 +41,15 @@ struct LightShadowData float3 GetShadowPositionOffset(float offsetScale, float NoL, float3 normal) { - float normalOffsetScale = saturate(1.0f - NoL); - return normal * (offsetScale * normalOffsetScale); + float normalOffsetScale = saturate(1.0f - NoL); + return normal * (offsetScale * normalOffsetScale); } float CalculateSubsurfaceOcclusion(float opacity, float sceneDepth, float shadowMapDepth) { - float thickness = max(sceneDepth - shadowMapDepth, 0); - float occlusion = 1 - thickness * lerp(1.0f, 100.0f, opacity); - return shadowMapDepth > 0.99f ? 1 : occlusion; + float thickness = max(sceneDepth - shadowMapDepth, 0); + float occlusion = 1 - thickness * lerp(1.0f, 100.0f, opacity); + return shadowMapDepth > 0.99f ? 1 : occlusion; } #endif diff --git a/Source/Shaders/ShadowsSampling.hlsl b/Source/Shaders/ShadowsSampling.hlsl index a2088c5f8..bf608a0c5 100644 --- a/Source/Shaders/ShadowsSampling.hlsl +++ b/Source/Shaders/ShadowsSampling.hlsl @@ -14,10 +14,10 @@ // Spot: 2, 5, 12, 29 #if SHADOWS_QUALITY == 0 - #define FilterSizeCSM 2 - #define FilterSizeCube 2 - #define FilterSizeSpot 2 - +#define FilterSizeCSM 2 +#define FilterSizeCube 2 +#define FilterSizeSpot 2 + #elif SHADOWS_QUALITY == 1 #define FilterSizeCSM 3 @@ -46,16 +46,16 @@ // Where: direction = normalize(worldPosition - lightPosition) int GetCubeFaceIndex(float3 direction) { - int cubeFaceIndex; - float3 absDirection = abs(direction); - float maxDirection = max(absDirection.x, max(absDirection.y, absDirection.z)); - if (maxDirection == absDirection.x) - cubeFaceIndex = absDirection.x == direction.x ? 0 : 1; - else if (maxDirection == absDirection.y) - cubeFaceIndex = absDirection.y == direction.y ? 2 : 3; - else - cubeFaceIndex = absDirection.z == direction.z ? 4 : 5; - return cubeFaceIndex; + int cubeFaceIndex; + float3 absDirection = abs(direction); + float maxDirection = max(absDirection.x, max(absDirection.y, absDirection.z)); + if (maxDirection == absDirection.x) + cubeFaceIndex = absDirection.x == direction.x ? 0 : 1; + else if (maxDirection == absDirection.y) + cubeFaceIndex = absDirection.y == direction.y ? 2 : 3; + else + cubeFaceIndex = absDirection.z == direction.z ? 4 : 5; + return cubeFaceIndex; } // Samples the shadow map with a fixed-size PCF kernel optimized with GatherCmpRed. @@ -64,15 +64,15 @@ float SampleShadowMapFixedSizePCF(Texture2DArray shadowMap, float2 shadowMapSize { #if FilterSizeCSM == 2 - #if FEATURE_LEVEL >= FEATURE_LEVEL_SM5 +#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5 - return shadowMap.SampleCmpLevelZero(ShadowSamplerPCF, float3(shadowPos.xy, cascadeIndex), sceneDepth); + return shadowMap.SampleCmpLevelZero(ShadowSamplerPCF, float3(shadowPos.xy, cascadeIndex), sceneDepth); - #else +#else return sceneDepth < shadowMap.SampleLevel(SamplerLinearClamp, float3(shadowPos.xy, cascadeIndex), 0).r; - #endif +#endif #else @@ -120,11 +120,11 @@ float SampleShadowMapFixedSizePCF(Texture2DArray shadowMap, float2 shadowMapSize if (value != 0.0f) { // Gather returns xyzw which is counter clockwise order starting with the sample to the lower left of the queried location - #if CAN_USE_GATHER +#if CAN_USE_GATHER v1[(col + FS_2) / 2] = shadowMap.GatherCmp(ShadowSampler, baseUV, sceneDepth, int2(col, row)); - #else +#else float4 gather; @@ -135,7 +135,7 @@ float SampleShadowMapFixedSizePCF(Texture2DArray shadowMap, float2 shadowMapSize v1[(col + FS_2) / 2] = gather; - #endif +#endif } else v1[(col + FS_2) / 2] = 0.0f; @@ -242,7 +242,7 @@ float SampleShadowMapOptimizedPCF(Texture2DArray shadowMap, float2 shadowMapSize #if FilterSizeCSM == 2 - return shadowMap.SampleCmpLevelZero(ShadowSamplerPCF, float3(shadowPos.xy, cascadeIndex), sceneDepth); + return shadowMap.SampleCmpLevelZero(ShadowSamplerPCF, float3(shadowPos.xy, cascadeIndex), sceneDepth); #elif FilterSizeCSM == 3 @@ -265,7 +265,7 @@ float SampleShadowMapOptimizedPCF(Texture2DArray shadowMap, float2 shadowMapSize return sum * 1.0f / 16; - #elif FilterSizeCSM == 5 +#elif FilterSizeCSM == 5 float uw0 = (4 - 3 * s); float uw1 = 7; @@ -347,41 +347,41 @@ float SampleShadowMapOptimizedPCF(Texture2DArray shadowMap, float2 shadowMapSize // Samples the shadow from the shadow map cascade float SampleShadowCascade(Texture2DArray shadowMap, float2 shadowMapSize, float sceneDepth, float2 shadowPosition, uint cascadeIndex) { - float shadow = SampleShadowMapFixedSizePCF(shadowMap, shadowMapSize, sceneDepth, shadowPosition, cascadeIndex); - //float shadow = SampleShadowMapOptimizedPCF(shadowMap, shadowMapSize, sceneDepth, shadowPosition, cascadeIndex); - return shadow; + float shadow = SampleShadowMapFixedSizePCF(shadowMap, shadowMapSize, sceneDepth, shadowPosition, cascadeIndex); + //float shadow = SampleShadowMapOptimizedPCF(shadowMap, shadowMapSize, sceneDepth, shadowPosition, cascadeIndex); + return shadow; } // Samples the shadow for the given directional light (cascaded shadow map sampling) float SampleShadow(LightData light, LightShadowData shadow, Texture2DArray shadowMap, float3 worldPosition, float viewDepth) { - // Create a blend factor which is one before and at the fade plane - float fade = saturate((viewDepth - shadow.CascadeSplits[shadow.NumCascades - 1] + shadow.FadeDistance) / shadow.FadeDistance); - BRANCH - if (fade >= 1.0) - { - return 1; - } + // Create a blend factor which is one before and at the fade plane + float fade = saturate((viewDepth - shadow.CascadeSplits[shadow.NumCascades - 1] + shadow.FadeDistance) / shadow.FadeDistance); + BRANCH + if (fade >= 1.0) + { + return 1; + } - // Figure out which cascade to sample from - uint cascadeIndex = 0; - for (uint i = 0; i < shadow.NumCascades - 1; i++) - { - if (viewDepth > shadow.CascadeSplits[i]) - cascadeIndex = i + 1; - } + // Figure out which cascade to sample from + uint cascadeIndex = 0; + for (uint i = 0; i < shadow.NumCascades - 1; i++) + { + if (viewDepth > shadow.CascadeSplits[i]) + cascadeIndex = i + 1; + } // Project into shadow space - float4 shadowPosition = mul(float4(worldPosition, 1.0f), shadow.ShadowVP[cascadeIndex]); - shadowPosition.xy /= shadowPosition.w; - shadowPosition.z -= shadow.Bias; + float4 shadowPosition = mul(float4(worldPosition, 1.0f), shadow.ShadowVP[cascadeIndex]); + shadowPosition.xy /= shadowPosition.w; + shadowPosition.z -= shadow.Bias; - // Sample shadow - float result = SampleShadowCascade(shadowMap, shadow.ShadowMapSize, shadowPosition.z, shadowPosition.xy, cascadeIndex); + // Sample shadow + float result = SampleShadowCascade(shadowMap, shadow.ShadowMapSize, shadowPosition.z, shadowPosition.xy, cascadeIndex); - // Increase the sharpness for higher cascades to match the filter radius - const float SharpnessScale[MaxNumCascades] = { 1.0f, 1.5f, 3.0f, 3.5f }; - float sharpness = shadow.Sharpness * SharpnessScale[cascadeIndex]; + // Increase the sharpness for higher cascades to match the filter radius + const float SharpnessScale[MaxNumCascades] = { 1.0f, 1.5f, 3.0f, 3.5f }; + float sharpness = shadow.Sharpness * SharpnessScale[cascadeIndex]; #if CSM_BLENDING // Sample the next cascade, and blend between the two results to smooth the transition @@ -408,33 +408,33 @@ float SampleShadow(LightData light, LightShadowData shadow, Texture2DArray shado } #endif - // Apply shadow fade and sharpness - result = saturate((result - 0.5) * sharpness + 0.5); - result = lerp(1.0f, result, (1 - fade) * shadow.Fade); - return result; + // Apply shadow fade and sharpness + result = saturate((result - 0.5) * sharpness + 0.5); + result = lerp(1.0f, result, (1 - fade) * shadow.Fade); + return result; } // Samples the shadow for the given directional light (cascaded shadow map sampling) for the material surface (supports subsurface shadowing) float SampleShadow(LightData light, LightShadowData shadow, Texture2DArray shadowMap, GBufferSample gBuffer, out float subsurfaceShadow) { - subsurfaceShadow = 1; + subsurfaceShadow = 1; - // Create a blend factor which is one before and at the fade plane - float viewDepth = gBuffer.ViewPos.z; - float fade = saturate((viewDepth - shadow.CascadeSplits[shadow.NumCascades - 1] + shadow.FadeDistance) / shadow.FadeDistance); - BRANCH - if (fade >= 1.0) - { - return 1; - } + // Create a blend factor which is one before and at the fade plane + float viewDepth = gBuffer.ViewPos.z; + float fade = saturate((viewDepth - shadow.CascadeSplits[shadow.NumCascades - 1] + shadow.FadeDistance) / shadow.FadeDistance); + BRANCH + if (fade >= 1.0) + { + return 1; + } - // Figure out which cascade to sample from - uint cascadeIndex = 0; - for (uint i = 0; i < shadow.NumCascades - 1; i++) - { - if (viewDepth > shadow.CascadeSplits[i]) - cascadeIndex = i + 1; - } + // Figure out which cascade to sample from + uint cascadeIndex = 0; + for (uint i = 0; i < shadow.NumCascades - 1; i++) + { + if (viewDepth > shadow.CascadeSplits[i]) + cascadeIndex = i + 1; + } #if defined(USE_GBUFFER_CUSTOM_DATA) // Subsurface shadowing @@ -458,51 +458,51 @@ float SampleShadow(LightData light, LightShadowData shadow, Texture2DArray shado } #endif - // Skip if surface is in a full shadow - float NoL = dot(gBuffer.Normal, light.Direction); - BRANCH - if (NoL <= 0) - { - return 0; - } + // Skip if surface is in a full shadow + float NoL = dot(gBuffer.Normal, light.Direction); + BRANCH + if (NoL <= 0) + { + return 0; + } - // Apply normal offset bias - float3 samplePosWS = gBuffer.WorldPos; - samplePosWS += GetShadowPositionOffset(shadow.NormalOffsetScale, NoL, gBuffer.Normal); + // Apply normal offset bias + float3 samplePosWS = gBuffer.WorldPos; + samplePosWS += GetShadowPositionOffset(shadow.NormalOffsetScale, NoL, gBuffer.Normal); - // Sample shadow - return SampleShadow(light, shadow, shadowMap, samplePosWS, viewDepth); + // Sample shadow + return SampleShadow(light, shadow, shadowMap, samplePosWS, viewDepth); } // Samples the shadow for the given spot light (PCF shadow map sampling) float SampleShadow(LightData light, LightShadowData shadow, Texture2D shadowMap, float3 worldPosition) { - float3 toLight = light.Position - worldPosition; - float toLightLength = length(toLight); - float3 L = toLight / toLightLength; - float dirCheck = dot(-light.Direction, L); + float3 toLight = light.Position - worldPosition; + float toLightLength = length(toLight); + float3 L = toLight / toLightLength; + float dirCheck = dot(-light.Direction, L); - // Skip pixels outside of the light influence - BRANCH - if (toLightLength > light.Radius || dirCheck < 0) - { - return 1; - } + // Skip pixels outside of the light influence + BRANCH + if (toLightLength > light.Radius || dirCheck < 0) + { + return 1; + } - // Negate direction and use normalized value - toLight = -L; + // Negate direction and use normalized value + toLight = -L; - // Project into shadow space - float4 shadowPosition = mul(float4(worldPosition, 1.0f), shadow.ShadowVP[0]); - shadowPosition.z -= shadow.Bias; - shadowPosition.xyz /= shadowPosition.w; + // Project into shadow space + float4 shadowPosition = mul(float4(worldPosition, 1.0f), shadow.ShadowVP[0]); + shadowPosition.z -= shadow.Bias; + shadowPosition.xyz /= shadowPosition.w; - float2 shadowMapUVs = shadowPosition.xy * float2(0.5f, -0.5f) + float2(0.5f, 0.5f); + float2 shadowMapUVs = shadowPosition.xy * float2(0.5f, -0.5f) + float2(0.5f, 0.5f); -#if FilterSizeSpot == 2 +#if FilterSizeSpot == 2 - // Use single hardware sample with filtering - float result = shadowMap.SampleCmpLevelZero(ShadowSamplerPCF, shadowMapUVs, shadowPosition.z); + // Use single hardware sample with filtering + float result = shadowMap.SampleCmpLevelZero(ShadowSamplerPCF, shadowMapUVs, shadowPosition.z); #else @@ -525,28 +525,28 @@ float SampleShadow(LightData light, LightShadowData shadow, Texture2D shadowMap, #endif - // Apply shadow fade and sharpness - result = saturate((result - 0.5) * shadow.Sharpness + 0.5); - result = lerp(1.0f, result, shadow.Fade); + // Apply shadow fade and sharpness + result = saturate((result - 0.5) * shadow.Sharpness + 0.5); + result = lerp(1.0f, result, shadow.Fade); - return result; + return result; } // Samples the shadow for the given spot light (PCF shadow map sampling) for the material surface (supports subsurface shadowing) float SampleShadow(LightData light, LightShadowData shadow, Texture2D shadowMap, GBufferSample gBuffer, out float subsurfaceShadow) { - subsurfaceShadow = 1; - float3 toLight = light.Position - gBuffer.WorldPos; - float toLightLength = length(toLight); - float3 L = toLight / toLightLength; - float dirCheck = dot(-light.Direction, L); + subsurfaceShadow = 1; + float3 toLight = light.Position - gBuffer.WorldPos; + float toLightLength = length(toLight); + float3 L = toLight / toLightLength; + float dirCheck = dot(-light.Direction, L); - // Skip pixels outside of the light influence - BRANCH - if (toLightLength > light.Radius || dirCheck < 0) - { - return 1; - } + // Skip pixels outside of the light influence + BRANCH + if (toLightLength > light.Radius || dirCheck < 0) + { + return 1; + } #if defined(USE_GBUFFER_CUSTOM_DATA) // Subsurface shadowing @@ -570,51 +570,51 @@ float SampleShadow(LightData light, LightShadowData shadow, Texture2D shadowMap, } #endif - // Skip if surface is in a full shadow - float NoL = dot(gBuffer.Normal, L); - BRANCH - if (NoL <= 0) - { - return 0; - } + // Skip if surface is in a full shadow + float NoL = dot(gBuffer.Normal, L); + BRANCH + if (NoL <= 0) + { + return 0; + } - // Apply normal offset bias - float3 samplePosWS = gBuffer.WorldPos; - samplePosWS += GetShadowPositionOffset(shadow.NormalOffsetScale, NoL, gBuffer.Normal); + // Apply normal offset bias + float3 samplePosWS = gBuffer.WorldPos; + samplePosWS += GetShadowPositionOffset(shadow.NormalOffsetScale, NoL, gBuffer.Normal); - // Sample shadow - return SampleShadow(light, shadow, shadowMap, samplePosWS); + // Sample shadow + return SampleShadow(light, shadow, shadowMap, samplePosWS); } // Samples the shadow for the given point light (PCF shadow map sampling) float SampleShadow(LightData light, LightShadowData shadow, TextureCube shadowMap, float3 worldPosition) { - float3 toLight = light.Position - worldPosition; - float toLightLength = length(toLight); - float3 L = toLight / toLightLength; + float3 toLight = light.Position - worldPosition; + float toLightLength = length(toLight); + float3 L = toLight / toLightLength; - // Skip pixels outside of the light influence - BRANCH - if (toLightLength > light.Radius) - { - return 1; - } + // Skip pixels outside of the light influence + BRANCH + if (toLightLength > light.Radius) + { + return 1; + } - // Negate direction and use normalized value - toLight = -L; + // Negate direction and use normalized value + toLight = -L; - // Figure out which cube face we're sampling from - int cubeFaceIndex = GetCubeFaceIndex(toLight); + // Figure out which cube face we're sampling from + int cubeFaceIndex = GetCubeFaceIndex(toLight); - // Project into shadow space - float4 shadowPosition = mul(float4(worldPosition, 1.0f), shadow.ShadowVP[cubeFaceIndex]); - shadowPosition.z -= shadow.Bias; - shadowPosition.xyz /= shadowPosition.w; + // Project into shadow space + float4 shadowPosition = mul(float4(worldPosition, 1.0f), shadow.ShadowVP[cubeFaceIndex]); + shadowPosition.z -= shadow.Bias; + shadowPosition.xyz /= shadowPosition.w; -#if FilterSizeCube == 2 +#if FilterSizeCube == 2 - // Use single hardware sample with filtering - float result = shadowMap.SampleCmpLevelZero(ShadowSamplerPCF, toLight, shadowPosition.z); + // Use single hardware sample with filtering + float result = shadowMap.SampleCmpLevelZero(ShadowSamplerPCF, toLight, shadowPosition.z); #else @@ -637,33 +637,33 @@ float SampleShadow(LightData light, LightShadowData shadow, TextureCube s #endif - // Apply shadow fade and sharpness - result = saturate((result - 0.5) * shadow.Sharpness + 0.5); - result = lerp(1.0f, result, shadow.Fade); + // Apply shadow fade and sharpness + result = saturate((result - 0.5) * shadow.Sharpness + 0.5); + result = lerp(1.0f, result, shadow.Fade); - return result; + return result; } // Samples the shadow for the given point light (PCF shadow map sampling) for the material surface (supports subsurface shadowing) float SampleShadow(LightData light, LightShadowData shadow, TextureCube shadowMap, GBufferSample gBuffer, out float subsurfaceShadow) { - subsurfaceShadow = 1; - float3 toLight = light.Position - gBuffer.WorldPos; - float toLightLength = length(toLight); - float3 L = toLight / toLightLength; + subsurfaceShadow = 1; + float3 toLight = light.Position - gBuffer.WorldPos; + float toLightLength = length(toLight); + float3 L = toLight / toLightLength; - // Skip pixels outside of the light influence - BRANCH - if (toLightLength > light.Radius) - { - return 1; - } + // Skip pixels outside of the light influence + BRANCH + if (toLightLength > light.Radius) + { + return 1; + } - // Negate direction and use normalized value - toLight = -L; + // Negate direction and use normalized value + toLight = -L; - // Figure out which cube face we're sampling from - int cubeFaceIndex = GetCubeFaceIndex(toLight); + // Figure out which cube face we're sampling from + int cubeFaceIndex = GetCubeFaceIndex(toLight); #if defined(USE_GBUFFER_CUSTOM_DATA) // Subsurface shadowing @@ -688,19 +688,19 @@ float SampleShadow(LightData light, LightShadowData shadow, TextureCube s #endif // Skip if surface is in a full shadow - float NoL = dot(gBuffer.Normal, L); - BRANCH - if (NoL <= 0) - { - return 0; - } + float NoL = dot(gBuffer.Normal, L); + BRANCH + if (NoL <= 0) + { + return 0; + } - // Apply normal offset bias - float3 samplePosWS = gBuffer.WorldPos; - samplePosWS += GetShadowPositionOffset(shadow.NormalOffsetScale, NoL, gBuffer.Normal); + // Apply normal offset bias + float3 samplePosWS = gBuffer.WorldPos; + samplePosWS += GetShadowPositionOffset(shadow.NormalOffsetScale, NoL, gBuffer.Normal); - // Sample shadow - return SampleShadow(light, shadow, shadowMap, samplePosWS); + // Sample shadow + return SampleShadow(light, shadow, shadowMap, samplePosWS); } #endif