     ao *= texture2D(uAO, vUV).r;
 #endif
 
-    //TODO: No kd? so not really energy conserving
-    //we could use disney brdf for irradiance map to compensate for that like in Frostbite
-#ifdef USE_NORMALS
+//TODO: No kd? so not really energy conserving
+//we could use disney brdf for irradiance map to compensate for that like in Frostbite
+
 #ifdef USE_REFLECTION_PROBES
-    float NdotV = saturate( dot( normalWorld, eyeDirWorld ) );
-    vec3 reflectance = EnvBRDFApprox( F0, roughness, NdotV );
-    vec3 irradianceColor = getIrradiance(eyeDirWorld, normalWorld);
-    vec3 reflectionColor = getPrefilteredReflection(eyeDirWorld, normalWorld, roughness);
-    vec3 kS = F0;
-    vec3 kD = vec3(1.0) - kS;
-    kD *= 1.0 - metallic;
-    indirectDiffuse = kD * baseColor * irradianceColor;
-    indirectSpecular = reflectionColor * reflectance;
-#endif
-
-    //lights
+  EvaluateLightProbe(data);
+#endif
+
+#if NUM_AMBIENT_LIGHTS > 0
+  for(int i=0; i<NUM_AMBIENT_LIGHTS; i++) {
+    AmbientLight light = uAmbientLights[i];
+    EvaluateAmbientLight(data, light, i);    
+  }
+#endif
 #if NUM_DIRECTIONAL_LIGHTS > 0
