// Copyright (C) 2009-2020, 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 LIGHT_TYPE 0 1 2 #pragma anki mutator SPECULAR 0 1 #define POINT_LIGHT_TYPE 0 #define SPOT_LIGHT_TYPE 1 #define DIR_LIGHT_TYPE 2 // VERT #pragma anki start vert #include out gl_PerVertex { Vec4 gl_Position; }; #if LIGHT_TYPE == DIR_LIGHT_TYPE void main() { Vec2 uv = Vec2(gl_VertexID & 1, gl_VertexID >> 1) * 2.0; Vec2 pos = uv * 2.0 - 1.0; gl_Position = Vec4(pos, 0.0, 1.0); } #else layout(location = 0) in Vec3 in_position; layout(set = 0, binding = 0, row_major) uniform u0_ { Mat4 u_mvp; }; void main() { gl_Position = u_mvp * Vec4(in_position, 1.0); } #endif #pragma anki end // FRAG #pragma anki start frag #include #include #include layout(location = 0) out Vec3 out_color; layout(set = 0, binding = 1, row_major) uniform u1_ { #if LIGHT_TYPE == POINT_LIGHT_TYPE DeferredPointLightUniforms u_unis; #elif LIGHT_TYPE == SPOT_LIGHT_TYPE DeferredSpotLightUniforms u_unis; #elif LIGHT_TYPE == DIR_LIGHT_TYPE DeferredDirectionalLightUniforms u_unis; #else # error See file #endif }; layout(set = 0, binding = 2) uniform sampler u_msSampler; layout(set = 0, binding = 3) uniform texture2D u_msRt0; layout(set = 0, binding = 4) uniform texture2D u_msRt1; layout(set = 0, binding = 5) uniform texture2D u_msRt2; layout(set = 0, binding = 6) uniform texture2D u_msDepthRt; #if LIGHT_TYPE == DIR_LIGHT_TYPE layout(set = 0, binding = 7) uniform samplerShadow u_shadowMapSampler; layout(set = 0, binding = 8) uniform texture2D u_shadowMap; #endif void main() { // Compute UV coordinates const Vec2 uvToRead = fma(Vec2(gl_FragCoord.xy), u_unis.m_inputTexUvScale, u_unis.m_inputTexUvBias); const Vec2 uvToWrite = fma(Vec2(gl_FragCoord.xy), u_unis.m_fbUvScale, u_unis.m_fbUvBias); const F32 depth = textureLod(u_msDepthRt, u_msSampler, uvToRead, 0.0).r; #if LIGHT_TYPE != DIR_LIGHT_TYPE // Do manual depth test if(gl_FragCoord.z < depth) { discard; } #endif // Decode and process gbuffer GbufferInfo gbuffer; readGBuffer(u_msRt0, u_msRt1, u_msRt2, u_msSampler, uvToRead, 0.0, gbuffer); gbuffer.m_subsurface = max(gbuffer.m_subsurface, SUBSURFACE_MIN * 8.0); const Vec4 worldPos4 = u_unis.m_invViewProjMat * Vec4(UV_TO_NDC(uvToWrite), depth, 1.0); const Vec3 worldPos = worldPos4.xyz / worldPos4.w; // Compute diff const Vec3 diffC = diffuseLambert(gbuffer.m_diffuse); // Compute spec const Vec3 viewDir = normalize(u_unis.m_camPos - worldPos); #if LIGHT_TYPE == DIR_LIGHT_TYPE const Vec3 l = -u_unis.m_lightDir; #else const Vec3 frag2Light = u_unis.m_position - worldPos; const Vec3 l = normalize(frag2Light); const F32 nol = max(0.0, dot(gbuffer.m_normal, l)); #endif #if SPECULAR == 1 const Vec3 specC = computeSpecularColorBrdf(gbuffer, viewDir, l); #else const Vec3 specC = Vec3(0.0); #endif // Compute factors #if LIGHT_TYPE == POINT_LIGHT_TYPE const F32 att = computeAttenuationFactor(u_unis.m_oneOverSquareRadius, frag2Light); const F32 lambert = nol; const F32 factor = att * max(lambert, gbuffer.m_subsurface); #elif LIGHT_TYPE == SPOT_LIGHT_TYPE const F32 att = computeAttenuationFactor(u_unis.m_oneOverSquareRadius, frag2Light); const F32 lambert = nol; const F32 spot = computeSpotFactor(l, u_unis.m_outerCos, u_unis.m_innerCos, u_unis.m_lightDir); const F32 factor = att * spot * max(lambert, gbuffer.m_subsurface); #else const F32 linearDepth = linearizeDepth(depth, u_unis.m_near, u_unis.m_far); F32 shadowFactor; if(linearDepth * (u_unis.m_far - u_unis.m_near) < u_unis.m_effectiveShadowDistance) { // Acceptable distance shadowFactor = computeShadowFactorDirLight(u_unis.m_lightMatrix, worldPos, u_shadowMap, u_shadowMapSampler); } else { shadowFactor = 1.0; } const F32 lambert = dot(l, gbuffer.m_normal); const F32 factor = shadowFactor * max(gbuffer.m_subsurface, lambert); #endif out_color = gbuffer.m_diffuse * gbuffer.m_emission; out_color += (specC + diffC) * u_unis.m_diffuseColor * factor; } #pragma anki end