nuclear@8: #include nuclear@6: #include "rt.h" nuclear@8: #include "erebus_impl.h" nuclear@8: nuclear@17: Color ray_trace(struct erebus *ctx, const Ray &ray, int iter) nuclear@6: { nuclear@17: const Scene *scn = ctx->scn; nuclear@17: if(!scn) { nuclear@17: return Color(1, 0, 0); nuclear@17: } nuclear@17: nuclear@43: if(iter > erb_getopti(ctx, ERB_OPT_MAX_ITER) || ray.energy < 0.0001) { nuclear@43: //return Color(1, 0, 1); nuclear@43: return Color(0, 0, 0); nuclear@43: } nuclear@43: nuclear@6: RayHit hit; nuclear@6: if(!(scn->intersect(ray, &hit))) { nuclear@8: return scn->get_env_color(ray); nuclear@6: } nuclear@6: nuclear@17: return shade(ctx, hit, iter); nuclear@6: } nuclear@6: nuclear@17: Color shade(struct erebus *ctx, const RayHit &hit, int iter) nuclear@6: { nuclear@8: assert(hit.obj->get_type() == ObjType::geom); nuclear@17: const Scene *scn = ctx->scn; nuclear@8: const GeomObject *obj = (const GeomObject*)hit.obj; nuclear@8: const Material *mtl = &obj->mtl; nuclear@8: const Reflectance *brdf = obj->brdf; nuclear@8: const Ray &ray = hit.world_ray; nuclear@26: //bool entering = true; nuclear@8: nuclear@43: Vector3 pos = ray.origin + ray.dir * hit.dist; nuclear@43: nuclear@17: Vector3 norm = hit.calc_normal(); nuclear@23: if(dot_product(ray.dir, norm) > 0.0) { nuclear@26: //entering = false; nuclear@23: norm = -norm; nuclear@23: } nuclear@23: nuclear@18: //return norm * 0.5 + Vector3(0.5, 0.5, 0.5); nuclear@17: Vector2 texcoords = hit.calc_texcoords(); nuclear@8: nuclear@17: Color color = mtl->get_attrib_color("diffuse", texcoords.x, texcoords.y); nuclear@28: Color specular = mtl->get_attrib_color("specular", texcoords.x, texcoords.y); nuclear@43: Color res = color * scn->get_env().ambient; nuclear@28: float shininess = mtl->get_attrib_value("shininess"); nuclear@8: nuclear@43: res += mtl->get_attrib_color("emissive", texcoords.x, texcoords.y); nuclear@43: nuclear@43: /* nuclear@43: // calculate direct illumination nuclear@43: Vector3 vdir = -ray.dir.normalized(); nuclear@43: std::list lights = scn->gen_light_list(); nuclear@43: auto it = lights.cbegin(); nuclear@43: while(it != lights.cend()) { nuclear@43: const ObjectInstance &inst = *it++; nuclear@43: GeomObject *light = (GeomObject*)inst.obj; nuclear@43: SceneNode *light_node = inst.node; nuclear@43: nuclear@43: if(obj == light) { nuclear@43: // don't try to get illumination from ourselves nuclear@43: continue; nuclear@43: } nuclear@43: nuclear@43: const Matrix4x4 &xform = light_node->get_matrix(); nuclear@43: const Matrix4x4 &inv_xform = light_node->get_inv_matrix(); nuclear@43: Vector3 spt = light->gen_surface_point().transformed(xform); nuclear@43: nuclear@43: Vector3 ldir = spt - pos; nuclear@43: if(dot_product(ldir, norm) < 0.0) { nuclear@43: continue; nuclear@43: } nuclear@43: Ray shadow_ray{pos, ldir}; nuclear@43: nuclear@43: RayHit shadow_hit; nuclear@43: shadow_hit.obj = 0; nuclear@43: if(scn->intersect(shadow_ray, &shadow_hit) && shadow_hit.obj != light && nuclear@43: shadow_hit.dist < 0.99999 && shadow_hit.dist > 1e-5) { nuclear@43: // we're in shadow, skip nuclear@43: continue; nuclear@43: } nuclear@43: nuclear@43: if(!shadow_hit.obj) { nuclear@43: shadow_hit.obj = light; nuclear@43: shadow_hit.dist = 1.0; nuclear@43: shadow_hit.world_ray = shadow_ray; nuclear@43: shadow_hit.local_ray = shadow_ray.transformed(inv_xform); nuclear@43: shadow_hit.node = inst.node; nuclear@43: } nuclear@43: nuclear@43: Vector2 tc = shadow_hit.calc_texcoords(); nuclear@43: Color lcol = light->mtl.get_attrib_color("emissive", tc.x, tc.y); nuclear@43: nuclear@43: ldir.normalize(); nuclear@43: norm.normalize(); nuclear@43: float ndotl = dot_product(ldir, norm); nuclear@43: nuclear@43: Vector3 refl = ldir.reflection(norm); nuclear@43: float vdotr = dot_product(vdir, refl); nuclear@43: nuclear@43: Color direct = ray.energy * lcol * (color * ndotl);// + specular * pow(vdotr, shininess)); nuclear@43: assert(direct.x >= 0.0 && direct.y >= 0.0 && direct.z >= 0.0); nuclear@43: res += direct; nuclear@43: } nuclear@43: */ nuclear@43: nuclear@8: Vector3 sample_dir; nuclear@43: float prob = brdf->sample(SurfaceGeometry(norm), -ray.dir, &sample_dir); nuclear@43: if(randf() <= prob) { nuclear@8: Ray sample_ray; nuclear@43: sample_ray.origin = pos; nuclear@8: sample_ray.dir = sample_dir; nuclear@28: sample_ray.energy = ray.energy * prob; nuclear@8: nuclear@17: res += ray_trace(ctx, sample_ray, iter + 1) * color; nuclear@8: } nuclear@29: nuclear@29: res.w = 1.0; nuclear@8: return res; nuclear@6: }