erebus

annotate liberebus/src/rt.cc @ 43:ed18af9da8f7

first attempt at separating direct from indirect failed miserably
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 11 Jun 2014 16:38:11 +0300
parents 5e27c85e79ca
children c4d48a21bc4a
rev   line source
nuclear@8 1 #include <assert.h>
nuclear@6 2 #include "rt.h"
nuclear@8 3 #include "erebus_impl.h"
nuclear@8 4
nuclear@17 5 Color ray_trace(struct erebus *ctx, const Ray &ray, int iter)
nuclear@6 6 {
nuclear@17 7 const Scene *scn = ctx->scn;
nuclear@17 8 if(!scn) {
nuclear@17 9 return Color(1, 0, 0);
nuclear@17 10 }
nuclear@17 11
nuclear@43 12 if(iter > erb_getopti(ctx, ERB_OPT_MAX_ITER) || ray.energy < 0.0001) {
nuclear@43 13 //return Color(1, 0, 1);
nuclear@43 14 return Color(0, 0, 0);
nuclear@43 15 }
nuclear@43 16
nuclear@6 17 RayHit hit;
nuclear@6 18 if(!(scn->intersect(ray, &hit))) {
nuclear@8 19 return scn->get_env_color(ray);
nuclear@6 20 }
nuclear@6 21
nuclear@17 22 return shade(ctx, hit, iter);
nuclear@6 23 }
nuclear@6 24
nuclear@17 25 Color shade(struct erebus *ctx, const RayHit &hit, int iter)
nuclear@6 26 {
nuclear@8 27 assert(hit.obj->get_type() == ObjType::geom);
nuclear@17 28 const Scene *scn = ctx->scn;
nuclear@8 29 const GeomObject *obj = (const GeomObject*)hit.obj;
nuclear@8 30 const Material *mtl = &obj->mtl;
nuclear@8 31 const Reflectance *brdf = obj->brdf;
nuclear@8 32 const Ray &ray = hit.world_ray;
nuclear@26 33 //bool entering = true;
nuclear@8 34
nuclear@43 35 Vector3 pos = ray.origin + ray.dir * hit.dist;
nuclear@43 36
nuclear@17 37 Vector3 norm = hit.calc_normal();
nuclear@23 38 if(dot_product(ray.dir, norm) > 0.0) {
nuclear@26 39 //entering = false;
nuclear@23 40 norm = -norm;
nuclear@23 41 }
nuclear@23 42
nuclear@18 43 //return norm * 0.5 + Vector3(0.5, 0.5, 0.5);
nuclear@17 44 Vector2 texcoords = hit.calc_texcoords();
nuclear@8 45
nuclear@17 46 Color color = mtl->get_attrib_color("diffuse", texcoords.x, texcoords.y);
nuclear@28 47 Color specular = mtl->get_attrib_color("specular", texcoords.x, texcoords.y);
nuclear@43 48 Color res = color * scn->get_env().ambient;
nuclear@28 49 float shininess = mtl->get_attrib_value("shininess");
nuclear@8 50
nuclear@43 51 res += mtl->get_attrib_color("emissive", texcoords.x, texcoords.y);
nuclear@43 52
nuclear@43 53 /*
nuclear@43 54 // calculate direct illumination
nuclear@43 55 Vector3 vdir = -ray.dir.normalized();
nuclear@43 56 std::list<ObjectInstance> lights = scn->gen_light_list();
nuclear@43 57 auto it = lights.cbegin();
nuclear@43 58 while(it != lights.cend()) {
nuclear@43 59 const ObjectInstance &inst = *it++;
nuclear@43 60 GeomObject *light = (GeomObject*)inst.obj;
nuclear@43 61 SceneNode *light_node = inst.node;
nuclear@43 62
nuclear@43 63 if(obj == light) {
nuclear@43 64 // don't try to get illumination from ourselves
nuclear@43 65 continue;
nuclear@43 66 }
nuclear@43 67
nuclear@43 68 const Matrix4x4 &xform = light_node->get_matrix();
nuclear@43 69 const Matrix4x4 &inv_xform = light_node->get_inv_matrix();
nuclear@43 70 Vector3 spt = light->gen_surface_point().transformed(xform);
nuclear@43 71
nuclear@43 72 Vector3 ldir = spt - pos;
nuclear@43 73 if(dot_product(ldir, norm) < 0.0) {
nuclear@43 74 continue;
nuclear@43 75 }
nuclear@43 76 Ray shadow_ray{pos, ldir};
nuclear@43 77
nuclear@43 78 RayHit shadow_hit;
nuclear@43 79 shadow_hit.obj = 0;
nuclear@43 80 if(scn->intersect(shadow_ray, &shadow_hit) && shadow_hit.obj != light &&
nuclear@43 81 shadow_hit.dist < 0.99999 && shadow_hit.dist > 1e-5) {
nuclear@43 82 // we're in shadow, skip
nuclear@43 83 continue;
nuclear@43 84 }
nuclear@43 85
nuclear@43 86 if(!shadow_hit.obj) {
nuclear@43 87 shadow_hit.obj = light;
nuclear@43 88 shadow_hit.dist = 1.0;
nuclear@43 89 shadow_hit.world_ray = shadow_ray;
nuclear@43 90 shadow_hit.local_ray = shadow_ray.transformed(inv_xform);
nuclear@43 91 shadow_hit.node = inst.node;
nuclear@43 92 }
nuclear@43 93
nuclear@43 94 Vector2 tc = shadow_hit.calc_texcoords();
nuclear@43 95 Color lcol = light->mtl.get_attrib_color("emissive", tc.x, tc.y);
nuclear@43 96
nuclear@43 97 ldir.normalize();
nuclear@43 98 norm.normalize();
nuclear@43 99 float ndotl = dot_product(ldir, norm);
nuclear@43 100
nuclear@43 101 Vector3 refl = ldir.reflection(norm);
nuclear@43 102 float vdotr = dot_product(vdir, refl);
nuclear@43 103
nuclear@43 104 Color direct = ray.energy * lcol * (color * ndotl);// + specular * pow(vdotr, shininess));
nuclear@43 105 assert(direct.x >= 0.0 && direct.y >= 0.0 && direct.z >= 0.0);
nuclear@43 106 res += direct;
nuclear@43 107 }
nuclear@43 108 */
nuclear@43 109
nuclear@8 110 Vector3 sample_dir;
nuclear@43 111 float prob = brdf->sample(SurfaceGeometry(norm), -ray.dir, &sample_dir);
nuclear@43 112 if(randf() <= prob) {
nuclear@8 113 Ray sample_ray;
nuclear@43 114 sample_ray.origin = pos;
nuclear@8 115 sample_ray.dir = sample_dir;
nuclear@28 116 sample_ray.energy = ray.energy * prob;
nuclear@8 117
nuclear@17 118 res += ray_trace(ctx, sample_ray, iter + 1) * color;
nuclear@8 119 }
nuclear@29 120
nuclear@29 121 res.w = 1.0;
nuclear@8 122 return res;
nuclear@6 123 }