00001
00002
00003
00004
00005
00006
00007 #include <Magick++.h>
00008 #include <cstdlib>
00009 #include <ctime>
00010 #include <dlfcn.h>
00011 #include <getopt.h>
00012 #include <glob.h>
00013 #include <iostream>
00014 #include <ncurses.h>
00015 #include <unistd.h>
00016 #include <signal.h>
00017 #include <string>
00018
00019 #include "raytrace_defs.h"
00020 #include "renderable.h"
00021 #include "ray.h"
00022 #include "scene.h"
00023 #include "color.h"
00024
00025 using std::vector;
00026 using std::cout;
00027 using std::endl;
00028 using std::string;
00029 using Magick::Image;
00030 using Magick::Color;
00031 using Magick::ColorRGB;
00032
00033 struct raytrace_info rt_info;
00034
00035 void trace_ray(ColorRGB &pixel, const Ray &ray, int depth);
00036
00041
00042 unsigned long trace_rays(Image & img, Point3D eye) {
00043
00044 double min_x, max_x;
00045 double min_y, max_y;
00046 Scene * scene = Scene::get_instance();
00047
00048 max_x = 16;
00049 min_x = -max_x;
00050 max_y = 16 * ((double)scene->get_viewport_pixel_height() / (double)scene->get_viewport_pixel_width());
00051 min_y = -max_y;
00052
00053
00054 double dx = (max_x - min_x) / scene->get_viewport_pixel_width();
00055 double dy = (max_y - min_y) / scene->get_viewport_pixel_height();
00056
00057
00058 double start_x = min_x + (dx * 0.5);
00059 double start_y = min_y + (dy * 0.5);
00060
00065
00066
00067
00068 Point3D screen_intersection(start_x, start_y, 0.0);
00069 rt_info.rendered_pixels = 0;
00070 for (int y = 0; y < scene->get_viewport_pixel_height(); ++y) {
00071 screen_intersection.x = start_x;
00072 for (int x = 0; x < scene->get_viewport_pixel_width(); ++x) {
00073 rt_info.rendered_pixels++;
00074
00075
00076
00077
00078 double modifier = 1.0;
00079 if(x + 1 == scene->get_viewport_pixel_width()) {
00080 modifier = -1.0;
00081 }
00082
00083 ColorRGB color;
00084 Point3D p = Point3D(screen_intersection.x, screen_intersection.y, screen_intersection.z);
00085 Ray ray(eye, p - eye);
00086 trace_ray(color, ray, 0);
00087
00088 p = Point3D(screen_intersection.x + (dx * modifier), screen_intersection.y, screen_intersection.z);
00089 ColorRGB next_color;
00090 Ray next_ray(eye, p - eye);
00091 trace_ray(next_color, next_ray, 0);
00092
00093 if(!(color == next_color)) {
00094 vector<ColorRGB> colors;
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 double sdx = dx / (2 * scene->get_subpixel_sqrt());
00113 double sdy = dy / (2 * scene->get_subpixel_sqrt());
00114
00115
00116 double sy = screen_intersection.y - (dy * 0.5) + (sdy * 0.5);
00117 for (int i = 0; i < scene->get_subpixel_sqrt(); i++) {
00118
00119
00120 double sx = screen_intersection.x - (dx * 0.5) + (sdx * 0.5);
00121 for (int j = 0; j < scene->get_subpixel_sqrt(); j++) {
00122 double sy_jitter = sy + jitter(sdy);
00123 double sx_jitter = sx + jitter(sdx);
00124
00125
00126 Point3D subpixel(sx_jitter, sy_jitter, screen_intersection.z);
00127
00128
00129
00130 Ray ray(eye, subpixel - eye);
00131
00132
00133 ColorRGB color;
00134 trace_ray(color, ray, 0);
00135 colors.push_back(color);
00136
00137 sx += sdx;
00138 }
00139 sy += sdy;
00140 }
00141
00142
00143 double red, green, blue;
00144 red = green = blue = 0.0;
00145 vector<ColorRGB>::iterator iter, end;
00146 for (iter = colors.begin(), end = colors.end(); iter != end; iter++) {
00147 red += iter->red();
00148 green += iter->green();
00149 blue += iter->blue();
00150 }
00151 int colors_size = colors.size();
00152 color = ColorRGB((red / colors_size), (green / colors_size), (blue / colors_size));
00153 }
00154
00155 img.pixelColor(x, y, color);
00156
00157 screen_intersection.x += dx;
00158 }
00159
00160 screen_intersection.y += dy;
00161 }
00162
00163 return rt_info.traced_rays;
00164 }
00165
00166
00172
00173 void trace_ray(ColorRGB &pixel, const Ray &ray, int depth) {
00174 Renderable * primitive = NULL;
00175 double dist = INF;
00176 Scene * scene = Scene::get_instance();
00177 int max_depth = scene->get_max_recurse_depth();
00178
00179 if (depth <= max_depth) {
00180
00181 if ( depth == 0 ) {
00182 rt_info.primary_rays++;
00183 }
00184
00185
00186 rt_info.traced_rays++;
00187 if (rt_info.traced_rays % REPORT_FACTOR == 0) {
00188 int x, y;
00189 getyx(stdscr, y, x);
00190 long t = (long)difftime(time(NULL), rt_info.start_time);
00191 mvprintw(y - 1, 0, "Elapsed time: %02i:%02i:%02i", t / 3600, (t / 60) % 60, t % 60);
00192 mvprintw(y, x + 2, "%02.2f%% done", 100 * (double)(rt_info.rendered_pixels) / (double)(scene->get_viewport_pixel_width() * scene->get_viewport_pixel_height()));
00193 move(y, x);
00194 refresh();
00195 }
00196
00197
00198 if ((primitive = scene->find_collision(ray, dist)) != NULL) {
00199 Vector dir = ray.direction();
00200 Point3D intersection_point = ray.origin() + (dir * dist);
00201 Vector reflect;
00202 Vector refract;
00203
00204
00205 pixel += primitive->get_color_contribution(intersection_point, ray, reflect, refract);
00206
00207
00208 double reflection_coefficient = primitive->get_reflection(intersection_point);
00209
00210
00211 if (reflection_coefficient > 0.0) {
00212 depth++;
00213 trace_ray(pixel, Ray(intersection_point, reflect), depth);
00214 depth--;
00215 }
00216
00217
00218 if (primitive->get_opacity(intersection_point) > OPAQUE) {
00219 depth++;
00220 trace_ray(pixel, Ray(intersection_point, refract), depth);
00221 depth--;
00222 }
00223
00224 }
00225 }
00226 }
00227
00228
00230
00231 void print_stats(string fname, int elapsed, long primary_rays, long traced_rays) {
00232 int hours, minutes, seconds;
00233 seconds = elapsed;
00234 hours = seconds / 3600;
00235 seconds %= 3600;
00236 minutes = seconds / 60;
00237 seconds %= 60;
00238 cout << endl;
00239 cout << endl;
00240 cout << "Traced " << rt_info.traced_rays << " light rays into the scene!" << endl;
00241 cout << endl;
00242 cout << endl;
00243
00244 printf("Rendering %s took %i seconds (%02i:%02i:%02i)\n", fname.c_str(), elapsed, hours, minutes, seconds);
00245
00246 cout.setf(cout.fixed);
00247 cout.precision(5);
00248 cout << "Average rays per primary ray : " << (double)traced_rays / (double)primary_rays << endl;
00249 cout << "Average time per " << REPORT_FACTOR << " primary rays: " << ((double)elapsed / (double)primary_rays) * REPORT_FACTOR << "s" << endl;
00250 cout << "Average time per " << REPORT_FACTOR << " rays : " << ((double)elapsed / (double)traced_rays ) * REPORT_FACTOR << "s" << endl;
00251 }
00252
00253
00255
00256 void load_plugins() {
00257 glob_t glob_data;
00258 glob("plugins/*.so", 0, NULL, &glob_data);
00259
00260 char ** iter = glob_data.gl_pathv;
00261 for (; *iter != NULL ; ++iter) {
00262
00263
00264 log_info("Attempting to load plugin '%s'...\n", *iter);
00265 printf("Attempting to load plugin '%s'...\n", *iter);
00266 if(dlopen(*iter, RTLD_NOW)) {
00267 log_info("Finished loading plugin '%s'\n", *iter);
00268 printf("Finished loading plugin '%s'\n", *iter);
00269 }
00270 else {
00271 log_crit("Failed to load plugin '%s' with error %s\n", *iter, dlerror());
00272 exit_mbrt(EXIT_FAILURE);
00273 }
00274 }
00275
00276 globfree(&glob_data);
00277 }
00278
00279
00282
00283 void register_signal_handlers() {
00284 struct sigaction sigact;
00285 sigact.sa_handler = exit_mbrt;
00286 sigaction(15, &sigact, NULL);
00287
00288 }
00289
00290
00291
00292 int main(int argc, char ** argv) {
00293 time_t start_time = time(NULL);
00294 string filename("scene.xml");
00295 srand(time(NULL));
00296
00297 openlog("mbrt", LOG_CONS, LOG_SYSLOG);
00298 log_info("****************** Starting mbrt ******************\n");
00299
00300
00301 register_signal_handlers();
00302 load_plugins();
00303
00304
00305
00306 extern char *optarg;
00307 extern int optind, opterr, optopt;
00308 int option_index = 0;
00309 static struct option long_options[] = {
00310 {"scene", 1, NULL, 's'},
00311 {"output", 1, NULL, 'o'},
00312 {0, 0, 0, 0}
00313 };
00314
00315 log_info("5***************** Starting mbrt ******************\n");
00316 string outfname("");
00317 int opt_val = -2;
00318 while ( (opt_val = getopt_long (argc, argv, "s:o:", long_options, &option_index)) != -1 ) {
00319 switch (opt_val) {
00320 case 's':
00321 filename = optarg;
00322 break;
00323 case 'o':
00324 outfname = optarg;
00325 break;
00326 }
00327 }
00328 log_info("4***************** Starting mbrt ******************\n");
00329 unsigned long traced_rays;
00330 int x, y;
00331 initscr();
00332 getmaxyx(stdscr, y, x);
00333 mvprintw(y - 1, 0, "Tracing %s...", filename.c_str());
00334
00335 log_info("3***************** Starting mbrt ******************\n");
00336
00338
00340
00341 log_info("3.9***************** Starting mbrt ******************\n");
00342 Scene * scene = Scene::get_instance(filename);
00343 log_info("3.8***************** Starting mbrt ******************\n");
00344 if(outfname == "") {
00345 log_info("3.7***************** Starting mbrt ******************\n");
00346 outfname = scene->get_output_filename();
00347 }
00348 log_info("3.6***************** Starting mbrt ******************\n");
00349
00350 log_info("2***************** Starting mbrt ******************\n");
00351
00352
00353 Image img(scene->get_geometry(), "red");
00354 log_info("1***************** Starting mbrt ******************\n");
00355
00356
00357 traced_rays = trace_rays(img, scene->get_camera());
00358
00359
00360 img.write(outfname);
00361
00362
00363
00364 time_t end_time = time(NULL);
00365 int elapsed = end_time - start_time;
00366 int primary_rays = 4 * scene->get_viewport_pixel_width() * scene->get_viewport_pixel_height();
00367 endwin();
00368 cout << outfname << endl;
00369 print_stats(filename, elapsed, primary_rays, traced_rays);
00370
00371 log_info("****************** Exiting mbrt ******************\n");
00372 closelog();
00373 exit(EXIT_SUCCESS);
00374 }
00375