-    for(int i=0; i<NUM_DIRECTIONAL_LIGHTS; i++) {
-        DirectionalLight light = uDirectionalLights[i];
-
-        //shadows
-        vec4 lightViewPosition = light.viewMatrix * vec4(vPositionWorld, 1.0);
-        float lightDistView = -lightViewPosition.z;
-        vec4 lightDeviceCoordsPosition = light.projectionMatrix * lightViewPosition;
-        vec2 lightDeviceCoordsPositionNormalized = lightDeviceCoordsPosition.xy / lightDeviceCoordsPosition.w;
-        float lightDeviceCoordsZ = lightDeviceCoordsPosition.z / lightDeviceCoordsPosition.w;
-        vec2 lightUV = lightDeviceCoordsPositionNormalized.xy * 0.5 + 0.5;
-
-        float illuminated = 0.0;
-        if (i == 0) illuminated += directionalShadow(uDirectionalLightShadowMaps[0], light.shadowMapSize, lightUV, lightDistView - light.bias, light.near, light.far);
-#if NUM_DIRECTIONAL_LIGHTS >= 2
-        if (i == 1) illuminated += directionalShadow(uDirectionalLightShadowMaps[1], light.shadowMapSize, lightUV, lightDistView - light.bias, light.near, light.far);
-#endif
-#if NUM_DIRECTIONAL_LIGHTS >= 3
-        if (i == 2) illuminated += directionalShadow(uDirectionalLightShadowMaps[2], light.shadowMapSize, lightUV, lightDistView - light.bias, light.near, light.far);
-#endif
-#if NUM_DIRECTIONAL_LIGHTS >= 4
-        if (i == 3) illuminated += directionalShadow(uDirectionalLightShadowMaps[3], light.shadowMapSize, lightUV, lightDistView - light.bias, light.near, light.far);
-#endif
-#if NUM_DIRECTIONAL_LIGHTS >= 5
-        if (i == 4) illuminated += directionalShadow(uDirectionalLightShadowMaps[4], light.shadowMapSize, lightUV, lightDistView - light.bias, light.near, light.far);
-#endif
-#if NUM_DIRECTIONAL_LIGHTS >= 6
-        if (i == 5) illuminated += directionalShadow(uDirectionalLightShadowMaps[5], light.shadowMapSize, lightUV, lightDistView - light.bias, light.near, light.far);
-#endif
-#if NUM_DIRECTIONAL_LIGHTS >= 7
-        if (i == 6) illuminated += directionalShadow(uDirectionalLightShadowMaps[6], light.shadowMapSize, lightUV, lightDistView - light.bias, light.near, light.far);
-#endif
-#if NUM_DIRECTIONAL_LIGHTS >= 8
-        if (i == 7) illuminated += directionalShadow(uDirectionalLightShadowMaps[7], light.shadowMapSize, lightUV, lightDistView - light.bias, light.near, light.far);
-#endif
-
-        if (illuminated > 0.0) {
-            vec3 L = normalize(-light.direction);
-            vec3 N = normalWorld;
-            vec3 H = normalize(V + L);
-            float NdotL = max(0.0, dot(N, L));
-            float HdotV = max(0.0, dot(H, V));
-            float NdotV = max(0.0, dot(N, V));
-
-            vec3 F = FresnelSchlick(HdotV, F0);
-
-            vec3 kS = F;
-            vec3 kD = vec3(1.0) - kS;
-
-            kD *= 1.0 - metallic;
-
-            float NDF = GGX(N, H, roughness * roughness); // TODO: roughtness^2 or not?
-
-            float G = GeometrySmith(N, V, L, roughness * roughness); // TODO: roughtness^2 or not?
-
-            vec3 nominator = NDF * G * F;
-            float denominator = 4.0 * NdotV * NdotL + 0.001;
-            vec3 brdf = nominator / denominator;
-
-            vec3 lightColor = decode(light.color, 3).rgb;
-            lightColor *= light.color.a; // intensity
-            vec3 finalLight = NdotL * lightColor * illuminated;
-
-            directDiffuse += kD * baseColor / PI * finalLight;
-            directSpecular += brdf * finalLight;
-        }
-    }
-#endif
-
-#if NUM_POINT_LIGHTS > 0
-    for(int i=0; i<NUM_POINT_LIGHTS; i++) {
-        PointLight light = uPointLights[i];
-
-        vec3 L = light.position - vPositionWorld;
-        float dist = length(L);
-        L /= dist;
-
-        float dotNL = max(0.0, dot(normalWorld, L));
-
-        // Based on UE4
-        float distanceRatio = clamp(1.0 - pow(dist/light.radius, 4.0), 0.0, 1.0);
-        float falloff = (distanceRatio * distanceRatio) / (dist * dist + 1.0);
-
-        vec3 lightColor = decode(light.color, 3).rgb;
-        lightColor *= light.color.a;
-        //TODO: specular light conservation
-        // directDiffuse += baseColor * dotNL * lightColor * falloff;
-        // directSpecular += directSpecularGGX(normalWorld, eyeDirWorld, L, roughness, F0) * light.color.rgb * falloff;
-
-        vec3 N = normalWorld;
-        vec3 H = normalize(V + L);
-        float NdotL = max(0.0, dot(N, L));
-        float HdotV = max(0.0, dot(H, V));
-        float NdotV = max(0.0, dot(N, V));
-
-        vec3 F = FresnelSchlick(HdotV, F0);
-
-        vec3 kS = F;
-        vec3 kD = vec3(1.0) - kS;
-
-        kD *= 1.0 - metallic;
-
-        float NDF = GGX(N, H, roughness);
-
-        float G = GeometrySmith(N, V, L, roughness * roughness);
-
-        vec3 nominator = NDF * G * F;
-        float denominator = 4.0 * NdotV * NdotL + 0.001;
-        vec3 brdf = nominator / denominator;
-
-        vec3 radiance = lightColor * falloff;
-
-        directDiffuse += kD * baseColor / PI * NdotL * radiance;
-        directSpecular += brdf * NdotL * radiance;
-    }
-#endif
-
-#if NUM_SPOT_LIGHTS > 0
-    for(int i=0; i<NUM_SPOT_LIGHTS; i++) {
-        SpotLight light = uSpotLights[i];
-
-        const float spotlightLinearAtt = 1.0;
-        float dist = distance(vPositionWorld, light.position);
-        vec3 vDir = (vPositionWorld - light.position) / dist;
-        float distAttenuation = 1.0/(dist * spotlightLinearAtt);
-
-        float fCosine = dot(light.direction, vDir);
-        float cutOff = cos(light.angle);
-
-        float fDif = 1.0 - cutOff;
-        float fFactor = clamp((fCosine - cutOff)/fDif, 0.0, 1.0);
-
-        fFactor = pow(fFactor, 2.0);
-
-        if (fCosine > cutOff) {
-          vec3 L = normalize(-light.direction);
-
-          float intensity = max(dot(normalWorld, L), 0.0);
-          //vec4 spec = vec4(0.0);
-          //if (intensity > 0.0) {
-          //  vec3 eye = vec3(0.0, 0.0, 1.0);
-          //  vec3 h = normalize(ecLightDir + eye);
-          //  float intSpec = max(dot(h, ecN), 0.0);
-          //  spec = vec4(1.0) * pow(intSpec, 128.0);
-          //}
-
-          const float distAttenuation = 1.0;
-          //return fFactor * distAttenuation * intensity * spotlightColor + spec;
-          directDiffuse += baseColor * fFactor * distAttenuation * intensity * light.color.rgb;
-
-        }
-
-        /*
-        // Based on UE4
-        float distanceRatio = clamp(1.0 - pow(dist/light.radius, 4.0), 0.0, 1.0);
-        float falloff = (distanceRatio * distanceRatio) / (dist * dist + 1.0);
-
-        vec3 lightColor = decode(light.color, 3).rgb;
-        lightColor *= light.color.a;
-        //TODO: specular light conservation
-        // directDiffuse += baseColor * dotNL * lightColor * falloff;
-        // directSpecular += directSpecularGGX(normalWorld, eyeDirWorld, L, roughness, F0) * light.color.rgb * falloff;
-
-        vec3 N = normalWorld;
-        vec3 H = normalize(V + L);
-        float NdotL = max(0.0, dot(N, L));
-        float HdotV = max(0.0, dot(H, V));
-        float NdotV = max(0.0, dot(N, V));
-
-        vec3 F = FresnelSchlick(HdotV, F0);
-
-        vec3 kS = F;
-        vec3 kD = vec3(1.0) - kS;
-
-        kD *= 1.0 - metallic;
-
-        float NDF = GGX(N, H, roughness);
-
-        float G = GeometrySmith(N, V, L, roughness);
-
-        vec3 nominator = NDF * G * F;
-        float denominator = 4.0 * NdotV * NdotL + 0.001;
-        vec3 brdf = nominator / denominator;
-
-        vec3 radiance = lightColor * falloff;
-
-        directDiffuse += kD * baseColor / PI * NdotL * radiance;
-        directSpecular += brdf * NdotL * radiance;
-        */
-    }
-#endif
-
-    vec3 indirectArea = vec3(0.0);
-
-#if NUM_AREA_LIGHTS > 0
-    for(int i=0; i<NUM_AREA_LIGHTS; i++) {
-        AreaLight light = uAreaLights[i];
-
-        // TODO: kD, kS
-        //if (length(emissiveColor) == 0.0) {
-            indirectArea += evalAreaLight(light, vPositionWorld, normalWorld, baseColor, specularColor, roughness); //TEMP: fix roughness
-            //indirectArea = evalAreaLight(light, vPositionWorld, normalWorld,roughness); //TEMP: fix roughness
-            //indirectArea = evalAreaLight(light, vPositionView, (uNormalMatrix*normalWorld).xyz, diffuseColor, specularColor, roughness); //TEMP: fix roughness
-        //}
-    }
-#endif
-    vec3 color = emissiveColor + ao * indirectDiffuse + ao * indirectSpecular + directDiffuse + directSpecular + indirectArea;
-    // color = vec3(metallic);
-#else  // USE_NORMALS
-    vec3 color = ao * baseColor;
-#endif // USE_NORMALS
-    gl_FragData[0] = encode(vec4(color, 1.0), uOutputEncoding);
-    gl_FragData[1] = encode(vec4(emissiveColor, 1.0), uOutputEncoding);
-}
+  for(int i=0; i<NUM_DIRECTIONAL_LIGHTS; i++) {
+    DirectionalLight light = uDirectionalLights[i];
+    EvaluateDirectionalLight(data, light, i);    
+  }
+#endif
+#if NUM_POINT_LIGHTS > 0  
+  for(int i=0; i<NUM_POINT_LIGHTS; i++) {
+    PointLight light = uPointLights[i];
+    EvaluatePointLight(data, light, i);   
+  }    
+#endif  
+#if NUM_SPOT_LIGHTS > 0  
+  for(int i=0; i<NUM_SPOT_LIGHTS; i++) {
+    SpotLight light = uSpotLights[i];
+    EvaluateSpotLight(data, light, i);   
+  }    
+#endif 
+#if NUM_AREA_LIGHTS > 0  
+  for(int i=0; i<NUM_AREA_LIGHTS; i++) {
+    AreaLight light = uAreaLights[i];
+    EvaluateAreaLight(data, light, i);   
+  }    
+#endif   
+  vec3 color = data.emissiveColor + ao * data.indirectDiffuse + ao * data.indirectSpecular + data.directDiffuse + data.directSpecular;  
+    
+    
+    
+    
+    
+    
+   
+   
+   
+   
+#endif // USE_USE_UNLIT_WORKFLOW
+  //gl_FragData[0] = encode(vec4(color, 1.0), uOutputEncoding);
+  gl_FragData[0] = encode(vec4(color, 1.0), uOutputEncoding);
+  gl_FragData[1] = encode(vec4(data.emissiveColor, 1.0), uOutputEncoding);
+  //gl_FragData[0] = vec4(toGamma(color), 1.0);
+  #ifdef USE_BLEND
+  gl_FragData[0].a = data.opacity;
+  #endif
+}


