verus/Verus/src/Shaders/DS.hlsl

281 lines
9.2 KiB
HLSL
Raw Normal View History

2019-09-01 13:49:15 +02:00
#include "Lib.hlsl"
#include "LibColor.hlsl"
#include "LibDeferredShading.hlsl"
#include "LibLighting.hlsl"
#include "LibVertex.hlsl"
#include "DS.inc.hlsl"
2019-10-02 19:35:07 +02:00
ConstantBuffer<UB_PerFrame> g_ubPerFrame : register(b0, space0);
ConstantBuffer<UB_PerMesh> g_ubPerMesh : register(b0, space1);
2019-09-01 13:49:15 +02:00
VK_PUSH_CONSTANT
2019-10-02 19:35:07 +02:00
ConstantBuffer<UB_PerObject> g_ubPerObject : register(b0, space2);
2019-09-01 13:49:15 +02:00
2019-10-02 19:35:07 +02:00
VK_SUBPASS_INPUT(0, g_texGBuffer0, g_samGBuffer0, t1, s1, space0);
VK_SUBPASS_INPUT(1, g_texGBuffer1, g_samGBuffer1, t2, s2, space0);
VK_SUBPASS_INPUT(2, g_texGBuffer2, g_samGBuffer2, t3, s3, space0);
VK_SUBPASS_INPUT(3, g_texGBuffer3, g_samGBuffer3, t4, s4, space0);
2019-09-01 13:49:15 +02:00
struct VSI
{
// Binding 0:
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 posFS /**/ : 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;
2019-10-02 19:35:07 +02:00
const float3 intactPos = DequantizeUsingDeq3D(si.pos.xyz, g_ubPerMesh._posDeqScale.xyz, g_ubPerMesh._posDeqBias.xyz);
2019-09-01 13:49:15 +02:00
// 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
2019-10-02 19:35:07 +02:00
const mataff matW = g_ubPerObject._matW;
const float3 color = g_ubPerObject.rgb;
const float coneIn = g_ubPerObject.a;
2019-09-01 13:49:15 +02:00
#endif
#ifdef DEF_DIR
const float glossScale = 0.5;
#else
const float glossScale = 1.0;
#endif
2019-10-02 19:35:07 +02:00
const matrix matWV = mul(ToFloat4x4(matW), ToFloat4x4(g_ubPerFrame._matV));
2019-09-01 13:49:15 +02:00
const float3x3 matW33 = (float3x3)matW;
2019-10-02 19:35:07 +02:00
const float3x3 matV33 = (float3x3)g_ubPerFrame._matV;
2019-09-01 13:49:15 +02:00
const float3x3 matWV33 = (float3x3)matWV;
#ifdef DEF_DIR
2019-10-02 19:35:07 +02:00
so.pos = float4(mul(float4(intactPos, 1), g_ubPerFrame._matQuad), 1);
so.posFS = float4(intactPos, 1);
2019-09-01 13:49:15 +02:00
#else
const float3 posW = mul(float4(intactPos, 1), matW);
2019-10-02 19:35:07 +02:00
so.pos = mul(float4(posW, 1), g_ubPerFrame._matVP);
2019-09-01 13:49:15 +02:00
so.posFS = so.pos;
2019-10-02 19:35:07 +02:00
#endif
2019-09-01 13:49:15 +02:00
// <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;
// Clip-space position:
#ifdef DEF_DIR
const float3 posCS = si.posFS.xyz;
#else
const float3 posCS = si.posFS.xyz / si.posFS.w;
#endif
// GBuffer tex. coord. from posCS:
2019-10-02 19:35:07 +02:00
const float2 tc0 = mul(float4(posCS.xy, 0, 1), g_ubPerFrame._matToUV).xy;
2019-09-01 13:49:15 +02:00
// 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:
2019-10-02 19:35:07 +02:00
const float rawGBuffer1 = VK_SUBPASS_LOAD(g_texGBuffer1, g_samGBuffer1, tc0).r;
const float3 posWV = DS_GetPosition(rawGBuffer1, g_ubPerFrame._matInvP, posCS.xy);
2019-09-01 13:49:15 +02:00
so.target0 = 0.0;
so.target1 = 0.0;
#if defined(DEF_OMNI) || defined(DEF_SPOT)
if (lightPosWV.z - posWV.z + radius >= 0.0) // Optimize finite volume lights.
#endif
{
// Light's diffuse & specular color:
const float3 colorDiff = si.color_coneOut.rgb;
const float3 colorSpec = saturate(colorDiff + dot(colorDiff, 0.1));
2019-10-02 19:35:07 +02:00
// GBuffer0 (color, spec):
const float4 rawGBuffer0 = VK_SUBPASS_LOAD(g_texGBuffer0, g_samGBuffer0, tc0);
const float spec = rawGBuffer0.a;
2019-09-01 13:49:15 +02:00
const float3 dirToEyeWV = normalize(-posWV);
2019-10-02 19:35:07 +02:00
// GBuffer2 (normal, emission, motion):
const float4 rawGBuffer2 = VK_SUBPASS_LOAD(g_texGBuffer2, g_samGBuffer2, tc0);
2019-09-01 13:49:15 +02:00
const float3 normalWV = DS_GetNormal(rawGBuffer2);
const float2 emission = DS_GetEmission(rawGBuffer2);
2019-10-02 19:35:07 +02:00
// GBuffer3 (lam, metal, gloss):
const float4 rawGBuffer3 = VK_SUBPASS_LOAD(g_texGBuffer3, g_samGBuffer3, tc0);
2019-09-01 13:49:15 +02:00
const float3 anisoWV = DS_GetAnisoSpec(rawGBuffer3);
const float2 lamScaleBias = DS_GetLamScaleBias(rawGBuffer3);
2019-10-02 19:35:07 +02:00
const float2 metal = DS_GetMetallicity(rawGBuffer3);
2019-09-01 13:49:15 +02:00
const float gloss64 = rawGBuffer3.a*64.0;
const float gloss64Scaled = gloss64 * glossScale;
// Special:
const float skinAlpha = emission.y;
const float hairAlpha = metal.y;
const float eyeAlpha = saturate(1.0 - gloss64);
const float rim = pow(1.0 - normalWV.z, 2.0)*(0.05 + 0.2*skinAlpha);
const float glossEye = 25.0*glossScale;
const float gloss = lerp(gloss64Scaled*gloss64Scaled*gloss64Scaled, glossEye*glossEye*glossEye, eyeAlpha);
#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
2019-10-02 19:35:07 +02:00
const float4 litRet = VerusLit(dirToLightWV, normalWV, dirToEyeWV,
2019-09-01 13:49:15 +02:00
lerp(gloss*(2.0 - lightFalloff), 12.0, hairAlpha),
lerp(lamScaleBias, float2(1, 0.4), hairAlpha),
float4(anisoWV, hairAlpha));
// Shadow:
#ifdef DEF_DIR
const float shadowAlpha = 1.0;
#else
const float shadowAlpha = 1.0;
#endif
const float intensityDiff = lightFalloff * coneIntensity*shadowAlpha;
const float intensitySpec = saturate(intensityDiff*2.0);
const float maxSpecAdd = lerp(0.2*spec, 0.1 + spec * 0.5, metal.x);
// Subsurface scattering effect for front & back faces:
const float3 colorSkinSSS_Face = float3(1.6, 1.2, 0.3);
const float3 colorSkinSSS_Back = float3(1.6, 0.8, 0.5);
const float3 colorDiffSSS_Face = lerp(colorDiff, colorDiff*colorSkinSSS_Face, skinAlpha*pow(1.0 - litRet.y, 2.0));
const float3 colorDiffSSS_Back = lerp(colorDiffSSS_Face, colorDiff*colorSkinSSS_Back, skinAlpha*litRet.x);
const float grey = Greyscale(rawGBuffer0.rgb);
const float3 metalSpec = saturate(rawGBuffer0.rgb / (grey + _SINGULARITY_FIX));
const float3 matSpec = lerp(float3(1, 1, 1), metalSpec, saturate(metal.x + (hairAlpha - eyeAlpha)*0.4))*FresnelSchlick(spec, maxSpecAdd, litRet.w);
const float3 maxDiff = colorDiffSSS_Back * intensityDiff;
const float3 maxSpec = matSpec * colorSpec + float3(-0.03, 0.0, 0.05)*skinAlpha;
#ifdef DEF_DIR
const float skyIntensity = 1.0;
const float3 skySpec = skyColor * matSpec*skyIntensity;
#endif
// Very bright light:
const float3 overbright = saturate(dot(maxDiff, 1.0 / 3.0) - 1.0); // Intensity above one.
const float3 diffBoost = overbright * maxDiff*litRet.y*(0.25 + rawGBuffer0.rgb);
#ifdef DEF_DIR
so.target0.rgb = maxDiff * litRet.y; // Lambert's cosine law.
2019-10-02 19:35:07 +02:00
so.target1.rgb = maxSpec * saturate(litRet.z*intensitySpec + rim) + diffBoost;
2019-09-01 13:49:15 +02:00
#else
so.target0.rgb = maxDiff * litRet.y; // Lambert's cosine law.
so.target1.rgb = maxSpec * saturate(litRet.z*intensitySpec) + diffBoost;
#endif
so.target0.rgb = max(so.target0.rgb, emission.x*GetEmissionScale());
so.target1.rgb = min(so.target1.rgb, 1.0 - emission.x*GetEmissionScale());
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:TInstancedDir INSTANCED DIR
//@main:TInstancedOmni INSTANCED OMNI
//@main:TInstancedSpot INSTANCED SPOT