# HG changeset patch # User John Tsiombikas # Date 1400901177 -10800 # Node ID e2d9bf168a416d10b617f841c844f14e219aafde # Parent f067148b3494c3fb764eb1fa72efafa5c896dabf semi-works ... diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/camera.cc --- a/liberebus/src/camera.cc Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/camera.cc Sat May 24 06:12:57 2014 +0300 @@ -2,32 +2,25 @@ #include #include "camera.h" +#define DEFAULT_FOV DEG_TO_RAD(50) + static void calc_sample_pos_rec(int sidx, float xsz, float ysz, float *pos); Camera::Camera() { - vfov = M_PI / 4.0; + vfov = DEFAULT_FOV; cached_matrix_valid = false; - - rdir_cache_width = rdir_cache_height = 0; - rdir_cache_fov = 0; - rdir_cache = 0; } Camera::Camera(const Vector3 &p) : pos(p) { - vfov = M_PI / 4.0; + vfov = DEFAULT_FOV; cached_matrix_valid = false; - - rdir_cache_width = rdir_cache_height = 0; - rdir_cache_fov = 0; - rdir_cache = 0; } Camera::~Camera() { - delete [] rdir_cache; } void Camera::set_fov(float vfov) @@ -77,38 +70,14 @@ Ray Camera::get_primary_ray(int x, int y, int xsz, int ysz, int sample) const { -#pragma omp single - { - if(!rdir_cache || rdir_cache_width != xsz || rdir_cache_height != ysz || - fabs(rdir_cache_fov - vfov) > 1e-4) { - printf("calculating primary ray direction cache (%dx%d)\n", xsz, ysz); - - delete [] rdir_cache; - rdir_cache = new Vector3[xsz * ysz]; - -#pragma omp parallel for - for(int i=0; ix = ppos.x; - rdir->y = ppos.y; - rdir->z = 1.0 / tan(vfov / 2.0); - rdir->normalize(); - - rdir++; - } - } - rdir_cache_width = xsz; - rdir_cache_height = ysz; - rdir_cache_fov = vfov; - } - } + Vector2 ppos = calc_sample_pos(x, y, xsz, ysz, sample); Ray ray; ray.origin = pos; - ray.dir = rdir_cache[y * xsz + x]; + ray.dir.x = ppos.x; + ray.dir.y = ppos.y; + ray.dir.z = 1.0 / tan(vfov / 2.0); + ray.dir.normalize(); // transform the ray direction with the camera matrix Matrix4x4 mat = get_matrix(); diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/camera.h --- a/liberebus/src/camera.h Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/camera.h Sat May 24 06:12:57 2014 +0300 @@ -11,10 +11,6 @@ mutable Matrix4x4 cached_matrix; mutable bool cached_matrix_valid; - mutable Vector3 *rdir_cache; - mutable int rdir_cache_width, rdir_cache_height; - mutable float rdir_cache_fov; - virtual void calc_matrix(Matrix4x4 *mat) const = 0; Vector2 calc_sample_pos(int x, int y, int xsz, int ysz, int sample) const; diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/erebus.cc --- a/liberebus/src/erebus.cc Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/erebus.cc Sat May 24 06:12:57 2014 +0300 @@ -9,6 +9,8 @@ #include "geomobj.h" #include "rt.h" +#define INF_SAMPLES (INT_MAX / 2) + using namespace std::chrono; struct Rect { @@ -24,15 +26,17 @@ Scene *scn; Image fbimg; + Image accum; // sample accumulator per pixel Vector4 options[ERB_NUM_OPTIONS]; // render state long cur_time; int cur_pixel_x, cur_pixel_y; Rect cur_rect; + int cur_sample; }; -static void render_pixel(struct erebus *ctx, int x, int y); +static void render_pixel(struct erebus *ctx, int x, int y, int sample); static std::mt19937 rnd_gen; @@ -51,6 +55,8 @@ ctx->scn = 0; ctx->cur_time = 0; ctx->cur_rect = INVALID_RECT; + + ctx->options[ERB_OPT_MAX_SAMPLES].x = (float)INF_SAMPLES; return ctx; } @@ -94,12 +100,14 @@ void erb_begin_frame(struct erebus *ctx, long ms) { + printf("starting new frame...\n"); ctx->cur_time = ms; int xsz = ctx->options[ERB_OPT_WIDTH].x; int ysz = ctx->options[ERB_OPT_HEIGHT].x; ctx->fbimg.create(xsz, ysz); + ctx->accum.create(xsz, ysz); } int erb_render(struct erebus *ctx, long timeout) @@ -113,31 +121,45 @@ Rect rect{x, y, width, height}; if(ctx->cur_rect != rect) { + // starting a new rendering apparently ctx->cur_rect = rect; ctx->cur_pixel_x = x; ctx->cur_pixel_y = y; + ctx->cur_sample = 0; } ctx->scn->update(); + int max_samples = ctx->options[ERB_OPT_MAX_SAMPLES].x; + if(timeout > 0) { auto start_time = steady_clock::now(); while(duration_cast(steady_clock::now() - start_time).count() < timeout) { - render_pixel(ctx, ctx->cur_pixel_x, ctx->cur_pixel_y); + render_pixel(ctx, ctx->cur_pixel_x, ctx->cur_pixel_y, ctx->cur_sample); if(++ctx->cur_pixel_x >= ctx->cur_rect.width) { + ctx->cur_pixel_x = ctx->cur_rect.x; if(++ctx->cur_pixel_y >= ctx->cur_rect.height) { - ctx->cur_rect = INVALID_RECT; - return 0; + ctx->cur_pixel_y = ctx->cur_rect.y; + if(++ctx->cur_sample >= max_samples) { + ctx->cur_rect = INVALID_RECT; + return 0; + } } } } return 1; } + if(ctx->options[ERB_OPT_MAX_SAMPLES].x == (float)INF_SAMPLES) { + max_samples = 128; + } + for(int i=0; imtl.set_attrib("albedo", Color(1.0, 0.3, 0.2)); SceneNode *sph_node = new SceneNode(sph); ctx->scn->add_object(sph); ctx->scn->add_node(sph_node); - TargetCamera *cam = new TargetCamera(Vector3(0, 0, -10), Vector3(0, 0, 0)); + sph = new Sphere; + sph->mtl.set_attrib("albedo", Color(0.3, 0.4, 1.0)); + sph_node = new SceneNode(sph); + sph_node->set_position(Vector3(0, -3.0, 0)); + //sph_node->set_scaling(Vector3(4.0, 4.0, 4.0) * 0.3); + ctx->scn->add_object(sph); + ctx->scn->add_node(sph_node); + + Sphere *lt = new Sphere; + lt->mtl.set_attrib("emissive", Color(10, 10, 10)); + SceneNode *lt_node = new SceneNode(lt); + lt_node->set_position(Vector3(-15, 15, -10)); + lt_node->set_scaling(Vector3(5, 5, 5)); + ctx->scn->add_object(lt); + ctx->scn->add_node(lt_node); + + TargetCamera *cam = new TargetCamera(Vector3(0, 4, -8), Vector3(0, 0, 0)); //ctx->scn->add_object(cam); ctx->scn->use_camera(cam); @@ -174,20 +213,28 @@ return unirnd(rnd_gen); } -static void render_pixel(struct erebus *ctx, int x, int y) +static void render_pixel(struct erebus *ctx, int x, int y, int sample) { Camera *cam = ctx->scn->get_active_camera(); if(!cam) return; int xsz = ctx->fbimg.get_width(); int ysz = ctx->fbimg.get_height(); - float *pix = ctx->fbimg.get_pixels() + (y * xsz + x) * 4; + int offs = (y * xsz + x) * 4; - Ray ray = cam->get_primary_ray(x, y, xsz, ysz, 0); - //Color c = ray_trace(ray, ctx->scn, 0); - Color c = ray.dir.normalized() * 0.5 + Vector3(0.5, 0.5, 0.5); - pix[0] = 1.0;//c.x; - pix[1] = c.y; - pix[2] = c.z; - pix[3] = c.w; + float *pix = ctx->fbimg.get_pixels() + offs; + float *accum = ctx->accum.get_pixels() + offs; + + Ray ray = cam->get_primary_ray(x, y, xsz, ysz, sample); + Color c = ray_trace(ray, ctx->scn, 0); + accum[0] += c.x; + accum[1] += c.y; + accum[2] += c.z; + accum[3] += c.w; + + float inv_samples = 1.0f / (float)(sample + 1); + pix[0] = accum[0] * inv_samples; + pix[1] = accum[1] * inv_samples; + pix[2] = accum[2] * inv_samples; + pix[3] = accum[3] * inv_samples; } diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/erebus.h --- a/liberebus/src/erebus.h Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/erebus.h Sat May 24 06:12:57 2014 +0300 @@ -7,6 +7,7 @@ ERB_OPT_WIDTH, ERB_OPT_HEIGHT, ERB_OPT_MAX_ITER, + ERB_OPT_MAX_SAMPLES, ERB_OPT_NUM_THREADS, ERB_OPT_GAMMA, diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/geomobj.cc --- a/liberebus/src/geomobj.cc Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/geomobj.cc Sat May 24 06:12:57 2014 +0300 @@ -18,6 +18,22 @@ return false; } +Vector3 GeomObject::calc_normal(const RayHit &hit) const +{ + // when you look at singularities, the singularities always look back at you :) + return -(hit.world_ray.dir).normalized(); +} + +Vector3 GeomObject::calc_tangent(const RayHit &hit) const +{ + return Vector3(1, 0, 0); // whatever... +} + +Vector2 GeomObject::calc_texcoords(const RayHit &hit) const +{ + return Vector2(); +} + // --- class Sphere --- bool Sphere::intersect(const Ray &ray, RayHit *hit) const @@ -47,6 +63,40 @@ return true; } +Vector3 Sphere::calc_normal(const RayHit &hit) const +{ + Vector3 pt = hit.world_ray.origin + hit.world_ray.dir * hit.dist; + return pt.normalized(); +} + +static inline Vector3 sphvec(float u, float v) +{ + float theta = u * M_PI * 2.0; + float phi = v * M_PI; + + return Vector3(sin(theta) * sin(phi), cos(phi), cos(theta) * sin(phi)); +} + +Vector3 Sphere::calc_tangent(const RayHit &hit) const +{ + Vector2 uv = calc_texcoords(hit); + Vector3 pnext = sphvec(uv.x + 0.05, 0.5); + Vector3 pprev = sphvec(uv.y - 0.05, 0.5); + return (pnext - pprev).normalized(); +} + +Vector2 Sphere::calc_texcoords(const RayHit &hit) const +{ + Vector3 pt = hit.world_ray.origin + hit.world_ray.dir * hit.dist; + pt.normalize(); + + float theta = atan2(pt.z, pt.x); + float phi = acos(pt.y); + + return Vector2(theta / M_PI + 0.5, phi / M_PI); +} + + // --- class Box --- bool Box::intersect(const Ray &ray, RayHit *hit) const diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/geomobj.h --- a/liberebus/src/geomobj.h Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/geomobj.h Sat May 24 06:12:57 2014 +0300 @@ -16,11 +16,19 @@ ObjType get_type() const override; bool intersect(const Ray &ray, RayHit *hit = 0) const override; + + virtual Vector3 calc_normal(const RayHit &hit) const; + virtual Vector3 calc_tangent(const RayHit &hit) const; + virtual Vector2 calc_texcoords(const RayHit &hit) const; }; class Sphere : public GeomObject { public: bool intersect(const Ray &ray, RayHit *hit = 0) const override; + + Vector3 calc_normal(const RayHit &hit) const override; + Vector3 calc_tangent(const RayHit &hit) const override; + Vector2 calc_texcoords(const RayHit &hit) const override; }; class Box : public GeomObject { diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/material.cc --- a/liberebus/src/material.cc Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/material.cc Sat May 24 06:12:57 2014 +0300 @@ -1,7 +1,7 @@ #include "material.h" MatAttrib::MatAttrib() - : value(1), color(1, 1, 1), map(0) + : value(0), color(0, 0, 0), map(0) { } diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/rt.cc --- a/liberebus/src/rt.cc Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/rt.cc Sat May 24 06:12:57 2014 +0300 @@ -1,16 +1,41 @@ +#include #include "rt.h" +#include "erebus_impl.h" + +#define MAX_ITER 8 Color ray_trace(const Ray &ray, const Scene *scn, int iter) { RayHit hit; if(!(scn->intersect(ray, &hit))) { - return Color(0, 0, 0, 0); + return scn->get_env_color(ray); } - return shade(hit, iter); + return shade(hit, scn, iter); } -Color shade(const RayHit &hit, int iter) +Color shade(const RayHit &hit, const Scene *scn, int iter) { - return Color(1, 0, 0, 1); + assert(hit.obj->get_type() == ObjType::geom); + const GeomObject *obj = (const GeomObject*)hit.obj; + const Material *mtl = &obj->mtl; + const Reflectance *brdf = obj->brdf; + const Ray &ray = hit.world_ray; + + Vector3 norm = obj->calc_normal(hit); + Vector2 texcoords = obj->calc_texcoords(hit); + + Color color = mtl->get_attrib_color("albedo", texcoords.x, texcoords.y); + Color res = mtl->get_attrib_color("emissive") + color * scn->get_env().ambient; + + Vector3 sample_dir; + float prob = brdf->sample(norm, -hit.world_ray.dir, &sample_dir); + if(iter < MAX_ITER && randf() <= prob) { + Ray sample_ray; + sample_ray.origin = ray.origin + ray.dir * hit.dist; + sample_ray.dir = sample_dir; + + res += ray_trace(sample_ray, scn, iter + 1) * color; + } + return res; } diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/rt.h --- a/liberebus/src/rt.h Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/rt.h Sat May 24 06:12:57 2014 +0300 @@ -6,6 +6,6 @@ #include "scene.h" Color ray_trace(const Ray &ray, const Scene *scn, int iter); -Color shade(const RayHit &hit, int iter); +Color shade(const RayHit &hit, const Scene *scn, int iter); #endif // RT_H_ diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/scene.cc --- a/liberebus/src/scene.cc Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/scene.cc Sat May 24 06:12:57 2014 +0300 @@ -1,5 +1,11 @@ #include "scene.h" +// default enviromental parameters +Environment::Environment() + : bgcolor(0.05, 0.05, 0.05), ambient(0.05, 0.05, 0.05) +{ +} + Scene::Scene() { active_cam = 0; @@ -17,6 +23,32 @@ delete root; } +void Scene::set_env(const Environment &env) +{ + this->env = env; +} + +Environment &Scene::get_env() +{ + return env; +} + +const Environment &Scene::get_env() const +{ + return env; +} + +Color Scene::get_env_color() const +{ + return env.bgcolor; +} + +Color Scene::get_env_color(const Ray &ray) const +{ + // TODO + return get_env_color(); +} + void Scene::add_object(Object *obj) { objects.push_back(obj); diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/scene.h --- a/liberebus/src/scene.h Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/scene.h Sat May 24 06:12:57 2014 +0300 @@ -4,9 +4,20 @@ #include #include "snode.h" #include "camera.h" +#include "color.h" + +struct Environment { + Color bgcolor; + Color ambient; + // TODO map & image-based lighting + + Environment(); +}; class Scene { private: + Environment env; + std::vector objects; std::vector nodes; @@ -18,6 +29,13 @@ Scene(); ~Scene(); + void set_env(const Environment &env); + Environment &get_env(); + const Environment &get_env() const; + + Color get_env_color() const; + Color get_env_color(const Ray &ray) const; + void add_object(Object *obj); int get_object_count() const; Object *get_object(int idx) const; diff -r f067148b3494 -r e2d9bf168a41 liberebus/src/snode.cc --- a/liberebus/src/snode.cc Sat May 24 02:27:08 2014 +0300 +++ b/liberebus/src/snode.cc Sat May 24 06:12:57 2014 +0300 @@ -158,6 +158,15 @@ } } + for(size_t i=0; iintersect(ray, hit)) { + if(!hit) return true; + if(hit->dist < nearest.dist) { + nearest = *hit; + } + } + } + if(nearest.dist < FLT_MAX) { *hit = nearest; hit->local_ray = local_ray; diff -r f067148b3494 -r e2d9bf168a41 src/main.cc --- a/src/main.cc Sat May 24 02:27:08 2014 +0300 +++ b/src/main.cc Sat May 24 06:12:57 2014 +0300 @@ -44,8 +44,8 @@ static bool init() { - width = glutGet(GLUT_WINDOW_WIDTH); - height = glutGet(GLUT_WINDOW_HEIGHT); + width = glutGet(GLUT_WINDOW_WIDTH) / 2; + height = glutGet(GLUT_WINDOW_HEIGHT) / 2; if(!(erb = erb_init())) { return false; @@ -62,6 +62,7 @@ glutIdleFunc(idle); erb_begin_frame(erb, 0); + glEnable(GL_TEXTURE_2D); return true; } @@ -74,14 +75,14 @@ { static unsigned char *defpix; - width = xsz; - height = ysz; + width = xsz / 2; + height = ysz / 2; - if(xsz <= rtex_width && ysz <= rtex_height) { + if(width <= rtex_width && height <= rtex_height) { return; } - rtex_width = next_pow2(xsz); - rtex_height = next_pow2(ysz); + rtex_width = next_pow2(width); + rtex_height = next_pow2(height); printf("resizing framebuffer texture: %dx%d\n", rtex_width, rtex_height); @@ -125,16 +126,13 @@ static void display() { if(render_pending) { - if(erb_render(erb, 128) == 0) { + if(erb_render(erb, 64) == 0) { render_pending = false; glutIdleFunc(0); } update_rect(0, 0, width, height, erb_get_framebuffer(erb)); } - glBindTexture(GL_TEXTURE_2D, rtex); - glEnable(GL_TEXTURE_2D); - float maxu = (float)width / (float)rtex_width; float maxv = (float)height / (float)rtex_height; @@ -145,8 +143,6 @@ glTexCoord2f(0, 0); glVertex2f(-1, 1); glEnd(); - glDisable(GL_TEXTURE_2D); - glutSwapBuffers(); assert(glGetError() == GL_NO_ERROR); }