uniform int uOutputEncoding;

float pi = 3.14159;
#define PI 3.14159265359
#define TwoPI (2.0 * 3.14159265359)

#if NUM_DIRECTIONAL_LIGHTS > 0

struct DirectionalLight {
    vec3 direction;
    vec4 color;
    mat4 projectionMatrix;
    mat4 viewMatrix;
    float near;
    float far;
    float bias;
    vec2 shadowMapSize;
};

uniform DirectionalLight uDirectionalLights[NUM_DIRECTIONAL_LIGHTS];
uniform sampler2D uDirectionalLightShadowMaps[NUM_DIRECTIONAL_LIGHTS];

#endif


#if NUM_POINT_LIGHTS > 0

struct PointLight {
    vec3 position;
    vec4 color;
    float radius;
};

uniform PointLight uPointLights[NUM_POINT_LIGHTS];

#endif

#if NUM_SPOT_LIGHTS > 0

struct SpotLight {
    vec3 position;
    vec3 direction;
    vec4 color;
    float angle;
    float distance;
};

uniform SpotLight uSpotLights[NUM_SPOT_LIGHTS];

#endif
//fron depth buf normalized z to linear (eye space) z
//http://stackoverflow.com/questions/6652253/getting-the-true-z-value-from-the-depth-buffer
float ndcDepthToEyeSpaceProj(float ndcDepth, float near, float far) {

varying vec3 vPositionWorld;
varying vec3 vPositionView;

#ifdef USE_INSTANCED_COLOR
varying vec4 vColor;
#endif
