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@46
|
35 Vec3 pos = ray.origin + ray.dir * hit.dist;
|
nuclear@43
|
36
|
nuclear@46
|
37 Vec3 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@46
|
43 //return norm * 0.5 + Vec3(0.5, 0.5, 0.5);
|
nuclear@46
|
44 Vec2 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@46
|
55 Vec3 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@46
|
68 const Mat4x4 &xform = light_node->get_matrix();
|
nuclear@46
|
69 const Mat4x4 &inv_xform = light_node->get_inv_matrix();
|
nuclear@46
|
70 Vec3 spt = light->gen_surface_point().transformed(xform);
|
nuclear@43
|
71
|
nuclear@46
|
72 Vec3 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@46
|
94 Vec2 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@46
|
101 Vec3 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@46
|
110 Vec3 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 }
|