Color xray::Shade(const Ray &ray, SurfPoint pt, const Object *obj, int ray_depth) {
Scene *scene = active_xrc->scene;
bool entering = true;
if(DotProduct(ray.dir, pt.normal) > 0.0) {
pt.normal = -pt.normal;
entering = false;
}
TexCoord tc = obj->GetTexCoords(pt.pos);
Vector3 vref = ray.dir.Normalized().Reflection(pt.normal);
MatPhong *mat;
if(!(mat = dynamic_cast<MatPhong*>(obj->GetMaterial()))) {
error("only phong materials supported currently\n");
exit(0);
}
Color diffuse = 0.0;
Color specular = 0.0;
int light_count = scene->lights.size();
for(int i=0; i<light_count; i++) {
Light *light = scene->lights[i];
Vector3 lpos = light->GetPRS(scene->anim.current_time).position;
Vector3 ldir = lpos - pt.pos;
ldir.Normalize();
scalar_t shadow_factor = ShadowRay(pt.pos, light);
if(shadow_factor == 0.0) continue;
Color lcol = light->GetColor() * light->GetIntensity();
scalar_t diffuse_coef = std::max(0.0, DotProduct(ldir, pt.normal));
diffuse += Color(mat->GetAttr(MAT_PHONG_DIFFUSE)(tc)) * lcol * diffuse_coef * shadow_factor;
scalar_t spec_pow = mat->GetAttr(MAT_PHONG_POWER)(tc).x;
scalar_t specular_coef = pow(std::max(0.0, DotProduct(ldir, vref)), spec_pow);
specular += Color(mat->GetAttr(MAT_PHONG_SPECULAR)(tc)) * lcol * specular_coef * shadow_factor;
}
scalar_t refl_coeff = mat->GetAttr(MAT_REFLECT)(tc).x;
scalar_t mat_ior = mat->GetAttr(MAT_IOR)(tc).x;
if(mat_ior > 1.0) {
refl_coeff *= std::max(0.0, std::min(Fresnel(DotProduct(-ray.dir, pt.normal), mat_ior), 1.0));
}
Color refl;
if(refl_coeff > active_xrc->ray_energy_threshold) {
Ray refl_ray = ray;
refl_ray.origin = pt.pos;
refl_ray.dir = ray.dir.Reflection(pt.normal);
refl_ray.energy *= refl_coeff;
float glossiness = mat->GetAttr(MAT_GLOSSINESS)(tc).x;
if(glossiness < small_number) {
refl = ShootRay(refl_ray, ray_depth + 1);
} else {
int samples = std::max(1, (active_xrc->glossy_samples / (ray_depth + 1)) / active_xrc->rays_per_pixel);
refl = SampleSolidAngle(refl_ray, glossiness, samples, ray_depth + 1);
active_xrc->stats.gloss_rays += samples;
}
}
scalar_t trans_coeff = mat->GetAttr(MAT_TRANSMIT)(tc).x;
Color trans;
if(trans_coeff > active_xrc->ray_energy_threshold) {
Ray trans_ray = ray;
trans_ray.origin = pt.pos;
trans_ray.energy *= trans_coeff;
scalar_t new_ior;
if(entering) {
new_ior = mat_ior;
trans_ray.Enter(new_ior);
} else {
trans_ray.Leave();
new_ior = trans_ray.ior;
}
trans_ray.dir = ray.dir.Refraction(pt.normal, ray.ior, new_ior);
if(DotProduct(trans_ray.dir, pt.normal) > 0.0) {
if(entering) {
trans_ray.Leave();
} else {
trans_ray.Enter(mat_ior);
}
}
trans = ShootRay(trans_ray, ray_depth + 1);
}
Color ambient = Color(mat->GetAttr(MAT_PHONG_AMBIENT)(tc)) * scene->ambient;
Color emissive = Color(mat->GetAttr(MAT_PHONG_EMISSIVE)(tc));
return ambient + emissive + diffuse + specular + refl * refl_coeff + trans * trans_coeff;
}