 
     const vec3 V = normalize(camera.position - fragment.position);
 
+    const float NdotV = max(dot(normal, V), 0.0);
+
     vec3 F0 = vec3(0.04);
     F0 = mix(F0, albedo, metallic);
 

        const float num_levels = 1 + floor(log2(maxsize));
        const float mip_level = clamp(pow(roughness, 0.25) * num_levels, 0.0, 10.0);

        const vec3 F_env = fresnel_schlick_roughness(max(dot(normal, V), 0.0), F0, roughness);
        const vec3 kS_env = F_env;
        const vec3 kD_env = (1.0 - kS_env) * (1.0 - metallic);

        const vec3 filtered = textureLod(environment_samplers[i], corrected_r, mip_level).rgb;
        const vec2 brdf  = texture(brdf_lut, vec2(max(dot(normal, V), 0.0), roughness)).rg;

        const float refractive_index = 1.5;
        const vec3 refracted_direction = refract(V, normal, 1.0 / refractive_index);

            const vec3 F = fresnel_schlick(clamp(dot(H, V), 0.0, 1.0), F0);

            const vec3 nominator = NDF * G * F;
            const float denominator = 4 * NdotV * NdotL + 0.001;
            const vec3 specular = nominator / denominator;

            const vec3 kS = F;
