From 0eaa93056d8f6aa6aa36b78cbc1cf66910917290 Mon Sep 17 00:00:00 2001 From: Mykhailo Moroz Date: Sat, 23 Apr 2022 04:43:33 +0300 Subject: [PATCH 1/2] Refraction, Absorption and fresnel --- D3D12Backend/Camera.cpp | 3 +- D3D12Backend/Shaders/CppShared.hlsli | 4 +- .../Shaders/LightingLibrary/Lighting.hlsli | 5 + .../Shaders/RaytracePass/RaytracePassLib.hlsl | 107 +++++++++++++----- .../SkyBoxPass/SkyBoxPassPixelShader.hlsl | 3 +- 5 files changed, 90 insertions(+), 32 deletions(-) diff --git a/D3D12Backend/Camera.cpp b/D3D12Backend/Camera.cpp index ee3f4d7..f5cf391 100644 --- a/D3D12Backend/Camera.cpp +++ b/D3D12Backend/Camera.cpp @@ -70,7 +70,8 @@ namespace Boolka void Camera::UpdateInput(float deltaTime, const Vector4& right, const Vector4& up, const Vector4& forward) { - static const float defaultMoveSpeed = 15.0f; + //TODO move into separate confing maybe? + static const float defaultMoveSpeed = 35.0f; const float defaultRotationSpeed = m_FieldOfView * 2.0f; float speedMult = 1.0f; diff --git a/D3D12Backend/Shaders/CppShared.hlsli b/D3D12Backend/Shaders/CppShared.hlsli index 579f3e1..6bd723c 100644 --- a/D3D12Backend/Shaders/CppShared.hlsli +++ b/D3D12Backend/Shaders/CppShared.hlsli @@ -32,7 +32,7 @@ struct AABB #define BLK_MAX_OBJECT_COUNT 2048 #define BLK_MAX_MESHLETS 262144 -#define BLK_RT_MAX_RECURSION_DEPTH 4 +#define BLK_RT_MAX_RECURSION_DEPTH 6 struct FrameConstantBuffer { @@ -109,6 +109,8 @@ struct RaytracePayload float3 light; uint recursionDepth; float3 color; + float previousIOR; + float3 previousPos; uint unused; RayDifferential rayDifferential; }; diff --git a/D3D12Backend/Shaders/LightingLibrary/Lighting.hlsli b/D3D12Backend/Shaders/LightingLibrary/Lighting.hlsli index 27577af..e5ec8e8 100644 --- a/D3D12Backend/Shaders/LightingLibrary/Lighting.hlsli +++ b/D3D12Backend/Shaders/LightingLibrary/Lighting.hlsli @@ -8,6 +8,11 @@ ConstantBuffer LightingData : register(b1); static const float ambientLight = 0.1f; +float3 Fresnel(float3 view, float3 normal, float3 F0) +{ + return F0 + (1.0 - F0)*pow(1.0 - max(dot(-view,normal), 0.0), 5.0); +} + float3 CalculateAmbient(MaterialData matData, float3 albedoVal) { return albedoVal * ambientLight * matData.diffuse * matData.transparency; diff --git a/D3D12Backend/Shaders/RaytracePass/RaytracePassLib.hlsl b/D3D12Backend/Shaders/RaytracePass/RaytracePassLib.hlsl index 3acd333..19eb62d 100644 --- a/D3D12Backend/Shaders/RaytracePass/RaytracePassLib.hlsl +++ b/D3D12Backend/Shaders/RaytracePass/RaytracePassLib.hlsl @@ -6,9 +6,9 @@ // Configure whether we are going to do additional depth samples to select one of two neighbours along each axis #define BLK_HIGH_QUALITY_RAY_DIFFERENTIALS 1 -#define BLK_REFLECTION_TMIN 0.01f +#define BLK_REFLECTION_TMIN 0.5f #define BLK_REFLECTION_TMAX 10000.0f -#define BLK_REFRACTION_TMIN 0.001f +#define BLK_REFRACTION_TMIN 0.5f #define BLK_REFRACTION_TMAX 10000.0f bool IsPerfectMirror(in const MaterialData matData) @@ -138,10 +138,11 @@ RayDifferential CalculateRefractionRayDifferentialsGB(in const GBufferData gbuff return Out; } +//TODO Unify Refraction and Reflection ray calculation, they share similar computations. inline void CalculateReflectionRayGB(in const GBufferData gbufferData, in const MaterialData matData, out float3 origin, - out float3 direction, - out RayDifferential rayDifferential) + out float3 direction, out float3 attenuation, + out RayDifferential rayDifferential) { uint2 vpos = DispatchRaysIndex().xy; float2 UV = vpos * Frame.invBackBufferResolution; @@ -153,6 +154,9 @@ inline void CalculateReflectionRayGB(in const GBufferData gbufferData, float3 worldSpaceNormal = CalculateWorldSpaceNormal(gbufferData.normal); float3 reflectionVector = reflect(cameraDirectionWorld, worldSpaceNormal); + float3 fresnel = Fresnel(cameraDirectionWorld, worldSpaceNormal, matData.specular); + + attenuation = fresnel; origin = worldPos; direction = reflectionVector; @@ -177,14 +181,21 @@ float3 GetCameraRay() inline void CalculateRefractionRayGB(in const GBufferData gbufferData, in const MaterialData matData, out float3 origin, - out float3 direction, out RayDifferential rayDifferential) + out float3 direction, out float3 attenuation, + out RayDifferential rayDifferential) { uint2 vpos = DispatchRaysIndex().xy; float2 UV = vpos * Frame.invBackBufferResolution; float3 viewPos = CalculateViewPos(UV, gbufferData.depth); float3 worldPos = CalculateWorldPos(viewPos); + float3 worldSpaceNormal = CalculateWorldSpaceNormal(gbufferData.normal); + + float3 fresnel = Fresnel(GetCameraRay(), worldSpaceNormal, matData.specular); + + attenuation = (1.0 - fresnel); + origin = worldPos; - direction = GetCameraRay(); + direction = refract(GetCameraRay(), worldSpaceNormal, 1.0/matData.indexOfRefraction); rayDifferential = CalculateRefractionRayDifferentialsGB(gbufferData, origin, direction); return; @@ -195,9 +206,10 @@ void ReflectionRayGeneration(in const GBufferData gbufferData, { float3 origin; float3 direction; + float3 attenuation; RayDifferential rayDifferential = (RayDifferential)0; - CalculateReflectionRayGB(gbufferData, matData, origin, direction, rayDifferential); + CalculateReflectionRayGB(gbufferData, matData, origin, direction, attenuation, rayDifferential); RayDesc ray; ray.Origin = origin; @@ -205,11 +217,11 @@ void ReflectionRayGeneration(in const GBufferData gbufferData, ray.TMin = BLK_REFLECTION_TMIN; ray.TMax = BLK_REFLECTION_TMAX; - RaytracePayload payload = {float3(0, 0, 0), 0, float3(1, 1, 1), 0, rayDifferential}; - payload.color = matData.transparency; + RaytracePayload payload = {float3(0, 0, 0), 0, float3(1, 1, 1), matData.indexOfRefraction, ray.Origin, 0, rayDifferential}; + payload.color = attenuation; TraceRay(sceneAS, RAY_FLAG_NONE, 1, 0, 0, 0, ray, payload); - light += payload.light; + light += payload.light*payload.color; } // No real support for refraction yet @@ -221,9 +233,10 @@ void RefractionRayGeneration(in const GBufferData gbufferData, in const Material { float3 origin; float3 direction; + float3 attenuation; RayDifferential rayDifferential = (RayDifferential)0; - CalculateRefractionRayGB(gbufferData, matData, origin, direction, rayDifferential); + CalculateRefractionRayGB(gbufferData, matData, origin, direction, attenuation, rayDifferential); RayDesc ray; ray.Origin = origin; @@ -231,11 +244,11 @@ void RefractionRayGeneration(in const GBufferData gbufferData, in const Material ray.TMin = BLK_REFRACTION_TMIN; ray.TMax = BLK_REFRACTION_TMAX; - RaytracePayload payload = {float3(0, 0, 0), 0, float3(1, 1, 1), 0, rayDifferential}; - payload.color = (1.0f - matData.transparency) * matData.specular; + RaytracePayload payload = {float3(0, 0, 0), 0, float3(1, 1, 1), 1.0/matData.indexOfRefraction, ray.Origin, 0, rayDifferential}; + payload.color = attenuation; - TraceRay(sceneAS, RAY_FLAG_CULL_BACK_FACING_TRIANGLES, 1, 0, 0, 0, ray, payload); - light += payload.light; + TraceRay(sceneAS, RAY_FLAG_NONE, 1, 0, 0, 0, ray, payload); + light += payload.light*payload.color; } [shader("raygeneration")] @@ -420,6 +433,14 @@ void ClosestHit(inout RaytracePayload payload, in BuiltInTriangleIntersectionAtt float3 viewPos = mul(float4(worldPos, 1.0f), Frame.viewMatrix).xyz; float3 viewDir = mul(float4(WorldRayDirection(), 0.0f), Frame.viewMatrix).xyz; + if(payload.previousIOR < 1.0)//meaning ray is moving inside + { + //TODO add this to material + float depth = distance(worldPos, payload.previousPos)/10.0; + //absorption + payload.color *= exp(-depth * (1.0 - float3(0.1, 0.3, 0.9))); + } + MaterialData matData = materialsData[materialID]; payload.light += CalculateLighting(matData, albedoVal, albedoVal, normalVal, viewPos, viewDir) * payload.color; @@ -429,24 +450,51 @@ void ClosestHit(inout RaytracePayload payload, in BuiltInTriangleIntersectionAtt float3 originaldDdy = payload.rayDifferential.dy.dD; uint originalRecursionDepth = payload.recursionDepth; + + if (payload.recursionDepth < BLK_RT_MAX_RECURSION_DEPTH - 1) { + float3 rayDir = WorldRayDirection(); + float3 normal = normalize(interpolatedVertex.normal); + + bool isUnderwater = dot(normal, rayDir) > 0.0; + // Refraction - if (IsTransparent(matData)) - { - payload.recursionDepth = originalRecursionDepth + 1; - payload.color = originalColor * (1.0f - matData.transparency); + + payload.recursionDepth = originalRecursionDepth + 1; + payload.previousPos = worldPos; - RayDesc ray; - ray.Origin = worldPos; - ray.Direction = WorldRayDirection(); - ray.TMin = BLK_REFLECTION_TMIN; - ray.TMax = BLK_REFLECTION_TMAX; + RayDesc ray; + ray.Origin = worldPos; - TraceRay(sceneAS, RAY_FLAG_CULL_BACK_FACING_TRIANGLES, 1, 0, 0, 0, ray, payload); + if(isUnderwater) + { + float3 fresnel = Fresnel(rayDir, -normal, matData.specular); + payload.color = originalColor;// *fresnel; + payload.previousIOR = matData.indexOfRefraction; + ray.Direction = refract(rayDir, -normal, matData.indexOfRefraction); + if(length(ray.Direction) < 0.5) //full internal reflection + { + payload.previousIOR = 1.0/matData.indexOfRefraction; + ray.Direction = reflect(rayDir, -normal); + payload.color = originalColor; + } } + else + { + float3 fresnel = Fresnel(rayDir, normal, matData.specular); + payload.color = originalColor;// * fresnel; + payload.previousIOR = 1.0/matData.indexOfRefraction; + ray.Direction = refract(rayDir, normal, 1.0/matData.indexOfRefraction); + } + + ray.TMin = BLK_REFRACTION_TMIN; + ray.TMax = BLK_REFRACTION_TMAX; - // Reflection + TraceRay(sceneAS, RAY_FLAG_NONE, 1, 0, 0, 0, ray, payload); + + //TODO figure out this for all cases + /*// Reflection if (IsPerfectMirror(matData)) { payload.recursionDepth = originalRecursionDepth + 1; @@ -461,8 +509,8 @@ void ClosestHit(inout RaytracePayload payload, in BuiltInTriangleIntersectionAtt ray.TMin = BLK_REFRACTION_TMIN; ray.TMax = BLK_REFRACTION_TMAX; - TraceRay(sceneAS, RAY_FLAG_CULL_BACK_FACING_TRIANGLES, 1, 0, 0, 0, ray, payload); - } + TraceRay(sceneAS, RAY_FLAG_NONE, 1, 0, 0, 0, ray, payload); + }*/ } } @@ -470,5 +518,6 @@ void ClosestHit(inout RaytracePayload payload, in BuiltInTriangleIntersectionAtt void MissShader(inout RaytracePayload payload) { float3 skyboxVal = skyBox.SampleLevel(anisoSampler, WorldRayDirection(), 0).xyz; - payload.light += skyboxVal; + //TODO Implement post process shader with exposure + payload.light += 3.0*skyboxVal; } diff --git a/D3D12Backend/Shaders/SkyBoxPass/SkyBoxPassPixelShader.hlsl b/D3D12Backend/Shaders/SkyBoxPass/SkyBoxPassPixelShader.hlsl index c8c4653..1c48c78 100644 --- a/D3D12Backend/Shaders/SkyBoxPass/SkyBoxPassPixelShader.hlsl +++ b/D3D12Backend/Shaders/SkyBoxPass/SkyBoxPassPixelShader.hlsl @@ -13,6 +13,7 @@ PSOut main(VSOut In) float2 UV = In.texcoord; float3 viewPos = CalculateViewPos(UV, 1.0f); float3 viewDirWorld = mul(float4(viewPos, 0.0f), Frame.invViewMatrix).xyz; - Out.color = skyBox.Sample(anisoSampler, viewDirWorld); + //TODO Implement post process shader with exposure + Out.color = 3.0*skyBox.Sample(anisoSampler, viewDirWorld); return Out; } From c57181f81824a7163dccc1c59627580d2fa2a2ae Mon Sep 17 00:00:00 2001 From: Mykhailo Moroz Date: Sat, 23 Apr 2022 05:53:10 +0300 Subject: [PATCH 2/2] Fix namig and the way light is computed --- D3D12Backend/Shaders/CppShared.hlsli | 4 +- .../Shaders/RaytracePass/RaytracePassLib.hlsl | 54 ++++++++++--------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/D3D12Backend/Shaders/CppShared.hlsli b/D3D12Backend/Shaders/CppShared.hlsli index 6bd723c..277e7a2 100644 --- a/D3D12Backend/Shaders/CppShared.hlsli +++ b/D3D12Backend/Shaders/CppShared.hlsli @@ -32,7 +32,7 @@ struct AABB #define BLK_MAX_OBJECT_COUNT 2048 #define BLK_MAX_MESHLETS 262144 -#define BLK_RT_MAX_RECURSION_DEPTH 6 +#define BLK_RT_MAX_RECURSION_DEPTH 4 struct FrameConstantBuffer { @@ -108,7 +108,7 @@ struct RaytracePayload { float3 light; uint recursionDepth; - float3 color; + float3 attenuation; float previousIOR; float3 previousPos; uint unused; diff --git a/D3D12Backend/Shaders/RaytracePass/RaytracePassLib.hlsl b/D3D12Backend/Shaders/RaytracePass/RaytracePassLib.hlsl index 19eb62d..8a00a0a 100644 --- a/D3D12Backend/Shaders/RaytracePass/RaytracePassLib.hlsl +++ b/D3D12Backend/Shaders/RaytracePass/RaytracePassLib.hlsl @@ -218,10 +218,10 @@ void ReflectionRayGeneration(in const GBufferData gbufferData, ray.TMax = BLK_REFLECTION_TMAX; RaytracePayload payload = {float3(0, 0, 0), 0, float3(1, 1, 1), matData.indexOfRefraction, ray.Origin, 0, rayDifferential}; - payload.color = attenuation; + payload.attenuation = attenuation; TraceRay(sceneAS, RAY_FLAG_NONE, 1, 0, 0, 0, ray, payload); - light += payload.light*payload.color; + light += payload.light; } // No real support for refraction yet @@ -245,10 +245,10 @@ void RefractionRayGeneration(in const GBufferData gbufferData, in const Material ray.TMax = BLK_REFRACTION_TMAX; RaytracePayload payload = {float3(0, 0, 0), 0, float3(1, 1, 1), 1.0/matData.indexOfRefraction, ray.Origin, 0, rayDifferential}; - payload.color = attenuation; + payload.attenuation = attenuation; TraceRay(sceneAS, RAY_FLAG_NONE, 1, 0, 0, 0, ray, payload); - light += payload.light*payload.color; + light += payload.light; } [shader("raygeneration")] @@ -424,34 +424,31 @@ void ClosestHit(inout RaytracePayload payload, in BuiltInTriangleIntersectionAtt float2 ddxRes, ddyRes; float3 dndx, dndy; CalculateRTHit(attr, payload.rayDifferential, interpolatedVertex, ddxRes, - ddyRes, dndx, dndy); + ddyRes, dndx, dndy); const float3 worldPos = interpolatedVertex.position; - + float3 albedoVal = SRGBToLinear(sceneTextures[materialID].SampleGrad(anisoSampler, interpolatedVertex.UV, ddxRes, ddyRes).rgb); float3 normalVal = normalize(mul(normalize(interpolatedVertex.normal), (float3x3)Frame.viewMatrix)); float3 viewPos = mul(float4(worldPos, 1.0f), Frame.viewMatrix).xyz; float3 viewDir = mul(float4(WorldRayDirection(), 0.0f), Frame.viewMatrix).xyz; - if(payload.previousIOR < 1.0)//meaning ray is moving inside + if (payload.previousIOR < 1.0)//meaning ray is moving inside { //TODO add this to material - float depth = distance(worldPos, payload.previousPos)/10.0; + float depth = distance(worldPos, payload.previousPos) / 10.0; //absorption - payload.color *= exp(-depth * (1.0 - float3(0.1, 0.3, 0.9))); + payload.attenuation *= exp(-depth * (1.0 - float3(0.1, 0.3, 0.9))); } MaterialData matData = materialsData[materialID]; - payload.light += CalculateLighting(matData, albedoVal, albedoVal, normalVal, viewPos, viewDir) * - payload.color; + payload.light += CalculateLighting(matData, albedoVal, albedoVal, normalVal, viewPos, viewDir) * payload.attenuation; - float3 originalColor = payload.color; + float3 originaldDdx = payload.rayDifferential.dx.dD; float3 originaldDdy = payload.rayDifferential.dy.dD; uint originalRecursionDepth = payload.recursionDepth; - - if (payload.recursionDepth < BLK_RT_MAX_RECURSION_DEPTH - 1) { float3 rayDir = WorldRayDirection(); @@ -460,45 +457,45 @@ void ClosestHit(inout RaytracePayload payload, in BuiltInTriangleIntersectionAtt bool isUnderwater = dot(normal, rayDir) > 0.0; // Refraction - + payload.recursionDepth = originalRecursionDepth + 1; payload.previousPos = worldPos; RayDesc ray; ray.Origin = worldPos; - if(isUnderwater) + if (isUnderwater) { float3 fresnel = Fresnel(rayDir, -normal, matData.specular); - payload.color = originalColor;// *fresnel; + payload.previousIOR = matData.indexOfRefraction; ray.Direction = refract(rayDir, -normal, matData.indexOfRefraction); - if(length(ray.Direction) < 0.5) //full internal reflection + if (length(ray.Direction) < 0.5) //full internal reflection { - payload.previousIOR = 1.0/matData.indexOfRefraction; + payload.previousIOR = 1.0 / matData.indexOfRefraction; ray.Direction = reflect(rayDir, -normal); - payload.color = originalColor; + } } else { float3 fresnel = Fresnel(rayDir, normal, matData.specular); - payload.color = originalColor;// * fresnel; - payload.previousIOR = 1.0/matData.indexOfRefraction; - ray.Direction = refract(rayDir, normal, 1.0/matData.indexOfRefraction); + + payload.previousIOR = 1.0 / matData.indexOfRefraction; + ray.Direction = refract(rayDir, normal, 1.0 / matData.indexOfRefraction); } ray.TMin = BLK_REFRACTION_TMIN; ray.TMax = BLK_REFRACTION_TMAX; TraceRay(sceneAS, RAY_FLAG_NONE, 1, 0, 0, 0, ray, payload); - + //TODO figure out this for all cases /*// Reflection if (IsPerfectMirror(matData)) { payload.recursionDepth = originalRecursionDepth + 1; - payload.color = originalColor * matData.transparency; + payload.attenuation = originalColor * matData.transparency; payload.rayDifferential.dx.dD = originaldDdx; payload.rayDifferential.dy.dD = originaldDdy; UpdateRayDifferentialsReflection(payload.rayDifferential, normalVal, dndx, dndy); @@ -512,6 +509,11 @@ void ClosestHit(inout RaytracePayload payload, in BuiltInTriangleIntersectionAtt TraceRay(sceneAS, RAY_FLAG_NONE, 1, 0, 0, 0, ray, payload); }*/ } + else + { + float3 skyboxVal = skyBox.SampleLevel(anisoSampler, WorldRayDirection(), 0).xyz; + payload.light += 3.0*skyboxVal*payload.attenuation; + } } [shader("miss")] @@ -519,5 +521,5 @@ void MissShader(inout RaytracePayload payload) { float3 skyboxVal = skyBox.SampleLevel(anisoSampler, WorldRayDirection(), 0).xyz; //TODO Implement post process shader with exposure - payload.light += 3.0*skyboxVal; + payload.light += 3.0*skyboxVal*payload.attenuation; }