void gbuffersLighting(inout vec4 albedo, in vec3 screenPos, in vec3 viewPos, in vec3 worldPos, inout vec3 shadow, in vec2 lightmap, in float NoU, in float NoL, in float NoE, in float subsurface, in float smoothness, in float emission) {
    //Variables
    float lViewPos = length(viewPos.xz);
    float ao = color.a * color.a;
    vec3 worldNormal = normalize(ToWorld(normal * 100000.0));

    //Vanilla Directional Lighting
    float vanillaDiffuse = (0.25 * NoU + 0.75) + (0.667 - abs(NoE)) * (1.0 - abs(NoU)) * 0.15;
          vanillaDiffuse *= vanillaDiffuse;

    #ifdef GBUFFERS_TERRAIN
    if (subsurface < 0.5) {
        NoL = pow(NoL, 1.5);
    }
    #endif

    //Block Lighting
    float blockLightMap = pow6(lightmap.x * lightmap.x) * 3.0 + max(lightmap.x - 0.05, 0.0);
          blockLightMap *= blockLightMap * 0.5;

    #ifdef NETHER
          blockLightMap = pow6(lightmap.x) * 3.0;
    #endif

    vec3 blockLighting = blockLightCol * blockLightMap * float(emission == 0.0);

    //Floodfill lighting
    #if !defined GBUFFERS_BASIC && !defined GBUFFERS_WATER && !defined GBUFFERS_TEXTURED
    vec3 voxelPos = ToVoxel(worldPos);

    #ifdef GBUFFERS_TERRAIN
    float floodfillDisable = float(mat == 10012);
    #else
    float floodfillDisable = 0.0;
    #endif

    float floodfillFade = maxOf(abs(worldPos));
          floodfillFade /= voxelVolumeSize * 0.5;
          floodfillFade = clamp(floodfillFade, 0.001, 1.0);

    vec3 voxelLighting = vec3(0.0);

    if (isInsideVoxelVolume(voxelPos) && floodfillDisable < 0.5) {
        vec3 voxelSamplePos = voxelPos + worldNormal;
             voxelSamplePos /= voxelVolumeSize;
             voxelSamplePos = clamp(voxelSamplePos, 0.0, 1.0);

        vec3 floodfillData = texture3D(floodfillSampler, voxelSamplePos).rgb;
        float lLighting = clamp(length(floodfillData), 0.0, 1.0);
        vec3 lighting = pow(floodfillData, vec3(0.75));
             lighting *= 0.6 + pow(lLighting, 1.3) * 0.4;

        voxelLighting = lighting * FLOODFILL_BRIGHTNESS;

        float mixFactor = length(pow(floodfillData, vec3(0.75)));
              mixFactor = clamp(pow(mixFactor, 0.1), 0.0, 1.0);
              mixFactor *= 1.0 - pow3(floodfillFade);
        #ifdef GBUFFERS_ENTITIES
        mixFactor = 0.5 + mixFactor * 0.5;
        #endif
        blockLighting = mix(blockLighting, voxelLighting, mixFactor);
    }
    #endif

    #ifdef OVERWORLD
    blockLighting *= 1.0 - lightmap.y * 0.5 * timeBrightness;
    #endif

    //Shadow Calculations
    //Some code made by Emin and gri573
    float shadowLength = shadowDistance * 0.9166667 - length(worldPos.xz);
    float shadow0 = 0.0;

    #ifdef GBUFFERS_WATER
    shadowLength = 1.0;
    #endif

    //Subsurface scattering
    float scattering = 0.0;
    
    #if defined OVERWORLD && defined GBUFFERS_TERRAIN
    if (subsurface > 0.0) {
        float VoL = dot(normalize(viewPos), lightVec) * 0.5 + 0.5;
        scattering = pow16(VoL) * (1.0 - wetness * 0.75) * subsurface * shadowFade;
        if (subsurface <= 0.49 || subsurface >= 0.51) {
            NoL = mix(NoL, NoL + 0.25, subsurface * 0.5);
            NoL = mix(NoL, 1.0, scattering * 0.75);
        } else {
            NoL = mix(NoL, 0.6, 0.75);
            NoL = mix(NoL, 1.0, scattering * 0.75);
        }
    }
    #endif

    if (NoL > 0.0001 && shadowLength > 0.0) {
        vec3 worldPosM = worldPos;

        #ifndef GBUFFERS_TEXTURED
            vec3 bias = worldNormal * min(0.1 + length(worldPos) / 250.0, 0.75);
            vec3 edgeFactor = 0.25 * (0.5 - fract(worldPosM + cameraPosition + worldNormal * 0.01));
            worldPosM += (1.0 - pow2(pow2(max(color.a, lightmap.y * lightmap.y)))) * edgeFactor;
            worldPosM += bias;
        #else
            vec3 centerWorldPos = floor(worldPosM + cameraPosition) - cameraPosition + 0.5;
            worldPosM = mix(centerWorldPos, worldPosM + vec3(0.0, 0.02, 0.0), lightmap.y);
        #endif

        vec3 shadowPos = ToShadow(worldPosM);

        float viewDistance = 1.0 - clamp(lViewPos * 0.01, 0.0, 1.0);
        float offset = 0.00125;
        #if defined GBUFFERS_TERRAIN
              offset *= 1.0 + subsurface * 2.0 * viewDistance;
        #endif

        #ifndef GBUFFERS_TERRAIN
        float subsurface = 0.0;
        #endif

        shadow = computeShadow(shadowPos, offset, lightmap.y, subsurface, viewDistance, shadow0);
    } else {
        shadow = getFakeShadow(lightmap.y);
    }

    NoL = clamp(NoL * 1.01 - 0.01, 0.0, 1.0);
    shadow *= NoL;

    //Scene Lighting
    #ifdef OVERWORLD
    float rainFactor = 1.0 - wetness * 0.75;

    vec3 sceneLighting = mix(ambientCol * lightmap.y * lightmap.y, lightCol, shadow * rainFactor * shadowFade) * lightmap.y;
         sceneLighting *= 1.0 + scattering * shadow;
    #elif defined END
    vec3 sceneLighting = mix(endAmbientCol, endLightCol, shadow) * 0.25;
    #elif defined NETHER
    vec3 sceneLighting = pow(netherColSqrt, vec3(0.75)) * 0.05;
    #endif

    //Specular Highlight
    vec3 specularHighlight = vec3(0.0);

    #if defined GBUFFERS_TERRAIN && !defined NETHER
	vec3 baseReflectance = vec3(0.04);

	float smoothnessF = mix(clamp(pow(length(albedo.rgb), 1.5) * 0.5 + NoL * 0.25, 0.25, 0.75), 1.0, smoothness);
          smoothnessF = clamp(smoothnessF, 0.0, 0.95);

    #ifdef OVERWORLD
	specularHighlight = getSpecularHighlight(normal, viewPos, smoothnessF, baseReflectance, lightCol, shadow * vanillaDiffuse, color.a);
    #else
    specularHighlight = getSpecularHighlight(normal, viewPos, smoothnessF, baseReflectance, endLightCol, shadow * vanillaDiffuse, color.a);
    #endif

    specularHighlight = clamp(specularHighlight * pow4(lightmap.y), vec3(0.0), vec3(3.0));
    #endif

    //Minimal Lighting
    #if defined OVERWORLD || defined END
    sceneLighting += minLightCol * (1.0 - lightmap.y);
    #endif

    //Vanilla AO
    #ifdef VANILLA_AO
    float aoMixer = (1.0 - ao) * (1.0 - pow6(lightmap.x));
    albedo.rgb = mix(albedo.rgb, albedo.rgb * ao * ao, aoMixer * AO_STRENGTH);
    #endif

    albedo.rgb = pow(albedo.rgb, vec3(2.2));
    albedo.rgb *= sceneLighting + blockLighting + emission;
    albedo.rgb *= vanillaDiffuse;
    albedo.rgb += specularHighlight;
    albedo.rgb = pow(albedo.rgb, vec3(1.0 / 2.2));
}