Ejemplo n.º 1
0
// Main rendering function. We compute a camera ray for each pixel of the image
// trace it and return a color. If the ray hits a sphere, we return the color of the
// sphere at the intersection point, else we return the background color.
void render(const unsigned size, const Sphere *spheres)
{
//  unsigned width = 640, height = 480;
  unsigned width = 1024, height = 768;
  Vec3 *image, *pixel, aux, raydir;
  Real invWidth = 1 / (Real)width, invHeight = 1 / (Real)height;
  Real fov = 30, aspectratio = width / (Real)height;
  Real xx, yy, angle = tan(M_PI * 0.5 * fov / 180.0);
  unsigned x, y, i;
  FILE *F;
  image = malloc(width * height * sizeof(*image));
  pixel = image;
  Vec3_new0(&aux);
  // Trace rays
  for (y = 0; y < height; ++y) {
    for (x = 0; x < width; ++x, ++pixel) {
      xx = (2 * ((x + 0.5) * invWidth) - 1) * angle * aspectratio;
      yy = (1 - 2 * ((y + 0.5) * invHeight)) * angle;
      Vec3_new(&raydir, xx, yy, -1);
      Vec3_normalize(&raydir);
      trace(pixel, &aux, &raydir, size, spheres, 0);
    }
  }
  // Save result to a PPM image (keep these flags if you compile under Windows)
  F = fopen("./untitled.ppm", "wb");
  fprintf(F, "P6\n%u %u\n255\n", width, height);
  for (i = 0; i < width * height; ++i) {
    fprintf(F, "%c%c%c",
            (unsigned char)(min(1.0, image[i].x) * 255),
            (unsigned char)(min(1.0, image[i].y) * 255),
            (unsigned char)(min(1.0, image[i].z) * 255));
  }
  fclose(F);
  free(image);
}
Ejemplo n.º 2
0
void generateSphere(Vector3int* dest, int num, double size) {
	int i;
	for(i=0; i < num; i++) {
		Vector3 tmp;
		tmp.x = random()-0.5;
		tmp.y = random()-0.5;
		tmp.z = random()-0.5;

		Vec3_normalize(&tmp);

		dest[i].x = (int)(tmp.x*size);
		dest[i].y = (int)(tmp.y*size);
		dest[i].z = (int)(tmp.z*size);
	}
}
Ejemplo n.º 3
0
// This is the main trace function. It takes a ray as argument (defined by its origin
// and direction). We test if this ray intersects any of the geometry in the scene.
// If the ray intersects an object, we compute the intersection point, the normal
// at the intersection point, and shade this point using this information.
// Shading depends on the surface property (is it transparent, reflective, diffuse).
// The function returns a color for the ray. If the ray intersects an object that
// is the color of the object at the intersection point, otherwise it returns
// the background color.
void trace(Vec3 *v,const Vec3 *rayorig, const Vec3 *raydir, 
  const unsigned size, const Sphere *spheres, const int depth)
{
  //if (raydir.length() != 1) std::cerr << "Error " << raydir << std::endl;
  Real tnear = INFINITY;
  const Sphere *sphere = NULL;
  unsigned i, j;
  Vec3 surfaceColor, phit, nhit, aux;
  Real bias;
  bool inside;
  // find intersection of this ray with the sphere in the scene
  for (i = 0; i < size; ++i) {
    Real t0 = INFINITY, t1 = INFINITY;
    if (Sphere_intersect(&spheres[i], rayorig, raydir, &t0, &t1)) {
      if (t0 < 0) t0 = t1;
      if (t0 < tnear) {
        tnear = t0;
        sphere = &spheres[i];
      }
    }
  }
  // if there's no intersection return black or background color
  if (!sphere) {
    Vec3_new1(v,2);
    return;
  }
  Vec3_new0(&surfaceColor); // color of the ray/surfaceof the object intersected by the ray
  // phit = rayorig + raydir * tnear; // point of intersection
  Vec3_axpy(&phit,tnear,raydir,rayorig);
  Vec3_subs(&nhit, &phit, &sphere->center); // normal at the intersection point
  Vec3_normalize(&nhit); // normalize normal direction
  // If the normal and the view direction are not opposite to each other 
  // reverse the normal direction. That also means we are inside the sphere so set
  // the inside bool to true. Finally reverse the sign of IdotN which we want
  // positive.
  bias = 1e-4; // add some bias to the point from which we will be tracing
  inside = false;
  if (Vec3_dot(raydir,&nhit) > 0) Vec3_minus(&nhit), inside = true;
  if ((sphere->transparency > 0 || sphere->reflection > 0) && depth < MAX_RAY_DEPTH) {
    Real facingratio = -Vec3_dot(raydir,&nhit);
    // change the mix value to tweak the effect
    Real fresneleffect = mix(pow(1 - facingratio, 3), 1, 0.1); 
    // compute reflection direction (not need to normalize because all vectors
    // are already normalized)
    Vec3 refldir, reflection, refraction;
    // refldir = raydir - nhit * 2 * raydir.dot(nhit);
    Vec3_axpy(&refldir, -2 * Vec3_dot(raydir, &nhit), &nhit, raydir);
    Vec3_normalize(&refldir);
    Vec3_axpy(&aux, bias, &nhit, &phit);
    trace( &reflection, &aux, &refldir, size, spheres, depth + 1);
    Vec3_new0(&refraction);
    // if the sphere is also transparent compute refraction ray (transmission)
    if (sphere->transparency) {
      Real ior = 1.1, eta = (inside) ? ior : 1 / ior; // are we inside or outside the surface?
      Real cosi = -Vec3_dot(&nhit,raydir);
      Real k = 1 - eta * eta * (1 - cosi * cosi);
      Vec3 refrdir;
      // refrdir = raydir * eta + nhit * (eta *  cosi - sqrt(k));
      refrdir = nhit; Vec3_scale(&refrdir, eta *  cosi - sqrt(k));
      Vec3_axpy(&refrdir, eta, raydir, &refrdir);
      Vec3_normalize(&refrdir);
      Vec3_axpy(&aux, -bias, &nhit, &phit);
      trace(&refraction, &aux, &refrdir, size, spheres, depth + 1);
    }
    // the result is a mix of reflection and refraction (if the sphere is transparent)
    //surfaceColor = (reflection * fresneleffect + 
    //  refraction * (1 - fresneleffect) * sphere->transparency) * sphere->surfaceColor;
    surfaceColor = refraction;
    Vec3_scale(&surfaceColor, (1 - fresneleffect) * sphere->transparency);
    Vec3_axpy(&surfaceColor, fresneleffect, &reflection, &surfaceColor);
    Vec3_prod(&surfaceColor, &surfaceColor, &sphere->surfaceColor);
  }
  else {
    // it's a diffuse object, no need to raytrace any further
    for (i = 0; i < size; ++i) {
      if (spheres[i].emissionColor.x > 0) {
        // this is a light
        Vec3 transmission, lightDirection;
        Vec3_new1(&transmission, 1);
        Vec3_subs(&lightDirection, &spheres[i].center, &phit);
        Vec3_normalize(&lightDirection);
        for (j = 0; j < size; ++j) {
          if (i != j) {
            Real t0, t1;
            Vec3_axpy(&aux, bias, &nhit, &phit);
            if (Sphere_intersect(&spheres[j], &aux, &lightDirection, &t0, &t1)) {
// Truco para suavizar sombras
if (spheres[j].transparency == 0.0) {
              Vec3_new0(&transmission);
              break;
} else {
  Vec3_scale(&transmission, spheres[j].transparency);
  Vec3_prod(&transmission, &transmission, &spheres[j].surfaceColor);
}
            }
          }
        }
        //surfaceColor += sphere->surfaceColor * transmission * 
        //  std::max(T(0), nhit.dot(lightDirection)) * spheres[i]->emissionColor;
        Vec3_prod(&aux, &sphere->surfaceColor, &transmission);
        Vec3_prod(&aux, &aux, &spheres[i].emissionColor);
        Vec3_axpy(&surfaceColor, max(0.0, Vec3_dot(&nhit, &lightDirection)), &aux, &surfaceColor);
      }
    }
  }

  Vec3_add(v, &surfaceColor, &sphere->emissionColor);
}