verus/Verus/src/Shaders/DS.hlsl

299 lines
10 KiB
HLSL

// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com)
#include "Lib.hlsl"
#include "LibColor.hlsl"
#include "LibDeferredShading.hlsl"
#include "LibDepth.hlsl"
#include "LibLighting.hlsl"
#include "LibVertex.hlsl"
#include "DS.inc.hlsl"
ConstantBuffer<UB_PerFrame> g_ubPerFrame : register(b0, space0);
ConstantBuffer<UB_TexturesFS> g_ubTexturesFS : register(b0, space1);
ConstantBuffer<UB_PerMeshVS> g_ubPerMeshVS : register(b0, space2);
ConstantBuffer<UB_ShadowFS> g_ubShadowFS : register(b0, space3);
VK_PUSH_CONSTANT
ConstantBuffer<UB_PerObject> g_ubPerObject : register(b0, space4);
VK_SUBPASS_INPUT(0, g_texGBuffer0, g_samGBuffer0, t1, s1, space1);
VK_SUBPASS_INPUT(1, g_texGBuffer1, g_samGBuffer1, t2, s2, space1);
VK_SUBPASS_INPUT(2, g_texGBuffer2, g_samGBuffer2, t3, s3, space1);
VK_SUBPASS_INPUT(3, g_texDepth, g_samDepth, t4, s4, space1);
Texture2D g_texShadowCmp : register(t5, space1);
SamplerComparisonState g_samShadowCmp : register(s5, space1);
Texture2D g_texShadow : register(t6, space1);
SamplerState g_samShadow : register(s6, space1);
struct VSI
{
VK_LOCATION_POSITION int4 pos : POSITION;
VK_LOCATION_NORMAL float3 nrm : NORMAL;
VK_LOCATION(8) int4 tc0 : TEXCOORD0;
_PER_INSTANCE_DATA
};
struct VSO
{
float4 pos : SV_Position;
float4 clipSpacePos : TEXCOORD0;
#if defined(DEF_OMNI) || defined(DEF_SPOT)
float3 radius_radiusSq_invRadiusSq : TEXCOORD1;
float3 lightPosWV : TEXCOORD2;
#endif
#if defined(DEF_DIR) || defined(DEF_SPOT)
float4 lightDirWV_invConeDelta : TEXCOORD3;
#endif
float4 color_coneOut : TEXCOORD4;
#ifdef DEF_DIR
float3 dirZenithWV : TEXCOORD5;
#endif
};
#ifdef _VS
VSO mainVS(VSI si)
{
VSO so;
// World matrix, instance data:
#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.rgb;
const float coneIn = g_ubPerObject.a;
#endif
#ifdef DEF_DIR
const float glossScale = 0.5;
#else
const float glossScale = 1.0;
#endif
const matrix matWV = mul(ToFloat4x4(matW), ToFloat4x4(g_ubPerFrame._matV));
const float3x3 matW33 = (float3x3)matW;
const float3x3 matV33 = (float3x3)g_ubPerFrame._matV;
const float3x3 matWV33 = (float3x3)matWV;
const float3 intactPos = DequantizeUsingDeq3D(si.pos.xyz, g_ubPerMeshVS._posDeqScale.xyz, g_ubPerMeshVS._posDeqBias.xyz);
#ifdef DEF_DIR
so.pos = float4(mul(float4(intactPos, 1), g_ubPerFrame._matQuad), 1);
so.clipSpacePos = float4(intactPos, 1);
#else
const float3 posW = mul(float4(intactPos, 1), matW);
so.pos = mul(float4(posW, 1), g_ubPerFrame._matVP);
so.clipSpacePos = so.pos;
#endif
// <MoreLightParams>
#if defined(DEF_OMNI) || defined(DEF_SPOT)
const float3 posUnit = mul(float3(0, 0, 1), matW33); // Need to know the scale.
so.radius_radiusSq_invRadiusSq.y = dot(posUnit, posUnit);
so.radius_radiusSq_invRadiusSq.x = sqrt(so.radius_radiusSq_invRadiusSq.y);
so.radius_radiusSq_invRadiusSq.z = 1.0 / so.radius_radiusSq_invRadiusSq.y;
const float4 posOrigin = float4(0, 0, 0, 1);
so.lightPosWV = mul(posOrigin, matWV).xyz;
#endif
so.color_coneOut = float4(color, glossScale);
#ifdef DEF_DIR
const float3 posUnit = mul(float3(0, 0, 1), matWV33); // Assume no scale in matWV33.
so.lightDirWV_invConeDelta = float4(posUnit, 1);
so.dirZenithWV = mul(float3(0, 1, 0), matV33);
#elif DEF_SPOT
so.lightDirWV_invConeDelta.xyz = normalize(mul(float3(0, 0, 1), matWV33));
const float3 posCone = mul(float3(0, 1, 1), matW33);
const float3 dirCone = normalize(posCone);
const float3 dirUnit = normalize(posUnit);
const float coneOut = dot(dirUnit, dirCone);
const float invConeDelta = 1.0 / (coneIn - coneOut);
so.lightDirWV_invConeDelta.w = invConeDelta;
so.color_coneOut.a = coneOut;
#endif
// </MoreLightParams>
return so;
}
#endif
#ifdef _FS
DS_ACC_FSO mainFS(VSO si)
{
DS_ACC_FSO 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;
// For Omni & Spot: light's radius and position:
#if defined(DEF_OMNI) || defined(DEF_SPOT)
const float radius = si.radius_radiusSq_invRadiusSq.x;
const float radiusSq = si.radius_radiusSq_invRadiusSq.y;
const float invRadiusSq = si.radius_radiusSq_invRadiusSq.z;
const float3 lightPosWV = si.lightPosWV;
#endif
// For Dir & Spot: light's direction & cone:
#ifdef DEF_DIR
const float3 lightDirWV = si.lightDirWV_invConeDelta.xyz;
const float3 dirZenithWV = si.dirZenithWV;
#elif DEF_SPOT
const float3 lightDirWV = si.lightDirWV_invConeDelta.xyz;
const float invConeDelta = si.lightDirWV_invConeDelta.w;
const float coneOut = si.color_coneOut.a;
#endif
#ifdef DEF_SPOT
const float glossScale = 0.5;
#else
const float glossScale = si.color_coneOut.a;
#endif
// GBuffer1:
const float depth = VK_SUBPASS_LOAD(g_texDepth, g_samDepth, tc0).r;
const float3 posWV = DS_GetPosition(depth, g_ubPerFrame._matInvP, ndcPos.xy);
so.target0 = 0.0;
so.target1 = 0.0;
#if defined(DEF_OMNI) || defined(DEF_SPOT)
if (posWV.z <= lightPosWV.z + radius)
#endif
{
// Light's diffuse & specular color:
const float3 hdrLightColor = si.color_coneOut.rgb;
// GBuffer0 (albedo, spec):
const float4 rawGBuffer0 = VK_SUBPASS_LOAD(g_texGBuffer0, g_samGBuffer0, tc0);
const float spec = rawGBuffer0.a;
const float3 dirToEyeWV = normalize(-posWV);
// GBuffer2 (normal, emission, motion):
const float4 rawGBuffer1 = VK_SUBPASS_LOAD(g_texGBuffer1, g_samGBuffer1, tc0);
const float3 normalWV = DS_GetNormal(rawGBuffer1);
const float2 emission = DS_GetEmission(rawGBuffer1);
// GBuffer3 (lam, metal, gloss):
const float4 rawGBuffer2 = VK_SUBPASS_LOAD(g_texGBuffer2, g_samGBuffer2, tc0);
const float3 anisoWV = DS_GetAnisoSpec(rawGBuffer2);
const float2 lamScaleBias = DS_GetLamScaleBias(rawGBuffer2);
const float2 metal = DS_GetMetallicity(rawGBuffer2);
const float gloss64 = rawGBuffer2.a * 64.0;
const float gloss64Scaled = gloss64 * glossScale;
// Special:
const float skinMask = emission.y;
const float hairMask = metal.y;
const float eyeMask = saturate(1.0 - gloss64);
const float eyeGloss = 25.0 * glossScale;
const float2 lamScaleBiasWithHair = lerp(lamScaleBias, float2(1, 0.4), hairMask);
const float gloss = lerp(gloss64Scaled * gloss64Scaled * gloss64Scaled, eyeGloss * eyeGloss * eyeGloss, eyeMask);
#ifdef DEF_DIR
const float3 dirToLightWV = -lightDirWV;
const float lightFalloff = 1.0;
const float3 reflectWV = reflect(-dirToEyeWV, normalWV);
const float zenith = dot(dirZenithWV, reflectWV);
const float zenithMask = saturate(zenith * gloss64Scaled * 0.15);
const float3 skyColor = 1.0;
#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;
#endif
const float4 litRet = VerusLit(dirToLightWV, normalWV, dirToEyeWV,
lerp(gloss * (2.0 - lightFalloff), 12.0, hairMask),
lamScaleBiasWithHair,
float4(anisoWV, hairMask));
// <Shadow>
float shadowMask = 1.0;
{
#ifdef DEF_DIR
const float lightPassOffset = saturate((lamScaleBiasWithHair.y - 0.5) * 5.0) * 2.0;
float4 config = g_ubShadowFS._shadowConfig;
const float lamBiasMask = saturate(lamScaleBiasWithHair.y * config.y);
config.y = 1.0 - lamBiasMask; // Keep penumbra blurry.
const float3 posForShadow = AdjustPosForShadow(posWV, normalWV, dirToLightWV, -posWV.z, lightPassOffset);
const float4 tcShadow = ShadowCoords(float4(posForShadow, 1), g_ubShadowFS._matSunShadow, -posForShadow.z);
shadowMask = ShadowMapCSM(
g_texShadowCmp,
g_samShadowCmp,
g_texShadow,
g_samShadow,
tcShadow,
config,
g_ubShadowFS._splitRanges,
g_ubShadowFS._matSunShadow,
g_ubShadowFS._matSunShadowCSM1,
g_ubShadowFS._matSunShadowCSM2,
g_ubShadowFS._matSunShadowCSM3);
#endif
}
// </Shadow>
const float lightFalloffWithCone = lightFalloff * coneIntensity;
const float diffLightMask = lightFalloffWithCone * shadowMask;
const float specLightMask = saturate(lightFalloffWithCone * 2.0) * shadowMask;
const float maxSpecAdd = (1.0 - spec) * lerp(0.01, 0.5, metal.x);
// Subsurface scattering effect for front & back faces:
const float3 frontSkinSSSColor = float3(1.6, 1.2, 0.3);
const float3 backSkinSSSColor = float3(1.6, 0.8, 0.5);
const float frontSkinSSSMask = 1.0 - litRet.y;
const float3 hdrLightFaceColor = hdrLightColor * lerp(1.0, frontSkinSSSColor, skinMask * frontSkinSSSMask * frontSkinSSSMask);
const float3 hdrLightColorSSS = lerp(hdrLightFaceColor, hdrLightColor * backSkinSSSColor, skinMask * litRet.x);
const float gray = Grayscale(rawGBuffer0.rgb);
const float3 metalSpec = saturate(rawGBuffer0.rgb / (gray + _SINGULARITY_FIX));
const float3 specHue = saturate(lerp(float3(1, 1, 1), metalSpec, saturate(metal.x + (hairMask - eyeMask) * 0.4)) +
float3(-0.03, 0.0, 0.05) * skinMask);
const float3 hdrMaxDiff = hdrLightColorSSS * diffLightMask;
const float3 hdrMaxSpec = hdrLightColorSSS * specLightMask * specHue * FresnelSchlick(spec, maxSpecAdd, litRet.w);
#ifdef DEF_DIR
so.target0.rgb = hdrMaxDiff * litRet.y;
so.target1.rgb = hdrMaxSpec * litRet.z;
#else
so.target0.rgb = hdrMaxDiff * litRet.y;
so.target1.rgb = hdrMaxSpec * litRet.z;
#endif
//so.target0.rgb = max(so.target0.rgb, emission.x);
//so.target1.rgb = min(so.target1.rgb, 1.0 - emission.x);
so.target0.a = 1.0;
so.target1.a = 1.0;
}
#if defined(DEF_OMNI) || defined(DEF_SPOT)
else
{
clip(-1.0);
}
#endif
return so;
}
#endif
//@main:#InstancedDir INSTANCED DIR
//@main:#InstancedOmni INSTANCED OMNI
//@main:#InstancedSpot INSTANCED SPOT