// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE // Classic deferred lighting shader #pragma anki mutator SPECULAR 0 1 #pragma anki mutator INDIRECT_DIFFUSE 0 1 2 #pragma anki technique vert pixel #include #if ANKI_PIXEL_SHADER # include # include # include # include # include ConstantBuffer g_consts : register(b0); StructuredBuffer g_visibleLightIds : register(t0); StructuredBuffer g_lights : register(t1); SamplerState g_gbufferSampler : register(s0); Texture2D g_gbufferTex0 : register(t2); Texture2D g_gbufferTex1 : register(t3); Texture2D g_gbufferTex2 : register(t4); Texture2D g_depthTex : register(t5); // For directional light: SamplerComparisonState g_shadowMapSampler : register(s1); Texture2D g_shadowMap : register(t6); # if INDIRECT_DIFFUSE StructuredBuffer g_giProbes : register(t7); SamplerState g_linearAnyClampSampler : register(s2); # endif ConstantBuffer g_globalRendererConsts : register(b1); # if INDIRECT_DIFFUSE Vec3 getDiffuseIndirect(Vec3 worldPos, Vec3 worldNormal) { # if INDIRECT_DIFFUSE == 1 const U32 probeCount = getStructuredBufferElementCount(g_giProbes); U32 i; for(i = 0; i < probeCount; ++i) { if(all(worldPos < g_giProbes[i].m_aabbMax) && all(worldPos > g_giProbes[i].m_aabbMin)) { break; } } const Bool probeFound = (i != probeCount); if(probeFound) { const GpuSceneGlobalIlluminationProbe probe = g_giProbes[i]; return sampleGlobalIllumination(worldPos, worldNormal, probe, getBindlessTexture3DVec4(probe.m_volumeTexture), g_linearAnyClampSampler); } else { return 0.0; } # else constexpr SampleClipmapFlag flags = kSampleClipmapFlagBackfacingProbeRejection | kSampleClipmapFlagBiasSamplePointSurfaceNormal | kSampleClipmapFlagUsePreviousFrame; const IndirectDiffuseClipmapConstants idConsts = g_globalRendererConsts.m_indirectDiffuseClipmaps; const Vec3 irradiance = sampleClipmapIrradiance(worldPos, worldNormal, g_globalRendererConsts.m_cameraPosition, idConsts, g_linearAnyClampSampler, flags); return irradiance; # endif } # endif Vec4 main(VertOut input) : SV_TARGET0 { const Vec2 uv = input.m_uv; const F32 depth = g_depthTex.SampleLevel(g_gbufferSampler, uv, 0.0).r; if(depth == 1.0f) { discard; } // Decode and process gbuffer GbufferInfo gbuffer = (GbufferInfo)0; unpackGBufferNoVelocity(g_gbufferTex0.SampleLevel(g_gbufferSampler, uv, 0.0), g_gbufferTex1.SampleLevel(g_gbufferSampler, uv, 0.0), g_gbufferTex2.SampleLevel(g_gbufferSampler, uv, 0.0), gbuffer); gbuffer.m_subsurface = max(gbuffer.m_subsurface, kSubsurfaceMin * 8.0); const Vec4 worldPos4 = mul(g_consts.m_invViewProjMat, Vec4(uvToNdc(uv), depth, 1.0)); const Vec3 worldPos = worldPos4.xyz / worldPos4.w; // Compute diff const Vec3 diffC = diffuseLobe(gbuffer.m_diffuse); Vec3 outColor = gbuffer.m_emission; const Vec3 viewDir = normalize(g_consts.m_cameraPos - worldPos); ANKI_MAYBE_UNUSED(viewDir); # if INDIRECT_DIFFUSE outColor += getDiffuseIndirect(worldPos, gbuffer.m_normal) * gbuffer.m_diffuse; # endif // Dir light if(g_globalRendererConsts.m_directionalLight.m_active) { const F32 dist = length(g_consts.m_cameraPos - worldPos); F32 shadowFactor; if(dist < g_consts.m_dirLight.m_effectiveShadowDistance) { // Acceptable distance shadowFactor = computeShadowFactorDirLight(g_consts.m_dirLight.m_lightMatrix, worldPos, g_shadowMap, g_shadowMapSampler); } else { shadowFactor = 1.0; } const Vec3 l = -g_globalRendererConsts.m_directionalLight.m_direction; const F32 lambert = dot(l, gbuffer.m_normal); const F32 factor = shadowFactor * max(gbuffer.m_subsurface, lambert); # if SPECULAR == 1 const Vec3 specC = specularIsotropicLobe(gbuffer.m_normal, gbuffer.m_f0, gbuffer.m_roughness, viewDir, l); # else const Vec3 specC = Vec3(0.0, 0.0, 0.0); # endif outColor += (specC + diffC) * g_globalRendererConsts.m_directionalLight.m_diffuseColor * factor; } // For all (other) lights const U32 lightCount = g_visibleLightIds[0]; for(U32 i = 1; i <= lightCount; ++i) { const GpuSceneLight light = g_lights[g_visibleLightIds[i]]; const Vec3 frag2Light = light.m_position - worldPos; const Vec3 l = normalize(frag2Light); const F32 nol = max(0.0, dot(gbuffer.m_normal, l)); const F32 att = computeAttenuationFactor(light.m_radius, frag2Light); const F32 lambert = nol; const F32 spot = light.m_isSpotLight ? computeSpotFactor(l, light.m_outerCos, light.m_innerCos, light.m_direction) : 1.0f; const F32 factor = att * spot * max(lambert, gbuffer.m_subsurface); # if SPECULAR == 1 const Vec3 specC = specularIsotropicLobe(gbuffer.m_normal, gbuffer.m_f0, gbuffer.m_roughness, viewDir, l); # else const Vec3 specC = Vec3(0.0, 0.0, 0.0); # endif outColor += (specC + diffC) * light.m_diffuseColor * factor; } return Vec4(outColor, 0.0); } #endif // ANKI_PIXEL_SHADER