@Override
    public Vector3 color(Scene scene, Ray ray) {
        Vector3 color = defaultColor;
        
        Collision collision = trace(scene, ray);
        
        if (collision != null) {  
            Vector3 collisionPoint = ray.getFrom().add(ray.getDirection().multiply(collision.getDistance()));
            Vector3 collisionNorm = collision.getPrimitive().getNorm(collisionPoint);
            
            if (collision.isInversed()) {
                collisionNorm = collisionNorm.inverse();
            }
            
            Material material = collision.getPrimitive().getMaterial(collisionPoint);
            
            // Ambient
            color = material.getAmbient();            
            
            // For all lights we need to calculate diffuse and specular components
            for (Light light : scene.getLights()) {
                double amountOfLight = findAmountOfLight(scene, light, collisionPoint);
                
                if (amountOfLight >= MathUtils.RAY_POWER_THRESHOLD) {
                    Vector3 lightDirection = collisionPoint.subtract(light.getPosition()).normalize();
                    
                    // Diffuse
                    double cos = collisionNorm.dotProduct(lightDirection.inverse());
                    Vector3 diffuseColor = material.getDiffuse().multiply(amountOfLight * cos);
                    color = color.add(diffuseColor);
                    
                    // Specular                    
                    Vector3 lightReflectionDirection = MathUtils.reflect(lightDirection.inverse(), collisionNorm);
                    cos = lightReflectionDirection.dotProduct(ray.getDirection().inverse());
                    Vector3 specularColor = material.getSpecular().multiply(amountOfLight * Math.pow(cos, material.getSpecularPower()));
                    color = color.add(specularColor);
                }
            }
            
            // Reflection
            if (material.getReflectionPower() * ray.getPower() >= MathUtils.RAY_POWER_THRESHOLD) {
                Vector3 reflectionDirection = MathUtils.reflect(ray.getDirection().inverse(), collisionNorm);                        
                Ray reflectionRay = new RayImpl(collisionPoint, reflectionDirection, ray.getPower() * material.getReflectionPower());
                Vector3 reflectionColor = color(scene, reflectionRay);
                color = color.add(reflectionColor);
            }          
            
            // Refraction
            color = color.add(refractionStrategy.refract(this, scene, ray, collisionPoint, collisionNorm, collision.getPrimitive()));            
        }
        
        return color.multiply(ray.getPower());
    }