verus/Verus/src/Shaders/DS.hlsl

255 lines
8.0 KiB
HLSL

// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
#include "Lib.hlsl"
#include "LibColor.hlsl"
#include "LibDeferredShading.hlsl"
#include "LibDepth.hlsl"
#include "LibLighting.hlsl"
#include "LibVertex.hlsl"
#include "DS.inc.hlsl"
CBUFFER(0, UB_PerFrame, g_ubPerFrame)
CBUFFER(1, UB_TexturesFS, g_ubTexturesFS)
CBUFFER(2, UB_PerMeshVS, g_ubPerMeshVS)
CBUFFER(3, UB_ShadowFS, g_ubShadowFS)
VK_PUSH_CONSTANT
CBUFFER(4, UB_PerObject, g_ubPerObject)
VK_SUBPASS_INPUT(0, g_texGBuffer0, g_samGBuffer0, 1, space1);
VK_SUBPASS_INPUT(1, g_texGBuffer1, g_samGBuffer1, 2, space1);
VK_SUBPASS_INPUT(2, g_texGBuffer2, g_samGBuffer2, 3, space1);
VK_SUBPASS_INPUT(3, g_texGBuffer3, g_samGBuffer3, 4, space1);
VK_SUBPASS_INPUT(4, g_texDepth, g_samDepth, 5, space1);
Texture2D g_texShadowCmp : REG(t6, space1, t5);
SamplerComparisonState g_samShadowCmp : REG(s6, space1, s5);
Texture2D g_texShadow : REG(t7, space1, t6);
SamplerState g_samShadow : REG(s7, space1, s6);
struct VSI
{
VK_LOCATION_POSITION int4 pos : POSITION;
VK_LOCATION_NORMAL float3 nrm : NORMAL;
VK_LOCATION(8) int2 tc0 : TEXCOORD0;
_PER_INSTANCE_DATA
};
struct VSO
{
float4 pos : SV_Position;
float4 clipSpacePos : TEXCOORD0;
#if defined(DEF_DIR) || defined(DEF_SPOT) // Direction and cone shape for spot.
float4 lightDirWV_invConeDelta : TEXCOORD1;
#endif
#if defined(DEF_OMNI) || defined(DEF_SPOT) // Omni and spot have position and radius.
float3 lightPosWV : TEXCOORD2;
float3 radius_radiusSq_invRadiusSq : TEXCOORD3;
#endif
float4 color_coneOut : TEXCOORD4;
};
#ifdef _VS
VSO mainVS(VSI si)
{
VSO so;
const float3 inPos = DequantizeUsingDeq3D(si.pos.xyz, g_ubPerMeshVS._posDeqScale.xyz, g_ubPerMeshVS._posDeqBias.xyz);
// <TheMatrix>
#ifdef DEF_INSTANCED
const mataff matW = GetInstMatrix(
si.matPart0,
si.matPart1,
si.matPart2);
const float3 color = si.instData.rgb;
const float coneIn = si.instData.a;
#else
const mataff matW = g_ubPerObject._matW;
const float3 color = g_ubPerObject._color.rgb;
const float coneIn = g_ubPerObject._color.a;
#endif
const matrix matWV = mul(ToFloat4x4(matW), ToFloat4x4(g_ubPerFrame._matV));
const float3x3 matWV33 = (float3x3)matWV;
// </TheMatrix>
#ifdef DEF_DIR // Fullscreen quad?
so.pos = float4(inPos, 1);
#else
const float3 posW = mul(float4(inPos, 1), matW);
so.pos = mul(float4(posW, 1), g_ubPerFrame._matVP);
#endif
so.clipSpacePos = so.pos;
// <MoreLightParams>
so.color_coneOut = float4(color, 0);
const float3 scaledFrontDir = mul(float3(0, 0, 1), matWV33);
#ifdef DEF_DIR
{
so.lightDirWV_invConeDelta = float4(scaledFrontDir, 1); // Assume not scaled.
}
#elif defined(DEF_SPOT)
{
const float3 frontDir = normalize(scaledFrontDir);
so.lightDirWV_invConeDelta.xyz = frontDir;
const float3 scaledConeDir = mul(float3(0, 1, 1), matWV33);
const float3 coneDir = normalize(scaledConeDir);
const float coneOut = dot(frontDir, coneDir);
const float invConeDelta = 1.0 / (coneIn - coneOut);
so.lightDirWV_invConeDelta.w = invConeDelta;
so.color_coneOut.a = coneOut;
}
#endif
#if defined(DEF_OMNI) || defined(DEF_SPOT)
{
so.lightPosWV = mul(float4(0, 0, 0, 1), matWV).xyz;
so.radius_radiusSq_invRadiusSq.y = dot(scaledFrontDir, scaledFrontDir);
so.radius_radiusSq_invRadiusSq.x = sqrt(so.radius_radiusSq_invRadiusSq.y);
so.radius_radiusSq_invRadiusSq.z = 1.0 / so.radius_radiusSq_invRadiusSq.y;
}
#endif
// </MoreLightParams>
return so;
}
#endif
#ifdef _FS
DS_ACC_FSO mainFS(VSO si)
{
DS_ACC_FSO so;
DS_Reset(so);
#ifdef DEF_DIR
const float3 ndcPos = si.clipSpacePos.xyz;
#else
const float3 ndcPos = si.clipSpacePos.xyz / si.clipSpacePos.w;
#endif
const float2 tc0 = mul(float4(ndcPos.xy, 0, 1), g_ubPerFrame._matToUV).xy;
// Direction and cone shape for spot:
#ifdef DEF_DIR
const float3 lightDirWV = si.lightDirWV_invConeDelta.xyz;
#elif defined(DEF_SPOT)
const float3 lightDirWV = si.lightDirWV_invConeDelta.xyz;
const float invConeDelta = si.lightDirWV_invConeDelta.w;
const float coneOut = si.color_coneOut.a;
#endif
// Omni and spot have position and radius:
#if defined(DEF_OMNI) || defined(DEF_SPOT)
const float3 lightPosWV = si.lightPosWV;
const float radius = si.radius_radiusSq_invRadiusSq.x;
const float radiusSq = si.radius_radiusSq_invRadiusSq.y;
const float invRadiusSq = si.radius_radiusSq_invRadiusSq.z;
#endif
// Depth:
const float depthSam = VK_SUBPASS_LOAD(g_texDepth, g_samDepth, tc0).r;
const float3 posWV = DS_GetPosition(depthSam, g_ubPerFrame._matInvP, ndcPos.xy);
#if defined(DEF_OMNI) || defined(DEF_SPOT)
if (posWV.z <= lightPosWV.z + radius)
#endif
{
// <SampleSurfaceData>
// GBuffer0 {Albedo.rgb, SSSHue}:
const float4 gBuffer0Sam = VK_SUBPASS_LOAD(g_texGBuffer0, g_samGBuffer0, tc0);
const float3 sssColor = SSSHueToColor(gBuffer0Sam.a);
// GBuffer1 {Normal.xy, Emission, MotionBlur}:
const float4 gBuffer1Sam = VK_SUBPASS_LOAD(g_texGBuffer1, g_samGBuffer1, tc0);
const float3 normalWV = DS_GetNormal(gBuffer1Sam);
// GBuffer2 {Occlusion, Roughness, Metallic, WrapDiffuse}:
const float4 gBuffer2Sam = VK_SUBPASS_LOAD(g_texGBuffer2, g_samGBuffer2, tc0);
const float roughness = gBuffer2Sam.g;
const float metallic = gBuffer2Sam.b;
const float wrapDiffuse = gBuffer2Sam.a;
// GBuffer3 {Tangent.xy, AnisoSpec, RoughDiffuse}:
const float4 gBuffer3Sam = VK_SUBPASS_LOAD(g_texGBuffer3, g_samGBuffer3, tc0);
const float3 tangentWV = DS_GetTangent(gBuffer3Sam);
const float anisoSpec = gBuffer3Sam.b;
const float roughDiffuse = frac(gBuffer3Sam.a);
// </SampleSurfaceData>
// <LightData>
#ifdef DEF_DIR
const float3 dirToLightWV = -lightDirWV;
const float lightFalloff = 1.0; // No falloff.
#else
const float3 toLightWV = lightPosWV - posWV;
const float3 dirToLightWV = normalize(toLightWV);
const float distToLightSq = dot(toLightWV, toLightWV);
const float lightFalloff = ComputePointLightIntensity(distToLightSq, radiusSq, invRadiusSq);
#endif
#ifdef DEF_SPOT // Extra step for spot light:
const float coneIntensity = ComputeSpotLightConeIntensity(dirToLightWV, lightDirWV, coneOut, invConeDelta);
#else
const float coneIntensity = 1.0; // No cone.
#endif
const float lightFalloffWithCone = lightFalloff * coneIntensity;
const float3 dirToEyeWV = normalize(-posWV);
const float3 lightColor = si.color_coneOut.rgb;
// </LightData>
// <Shadow>
float shadowMask = 1.0;
{
#ifdef DEF_DIR
float4 shadowConfig = g_ubShadowFS._shadowConfig;
shadowConfig.y = 1.0 - saturate(wrapDiffuse * shadowConfig.y);
const float3 posForShadow = AdjustPosForShadow(posWV, normalWV, dirToLightWV, -posWV.z);
shadowMask = ShadowMapCSM(
g_texShadowCmp,
g_samShadowCmp,
g_texShadow,
g_samShadow,
posWV,
posForShadow,
g_ubShadowFS._matShadow,
g_ubShadowFS._matShadowCSM1,
g_ubShadowFS._matShadowCSM2,
g_ubShadowFS._matShadowCSM3,
g_ubShadowFS._matScreenCSM,
g_ubShadowFS._csmSplitRanges,
shadowConfig);
#endif
}
// </Shadow>
const float lightMinRoughness = 0.015;
const float lightRoughness = lightMinRoughness + roughness * (1.0 / (1.0 - lightMinRoughness));
float3 punctualDiff, punctualSpec;
VerusLit(normalWV, dirToLightWV, dirToEyeWV, tangentWV,
gBuffer0Sam.rgb, sssColor,
lightRoughness, metallic, roughDiffuse, wrapDiffuse, anisoSpec,
punctualDiff, punctualSpec);
so.target1.rgb = punctualDiff * lightColor * shadowMask * lightFalloffWithCone;
so.target2.rgb = punctualSpec * lightColor * shadowMask * saturate(lightFalloffWithCone * 4.0);
so.target1.rgb = SaturateHDR(so.target1.rgb);
so.target2.rgb = SaturateHDR(so.target2.rgb);
#if defined(DEF_OMNI) || defined(DEF_SPOT)
const float assumedAlbedo = 0.1;
so.target0.rgb = assumedAlbedo * lightColor * lightFalloffWithCone;
so.target0.rgb = SaturateHDR(so.target0.rgb);
#endif
}
#if defined(DEF_OMNI) || defined(DEF_SPOT)
else
{
discard;
}
#endif
return so;
}
#endif
//@main:#InstancedDir INSTANCED DIR
//@main:#InstancedOmni INSTANCED OMNI
//@main:#InstancedSpot INSTANCED SPOT