void render(t_rt *rt) { int x; int y; float increment_x; float increment_y; t_camera *camera; t_ray ray; t_hit hit; if (rt->rendered) { mlx_update(rt->gfx); return ; } camera = rt->scene->active_camera; if (camera == NULL) die("No main camera set."); increment_x = camera->viewplane.width / camera->resolution_width; increment_y = camera->viewplane.height / camera->resolution_height; vec3_copy(&ray.origin, &camera->position); y = 0; while (y < rt->height) { x = 0; while (x < rt->width) { set_ray_direction(&ray, camera, increment_x * x, increment_y * y); raycast(&ray, &hit, 2, NULL); if (hit.object != NULL) draw_pixel(rt->gfx, x, y, vec3_to_color(&hit.color)); else draw_pixel(rt->gfx, x, y, 0x333333); x++; } y++; } rt->rendered = 1; mlx_update(rt->gfx); }
/* Do the actual raytracing */ void raytrace(Image *src, Camera *camera, BlackHole *blackhole, KerrMetric *kerr) { // TODO: better to walk across local sky with spherical coordinates? I think this might warp the view because have effectively made the viewing plane curved... double arcLengthHoriz = camera->lensAngle; double arcLengthVert = ((double)src->rows/(double)src->cols)*arcLengthHoriz; double horizStep = arcLengthHoriz/src->cols; double vertStep = arcLengthVert/src->rows; double rayPhi, rayTheta; printf("arcLengthHoriz: %f\n", arcLengthHoriz); printf("arcLengthVert: %f\n", arcLengthVert); printf("Raytracing...\n\n"); // walk along the local sky, shooting a ray for each pixel for (int row=0;row<src->rows;row++) { rayTheta = (M_PI/2) - arcLengthVert/2 + row*vertStep; for (int col=0;col<src->cols;col++) { rayPhi = (M_PI) + arcLengthHoriz/2 - col*horizStep; Ray ray; set_ray_location(&ray, rayTheta, rayPhi); // direction of incoming ray in camera spherical coord set_ray_normal(&ray); // direction of incoming ray in camera Cartesian coord set_ray_direction(&ray, camera); // direction of motion of incoming ray in camera Cartesian coord set_ray_momenta(&ray, kerr); // printf("Ray info:\n"); // printf(" Theta, Phi: (%f, %f)\n", ray.theta, ray.phi); // printf(" Nx, Ny, Nz: (%f, %f, %f)\n", ray.Nx, ray.Ny, ray.Nz); // printf(" Fx, Fy, Fz: (%f, %f, %f)\n", ray.Fx, ray.Fy, ray.Fz); // printf(" Fr, Ftheta, Fphi: (%f, %f, %f)\n", ray.Fr, ray.Ftheta, ray.Fphi); // printf(" Pt, Pr, Ptheta, Pphi: (%f, %f, %f, %f)\n", ray.Pt, ray.Pr, ray.Ptheta, ray.Pphi); // printf(" Axial angular momentum (b): %f\n", ray.b); // printf(" Carter constant (q): %f\n\n", ray.q); // check, using the ray constants b and q, whether it came from the horizon or the celestial sphere // first though, need to calculate some condition requirements double b1, b2 = 0.0; double r1, r2 = 0.0; double q0 = 0.0; double r0 = 0.0; // localize some things, also precalculate to keep things pretty & readable double b = ray.b; double a = kerr->a; double q = ray.q; double cubeRoot2 = pow(2, 1/3.); // 1.259921049894873... // calculate the radius bounds of unstably trapped photons r1 = 2.0*(1.0 + cos((2.0/3.0)*acos(-a))); r2 = 2.0*(1.0 + cos((2.0/3.0)*acos(a))); // printf("Radius interval of unstably trapped photons [r1, r2]: %f, %f\n", r1, r2); // calculate a constant of motion for photons on the radius bounds b2 = -((r1*r1*r1) - 3*r1*r1 + a*a*r1 + a*a) / (a*(r1 - 1)); b1 = -((r2*r2*r2) - 3*r2*r2 + a*a*r2 + a*a) / (a*(r2 - 1)); printf("b1, b2: %f, %f\n", b1, b2); // get the value of r0 from parametric equations b(r0) in order to calculate q(r0) double tmpQ = (a*a + a*b - 3); double tmp = pow(sqrt(108.0*tmpQ*tmpQ*tmpQ + (54 - 54.0*a*a)*(54 - 54.0*a*a)) - 54.0*a*a + 54.0, 1/3.); r0 = -(cubeRoot2*tmpQ / tmp) + (tmp / 3.0*cubeRoot2) + 1.0; // printf("r0: %f\n", r0); double r03 = r0*r0*r0; // calculate another constant of motion q0 = -(r03*(r03 - 6.0*r0*r0 + 9.0*r0 - 4.0*a*a)) / (a*a*(b - 1)*(b - 1)); // printf("q0(r0): %f\n", q0); if ((b1 < b && b < b2) && q < q0) { // there are no radial turning points for this {b, q} if (ray.Pr > 0) { // ray came from horizon src->data[row][col].rgb[0] = 1.0; src->data[row][col].rgb[1] = 0.0; src->data[row][col].rgb[2] = 0.0; } else { // ray came from celestial sphere src->data[row][col].rgb[0] = 0.0; src->data[row][col].rgb[1] = 1.0; src->data[row][col].rgb[2] = 0.0; // src->data[row][col].rgb[0] = 176.0/255; // src->data[row][col].rgb[1] = 196.0/255; // src->data[row][col].rgb[2] = 222.0/255; } } else { // there are two radial turning points... // need to calculate some roots of equations for a null geodesic double rUp = 0.0; double delta = kerr->delta; double P = sqrt(delta*((b-a)*(b-a) + q)); printf("P: %f\n", P); printf("a: %f\n", a); // the two positive real roots of R(r) = 0; we want the bigger one double rUp1 = -a*a - P + a*b; double rUp2 = -a*a + P + a*b; printf("rUp1: sqrt(%f)\n", rUp1); printf("rUp2: sqrt(%f)\n\n", rUp2); if (rUp1 > rUp2) { rUp = rUp1; } else { rUp = rUp2; } // printf("rUp: %f\n", rUp); if (camera->location[0] >= rUp) { // ray came from celestial sphere src->data[row][col].rgb[0] = 0.0; src->data[row][col].rgb[1] = 0.0; src->data[row][col].rgb[2] = 1.0; // src->data[row][col].rgb[0] = 176.0/255; // src->data[row][col].rgb[1] = 196.0/255; // src->data[row][col].rgb[2] = 222.0/255; } else { // ray came from horizon src->data[row][col].rgb[0] = 0.5; src->data[row][col].rgb[1] = 0.0; src->data[row][col].rgb[2] = 0.5; } } } } }