public override Color shade(ref Shade sr)
    {
        Vector3 wo         = -sr.ray.direction;
        Color   L          = ambient_brdf.rho(ref sr, ref wo) * sr.w.ambient_ptr.L(ref sr);
        int     num_lights = sr.w.lights.Count;

        for (int j = 0; j < num_lights; j++)
        {
            Vector3 wi     = sr.w.lights[j].get_direction(ref sr);
            float   ndotwi = Vector3.Dot(sr.normal, wi);
            if (ndotwi > 0.0)
            {
                bool inshadow = false;
                if (sr.w.lights [j].cast_shadows)
                {
                    Ray shadowRay = new Ray(sr.hit_point, wi);
                    inshadow = sr.w.lights [j].in_shadow(ref shadowRay, ref sr);
                }
                if (!inshadow)
                {
                    L += (diffuse_brdf.f(ref sr, ref wo, ref wi) + specular_brdf.f(ref sr, ref wo, ref wi)) * sr.w.lights [j].L(ref sr) * ndotwi;
                }
            }
        }

        return(L);
    }
    public override Color shade(ref Shade sr)
    {
        Vector3 wo         = -sr.ray.direction;
        Color   L          = ambient_brdf.rho(ref sr, ref wo) * sr.w.ambient_ptr.L(ref sr);
        int     num_lights = sr.w.lights.Count;

        for (int j = 0; j < num_lights; j++)
        {
            Vector3 wi     = sr.w.lights[j].get_direction(ref sr);
            float   ndotwi = Vector3.Dot(sr.normal, wi);
            if (ndotwi > 0.0)
            {
                L += diffuse_brdf.f(ref sr, ref wo, ref wi) * sr.w.lights[j].L(ref sr) * ndotwi;
            }
        }

        return(L);
    }