Exemple #1
0
Color ray_shade(int level, Real w, Ray v, RContext *rc, Object *ol)
{
  Inode *i = ray_intersect(ol, v);
  if (i != NULL) { Light *l; Real wf;
    Material *m = i->m;
    Vector3 p = ray_point(v, i->t); 
    Cone  recv = cone_make(p, i->n, PIOVER2);
    Color c = c_mult(m->c, c_scale(m->ka, ambient(rc)));
    rc->p = p;

    for (l = rc->l; l != NULL; l = l->next) 
      if ((*l->transport)(l, recv, rc) && (wf = shadow(l, p, ol)) > RAY_WF_MIN)
	c = c_add(c, c_mult(m->c,
		     c_scale(wf * m->kd * v3_dot(l->outdir,i->n), l->outcol)));

    if (level++ < MAX_RAY_LEVEL) {
      if ((wf = w * m->ks) > RAY_WF_MIN) {
	Ray r = ray_make(p, reflect_dir(v.d, i->n));
        c = c_add(c, c_mult(m->s,
		     c_scale(m->ks, ray_shade(level, wf, r, rc, ol))));
      }
      if ((wf = w * m->kt) > RAY_WF_MIN) {
	Ray t = ray_make(p, refract_dir(v.d, i->n, (i->enter)? 1/m->ir: m->ir));
	if (v3_sqrnorm(t.d) > 0) {
	  c = c_add(c, c_mult(m->s,
		       c_scale(m->kt, ray_shade(level, wf, t, rc, ol))));
	}
      }
    }
    inode_free(i); 
    return c;
  } else {
    return BG_COLOR;
  }
}
// 屈折面
Color PathTracer::Radiance_Refraction(const Scene &scene, const Ray &ray, Random &rnd, const int depth, Scene::IntersectionInformation &intersect, const Vector3 &normal, double russian_roulette_prob) {
  bool into = intersect.hit.normal.dot(normal) > 0.0;

  Vector3 reflect_dir = ray.dir - normal*2*ray.dir.dot(normal);
  reflect_dir.normalize();
  double n_vacuum = REFRACTIVE_INDEX_VACUUM;
  double n_obj = intersect.object->material.refraction_rate;
  double n_ratio = into ? n_vacuum/n_obj : n_obj/n_vacuum;

  double dot = ray.dir.dot(normal);
  double cos2t = 1-n_ratio*n_ratio*(1-dot*dot);

  // 反射方向の直接光の評価
  Color reflect_direct;
  Ray reflect_ray(intersect.hit.position, reflect_dir);
  Scene::IntersectionInformation reflected_hit;
  if (m_performNextEventEstimation && scene.CheckIntersection(reflect_ray, reflected_hit)) {
    reflect_direct = reflected_hit.object->material.emission;
  }

  if (cos2t < 0) {
    // 全反射
    Color income = reflect_direct + Radiance(scene, Ray(intersect.hit.position, reflect_dir), rnd, depth+1);
    Color weight = intersect.object->material.color / russian_roulette_prob;
    return Vector3(weight.x*income.x, weight.y*income.y, weight.z*income.z);
  }

  // 屈折方向
  Vector3 refract_dir( ray.dir*n_ratio - intersect.hit.normal * (into ? 1.0 : -1.0) * (dot*n_ratio + sqrt(cos2t)) );
  refract_dir.normalize();
  const Ray refract_ray(intersect.hit.position, refract_dir);
  // 屈折方向の直接光の評価
  Color refract_direct;
  if (m_performNextEventEstimation && scene.CheckIntersection(refract_ray, reflected_hit)) {
    refract_direct = reflected_hit.object->material.emission;
  }

  // Fresnel の式
  double F0 = (n_obj-n_vacuum)*(n_obj-n_vacuum)/((n_obj+n_vacuum)*(n_obj+n_vacuum));
  double c = 1 - ( into ? -dot : -refract_dir.dot(normal) );  // 1-cosθ
  double Fr = F0 + (1-F0)*pow(c, 5.0);    // Fresnel (反射の割合)
  double n_ratio2 = n_ratio*n_ratio;  // 屈折前後での放射輝度の変化率
  double Tr = (1-Fr)*n_ratio2;        // 屈折直後→直前の割合

  Color income, weight;

  if (depth > 2) {
    // 反射 or 屈折のみ追跡
    const double reflect_prob = 0.1 + 0.8 * Fr;
    if (rnd.nextDouble() < reflect_prob) {
      // 反射
      income = (reflect_direct + Radiance(scene, Ray(intersect.hit.position, reflect_dir), rnd, depth+1)) * Fr;
      weight = intersect.texturedHitpointColor / (russian_roulette_prob * reflect_prob);
    } else {
      // 屈折
      income = (refract_direct + Radiance(scene, refract_ray, rnd, depth+1)) * Tr;
      weight = intersect.texturedHitpointColor / (russian_roulette_prob * (1 - reflect_prob));
    }
  } else {
    // 反射と屈折両方追跡
    m_omittedRayCount++;
    income =
      (reflect_direct + Radiance(scene, Ray(intersect.hit.position, reflect_dir), rnd, depth+1)) * Fr +
      (refract_direct + Radiance(scene, refract_ray, rnd, depth + 1)) *Tr;
    weight = intersect.texturedHitpointColor / russian_roulette_prob;
  }

  return /*intersect.object->material.emission +*/ Vector3(weight.x*income.x, weight.y*income.y, weight.z*income.z);
}