# HG changeset patch # User John Tsiombikas # Date 1397450085 -10800 # Node ID 79609d4827627b67bb165d4ae871930f0508ac5e # Parent 4d87b0aafbb0815070ddc60d65f02b70e2469fae the renderer renders, also fixed an unnoticed matrix conversion problem between scenegraph and min3d diff -r 4d87b0aafbb0 -r 79609d482762 Makefile --- a/Makefile Sun Apr 13 09:54:51 2014 +0300 +++ b/Makefile Mon Apr 14 07:34:45 2014 +0300 @@ -1,6 +1,6 @@ baseobj = main.obj logger.obj screen.obj scrman.obj swapbuf.obj rbtree.obj modelobj = modeller.obj min3d.obj m3drast.obj lines.obj -rendobj = renderer.obj vmath.obj +rendobj = renderer.obj vmath.obj raytrace.obj scnobj = scene.obj object.obj light.obj camera.obj snode.obj sysobj = gfx.obj vbe.obj dpmi.obj timer.obj mouse.obj keyb.obj obj = $(baseobj) $(modelobj) $(rendobj) $(scnobj) $(sysobj) diff -r 4d87b0aafbb0 -r 79609d482762 src/camera.cc --- a/src/camera.cc Sun Apr 13 09:54:51 2014 +0300 +++ b/src/camera.cc Mon Apr 14 07:34:45 2014 +0300 @@ -41,7 +41,7 @@ { } -bool Camera::intersect(const Ray &ray, float *dist) const +bool Camera::intersect(const Ray &ray, RayHit *hit) const { return false; } diff -r 4d87b0aafbb0 -r 79609d482762 src/camera.h --- a/src/camera.h Sun Apr 13 09:54:51 2014 +0300 +++ b/src/camera.h Mon Apr 14 07:34:45 2014 +0300 @@ -22,7 +22,7 @@ void draw() const; - bool intersect(const Ray &ray, float *dist = 0) const; + bool intersect(const Ray &ray, RayHit *hit = 0) const; Ray get_primary_ray(int x, int y) const; }; diff -r 4d87b0aafbb0 -r 79609d482762 src/light.cc --- a/src/light.cc Sun Apr 13 09:54:51 2014 +0300 +++ b/src/light.cc Mon Apr 14 07:34:45 2014 +0300 @@ -3,12 +3,23 @@ Light::Light() { type = NODE_LIGHT; + intens = 1.0; color.x = color.y = color.z = 1.0; atten.x = 1.0; atten.y = 0.0; atten.z = 0.0; } +void Light::set_intensity(float val) +{ + intens = val; +} + +float Light::get_intensity() const +{ + return intens; +} + void Light::set_color(const Vector3 &color) { this->color = color; @@ -19,6 +30,11 @@ return color; } +Vector3 Light::get_color(const Vector3 &pt) const +{ + float d = (get_position() - pt).length(); + return color * calc_attenuation(d) * intens; +} void Light::set_attenuation(const Vector3 &atten) { @@ -30,11 +46,18 @@ return atten; } +float Light::calc_attenuation(float d) const +{ + float denom = atten.x + atten.y * d + atten.z * d * d; + float at = denom == 0.0 ? 1.0 : 1.0 / denom; + return at > 1.0 ? 1.0 : at; +} + void Light::draw() const { } -bool Light::intersect(const Ray &ray, float *dist) +bool Light::intersect(const Ray &ray, RayHit *hit) const { - return false; + return false; // TODO } diff -r 4d87b0aafbb0 -r 79609d482762 src/light.h --- a/src/light.h Sun Apr 13 09:54:51 2014 +0300 +++ b/src/light.h Mon Apr 14 07:34:45 2014 +0300 @@ -6,21 +6,30 @@ class Light : public SceneNode { private: + float intens; Vector3 color; Vector3 atten; public: Light(); + void set_intensity(float val); + float get_intensity() const; + void set_color(const Vector3 &color); const Vector3 &get_color() const; + // includes attenuation and intensity + Vector3 get_color(const Vector3 &pt) const; + void set_attenuation(const Vector3 &atten); const Vector3 &get_attenuation() const; + float calc_attenuation(float d) const; + void draw() const; - bool intersect(const Ray &ray, float *dist); + bool intersect(const Ray &ray, RayHit *hit = 0) const; }; #endif // LIGHT_H_ diff -r 4d87b0aafbb0 -r 79609d482762 src/main.cc --- a/src/main.cc Sun Apr 13 09:54:51 2014 +0300 +++ b/src/main.cc Mon Apr 14 07:34:45 2014 +0300 @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "inttypes.h" #include "gfx.h" @@ -102,6 +103,9 @@ signal(SIGILL, sig); signal(SIGFPE, sig); + // mask all fpe except invalid op + _control87(~_EM_INVALID, _MCW_EM); + init_timer(128); if(!novideo) { @@ -144,11 +148,21 @@ scene = new Scene; Sphere *sph = new Sphere; + sph->mtl.diffuse = Vector3(1.0, 0.3, 0.1); + sph->mtl.roughness = 0.4; scene->add(sph); Box *box = new Box; + box->mtl.diffuse = Vector3(0.1, 0.4, 1.0); + box->mtl.roughness = 0.9; + box->set_position(Vector3(0, -1.1, 0)); + box->set_scaling(Vector3(4, 0.1, 4)); scene->add(box); - box->set_scaling(Vector3(2, 0.25, 2)); + + Light *lt = new Light; + lt->set_intensity(0.8); + lt->set_position(Vector3(-10, 10, 10)); + scene->add(lt); Modeller *modeller = new Modeller; if(!modeller->init()) { @@ -322,7 +336,7 @@ return; } - fprintf(fp, "P6\n" PPM_COMMENT "\n%d %d\n255\n", fb_width, fb_height); + fprintf(fp, "P6\n# " PPM_COMMENT "\n%d %d\n255\n", fb_width, fb_height); for(int i=0; imstack[m3dctx->mmode].m[top], m, 16 * sizeof *m); } +void m3d_load_transpose_matrix(const float *m) +{ + int i, j, lin = 0; + int top = m3dctx->mstack[m3dctx->mmode].top; + float *dest = m3dctx->mstack[m3dctx->mmode].m[top]; + + for(i=0; i<4; i++) { + for(j=0; j<4; j++) { + *dest++ = m[j * 4 + i]; + } + } +} + #define M(i,j) (((i) << 2) + (j)) void m3d_mult_matrix(const float *m2) { @@ -137,7 +150,7 @@ for(i=0; i<4; i++) { for(j=0; j<4; j++) { - dest[M(i,j)] = m1[M(0,j)] * m2[M(i,0)] + + *dest++ = m1[M(0,j)] * m2[M(i,0)] + m1[M(1,j)] * m2[M(i,1)] + m1[M(2,j)] * m2[M(i,2)] + m1[M(3,j)] * m2[M(i,3)]; @@ -145,6 +158,24 @@ } } +void m3d_mult_transpose_matrix(const float *m2) +{ + int i, j, top = m3dctx->mstack[m3dctx->mmode].top; + float m1[16]; + float *dest = m3dctx->mstack[m3dctx->mmode].m[top]; + + memcpy(m1, dest, sizeof m1); + + for(i=0; i<4; i++) { + for(j=0; j<4; j++) { + *dest++ = m1[M(0,j)] * m2[M(0,i)] + + m1[M(1,j)] * m2[M(1,i)] + + m1[M(2,j)] * m2[M(2,i)] + + m1[M(3,j)] * m2[M(3,i)]; + } + } +} + void m3d_translate(float x, float y, float z) { float m[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; diff -r 4d87b0aafbb0 -r 79609d482762 src/min3d.h --- a/src/min3d.h Sun Apr 13 09:54:51 2014 +0300 +++ b/src/min3d.h Mon Apr 14 07:34:45 2014 +0300 @@ -61,7 +61,9 @@ void m3d_pop_matrix(void); void m3d_load_identity(void); void m3d_load_matrix(const float *m); +void m3d_load_transpose_matrix(const float *m); void m3d_mult_matrix(const float *m); +void m3d_mult_transpose_matrix(const float *m); void m3d_translate(float x, float y, float z); void m3d_rotate(float angle, float x, float y, float z); void m3d_scale(float x, float y, float z); diff -r 4d87b0aafbb0 -r 79609d482762 src/modeller.cc --- a/src/modeller.cc Sun Apr 13 09:54:51 2014 +0300 +++ b/src/modeller.cc Mon Apr 14 07:34:45 2014 +0300 @@ -11,7 +11,7 @@ struct ModellerImpl { int mx, my; - float cam_theta, cam_phi, cam_dist; + float cam_theta, cam_phi, cam_dist, cam_fov; Camera *viewport_cam; struct m3d_image rbuf; @@ -41,6 +41,7 @@ mod->cam_phi = 25; mod->cam_dist = 5; + mod->cam_fov = 50.0; m3d_init(); mod->rbuf.pixels = fb_pixels; @@ -50,7 +51,7 @@ m3d_matrix_mode(M3D_PROJECTION); m3d_load_identity(); - m3d_perspective(50.0, (float)fb_width / (float)fb_height, 0.5, 500.0); + m3d_perspective(mod->cam_fov, (float)fb_width / (float)fb_height, 0.5, 500.0); m3d_enable(M3D_CULL_FACE); return true; @@ -155,11 +156,14 @@ scene->set_active_camera(mod->viewport_cam); } Vector3 dir; - dir.x = sin(DEG2RAD(mod->cam_theta)) * cos(DEG2RAD(mod->cam_phi)) * mod->cam_dist; - dir.y = sin(DEG2RAD(mod->cam_phi)); - dir.z = cos(DEG2RAD(mod->cam_theta)) * cos(DEG2RAD(mod->cam_phi)) * mod->cam_dist; + float theta = -DEG2RAD(mod->cam_theta); + float phi = DEG2RAD(mod->cam_phi); + dir.x = sin(theta) * cos(phi) * mod->cam_dist; + dir.y = sin(phi) * mod->cam_dist; + dir.z = cos(theta) * cos(phi) * mod->cam_dist; mod->viewport_cam->set_position(dir); mod->viewport_cam->set_target(Vector3(0, 0, 0)); + mod->viewport_cam->set_fov(DEG2RAD(mod->cam_fov)); rs->message(message_atom("start")); } diff -r 4d87b0aafbb0 -r 79609d482762 src/object.cc --- a/src/object.cc Sun Apr 13 09:54:51 2014 +0300 +++ b/src/object.cc Mon Apr 14 07:34:45 2014 +0300 @@ -13,6 +13,11 @@ { } +Vector3 Object::hit_normal(const RayHit &hit) const +{ + return Vector3(0, 0, 0); +} + // ---- sphere ---- Sphere::Sphere() { @@ -83,7 +88,7 @@ post_draw(); } -bool Sphere::intersect(const Ray &wray, float *dist) const +bool Sphere::intersect(const Ray &wray, RayHit *hit) const { Ray ray = transform(get_inv_matrix(), wray); @@ -111,10 +116,21 @@ if(t < 1e-4) return false; - if(dist) *dist = t; + if(hit) { + hit->ray = wray; + hit->lray = ray; + hit->dist = t; + hit->obj = this; + hit->subobj = 0; + } return true; } +Vector3 Sphere::hit_normal(const RayHit &hit) const +{ + return hit.lray.origin + hit.lray.dir * hit.dist; +} + // ---- box ---- Box::Box() @@ -165,7 +181,57 @@ post_draw(); } -bool Box::intersect(const Ray &ray, float *dist) const +bool Box::intersect(const Ray &wray, RayHit *hit) const { - return false; // TODO + Ray ray = transform(get_inv_matrix(), wray); + + Vector3 param[2] = { Vector3(-1, -1, -1), Vector3(1, 1, 1) }; + Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z); + int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0}; + + float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x; + float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x; + float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y; + float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y; + + if(tmin > tymax || tymin > tmax) { + return false; + } + if(tymin > tmin) tmin = tymin; + if(tymax < tmax) tmax = tymax; + + float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z; + float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z; + + if(tmin > tzmax || tzmin > tmax) { + return false; + } + if(tzmin > tmin) tmin = tzmin; + if(tzmax < tmax) tmax = tzmax; + + float t = tmin < 1e-4 ? tmax : tmin; + if(t >= 1e-4) { + if(hit) { + hit->dist = t; + hit->ray = wray; + hit->lray = ray; + hit->obj = this; + hit->subobj = 0; + } + return true; + } + return false; } + +Vector3 Box::hit_normal(const RayHit &hit) const +{ + Vector3 lpt = hit.lray.origin + hit.lray.dir * hit.dist; + + if(fabs(lpt.x) > fabs(lpt.y) && fabs(lpt.x) > fabs(lpt.z)) { + return Vector3(lpt.x, 0, 0); + } + if(fabs(lpt.y) > fabs(lpt.z)) { + return Vector3(0, lpt.y, 0); + } + return Vector3(0, 0, lpt.z); +} diff -r 4d87b0aafbb0 -r 79609d482762 src/object.h --- a/src/object.h Sun Apr 13 09:54:51 2014 +0300 +++ b/src/object.h Mon Apr 14 07:34:45 2014 +0300 @@ -3,11 +3,16 @@ #include "vmath.h" #include "snode.h" +#include "material.h" class Object : public SceneNode { public: + Material mtl; + Object(); virtual ~Object(); + + virtual Vector3 hit_normal(const RayHit &hit) const; }; class Sphere : public Object { @@ -17,7 +22,8 @@ void draw(bool emph = false) const; - bool intersect(const Ray &ray, float *dist = 0) const; + bool intersect(const Ray &ray, RayHit *hit = 0) const; + Vector3 hit_normal(const RayHit &hit) const; }; class Box : public Object { @@ -27,7 +33,8 @@ void draw(bool emph = false) const; - bool intersect(const Ray &ray, float *dist = 0) const; + bool intersect(const Ray &ray, RayHit *hit = 0) const; + Vector3 hit_normal(const RayHit &hit) const; }; #endif // OBJECT_H_ diff -r 4d87b0aafbb0 -r 79609d482762 src/raytrace.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/raytrace.cc Mon Apr 14 07:34:45 2014 +0300 @@ -0,0 +1,58 @@ +#include +#include +#include "raytrace.h" +#include "rayzor.h" +#include "scene.h" +#include "logger.h" + +Vector3 ray_trace(const Ray &ray, int iter) +{ + RayHit hit; + if(!scene->intersect(ray, &hit)) { + return scene->get_background(ray); + } + + return shade(hit, iter); +} + +static inline float positive(float x) +{ + return x < 0.0f ? 0.0f : x; +} + +Vector3 shade(const RayHit &hit, int iter) +{ + Vector3 pos = hit.ray.origin + hit.ray.dir * hit.dist; + Vector3 norm = hit.obj->hit_normal(hit); + norm = normalize(transform(normal_matrix(hit.obj->get_matrix()), norm)); + Vector3 vdir = -normalize(hit.ray.dir); + + Vector3 color = scene->get_ambient(); + + const Vector3 &kd = hit.obj->mtl.diffuse; + const Vector3 &ks = hit.obj->mtl.specular; + float roughness = hit.obj->mtl.roughness; + + int num_lights = scene->get_light_count(); + for(int i=0; iget_light(i); + Vector3 ldir = lt->get_position() - pos; + Vector3 lcol = lt->get_color(pos); + + RayHit hit; + if(!scene->intersect(Ray(pos, ldir), &hit) || hit.dist > 1.0) { + // if we can see the light, calculate and add its contribution + ldir.normalize(); + float ndotl = positive(dot(norm, ldir)); + Vector3 diffuse = kd * lcol * ndotl; + + Vector3 hdir = normalize(ldir + vdir); + float ndoth = positive(dot(norm, hdir)); + Vector3 specular = ks * lcol * pow(ndoth, roughness * 128.0); + + color = color + lerp(specular, diffuse, roughness); + } + } + + return color; +} diff -r 4d87b0aafbb0 -r 79609d482762 src/raytrace.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/raytrace.h Mon Apr 14 07:34:45 2014 +0300 @@ -0,0 +1,20 @@ +#ifndef RAYTRACE_H_ +#define RAYTRACE_H_ + +#include "vmath.h" +#include "vmathray.h" + +class Object; + +struct RayHit { + Ray ray; // the ray in world coordinates + Ray lray; // the local coordinate system ray + float dist; // parametric distance along the ray + const Object *obj; // pointer to the object that has been hit + const void *subobj; // object-specific subobject pointer (can be null). +}; + +Vector3 ray_trace(const Ray &ray, int iter = 0); +Vector3 shade(const RayHit &hit, int iter); + +#endif // RAYTRACE_H_ diff -r 4d87b0aafbb0 -r 79609d482762 src/renderer.cc --- a/src/renderer.cc Sun Apr 13 09:54:51 2014 +0300 +++ b/src/renderer.cc Mon Apr 14 07:34:45 2014 +0300 @@ -1,4 +1,5 @@ #include +#include #include "renderer.h" #include "rayzor.h" #include "scene.h" @@ -6,6 +7,15 @@ #include "scrman.h" #include "timer.h" #include "logger.h" +#include "raytrace.h" + +enum { + MSG_START, + MSG_GAMMA, + MSG_USE_GAMMA, + + NUM_MESSAGES +}; struct RendererImpl { bool in_progress; @@ -13,14 +23,13 @@ uint32_t *pixels; - MsgAtom msg_start; + float gamma, inv_gamma; + bool use_gamma; + + MsgAtom msg[NUM_MESSAGES]; }; -static Vector3 ray_trace(const Ray &ray, int iter = 0); -static Vector3 shade(const Ray &ray, float t, int iter); - - Renderer::Renderer() { set_name("renderer"); @@ -37,7 +46,13 @@ } memset(rend->pixels, 0, fb_width * fb_height * 4); - rend->msg_start = message_atom("start"); + rend->gamma = 1.8; + rend->inv_gamma = 1.0 / rend->gamma; + rend->use_gamma = true; + + rend->msg[MSG_START] = message_atom("start"); + rend->msg[MSG_GAMMA] = message_atom("gamma"); + rend->msg[MSG_USE_GAMMA] = message_atom("use-gamma"); return true; } @@ -69,6 +84,13 @@ Ray ray = cam->get_primary_ray(rend->cur_x, rend->cur_y); Vector3 color = ray_trace(ray); + // gamma-correct before storing the pixel + if(rend->use_gamma) { + color.x = pow(color.x, rend->inv_gamma); + color.y = pow(color.y, rend->inv_gamma); + color.z = pow(color.z, rend->inv_gamma); + } + int r = color.x > 1.0 ? 255 : (int)(color.x * 255.0); int g = color.y > 1.0 ? 255 : (int)(color.y * 255.0); int b = color.z > 1.0 ? 255 : (int)(color.z * 255.0); @@ -104,24 +126,33 @@ } } -void Renderer::message(MsgAtom msg) +void Renderer::message(MsgAtom msg, ...) { - if(msg == rend->msg_start) { - rend->cur_x = rend->cur_y = 0; - rend->in_progress = true; - memset(rend->pixels, 0, fb_width * fb_height * 4); + va_list ap; + va_start(ap, msg); - printlog("starting a new rendering!\n"); + for(int i=0; imsg[i]) { + switch(i) { + case MSG_START: + rend->cur_x = rend->cur_y = 0; + rend->in_progress = true; + memset(rend->pixels, 0, fb_width * fb_height * 4); + + printlog("starting a new rendering!\n"); + break; + + case MSG_GAMMA: + rend->gamma = va_arg(ap, float); + rend->inv_gamma = 1.0 / rend->gamma; + break; + + case MSG_USE_GAMMA: + rend->use_gamma = va_arg(ap, bool); + break; + } + } } + + va_end(ap); } - - -static Vector3 ray_trace(const Ray &ray, int iter) -{ - return shade(ray, 0, iter); -} - -static Vector3 shade(const Ray &ray, float t, int iter) -{ - return Vector3(1.0, 0.0, 0.0); -} diff -r 4d87b0aafbb0 -r 79609d482762 src/renderer.h --- a/src/renderer.h Sun Apr 13 09:54:51 2014 +0300 +++ b/src/renderer.h Mon Apr 14 07:34:45 2014 +0300 @@ -19,7 +19,7 @@ void handle_keyboard(int key, bool press); - void message(MsgAtom msg); + void message(MsgAtom msg, ...); }; #endif // RENDERER_H_ diff -r 4d87b0aafbb0 -r 79609d482762 src/scancode.h --- a/src/scancode.h Sun Apr 13 09:54:51 2014 +0300 +++ b/src/scancode.h Mon Apr 14 07:34:45 2014 +0300 @@ -8,9 +8,9 @@ '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* f - 1c */ KB_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', /* 1d - 29 */ KB_LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KB_RSHIFT, /* 2a - 36 */ - KB_NUM_KB_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, /* 37 - 44 */ - KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_KB_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_KB_PLUS, /* 45 - 4e */ - KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_KB_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12, /* 4d - 58 */ + KB_NUM_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, /* 37 - 44 */ + KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_PLUS, /* 45 - 4e */ + KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12, /* 4d - 58 */ 0, 0, 0, 0, 0, 0, 0, /* 59 - 5f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 70 - 7f */ diff -r 4d87b0aafbb0 -r 79609d482762 src/scene.cc --- a/src/scene.cc Sun Apr 13 09:54:51 2014 +0300 +++ b/src/scene.cc Mon Apr 14 07:34:45 2014 +0300 @@ -1,4 +1,5 @@ #include +#include #include "scene.h" #include "min3d.h" @@ -6,6 +7,14 @@ { name = 0; active_cam = 0; + + fog_exp = 1.0; + + set_ambient(Vector3(0.05, 0.05, 0.05)); + + set_background(Vector3(0.4, 0.3, 0.05), SCN_BG_LOW); + set_background(Vector3(0.6, 0.6, 0.6), SCN_BG_MID); + set_background(Vector3(0.1, 0.5, 1.0), SCN_BG_HIGH); } Scene::~Scene() @@ -41,6 +50,51 @@ return name ? name : ""; } +void Scene::set_background(const Vector3 &col, int idx) +{ + if(idx == -1) { + bg[0] = bg[1] = bg[2] = col; + } else { + bg[idx] = col; + } +} + +const Vector3 &Scene::get_background(int idx) const +{ + return bg[idx == -1 ? 0 : idx]; +} + +#define LERP(a, b, t) ((a) + ((b) - (a)) * t) + +Vector3 Scene::get_background(const Ray &ray) const +{ + Vector3 dir = normalize(ray.dir); + + float v; + if(dir.z == 0.0) { + v = dir.y > 0.0 ? 1.0 : -1.0; + } else { + float angle = atan2(dir.z, dir.y); + v = angle / M_PI; + } + + float r = v >= 0.0 ? LERP(bg[1].x, bg[2].x, v) : LERP(bg[1].x, bg[0].x, -v); + float g = v >= 0.0 ? LERP(bg[1].y, bg[2].y, v) : LERP(bg[1].y, bg[0].y, -v); + float b = v >= 0.0 ? LERP(bg[1].z, bg[2].z, v) : LERP(bg[1].z, bg[0].z, -v); + return Vector3(r, g, b); +} + +void Scene::set_ambient(const Vector3 &col) +{ + ambient = col; +} + +const Vector3 &Scene::get_ambient() const +{ + return ambient; +} + + void Scene::add(SceneNode *node) { nodes.push_back(node); @@ -180,3 +234,23 @@ { return idx >= 0 && idx < (int)sel.size() ? sel[idx] : -1; } + +bool Scene::intersect(const Ray &ray, RayHit *hit) const +{ + if(hit) { + hit->dist = FLT_MAX; + hit->obj = 0; + } + + int num_obj = (int)objects.size(); + for(int i=0; iintersect(ray, hit ? &tmphit : 0)) { + if(!hit) return true; + if(tmphit.dist < hit->dist) { + *hit = tmphit; + } + } + } + return hit && hit->obj; +} diff -r 4d87b0aafbb0 -r 79609d482762 src/scene.h --- a/src/scene.h Sun Apr 13 09:54:51 2014 +0300 +++ b/src/scene.h Mon Apr 14 07:34:45 2014 +0300 @@ -7,6 +7,9 @@ #include "object.h" #include "light.h" #include "camera.h" +#include "raytrace.h" + +enum { SCN_BG_LOW, SCN_BG_MID, SCN_BG_HIGH }; class Scene { private: @@ -18,6 +21,10 @@ vector cameras; Camera *active_cam; + Vector3 bg[3]; + Vector3 ambient; + float fog_exp; + vector sel; public: @@ -29,6 +36,13 @@ void set_name(const char *name); const char *get_name() const; + void set_background(const Vector3 &col, int idx = -1); + const Vector3 &get_background(int idx = -1) const; + Vector3 get_background(const Ray &ray) const; + + void set_ambient(const Vector3 &col); + const Vector3 &get_ambient() const; + void add(SceneNode *node); int get_node_count() const; @@ -54,6 +68,8 @@ void clear_selection(); int get_selection_count() const; int get_selection(int idx = 0) const; + + bool intersect(const Ray &ray, RayHit *hit = 0) const; }; #endif // SCENE_H_ diff -r 4d87b0aafbb0 -r 79609d482762 src/screen.cc --- a/src/screen.cc Sun Apr 13 09:54:51 2014 +0300 +++ b/src/screen.cc Mon Apr 14 07:34:45 2014 +0300 @@ -78,6 +78,6 @@ { } -void Screen::message(MsgAtom ma) +void Screen::message(MsgAtom msg, ...) { } diff -r 4d87b0aafbb0 -r 79609d482762 src/screen.h --- a/src/screen.h Sun Apr 13 09:54:51 2014 +0300 +++ b/src/screen.h Mon Apr 14 07:34:45 2014 +0300 @@ -26,7 +26,7 @@ virtual void handle_mbutton(int bn, bool press, int x, int y); virtual void handle_mmotion(int x, int y); - virtual void message(MsgAtom ma); + virtual void message(MsgAtom msg, ...); }; #endif // SCREEN_H_ diff -r 4d87b0aafbb0 -r 79609d482762 src/snode.cc --- a/src/snode.cc Sun Apr 13 09:54:51 2014 +0300 +++ b/src/snode.cc Mon Apr 14 07:34:45 2014 +0300 @@ -192,7 +192,7 @@ { m3d_matrix_mode(M3D_MODELVIEW); m3d_push_matrix(); - m3d_mult_matrix(get_matrix()[0]); + m3d_mult_transpose_matrix(get_matrix()[0]); } void SceneNode::post_draw() const @@ -228,7 +228,7 @@ } } -bool SceneNode::intersect(const Ray &ray, float *dist) const +bool SceneNode::intersect(const Ray &ray, RayHit *hit) const { return false; } diff -r 4d87b0aafbb0 -r 79609d482762 src/snode.h --- a/src/snode.h Sun Apr 13 09:54:51 2014 +0300 +++ b/src/snode.h Mon Apr 14 07:34:45 2014 +0300 @@ -6,6 +6,7 @@ #include "quat.h" #include "vmathmat.h" #include "vmathray.h" +#include "raytrace.h" enum NodeType { NODE_NULL, @@ -82,7 +83,7 @@ virtual void draw(bool emph = false) const; - virtual bool intersect(const Ray &ray, float *dist = 0) const; + virtual bool intersect(const Ray &ray, RayHit *hit = 0) const; }; #endif /* SCENE_NODE_H_ */ diff -r 4d87b0aafbb0 -r 79609d482762 src/vmath.cc --- a/src/vmath.cc Sun Apr 13 09:54:51 2014 +0300 +++ b/src/vmath.cc Mon Apr 14 07:34:45 2014 +0300 @@ -8,13 +8,17 @@ Vector3 vi = normalize(cross(vk, vj)); vj = cross(vi, vk); - Matrix4x4 m( + Matrix4x4 rm( vi.x, vi.y, vi.z, 0, vj.x, vj.y, vj.z, 0, -vk.x, -vk.y, -vk.z, 0, 0, 0, 0, 1); - translate(-pos.x, -pos.y, -pos.z); - *this = *this * m; + Matrix4x4 tm( + 1, 0, 0, -pos.x, + 0, 1, 0, -pos.y, + 0, 0, 1, -pos.z, + 0, 0, 0, 1); + *this = *this * (rm * tm); } void Matrix4x4::transpose() diff -r 4d87b0aafbb0 -r 79609d482762 src/vmath.h --- a/src/vmath.h Sun Apr 13 09:54:51 2014 +0300 +++ b/src/vmath.h Mon Apr 14 07:34:45 2014 +0300 @@ -50,6 +50,11 @@ return Vector3(a.x - b.x, a.y - b.y, a.z - b.z); } +inline Vector3 operator -(const Vector3 &v) +{ + return Vector3(-v.x, -v.y, -v.z); +} + inline Vector3 operator *(const Vector3 &a, const Vector3 &b) { return Vector3(a.x * b.x, a.y * b.y, a.z * b.z); @@ -85,6 +90,13 @@ return Vector3(x, y, z); } +inline Vector3 lerp(const Vector3 &a, const Vector3 &b, float t) +{ + return Vector3(a.x + (b.x - a.x) * t, + a.y + (b.y - a.y) * t, + a.z + (b.z - a.z) * t); +} + // ---- Vector4 ---- class Vector4 { @@ -129,6 +141,11 @@ return Vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } +inline Vector4 operator -(const Vector4 &v) +{ + return Vector4(-v.x, -v.y, -v.z, -v.w); +} + inline Vector4 operator *(const Vector4 &v, float s) { return Vector4(v.x * s, v.y * s, v.z * s, v.w * s); @@ -153,4 +170,13 @@ return Vector4(x, y, z, w); } +inline Vector4 lerp(const Vector4 &a, const Vector4 &b, float t) +{ + return Vector4(a.x + (b.x - a.x) * t, + a.y + (b.y - a.y) * t, + a.z + (b.z - a.z) * t, + a.w + (b.w - a.w) * t); +} + + #endif // VMATH_H_ diff -r 4d87b0aafbb0 -r 79609d482762 src/vmathmat.h --- a/src/vmathmat.h Sun Apr 13 09:54:51 2014 +0300 +++ b/src/vmathmat.h Mon Apr 14 07:34:45 2014 +0300 @@ -130,4 +130,12 @@ *this = *this * m; } +inline Matrix4x4 normal_matrix(const Matrix4x4 &m) +{ + return Matrix4x4(m[0][0], m[0][1], m[0][2], 0, + m[1][0], m[1][1], m[1][2], 0, + m[2][0], m[2][1], m[2][2], 0, + m[3][0], m[3][1], m[3][2], 1); +} + #endif // VMATH_MATRIX_H_