diff --git a/Assets/BuiltIn/Shader/SSR/HLSL/LibSSR.hlsl b/Assets/BuiltIn/Shader/SSR/HLSL/LibSSR.hlsl new file mode 100644 index 000000000..fbaf8c7fd --- /dev/null +++ b/Assets/BuiltIn/Shader/SSR/HLSL/LibSSR.hlsl @@ -0,0 +1,80 @@ +#define LENGTH 20.0 + +float3 SSR(const float3 position, const float3 reflection, const float roughness) +{ + float4 projectedCoord; + + float3 beginPosition; + float3 endPosition; + + float3 rayPosition = position; + float4 viewPosition; + + float3 dir = reflection * LENGTH; + + float mipLevel = roughness * 7.0; + + // base color + // convert 3d position to 2d texture coord + viewPosition = mul(float4(position, 1.0), uView); + projectedCoord = mul(float4(viewPosition.xyz, 1.0), uProjection); + projectedCoord.xy = projectedCoord.xy / projectedCoord.w; + projectedCoord.xy = float2(0.5, -0.5) * projectedCoord.xy + float2(0.5, 0.5); + + // default reflect color is from position + float3 baseColor = uTexLastFrame.SampleLevel(uTexLastFrameSampler, projectedCoord.xy, mipLevel).rgb; + + // ray test + for (int i = 6; i >= 0; --i) + { + // begin ray + beginPosition = rayPosition; + + // end ray + endPosition = rayPosition + dir; + + // mid ray + rayPosition += dir * 0.5; + + // convert 3d position to 2d texture coord + viewPosition = mul(float4(rayPosition, 1.0), uView); + projectedCoord = mul(float4(viewPosition.xyz, 1.0), uProjection); + projectedCoord.xy = projectedCoord.xy / projectedCoord.w; + projectedCoord.xy = float2(0.5, -0.5) * projectedCoord.xy + float2(0.5, 0.5); + + float3 testPosition = uTexPosition.Sample(uTexPositionSampler, projectedCoord.xy).xyz; + + float3 d1 = testPosition - beginPosition; + float lengthSQ1 = d1.x*d1.x + d1.y*d1.y + d1.z*d1.z; + + float3 d2 = testPosition - endPosition; + float lengthSQ2 = d2.x*d2.x + d2.y*d2.y + d2.z*d2.z; + + // beginPosition is nearer + if (lengthSQ1 < lengthSQ2) + { + rayPosition = beginPosition; + } + + // binary search test + dir *= 0.5; + } + + float z = mul(float4(reflection, 0.0), uView).z; + z = clamp(z, 0.0, 1.0); + + // convert 3d position to 2d texture coord + viewPosition = mul(float4(rayPosition, 1.0), uView); + projectedCoord = mul(float4(viewPosition.xyz, 1.0), uProjection); + projectedCoord.xy = projectedCoord.xy / projectedCoord.w; + projectedCoord.xy = float2(0.5, -0.5) * projectedCoord.xy + float2(0.5, 0.5); + + // default reflect color is from position + float3 color = uTexLastFrame.SampleLevel(uTexLastFrameSampler, projectedCoord.xy, mipLevel).rgb; + + // edge factor + float2 dCoords = smoothstep(float2(0.0, 0.0), float2(0.5, 0.5), abs(float2(0.5, 0.5) - projectedCoord.xy)); + float screenEdgefactor = clamp(1.0 - (dCoords.x + dCoords.y), 0.0, 1.0); + + return lerp(baseColor * 0.7, color, screenEdgefactor * z); +} \ No newline at end of file diff --git a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/LibSG.hlsl b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/LibSG.hlsl index e5beb5fec..3c053b53e 100644 --- a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/LibSG.hlsl +++ b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/LibSG.hlsl @@ -1,12 +1,16 @@ static const float PI = 3.1415926; #include "LibSolverMetallic.hlsl" +#if defined(ENABLE_SSR) +#include "../../../SSR/HLSL/LibSSR.hlsl" +#endif #include "../../../PostProcessing/HLSL/LibToneMapping.hlsl" float3 SG( const float3 baseColor, const float spec, const float gloss, + const float3 position, const float3 worldViewDir, const float3 worldLightDir, const float3 worldNormal, @@ -55,7 +59,10 @@ float3 SG( color += indirectColor * diffuseColor * indirectMultiplier / PI; // IBL reflection - // ... +#if defined(ENABLE_SSR) + float3 reflection = -normalize(reflect(worldViewDir, worldNormal)); + color = color + sRGB(SSR(position, reflection, roughness)) * metallic * specularColor; +#endif return color; } \ No newline at end of file diff --git a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightBakeFS.d.hlsl b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightBakeFS.d.hlsl index 9881e9493..35d7bb116 100644 --- a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightBakeFS.d.hlsl +++ b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightBakeFS.d.hlsl @@ -82,6 +82,7 @@ float4 main(PS_INPUT input) : SV_TARGET albedo, data.r, data.g, + position, viewDir, uLightDirection.xyz, normal, diff --git a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightBakeFS.hlsl b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightBakeFS.hlsl index 67e293298..b2dec2635 100644 --- a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightBakeFS.hlsl +++ b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightBakeFS.hlsl @@ -92,6 +92,7 @@ float3 SG( const float3 baseColor, const float spec, const float gloss, + const float3 position, const float3 worldViewDir, const float3 worldLightDir, const float3 worldNormal, @@ -160,6 +161,7 @@ float4 main(PS_INPUT input) : SV_TARGET albedo, data.r, data.g, + position, viewDir, uLightDirection.xyz, normal, diff --git a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightFS.d.hlsl b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightFS.d.hlsl index a623afb58..a7e9788fd 100644 --- a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightFS.d.hlsl +++ b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightFS.d.hlsl @@ -36,8 +36,12 @@ cbuffer cbPerFrame float3 uLightMultiplier; float3 uShadowDistance; float4x4 uShadowMatrix[3]; + float4x4 uProjection; + float4x4 uView; }; +#define ENABLE_SSR + #include "LibShadow.hlsl" #include "LibSG.hlsl" @@ -72,6 +76,7 @@ float4 main(PS_INPUT input) : SV_TARGET albedo, data.r, data.g, + position, viewDir, uLightDirection.xyz, normal, diff --git a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightFS.hlsl b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightFS.hlsl index bd158e596..714278044 100644 --- a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightFS.hlsl +++ b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/HLSL/SGDirectionalLightFS.hlsl @@ -28,6 +28,8 @@ cbuffer cbPerFrame float3 uLightMultiplier; float3 uShadowDistance; float4x4 uShadowMatrix[3]; + float4x4 uProjection; + float4x4 uView; }; float texture2DCompare(float3 uv, float compare) { float depth = uShadowMap.SampleLevel(uShadowMapSampler, uv, 0).r; @@ -80,6 +82,51 @@ float solveMetallic(float3 diffuse, float3 specular, float oneMinusSpecularStren float D = b * b - 4.0 * a * c; return clamp((-b + sqrt(D)) / (2.0 * a), 0.0, 1.0); } +float3 SSR(const float3 position, const float3 reflection, const float roughness) +{ + float4 projectedCoord; + float3 beginPosition; + float3 endPosition; + float3 rayPosition = position; + float4 viewPosition; + float3 dir = reflection * 20.0; + float mipLevel = roughness * 7.0; + viewPosition = mul(float4(position, 1.0), uView); + projectedCoord = mul(float4(viewPosition.xyz, 1.0), uProjection); + projectedCoord.xy = projectedCoord.xy / projectedCoord.w; + projectedCoord.xy = float2(0.5, -0.5) * projectedCoord.xy + float2(0.5, 0.5); + float3 baseColor = uTexLastFrame.SampleLevel(uTexLastFrameSampler, projectedCoord.xy, mipLevel).rgb; + for (int i = 6; i >= 0; --i) + { + beginPosition = rayPosition; + endPosition = rayPosition + dir; + rayPosition += dir * 0.5; + viewPosition = mul(float4(rayPosition, 1.0), uView); + projectedCoord = mul(float4(viewPosition.xyz, 1.0), uProjection); + projectedCoord.xy = projectedCoord.xy / projectedCoord.w; + projectedCoord.xy = float2(0.5, -0.5) * projectedCoord.xy + float2(0.5, 0.5); + float3 testPosition = uTexPosition.Sample(uTexPositionSampler, projectedCoord.xy).xyz; + float3 d1 = testPosition - beginPosition; + float lengthSQ1 = d1.x*d1.x + d1.y*d1.y + d1.z*d1.z; + float3 d2 = testPosition - endPosition; + float lengthSQ2 = d2.x*d2.x + d2.y*d2.y + d2.z*d2.z; + if (lengthSQ1 < lengthSQ2) + { + rayPosition = beginPosition; + } + dir *= 0.5; + } + float z = mul(float4(reflection, 0.0), uView).z; + z = clamp(z, 0.0, 1.0); + viewPosition = mul(float4(rayPosition, 1.0), uView); + projectedCoord = mul(float4(viewPosition.xyz, 1.0), uProjection); + projectedCoord.xy = projectedCoord.xy / projectedCoord.w; + projectedCoord.xy = float2(0.5, -0.5) * projectedCoord.xy + float2(0.5, 0.5); + float3 color = uTexLastFrame.SampleLevel(uTexLastFrameSampler, projectedCoord.xy, mipLevel).rgb; + float2 dCoords = smoothstep(float2(0.0, 0.0), float2(0.5, 0.5), abs(float2(0.5, 0.5) - projectedCoord.xy)); + float screenEdgefactor = clamp(1.0 - (dCoords.x + dCoords.y), 0.0, 1.0); + return lerp(baseColor * 0.7, color, screenEdgefactor * z); +} static const float gamma = 2.2; static const float invGamma = 1.0 / 2.2; float3 sRGB(float3 color) @@ -94,6 +141,7 @@ float3 SG( const float3 baseColor, const float spec, const float gloss, + const float3 position, const float3 worldViewDir, const float3 worldLightDir, const float3 worldNormal, @@ -126,6 +174,8 @@ float3 SG( float3 directionalLight = NdotL * directionLightColor * visibility; float3 color = (directionalLight * directMultiplier + pointLightColor * lightMultiplier) * diffuseColor + specular * specularColor * visibility + light.a * specularColor; color += indirectColor * diffuseColor * indirectMultiplier / PI; + float3 reflection = -normalize(reflect(worldViewDir, worldNormal)); + color = color + sRGB(SSR(position, reflection, roughness)) * metallic * specularColor; return color; } float4 main(PS_INPUT input) : SV_TARGET @@ -152,6 +202,7 @@ float4 main(PS_INPUT input) : SV_TARGET albedo, data.r, data.g, + position, viewDir, uLightDirection.xyz, normal, diff --git a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/SGDirectionalLight.xml b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/SGDirectionalLight.xml index 13278d746..656270c9f 100644 --- a/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/SGDirectionalLight.xml +++ b/Assets/BuiltIn/Shader/SpecularGlossiness/Lighting/SGDirectionalLight.xml @@ -19,6 +19,8 @@ + + diff --git a/Projects/Skylicht/Engine/Source/Material/Shader/CShader.cpp b/Projects/Skylicht/Engine/Source/Material/Shader/CShader.cpp index d704391f0..3c8054d30 100644 --- a/Projects/Skylicht/Engine/Source/Material/Shader/CShader.cpp +++ b/Projects/Skylicht/Engine/Source/Material/Shader/CShader.cpp @@ -33,6 +33,7 @@ This file is part of the "Skylicht Engine". #include "ShaderCallback/CShaderShadow.h" #include "ShaderCallback/CShaderSH.h" #include "ShaderCallback/CShaderParticle.h" +#include "ShaderCallback/CShaderDeferred.h" namespace Skylicht { @@ -50,6 +51,7 @@ namespace Skylicht addCallback(); addCallback(); addCallback(); + addCallback(); } CShader::~CShader() @@ -1052,21 +1054,13 @@ namespace Skylicht { } break; - case DEFERRED_VIEW: - { - } - break; - case DEFERRED_PROJECTION: - { - } - break; + */ case CUSTOM_VALUE: { // todo // set params in callback } break; - */ default: return false; } diff --git a/Projects/Skylicht/Engine/Source/Material/Shader/ShaderCallback/CShaderDeferred.cpp b/Projects/Skylicht/Engine/Source/Material/Shader/ShaderCallback/CShaderDeferred.cpp new file mode 100644 index 000000000..6dec3d11b --- /dev/null +++ b/Projects/Skylicht/Engine/Source/Material/Shader/ShaderCallback/CShaderDeferred.cpp @@ -0,0 +1,67 @@ +/* +!@ +MIT License + +Copyright (c) 2020 Skylicht Technology CO., LTD + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +This file is part of the "Skylicht Engine". +https://github.com/skylicht-lab/skylicht-engine +!# +*/ + +#include "pch.h" +#include "CShaderDeferred.h" + +namespace Skylicht +{ + core::matrix4 CShaderDeferred::s_projection; + core::matrix4 CShaderDeferred::s_view; + + CShaderDeferred::CShaderDeferred() + { + + } + + CShaderDeferred::~CShaderDeferred() + { + + } + + void CShaderDeferred::OnSetConstants(CShader *shader, SUniform *uniform, IMaterialRenderer* matRender, bool vertexShader) + { + switch (uniform->Type) + { + case DEFERRED_VIEW: + { + if (vertexShader == true) + matRender->setShaderVariable(uniform->UniformShaderID, s_view.pointer(), uniform->SizeOfUniform, video::EST_VERTEX_SHADER); + else + matRender->setShaderVariable(uniform->UniformShaderID, s_view.pointer(), uniform->SizeOfUniform, video::EST_PIXEL_SHADER); + } + break; + case DEFERRED_PROJECTION: + { + if (vertexShader == true) + matRender->setShaderVariable(uniform->UniformShaderID, s_projection.pointer(), uniform->SizeOfUniform, video::EST_VERTEX_SHADER); + else + matRender->setShaderVariable(uniform->UniformShaderID, s_projection.pointer(), uniform->SizeOfUniform, video::EST_PIXEL_SHADER); + } + break; + default: + break; + } + } +} \ No newline at end of file diff --git a/Projects/Skylicht/Engine/Source/Material/Shader/ShaderCallback/CShaderDeferred.h b/Projects/Skylicht/Engine/Source/Material/Shader/ShaderCallback/CShaderDeferred.h new file mode 100644 index 000000000..0a62093c6 --- /dev/null +++ b/Projects/Skylicht/Engine/Source/Material/Shader/ShaderCallback/CShaderDeferred.h @@ -0,0 +1,55 @@ +/* +!@ +MIT License + +Copyright (c) 2020 Skylicht Technology CO., LTD + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +This file is part of the "Skylicht Engine". +https://github.com/skylicht-lab/skylicht-engine +!# +*/ + +#pragma once + +#include "Material/Shader/CShader.h" + +namespace Skylicht +{ + class CShaderDeferred : public IShaderCallback + { + protected: + static core::matrix4 s_projection; + static core::matrix4 s_view; + + public: + CShaderDeferred(); + + virtual ~CShaderDeferred(); + + virtual void OnSetConstants(CShader *shader, SUniform *uniform, IMaterialRenderer* matRender, bool vertexShader); + + public: + static void setProjection(const core::matrix4& mat) + { + s_projection = mat; + } + + static void setView(const core::matrix4& mat) + { + s_view = mat; + } + }; +} \ No newline at end of file diff --git a/Projects/Skylicht/Engine/Source/RenderPipeline/CDeferredRP.cpp b/Projects/Skylicht/Engine/Source/RenderPipeline/CDeferredRP.cpp index e14674a41..1d0cc9e1a 100644 --- a/Projects/Skylicht/Engine/Source/RenderPipeline/CDeferredRP.cpp +++ b/Projects/Skylicht/Engine/Source/RenderPipeline/CDeferredRP.cpp @@ -30,6 +30,7 @@ This file is part of the "Skylicht Engine". #include "Material/Shader/CShaderManager.h" #include "Material/Shader/ShaderCallback/CShaderShadow.h" #include "Material/Shader/ShaderCallback/CShaderLighting.h" +#include "Material/Shader/ShaderCallback/CShaderDeferred.h" #include "Lighting/CLightCullingSystem.h" #include "Lighting/CPointLight.h" #include "IndirectLighting/CIndirectLightingData.h" @@ -338,6 +339,10 @@ namespace Skylicht entityManager->setCamera(camera); entityManager->setRenderPipeline(this); + // save projection/view for advance shader SSR + CShaderDeferred::setProjection(driver->getTransform(video::ETS_PROJECTION)); + CShaderDeferred::setView(m_viewMatrix = driver->getTransform(video::ETS_VIEW)); + // STEP 01: // draw baked indirect lighting m_isIndirectPass = true; @@ -465,7 +470,11 @@ namespace Skylicht // ssr (last frame) if (m_postProcessor != NULL) + { m_directionalLightPass.TextureLayer[7].Texture = m_postProcessor->getLastFrameBuffer(); + m_directionalLightPass.TextureLayer[7].TextureWrapU = ETC_CLAMP_TO_BORDER; + m_directionalLightPass.TextureLayer[7].TextureWrapV = ETC_CLAMP_TO_BORDER; + } beginRender2D(renderW, renderH); diff --git a/Projects/Skylicht/Engine/Source/RenderPipeline/CPostProcessorRP.cpp b/Projects/Skylicht/Engine/Source/RenderPipeline/CPostProcessorRP.cpp index 7af8a6737..b93f9d801 100644 --- a/Projects/Skylicht/Engine/Source/RenderPipeline/CPostProcessorRP.cpp +++ b/Projects/Skylicht/Engine/Source/RenderPipeline/CPostProcessorRP.cpp @@ -106,7 +106,12 @@ namespace Skylicht } if (m_screenSpaceReflection) + { m_lastFrameBuffer = driver->addRenderTargetTexture(m_size, "last_frame", ECF_A8R8G8B8); + + driver->setRenderTarget(m_lastFrameBuffer, true, false); + driver->setRenderTarget(NULL); + } else m_lastFrameBuffer = NULL; } diff --git a/Samples/Sponza/Source/CViewInit.cpp b/Samples/Sponza/Source/CViewInit.cpp index 1ffbe1618..83eac5101 100644 --- a/Samples/Sponza/Source/CViewInit.cpp +++ b/Samples/Sponza/Source/CViewInit.cpp @@ -231,7 +231,7 @@ void CViewInit::initProbes() probes.push_back(probe); } - CLightProbeRender::showProbe(true); + CLightProbeRender::showProbe(false); context->setProbes(probes); }