# HG changeset patch # User John Tsiombikas # Date 1402137396 -10800 # Node ID b1fc96c71bcc3a7fa5c444aac0d014411a90978b # Parent 53a98c148bf8302bbc1932996976aded4d0e6982 - lambert BRDF importance sampling - UI + commandline arguments - font rendering for showing status/progress diff -r 53a98c148bf8 -r b1fc96c71bcc data/serif.glyphmap Binary file data/serif.glyphmap has changed diff -r 53a98c148bf8 -r b1fc96c71bcc erebus.vcxproj --- a/erebus.vcxproj Sat Jun 07 09:14:17 2014 +0300 +++ b/erebus.vcxproj Sat Jun 07 13:36:36 2014 +0300 @@ -100,7 +100,7 @@ Console true - opengl32.lib;glut32.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;liberebus.lib;%(AdditionalDependencies) + opengl32.lib;glut32.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;liberebus.lib;libdrawtext-dbg.lib;%(AdditionalDependencies) $(OutDir);%(AdditionalLibraryDirectories) @@ -136,7 +136,7 @@ true true true - opengl32.lib;glut32.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;liberebus.lib;%(AdditionalDependencies) + opengl32.lib;glut32.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;liberebus.lib;libdrawtext.lib;%(AdditionalDependencies) $(OutDir);%(AdditionalLibraryDirectories) diff -r 53a98c148bf8 -r b1fc96c71bcc liberebus/src/brdf.cc --- a/liberebus/src/brdf.cc Sat Jun 07 09:14:17 2014 +0300 +++ b/liberebus/src/brdf.cc Sat Jun 07 13:36:36 2014 +0300 @@ -18,7 +18,7 @@ } tangent = Vector3(1.0f, 0.0f, 0.0f); - if(fabs(dot_product(normal, tangent)) - 1.0f < 1e-4f) { + if(fabs(fabs(dot_product(normal, tangent)) - 1.0f) < 1e-4f) { tangent = Vector3(0.0f, 0.0f, 1.0f); } Vector3 bitan = cross_product(normal, tangent); @@ -187,8 +187,14 @@ // --- class LambertRefl --- Vector3 LambertRefl::sample_dir(const SurfaceGeometry &geom, const Vector3 &outdir) const { - Vector3 dir = Vector3{randf(-1, 1), randf(-1, 1), randf(-1, 1)}.normalized(); - return dot_product(dir, geom.normal) < 0.0 ? -dir : dir; + // TODO: write a better uniform disk sampling that doesn't rely in rejection + Vector3 dir; + do { + dir = Vector3(randf(-1, 1), randf(-1, 1), 0); + } while(dir.length_sq() > 1.0); + dir.z = sqrt(1.0 - (dir.x * dir.x + dir.y * dir.y)); + + return geom.sample_to_world(dir); } float LambertRefl::eval(const SurfaceGeometry &geom, const Vector3 &outdir, const Vector3 &indir) const diff -r 53a98c148bf8 -r b1fc96c71bcc liberebus/src/erebus.cc --- a/liberebus/src/erebus.cc Sat Jun 07 09:14:17 2014 +0300 +++ b/liberebus/src/erebus.cc Sat Jun 07 13:36:36 2014 +0300 @@ -25,10 +25,8 @@ struct erebus *ctx = 0; try { ctx = new struct erebus; - ctx->tpool = new ThreadPool; } catch(...) { - delete ctx; return 0; } @@ -37,6 +35,7 @@ ctx->scn = 0; ctx->cur_time = 0; ctx->cur_frame = 0; + ctx->tpool = 0; erb_setoptf(ctx, ERB_OPT_GAMMA, 2.2); erb_setopti(ctx, ERB_OPT_MAX_ITER, 6); @@ -130,7 +129,11 @@ void erb_begin_frame(struct erebus *ctx, long ms) { - printf("starting new frame...\n"); + if(!ctx->tpool) { + int num_threads = erb_getopti(ctx, ERB_OPT_NUM_THREADS); + ctx->tpool = new ThreadPool(num_threads); + } + ++ctx->cur_frame; ctx->cur_sample = 0; ctx->cur_time = ms; @@ -201,7 +204,39 @@ int erb_get_progress(struct erebus *ctx) { - return 0; // TODO + struct erb_render_status st; + if(erb_get_status(ctx, &st) == -1) { + return 0; + } + return st.progress_percent; +} + +int erb_get_status(struct erebus *ctx, struct erb_render_status *stat) +{ + long pending = ctx->tpool->pending(); + if(!pending) { + return -1; + } + int xsz = ctx->fbimg.get_width(); + int ysz = ctx->fbimg.get_height(); + int xblocks = (xsz + BLKSZ - 1) / BLKSZ; + int yblocks = (ysz + BLKSZ - 1) / BLKSZ; + long num_blocks = xblocks * yblocks; + + stat->frames = stat->max_frames = 0; // TODO + + stat->blocks = num_blocks - pending; + stat->max_blocks = num_blocks; + + stat->samples = ctx->cur_sample ? ctx->cur_sample - 1 : 0; + if((stat->max_samples = erb_getopti(ctx, ERB_OPT_MAX_SAMPLES)) == INF_SAMPLES) { + stat->max_samples = stat->samples; + + stat->progress_percent = 100 * stat->blocks / stat->max_blocks; + } else { + stat->progress_percent = 100 * stat->samples / stat->max_samples; + } + return 0; } int erb_load_scene(struct erebus *ctx, const char *fname) diff -r 53a98c148bf8 -r b1fc96c71bcc liberebus/src/erebus.h --- a/liberebus/src/erebus.h Sat Jun 07 09:14:17 2014 +0300 +++ b/liberebus/src/erebus.h Sat Jun 07 13:36:36 2014 +0300 @@ -14,6 +14,13 @@ ERB_NUM_OPTIONS }; +struct erb_render_status { + long progress_percent; // derived from the data below + long blocks, max_blocks; // completed pixel blocks in current sample pass + long samples, max_samples; // completed samples in current frame + long frames, max_frames; // completed frames in multi-frame job +}; + #ifdef __cplusplus extern "C" { #endif @@ -36,6 +43,7 @@ int erb_render_rect(struct erebus *ctx, int x, int y, int width, int height, long timeout); int erb_get_progress(struct erebus *ctx); +int erb_get_status(struct erebus *ctx, struct erb_render_status *stat); int erb_load_scene(struct erebus *ctx, const char *fname); diff -r 53a98c148bf8 -r b1fc96c71bcc liberebus/src/threadpool.cc --- a/liberebus/src/threadpool.cc Sat Jun 07 09:14:17 2014 +0300 +++ b/liberebus/src/threadpool.cc Sat Jun 07 13:36:36 2014 +0300 @@ -50,7 +50,6 @@ putchar('.'); fflush(stdout); } - #else // spin until all threads are done... std::unique_lock lock(workq_mutex); diff -r 53a98c148bf8 -r b1fc96c71bcc src/main.cc --- a/src/main.cc Sat Jun 07 09:14:17 2014 +0300 +++ b/src/main.cc Sat Jun 07 13:36:36 2014 +0300 @@ -5,19 +5,21 @@ #include #include #include +#include #include "opengl.h" #include "erebus.h" using namespace std::chrono; -#define SCALE 2 - static bool init(); static void cleanup(); +static void begin_frame(long tm); +static void end_frame(); static void resize_rtarget(int xsz, int ysz); static void update_rect(int x, int y, int xsz, int ysz, float *pixels); static void idle(); static void display(); +static void display_statusbar(const erb_render_status &status); static void save_image(const char *fname = 0); static void reshape(int x, int y); static void keyb(unsigned char key, int x, int y); @@ -28,22 +30,32 @@ static void sball_motion(int x, int y, int z); static int next_pow2(int x); static void sighandler(int s); +static bool parse_args(int argc, char **argv); -static int width, height, rtex_width, rtex_height; +static int win_width, win_height, width, height, rtex_width, rtex_height; static unsigned int rtex; +static int opt_samples = -1; +static int opt_iter = -1; +static int opt_threads = -1; +static float opt_imgscale = 2.0f; + static erebus *erb; static bool render_pending; +static bool show_status = true; +static steady_clock::time_point start_time; static std::vector sfiles; +static dtx_font *font; + int main(int argc, char **argv) { glutInitWindowSize(1024, 600); glutInit(&argc, argv); - for(int i=1; i(dur).count(); + long msec, sec, min, hr, days; + + msec = full_msec; + printf("done in "); + if((sec = msec / 1000) > 0) { + msec %= 1000; + if((min = sec / 60) > 0) { + sec %= 60; + if((hr = min / 60) > 0) { + min %= 60; + if((days = hr / 24) > 0) { + hr %= 24; + printf("%ld days ", days); + } + printf("%ld hours ", hr); + } + printf("%ld min ", min); + } + printf("%ld sec ", sec); + } + printf("%ld ms (%ld total msec)\n", msec, full_msec); + + render_pending = false; + glutIdleFunc(0); +} + static void resize_rtarget(int xsz, int ysz) { static unsigned char *defpix; - width = xsz / SCALE; - height = ysz / SCALE; + win_width = xsz; + win_height = ysz; + + width = xsz / opt_imgscale; + height = ysz / opt_imgscale; if(width <= rtex_width && height <= rtex_height) { return; @@ -160,28 +231,90 @@ static void display() { + static struct erb_render_status status; + if(render_pending) { if(erb_render(erb, 64) == 0) { - render_pending = false; - glutIdleFunc(0); + end_frame(); } update_rect(0, 0, width, height, erb_get_framebuffer(erb)); + erb_get_status(erb, &status); } float maxu = (float)width / (float)rtex_width; float maxv = (float)height / (float)rtex_height; glBegin(GL_QUADS); + glColor4f(1, 1, 1, 1); glTexCoord2f(0, maxv); glVertex2f(-1, -1); glTexCoord2f(maxu, maxv); glVertex2f(1, -1); glTexCoord2f(maxu, 0); glVertex2f(1, 1); glTexCoord2f(0, 0); glVertex2f(-1, 1); glEnd(); + // draw progress information etc... + if(show_status) { + display_statusbar(status); + } + glutSwapBuffers(); assert(glGetError() == GL_NO_ERROR); } +static void display_statusbar(const erb_render_status &status) +{ + if(!font) return; + + bool show_progress = opt_samples > 0; + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_TEXTURE_2D); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, win_width, 0, win_height, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + int font_height = dtx_glyph_height('Q'); + int prog_width = show_progress ? status.progress_percent * win_width / 100 : 0; + + glBegin(GL_QUADS); + glColor4f(0, 0, 0, 1); + glVertex2f(prog_width, 0); + glVertex2f(win_width, 0); + glVertex2f(win_width, font_height); + glVertex2f(prog_width, font_height); + + glColor4f(0.25, 0, 0, 1); + glVertex2f(0, 0); + glVertex2f(prog_width, 0); + glVertex2f(prog_width, font_height); + glVertex2f(0, font_height); + glEnd(); + + glTranslatef(5, 5, 0); + + glColor4f(1, 1, 1, 1); + + if(opt_samples > 0) { + dtx_printf("samples: %d / %d\n", status.samples, status.max_samples); + + glTranslatef(win_width - dtx_string_width("progress: 100%") - 5, 0, 0); + dtx_printf("progress: %d%%\n", status.progress_percent); + } else { + dtx_printf("samples: %d\n", status.samples); + } + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + glPopAttrib(); +} + static void save_image(const char *fname) { float *fb = erb_get_framebuffer(erb); @@ -204,19 +337,22 @@ { switch(key) { case 27: + end_frame(); exit(0); case ' ': - printf("begin rendering\n"); - render_pending = true; - glutIdleFunc(idle); - erb_begin_frame(erb, 0); + begin_frame(0); break; case '`': printf("saving image.\n"); save_image(); break; + + case 'p': + show_status = !show_status; + glutPostRedisplay(); + break; } if(erb_input_keyboard(erb, key, true)) { @@ -272,3 +408,47 @@ { exit(0); } + +static bool parse_args(int argc, char **argv) +{ + for(int i=1; i