/** * The fresnel rayTrace function creates a fresnel effect for the objects it affects. */ glm::vec3 rayTrace(Ray &ray, const float& t, const glm::vec3& normal, RayTracerState& state) { glm::vec3 n = glm::normalize(normal); glm::vec3 v = glm::normalize(ray.getDirection()); if(glm::dot(n, v) < 0.0f){ glm::vec3 refl_dir = reflect(n, v); glm::vec3 refract_dir = refract(n, v, eta_in); float fresnel = RF0_in + (1.0f-RF0_in)*glm::pow((1.0f-glm::dot(-v, n)), 5.0f); float reflect_contribution = ray.getColorContribution()*fresnel; float refract_contribution = ray.getColorContribution()*(1.0f-fresnel); glm::vec3 reflect = state.rayTrace(ray.spawn(t, refl_dir, reflect_contribution)); glm::vec3 refract = state.rayTrace(ray.spawn(t, refract_dir, refract_contribution)); return glm::mix(refract, reflect, fresnel); } else { glm::vec3 refl_dir(glm::reflect(v, n)); glm::vec3 refract_dir = refract(-n, v, eta_out); float fresnel = RF0_out + (1.0f-RF0_out)*glm::pow((1.0f-glm::dot(refract_dir, n)), 5.0f); float reflect_contribution = ray.getColorContribution()*fresnel; float refract_contribution = ray.getColorContribution()*(1.0f-fresnel); glm::vec3 reflect = state.rayTrace(ray.spawn(t, refl_dir, reflect_contribution)); glm::vec3 refract = state.rayTrace(ray.spawn(t, refract_dir, refract_contribution)); return glm::mix(refract, reflect, fresnel); } }
// Found uncorrected value by solving equation. This is OK since // unrefract is never called in loops. // // Convergence is quite fast just a few iterations. double SkyPoint::unrefract(const double alt) { double h0 = alt; double h1 = alt - (refract( h0 ) - h0); // It's probably okay to add h0 in refract() and subtract it here, since refract() is called way more frequently. while( fabs(h1 - h0) > 1e-4 ) { h0 = h1; h1 = alt - (refract( h0 ) - h0); } return h1; }
glm::vec3 indirect(const glm::vec3 &c, const glm::vec3 &p, const glm::vec3 &n, const Glass &glass, int iterations) { float ior = 1.5f; // Calcul du rayon réfléchi glm::vec3 direction = reflect(c,n); glm::vec3 directionNorm = glm::normalize(direction); Ray rayReflexion{p+directionNorm*0.1f, directionNorm}; // Calcul du rayon réfracté glm::vec3 vecRefract; refract(-c, n, ior, vecRefract); Ray rayRefraction{p+vecRefract*0.1f, vecRefract}; // Calcul du coefficient reflechi/refracte float coeff = fresnelR(-c, n, ior); float rand = random_u(); if (rand < coeff) { return radiance(rayReflexion, iterations-1); } return radiance(rayRefraction, iterations-1) * glass.color; //return radiance(rayReflexion, iterations-1) * coeff + radiance(rayRefraction, iterations-1) * (1- coeff); }
Spectrum GlassBSDF::sample_f(const Vector3D& wo, Vector3D* wi, float* pdf) { // TODO Part 5: // Compute Fresnel coefficient and either reflect or refract based on it. if (!refract(wo, wi, ior)) { reflect(wo, wi); *pdf = 1.0; return reflectance * (1.0 / fabs(wi->z)); } double R = (ior - 1.0) * (ior - 1.0) / (ior + 1.0) / (ior + 1.0); double c = 1.0 - fabs(wi->z); R = R + (1.0 - R) * c * c * c * c * c; if (coin_flip(R)) { reflect(wo, wi); *pdf = R; return reflectance * (R / fabs(wi->z)); } *pdf = 1.0 - R; double nr; if (wi->z > 0) { nr = ior; } else { nr = 1.0 / ior; } return transmittance * ((1.0 - R) * nr * nr / fabs(wi->z)); }
t_bool dielectric(t_material *material, const t_ray *r, const t_hit_record *h, t_vec3 *attenuation, t_ray *scattered) { t_vec3 outward_normal; t_vec3 reflected; t_vec3 refracted; float ni_over_nt; float reflect_probe; float cosine; vec3_reflect(&reflected, &RAY_DIRECTION(r), &h->normal); vec3_assign(attenuation, &material->texture.albedo); if (vec3_dot(&RAY_DIRECTION(r), &h->normal) > 0) { vec3_mul_f(&outward_normal, &h->normal, -1.f); //TODO pass idx ni_over_nt = REF_IDX; cosine = REF_IDX * vec3_dot(&RAY_DIRECTION(r), &h->normal) / vec3_length(&RAY_DIRECTION(r)); } else { vec3_assign(&outward_normal, &h->normal); ni_over_nt = 1.0f / REF_IDX; cosine = - vec3_dot(&RAY_DIRECTION(r), &h->normal) / vec3_length(&RAY_DIRECTION(r)); } if (refract(&RAY_DIRECTION(r), &outward_normal, ni_over_nt, &refracted)) reflect_probe = schlick(cosine, REF_IDX); else reflect_probe = 1.0f; if (drand48() < reflect_probe) ray_assign(scattered, &h->pos, &reflected); else ray_assign(scattered, &h->pos, &refracted); return (TRUE); }
static void Vector4Refract(benchmark::State& state) { Vector4 a(0.2, 0.2, 0.3), n(0, 1, 0), r; benchmark::DoNotOptimize(a); benchmark::DoNotOptimize(n); for (auto _ : state) { r = refract(a, n, 1.0, 1.3); benchmark::DoNotOptimize(r); } }
Color Refr::shade(const Ray& ray, const IntersectionInfo& info) { // ior = eta2 / eta1 Vector refr; if (dot(ray.dir, info.normal) < 0) { // entering the geometry refr = refract(ray.dir, info.normal, 1 / ior); } else { // leaving the geometry refr = refract(ray.dir, -info.normal, ior); } if (refr.lengthSqr() == 0) return Color(0, 0, 0); Ray newRay = ray; newRay.start = info.ip - faceforward(ray.dir, info.normal) * 0.000001; newRay.dir = refr; newRay.depth++; return raytrace(newRay) * multiplier; }
/******* Fonction à écrire par les etudiants ******/ Color trace_ray (Ray ray_) { /** * \todo : recursive raytracing * * La fonction trace_ray() renvoie une couleur obtenue par la somme de l'éclairage direct (couleur calculée par la fonction * compute_direct_lighting()) et des couleurs provenant des reflets et transparences éventuels aux points d'intersection. * Dans la première partie du TP, seul l'éclairage direct sera calculé. Dans la seconde partie, les reflets et transparences seront rajoutés. * * Pour la première étape, la fonction trace_ray() ne calculant que les rayons primaires, l'intersection * entre le rayon et la scène doit être calculée (fonction intersect_scene() du module \ref RayAPI). * S'il n'y a pas d'intersection, une couleur blanche (triplet RGB [1, 1, 1], élément neutre de la multiplication des couleurs) * devra être retournée. * S'il y a une intersection, la couleur retournée sera la couleur résultante de l'éclairage direct du point d'intersection par les * sources lumineuses de la scène et calculée par la fonction compute_direct_lighting() à écrire dans la suite. * * Pour la deuxième étape, à partir des fonctions définies dans le module \ref RayAPI et permettant d'accéder aux informations de * profondeur et d'importance sur le rayon, définir un cas d'arêt dela récursivité et renvoyer si ce cas est vérifié la couleur * résultante de l'éclairage direct. Si la récursivité n'est pas terminée, en utilisant les fonctions définies dans le module \ref LightAPI, * calculer la couleur réfléchie. Pour cela, il faut tester si le matériau est réflechissant et, si c'est le cas, calculer le rayon * réfléchi et le coefficient de réflexion (une couleur). La couleur calculée en lançant le rayon réfléchi devra alors être multipliée par ce coefficient avant d'être ajoutée * à la couleur renvoyée par trace_ray(). * * Pour la troisème étape et de façon très similaire à la réflexion, utiliser les fonctions définies dans le module \ref LightAPI pour calculer la couleur réfractée. * Pour cela, il faut tester si le matériau est transparent et, si c'est le cas, calculer le rayon réfracté et le coefficient de * transparence (une couleur). La couleur calculée en lançant le rayon réfracté devra alors être multipliée par ce coefficient avant * d'être ajoutée à la couleur renvoyée par trace_ray(). * */ Color l = init_color (0.075f, 0.075f, 0.075f); Isect isect_; int isInter = intersect_scene (&ray_, &isect_ ); if (isInter!=0){ l = compute_direct_lighting (ray_, isect_); } if (ray_depth(ray_)>10 || ray_importance(ray_)<0.01f) return (l); //reflection if(isect_has_reflection(isect_)){ Ray refl_ray; Color refl_col = reflect(ray_, isect_, &refl_ray); l = l+refl_col*(trace_ray(refl_ray)); } //refraction if(isect_has_refraction(isect_)){ Ray rafr_ray; Color rafr_col = refract(ray_, isect_, &rafr_ray); if(color_is_black(rafr_col)==0) l = l+rafr_col*(trace_ray(rafr_ray)); } return l; }
Spectrum RefractionBSDF::sample_f(const Vector3D& wo, Vector3D* wi, float* pdf) { // TODO: // Implement RefractionBSDF refract(wo,wi,this->ior); *pdf = 1; return this->transmittance; // return Spectrum(); }
void Refr::spawnRay(const IntersectionInfo& x, const Vector& w_in, Ray& w_out, Color& out_color, float& pdf) { Vector refr; if (dot(w_in, x.normal) < 0) { // entering the geometry refr = refract(w_in, x.normal, 1 / ior); } else { // leaving the geometry refr = refract(w_in, -x.normal, ior); } if (refr.lengthSqr() == 0) { pdf = 0; return; } w_out.dir = refr; w_out.start = x.ip + w_out.dir * 1e-6; w_out.flags &= ~RF_DIFFUSE; out_color = Color(1, 1, 1) * multiplier; pdf = 1; }
Spectrum GlassBSDF::sample_f(const Vector3D& wo, Vector3D* wi, float* pdf) { // TODO Part 5: // Compute Fresnel coefficient and either reflect or refract based on it. double no, ni; if (wo.z < 0) { //r = ior/1; no = ior; ni = 1.0; } else { //r = 1.0/ior; no = 1.0; ni = ior; } bool totalIR = refract(wo, wi, ior); if (!totalIR) { reflect(wo, wi); *pdf = 1.0; return reflectance / abs_cos_theta(*wi); } else { float Ro = ((no - ni)/ (no + ni)) * ((no - ni)/ (no + ni)); float R = Ro + (1.0 - Ro)*pow((1.0 - abs_cos_theta(wo)), 5.0); R = clamp(R, 0.0, 1.0); if (coin_flip(R)) { reflect(wo, wi); *pdf = R; return R * (reflectance / abs_cos_theta(*wi)); } else { refract(wo, wi, ior); *pdf = 1.0 - R; //double r; //printf("%s\n", "here"); return (1.0 - R) * (transmittance * no/ni * no/ni) / abs_cos_theta(*wi); } } }
void InspectionShader::shade( Scene & scene, RandomNumberGenerator & rng, RayIntersection & intersection ) { RGBColor color( 0.0f, 0.0f, 0.0f ); const float index_in = intersection.ray.index_of_refraction; const float index_out = intersection.material->index_of_refraction; const Vector4 from_dir = intersection.fromDirection(); switch( property ) { case FresnelDialectric: { Vector4 refracted = refract( from_dir, intersection.normal, index_in, index_out ); float fresnel = 1.0f; if( refracted.magnitude() > 0.0001 ) { fresnel = Fresnel::Dialectric::Unpolarized( dot( from_dir, intersection.normal ), dot( refracted, intersection.normal.negated() ), index_in, index_out ); } color = RGBColor( fresnel, fresnel, fresnel ); } break; case FresnelConductor: { float absorptionCoeff = 2.0; // FIXME: material specific float fresnel = Fresnel::Conductor::Unpolarized( dot( from_dir, intersection.normal ), index_out, absorptionCoeff ); color = RGBColor( fresnel, fresnel, fresnel ); } break; case Normal: { auto shifted = add( scale( intersection.normal, 0.5 ), Vector4( 0.5, 0.5, 0.5 ) ); color = RGBColor( shifted.x, shifted.y, shifted.z ); } break; case IndexOfRefraction: { float v = index_out / 3.0; color = RGBColor( v, v, v ); } break; case TextureUVCoordinate: { color = RGBColor( intersection.u, intersection.v, 0.0 ); } break; default: ; } intersection.sample.color = color; }
void Raytracer::Trace(const Ray& aRay, Color* aColor, int aDepth) { aq_float T; Intersection RayIntersection; if (!mScene->Intersect(aRay, &T, &RayIntersection)) { *aColor = mScene->Properties.BackgroundColor; return; } *aColor = COLOR::BLACK; for (Light* light : mScene->GetLights()) { *aColor += Shade(aRay, RayIntersection, *light); } *aColor = clamp(*aColor, 0.0, 100.0); //Russian roulette for stopping recursive if (aDepth > mScene->Properties.RecursiveDepth) { aq_float AvgReflectance = sum(RayIntersection.Mat.kr) / 3; if (AvgReflectance < Utils::RandFloatInterval(0.0, 1.2)) { return; } } //Ambient occlusion //*aColor += 0.2 * IndirectLighting(aRay, RayIntersection, aDepth); //Reflection if (sum(RayIntersection.Mat.kr) > 0) { Ray ReflectedRay(RayIntersection.Local.Pos, reflect(aRay.Dir, RayIntersection.Local.Normal)); Color ReflectedColor; Trace(ReflectedRay, &ReflectedColor, aDepth + 1); *aColor = mix(*aColor, ReflectedColor, RayIntersection.Mat.kr); } ////Refraction if (RayIntersection.Mat.Transparency > 0) { Ray RefractedRay(RayIntersection.Local.Pos, refract(aRay.Dir, RayIntersection.Local.Normal, RayIntersection.Mat.RefractiveIndex)); Color RefractedColor; Trace(RefractedRay, &RefractedColor, aDepth + 1); *aColor = mix(*aColor, RefractedColor, RayIntersection.Mat.Transparency); } }
Color3f sample(BSDFQueryRecord &bRec, const Point2f &sample) const { // sample the mirco scale normal Vector3f m = Microfacet::sample(m_alpha, sample); float pdf = Microfacet::pdf(m_alpha, m); if(pdf == 0.0) { std::cout << "sample pdf should nearly never be zero"; return Color3f(0.0f); } float wiDotM = bRec.wi.dot(m); float cosThetaT = 0.0f; float F = dielectricReflectance(wiDotM, cosThetaT, m_intIOR / m_extIOR); bool sampleReflection = true; // check if reflection or refraction // for reuseable sample if(bRec.sampler->next1D() > F) { sampleReflection = false; } if (sampleReflection) { bRec.wo = 2.0f * wiDotM * m - bRec.wi;; bRec.eta = 1.0f; /* Side check */ if (Frame::cosTheta(bRec.wi) * Frame::cosTheta(bRec.wo) <= 0) return Color3f(0.0f); } else { if (cosThetaT == 0) return Color3f(0.0f); bRec.wo = refract(bRec.wi, m, m_intIOR / m_extIOR, cosThetaT); bRec.eta = cosThetaT < 0 ? m_intIOR / m_extIOR : m_extIOR / m_extIOR; /* Side check */ if (Frame::cosTheta(bRec.wi) * Frame::cosTheta(bRec.wo) >= 0) return Color3f(0.0f); } float G = Microfacet::G(m_alpha, bRec.wi, bRec.wo, m); float D = Microfacet::D(m_alpha, m); return std::abs(D * G * bRec.wi.dot(m) / (pdf * Frame::cosTheta(bRec.wi))); }
DistributionSample RefractiveMaterial::sampleBxDF( RandomNumberGenerator & rng, const RayIntersection & intersection ) const { // Perfect Fresnel refractor DistributionSample sample; const float index_in = intersection.ray.index_of_refraction; const float index_out = index_of_refraction; const Vector4 from_dir = intersection.fromDirection(); // FIXME: HACK - This assumes that if we hit the surface of an object with the same // index of refraction as the material we're in, then we are moving back into // free space. This might not be true if there are numerical errors tracing // abutting objects of the same material type, or for objects that are intersecting. if( index_out == index_in ) { sample.new_index_of_refraction = 1.0f; } Vector4 refracted = refract( from_dir, intersection.normal, index_in, index_out ); float fresnel = 1.0f; // default to total internal reflection if refract() returns // a zero length vector if( refracted.magnitude() > 0.0001 ) { fresnel = Fresnel::Dialectric::Unpolarized( dot( from_dir, intersection.normal ), dot( refracted, intersection.normal.negated() ), index_in, index_out ); } const float draw = rng.uniform01(); // Use RNG to choose whether to reflect or refract based on Fresnel coefficient. // Random selection accounts for fresnel or 1-fresnel scale factor. if( fresnel == 1.0f || draw < fresnel ) { // Trace reflection (mirror ray scaled by fresnel or 1 for total internal reflection) sample.direction = mirror( from_dir, intersection.normal ); // FIXME - How do we determine pdf_sample for total internal reflection? sample.pdf_sample = fresnel; sample.new_index_of_refraction = index_in; } else { // Trace refraction (refracted ray scaled by 1-fresnel) sample.direction = refracted; sample.pdf_sample = 1.0 - fresnel; sample.new_index_of_refraction = index_out; } return sample; }
bool Tracer::scatterRefractive(const IntersectDescr& node, Ray& ray) const { // here we throw the dice to dices whether to reflect or to refract const double probability = ::uniform_distrib_( ::rand_gen_ ); // heuristic to determine material transition // note, this assumes that only one type of refractive material exists AND // that two objects do not intersect, such that an interface within a // non-air material exists (well, its not that strict, but simpler to // explain this way) const double surface_dot = node.normal_.dot( node.incident_ ); const bool is_entry = ( surface_dot <= 0. ); // 1.52 is for crown glass const double refractive_idx_from = is_entry ? 1.0 : 1.52; const double refractive_idx_to = is_entry ? 1.52 : 1.0; // The reflectance and refract functions require the normal to point into // the direction of the first material. If this is not the case, we invert // its direction. const Vector corrected_normal = is_entry ? node.normal_ : -1. * node.normal_; const double reflect = reflectance( corrected_normal, node.incident_, refractive_idx_from, refractive_idx_to ); if( probability <= reflect ) { return scatterSpecular( node, ray ); } else { Vector refracted_dir = refract( corrected_normal, node.incident_, refractive_idx_from, refractive_idx_to ); if( refracted_dir.length() > 1e-4 ) { ray = Ray{ node.point_, refracted_dir.normalized() }; return true; } else { return false; } } return false; // should never get here, though }
nex::color fresnel_refraction_btdf::sample(const lumen::sample& sample, const surface& surface, const nex::vector& wo, nex::vector* wi, float* pdf) const { float eta = ni / nt; *wi = refract(wo, surface.normal, &eta); *pdf = 1.0f; // check for total internal reflection if (*wi == nex::vector(0.0f, 0.0f, 0.0f)) { return nex::color::black(); } return (1.0f - fresnel(ni, nt, nex::dot(surface.normal, wo))) * transmittance / (eta * eta) / std::abs(nex::dot(surface.normal, *wi)); }
extern "C" void execute(void *params, BVHShader_functions *func, void *env) { BVHShader_surface *surface = (BVHShader_surface*)env; BVHShader_params *p = (BVHShader_params*)params; float rayRefract[3]; float rayReflect[3]; BVHColor colorRefraction; BVHColor colorReflection; float fresnelFactor; // Calculate refraction ray refract(surface->normal, surface->rayInput, rayRefract, p->indexRel); invert(rayRefract); normalize(rayRefract); // Calculate reflection ray reflect(surface->normal, surface->rayInput, rayReflect); invert(rayReflect); normalize(rayReflect); // Normalize vector normalize(surface->rayOutput); // Get fresnel fresnelFactor = fresnel(surface->normal, surface->rayInput, p->indexRel); // Calculate reflection and refraction color if (dotAbs(surface->rayOutput, rayRefract) > 0.9999f) { colorRefraction.init(1.0f / dotAbs(surface->rayOutput, surface->normal)); colorReflection.init(0.0f); } else if (dotAbs(surface->rayOutput, rayReflect) > 0.9999f) { colorRefraction.init(0.0f); colorReflection.init(1.0f / dotAbs(surface->rayOutput, surface->normal)); } else { colorRefraction.init(0.0f); colorReflection.init(0.0f); } surface->color = p->color * (colorRefraction * (1.0f - fresnelFactor) + colorReflection * fresnelFactor); surface->emission.init(0.0f); }
void propagate(ray_array& rays, const T& lens, double step_size, double max_vel, std::ofstream& output) { // move simulation every timestep for (auto& ray : rays) { for (size_t i = 0; i < TIME_RES; i+= 1) { if (ray.p.x > lens.origin.x + lens.radius + 1) { continue; } ray.p += ray.v * step_size; double n1 = ray.previous_index; double n2 = refractive_index_at(lens, ray.p); // If the ray passed through a refraction index change if (n1 != n2) { vec n = normal_at(lens, ray.p); vec l = normalize(ray.v); double ior = n1 / n2; if (dot(-n, l) < 0.0) { n = -n; } vec speed = refract(l, n, ior); if (is_null(speed)) { speed = reflect(l, n); } // Multiply with ior * length(ray.v) to get the proper velocity // for the refracted vector ray.v = normalize(speed) * ior * length(ray.v); } ray.previous_index = n2; if (i % 1000 == 0) { output << ray.p.x <<'\t'<< ray.p.y << '\t' << ray.v.x <<'\t'<< ray.v.y << '\n'; } } output << '\n' << '\n'; } }
glm::vec3 indirect(const Ray &rOrigine, const Ray &rReflect, const glm::vec3 &p, const glm::vec3 & n, int countdown, const Glass &glass) { float fresnel = fresnelR(-rOrigine.direction,n, 1.5); glm::vec3 refracted; bool canRefract = refract(-rOrigine.direction, n, 1.5, refracted); Ray rRefracted{p+refracted*0.1f, refracted}; if(canRefract) { float u = random_u(); if(u < fresnel) return radiance(rReflect, countdown); else return radiance(rRefracted, countdown); } //return fresnel*radiance(rReflect, countdown)+(1-fresnel)*radiance(rRefracted, countdown); else return fresnel*radiance(rReflect, countdown); }
a3Spectrum a3Dieletric::sample(const t3Vector3f& wi, t3Vector3f& wo, float* pdf, const a3Intersection& its) const { static a3Random random; t3Vector3f n = its.getNormal(); // 入射光 / 出射光所在折射率 float etai = 1.0f, etat = its.shape->refractiveIndex; // 光密到光疏 if(wi.dot(n) > 0) { t3Math::swap(etai, etat); // 翻转法线 保持与入射光线一个平面 n = -n; } float eta = etai / etat; // 菲涅尔反射(反射的概率) //float Fr = a3FresnelDielectric(costhetai, costhetat, etai, etat); float Fr = reflectance(n, wi, etai, etat); //float P = 0.25 + 0.5 * Fr; float r = random.randomFloat(); if(r > Fr) { bool TIR = false; wo = refract(n, wi, etai, etat, TIR); *pdf = 1.0f; eta = 1 / eta; return getColor(its) * specularTransmittance / t3Math::Abs(wo.dot(n)); } else { wo = reflect(n, wi); *pdf = 1.0f; // 镜面反射 return getColor(its) * specularReflectance / t3Math::Abs(wo.dot(n)); } }
bool RayBouncer::RefractionBounce( RayBounce& raybounce, const Ray& ray, const Scene& scene, const RayShader& shader, const PrimitiveHit& primitivehit, const real& ior1, const real& ior2, std::size_t depth ) const { const Primitive& primitive = primitivehit.first; const PrecalculatedMaterial& material = primitivehit.second; const Hit& hit = primitivehit.third; bool hastransparency = std::any_of( material.refractivity.begin( ), material.refractivity.end( ), real_compare<std::less<>, 1>( ) ); if ( !hastransparency ) return false; Fur::optional<vec3> oprefractionraydir = refract( ray.direction, hit.inside ? hit.normal * real_neg_one : hit.normal, ior1, ior2 ); if ( !oprefractionraydir ) return false; // Not total internal reflection const vec3& refractionraydir = *oprefractionraydir; Ray refractionray( hit.contact + refractionraydir * scene.Bias(), refractionraydir ); raybounce.ray = refractionray; Bounce( raybounce, refractionray, scene, shader, primitivehit, depth + 1 ); return true; }
bool Dielectric::scatter(const Ray& r_in, const HitRecord& record, vec3& attenuation, Ray& scattered) const { vec3 outward_normal; vec3 reflected = reflect(r_in.direction(), record.normal); float ni_over_nt; attenuation = vec3(1,1,1); vec3 refracted; float reflect_probability; float cosine; if (dot(r_in.direction(), record.normal) > 0) { outward_normal = -record.normal; ni_over_nt = refractive_index; cosine = refractive_index * dot(r_in.direction(), record.normal) / r_in.direction().length(); } else { outward_normal = record.normal; ni_over_nt = 1.0f / refractive_index; cosine = -dot(r_in.direction(), record.normal) / r_in.direction().length(); } if (refract(r_in.direction(), outward_normal, ni_over_nt, refracted)) { reflect_probability = schlick(cosine, refractive_index); } else { reflect_probability = 1.0f; } if (drand48() < reflect_probability) { scattered = Ray(record.point, reflected); // REFLECT vs } else { scattered = Ray(record.point, refracted); // REFRACT !! } return true; }
Vector3D Ray::Refract(Intersection &inter, Environment &env, int recursion) { Vector3D position = source + direction * inter.dist; double n1, n2; if(ior - 1.0 < 1.0e-6) { n1 = 1.0; n2 = inter.obj->surface().refracao; } else { n1 = inter.obj->surface().refracao; n2 = 1.0; } Vector3D refract_direction = refract(inter.obj->Normal(position), direction, n1, n2); if(refract_direction[0] <= -499) { return BACKGROUND_COLOR; } Ray refraction(position, refract_direction.Normalize()); refraction.ior = n2; return refraction.Trace(env, recursion + 1); }
Spectrum GlassBSDF::sample_f(const Vector3D& wo, Vector3D* wi, float* pdf) { // TODO: // Compute Fresnel coefficient and either reflect or refract based on it. *pdf = 1.f; if (!refract(wo, wi, ior)) { reflect(wo, wi); return this->reflectance * (1.f / fabs(wo.z)); } double ni, nt; if (wo.z > 0) { ni = 1; nt = ior; } else { ni = ior; nt = 1; } double cosi = fabs(wo.z); double cost = fabs(wi->z); double rpar = ((nt*cosi) - (ni*cost)) / ((nt*cosi) + (ni*cost)); double rver = ((ni*cosi) - (nt*cost)) / ((ni*cosi) + (nt*cost)); double fresnel = (rpar*rpar + rver*rver) / 2.f; if((double)(std::rand()) / RAND_MAX <= fresnel){ reflect(wo, wi); return this->reflectance * (1.f / fabs(wo.z)); } else{ return transmittance * double((nt*nt)/(ni*ni) * (1-fresnel) / fabs(cosi)); } // return Spectrum(); }
bool RayTracer::shade(SbVec3f *ray_origin, SbVec3f *ray_direction, SbVec3f *retColor, int recursionDepth, int flag){ float t_value, t_min = 999; float epsilon = 0.01; SbVec3f normal_at_intersection; SbVec3f normal_at_intersection1, actual_ray_direction ; bool should_color = false; SbVec3f color; color[0] = 0.0; color[1] = 0.0; color[2] = 0.0; //Cone *tempCone = new Cone(); for(int k =0; k<objects.size(); k++){ //Object temp1 ; //temp1 = spheres.at(k); Sphere tempSphere; Cube tempCube; Cone tempCone; Object temp; bool intersects = false; int shapetype = 0; shapetype = objects.at(k).shapeType ; if(shapetype == 1){ tempSphere = objects.at(k); intersects = tempSphere.intersection(ray_origin, ray_direction, &t_value); } else if (shapetype ==2){ //std::cout<<"cube"; tempCube = objects.at(k); intersects = tempCube.intersection(ray_origin, ray_direction, &t_value); //temp = (Cube)tempCube; }else{ tempCone = objects.at(k); intersects = tempCone.intersection(ray_origin, ray_direction, &t_value); } if(intersects) { if(t_value < t_min && t_value > 0 && t_value !=999) { t_min = t_value; SbVec3f V = -(*ray_direction); //view vector V.normalize(); SbVec3f point_of_intersection ; if(shapetype == 1){ normal_at_intersection = tempSphere.calculate_normal(ray_origin, ray_direction, t_value); normal_at_intersection.normalize(); // N vector at the point of intersection point_of_intersection = tempSphere.point_of_intersection( ray_origin, ray_direction, t_value); temp = tempSphere; }else if(shapetype == 2){ normal_at_intersection = tempCube.calculate_normal(ray_origin, ray_direction, t_value); normal_at_intersection.normalize(); // N vector at the point of intersection point_of_intersection = tempCube.point_of_intersection( ray_origin, ray_direction, t_value); temp = tempCube; } else{ normal_at_intersection = tempCone.calculate_normal(ray_origin, ray_direction, t_value); normal_at_intersection.normalize(); // N vector at the point of intersection point_of_intersection = tempCone.point_of_intersection( ray_origin, ray_direction, t_value); temp = tempCone; } for(int i = 0; i <3; i++) {// set the ambient color component color[i] = (0.2 * temp.material->ambientColor[0][i] * (1 - temp.transparency )); } //*retColor = color; return true;//ntc // iterate through all the lights and add the diffuse and specular component for(int j = 0; j < lights.size(); j++){ SbVec3f poi; actual_ray_direction = lights.at(j).position - point_of_intersection ; actual_ray_direction.normalize(); poi = point_of_intersection + (epsilon * actual_ray_direction); bool shadowFlag = false; if(shadow_on == 0 || shadow_on == 1) { if(shadow_on == 1) shadowFlag = shadow_ray_intersection(&poi, &actual_ray_direction , j ); //shadowFlag = true; if(!shadowFlag) { SbVec3f L = lights.at(j).position - point_of_intersection; L.normalize(); SbVec3f R; R = (2 * normal_at_intersection.dot(L) * normal_at_intersection) - L; R.normalize(); float NdotL = normal_at_intersection.dot(L); float cos_theta = V.dot(R); for(int i = 0; i <3; i++){ if(NdotL > 0) color[i] += (( NdotL * temp.material->diffuseColor[0][i] * lights.at(j).intensity * lights.at(j).color[i] * (1 - temp.transparency ))); if(cos_theta > 0) color[i] += (( pow(cos_theta, 50) * temp.material->specularColor[0][i]* lights.at(j).intensity * lights.at(j).color[i]) ); } } } else { // soft shadows { //shadowLevel = soft_shadow_ray_intersection(&point_of_intersection, j ); SbVec3f actual_ray_direction, offset_ray_direction; SbVec3f tempu, tempv, tempn; int number_of_shadow_rays; number_of_shadow_rays = NUMBER_OF_SHADOW_RAYS; float epsilon = 0.01; float R = 0.1; actual_ray_direction = lights.at(j).position - point_of_intersection ; actual_ray_direction.normalize(); SbVec3f point = point_of_intersection + (epsilon * actual_ray_direction); calculate_coordinate_system(&tempu, &tempv, &tempn, actual_ray_direction); for(int ir =0; ir< number_of_shadow_rays; ir++){ float du, dv; //float t; du = get_random_number(); dv = get_random_number(); du = R * (du - 0.5); dv = R * (dv - 0.5); offset_ray_direction = actual_ray_direction + (du * tempu) + (dv * tempv); offset_ray_direction.normalize(); //offset_ray_direction = actual_ray_direction - (R/2 * u) - (R/2 * v) + (du * R * u) + (dv *R * v); SbVec3f poi; poi = point + (epsilon * offset_ray_direction); //offset_ray_direction = actual_ray_direction; if(!shadow_ray_intersection(&poi, &offset_ray_direction, j)){ //normal_at_intersection = temp.calculate_normal(&poi, &offset_ray_direction, t_value); //normal_at_intersection.normalize(); SbVec3f V = -1 * (*ray_direction); //view vector V.normalize(); SbVec3f L = offset_ray_direction; L.normalize(); SbVec3f R; R = (2 * normal_at_intersection.dot(L) * normal_at_intersection) - L; R.normalize(); float NdotL = normal_at_intersection.dot(L); float cos_theta = V.dot(R); //if(temp.transparency > 0) std::cout<<"trnas"; for(int i = 0; i <3; i++){ { if(NdotL > 0) color[i] += (( NdotL * temp.material->diffuseColor[0][i] * lights.at(j).intensity * lights.at(j).color[i] * (1 - temp.transparency ))/ number_of_shadow_rays); if(cos_theta > 0) color[i] += (( pow(cos_theta, 50) * temp.material->specularColor[0][i]* lights.at(j).intensity * lights.at(j).color[i]) / number_of_shadow_rays); } } } } } } } SbVec3f refColor(0.0,0.0,0.0); SbVec3f refracColor(0.0,0.0,0.0); // if the current depth of recustion is less than the maximum depth, //reflect the ray and add the color returned dude to the result of reflection //std::cout<<"here"; if(refraction_on && recursionDepth < 2){ if(temp.isTransparent){ SbVec3f T; if(refract(ray_direction, &normal_at_intersection, &T)){ T.normalize(); SbVec3f poi; poi = point_of_intersection + (epsilon * T); shade(&poi, &T, &refracColor, recursionDepth+1); color = color + (temp.transparency * refracColor); } } } if(reflection_on && recursionDepth < 2){ if(temp.isShiny){//} && !temp.isTransparent){ // compute replection of the ray, R1 SbVec3f R1; R1 = reflect(&normal_at_intersection, ray_direction); SbVec3f poi; poi = point_of_intersection + (epsilon * R1); shade(&poi, &R1, &refColor, recursionDepth+1); color = color + ((1 - temp.transparency) * temp.shininess * refColor); } } should_color = true; } } } *retColor = color; return should_color; }
Vector getPixel(Ray ray, Stack * stack, real magnitude, real refractiveIndex, int depth, ulong *seed) { ItemPtr item = getClosestItem(ray); if(item==NULL) { return ZERO; } Vector point = getIntersectPoint(item, ray) + ray.from; int specularRoughness = getSpecularRoughness(item, point); Vector normal = getNormal(item, ray, point); Vector diffuseColor = ZERO; Vector specularColor = ZERO; Ray reflection; reflection.ray = reflect(ray.ray, normal); reflection.from = point+(reflection.ray*.001f); if(length2(getDiffuse(item, point))>0 || length2(getSpecular(item, point))>0) { for(int i=0;i<lightNumber;i++) { ItemPtr light = &lights[i]; Vector lightVector = light->center-point; Vector lightPixel = fast_normalize(lightVector); real diffuseFactor = dot(normal, lightPixel); real specularFactor = dot(reflection.ray, lightPixel); if(diffuseFactor>0 || specularFactor>0) { int hitLight=0; Ray movedLightRay; movedLightRay.from=reflection.from; Vector right = getRight(lightPixel); Vector up = getUp(lightPixel, right); for(int i=0;i<SHADOW_RUNS;i++) { //TODO: this can be much faster methinks real r = random(seed)*2-1; real u = random(seed)*sqrt(1-r*r); movedLightRay.ray = fast_normalize(lightVector+right*r*light->radius+up*u*light->radius); ItemPtr closestItem = getClosestItem(movedLightRay); if(closestItem!=NULL && closestItem->type==LIGHT) { hitLight++; } } if(hitLight > 0) { real lightValue = ((real)hitLight) / SHADOW_RUNS; if(diffuseFactor>0) { diffuseFactor *= lightValue; diffuseColor = diffuseColor+light->light*diffuseFactor; } if(specularFactor>0) { specularFactor = lightValue * pow(specularFactor, specularRoughness); specularColor = specularColor+light->light*specularFactor; } } } } } Vector color = (diffuseColor*getDiffuse(item, point)+specularColor*getSpecular(item, point)) * magnitude; if(depth > 0) { Ray refraction; if(getRefraction(item, point)) { refraction.ray = refract(ray.ray, normal, item, refractiveIndex); refraction.from = point+(refraction.ray*.001f); if(length2(refraction.ray)>0) { push(stack, depth-1, refraction, magnitude, getRefraction(item, point)); } } if(getReflection(item, point) > 0) { push(stack, depth-1, reflection, magnitude * getReflection(item, point), refractiveIndex); } } return color; }
Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &sample) const { bool sampleReflection = (bRec.typeMask & EDeltaReflection) && (bRec.component == -1 || bRec.component == 0); bool sampleTransmission = (bRec.typeMask & EDeltaTransmission) && (bRec.component == -1 || bRec.component == 1); if (!sampleTransmission && !sampleReflection) return Spectrum(0.0f); Float cosThetaI = Frame::cosTheta(bRec.wi), etaI = m_extIOR, etaT = m_intIOR; bool entering = cosThetaI > 0.0f; /* Determine the respective indices of refraction */ if (!entering) std::swap(etaI, etaT); /* Using Snell's law, calculate the squared sine of the angle between the normal and the transmitted ray */ Float eta = etaI / etaT, sinThetaTSqr = eta*eta * Frame::sinTheta2(bRec.wi); Float Fr, cosThetaT = 0; if (sinThetaTSqr >= 1.0f) { /* Total internal reflection */ Fr = 1.0f; } else { cosThetaT = std::sqrt(1.0f - sinThetaTSqr); /* Compute the Fresnel refletance */ Fr = fresnelDielectric(std::abs(cosThetaI), cosThetaT, etaI, etaT); if (entering) cosThetaT = -cosThetaT; } /* Calculate the refracted/reflected vectors+coefficients */ if (sampleTransmission && sampleReflection) { /* Importance sample according to the reflectance/transmittance */ if (sample.x <= Fr) { bRec.sampledComponent = 0; bRec.sampledType = EDeltaReflection; bRec.wo = reflect(bRec.wi); pdf = Fr * std::abs(Frame::cosTheta(bRec.wo)); return m_specularReflectance->getValue(bRec.its) * Fr; } else { bRec.sampledComponent = 1; bRec.sampledType = EDeltaTransmission; /* Given cos(N, transmittedRay), compute the transmitted direction */ bRec.wo = refract(bRec.wi, eta, cosThetaT); pdf = (1-Fr) * std::abs(Frame::cosTheta(bRec.wo)); /* When transporting radiance, account for the solid angle change at boundaries with different indices of refraction. */ return m_specularTransmittance->getValue(bRec.its) * (1-Fr) * (bRec.quantity == ERadiance ? (eta*eta) : (Float) 1); } } else if (sampleReflection) { bRec.sampledComponent = 0; bRec.sampledType = EDeltaReflection; bRec.wo = reflect(bRec.wi); pdf = std::abs(Frame::cosTheta(bRec.wo)); return m_specularReflectance->getValue(bRec.its) * Fr; } else { bRec.sampledComponent = 1; bRec.sampledType = EDeltaTransmission; if (Fr == 1.0f) /* Total internal reflection */ return Spectrum(0.0f); bRec.wo = refract(bRec.wi, eta, cosThetaT); pdf = std::abs(Frame::cosTheta(bRec.wo)); /* When transporting radiance, account for the solid angle change at boundaries with different indices of refraction. */ return m_specularTransmittance->getValue(bRec.its) * ((1-Fr) * (bRec.quantity == ERadiance ? (eta*eta) : (Float) 1)); } }
static Color3 raycolor(const Scene* scene, RayInfo ray, int n) { Geometry* const* geometry = scene->get_geometries(); const PointLight* light = scene->get_lights(); IntersectionInfo intersection; intersection.t0 = EP; intersection.t1 = 1000000; int index; for(int i=0; i<scene->num_geometries();i++) { Matrix4 inversematrix; make_inverse_transformation_matrix(&inversematrix, geometry[i]->position, geometry[i]->orientation, geometry[i]->scale ); RayInfo rayinformation; rayinformation.origin = inversematrix.transform_point(ray.origin); rayinformation.direction = inversematrix.transform_vector(ray.direction); bool check = geometry[i]->check_geometry(rayinformation,intersection); if(check) { index = i; } } Color3 color = Color3::Black; if(intersection.t1 != 1000000) { Matrix4 transmatrix; make_transformation_matrix(&transmatrix, geometry[index]->position, geometry[index]->orientation, geometry[index]->scale ); intersection.worldposition = transmatrix.transform_point(intersection.localposition); Matrix3 normalmatrix; make_normal_matrix(&normalmatrix, transmatrix ); intersection.worldnormal = normalize(normalmatrix*intersection.localnormal); color = intersection.material.ambient*scene->ambient_light; for(int i=0; i<scene->num_lights();i++) { RayInfo shadowworldrayinfo; shadowworldrayinfo.origin = intersection.worldposition; shadowworldrayinfo.direction = normalize(light[i].position - intersection.worldposition); bool hit = false; IntersectionInfo shadowintersection; shadowintersection.t0 = EP; shadowintersection.t1 = length(light[i].position - intersection.worldposition); real_t d = dot(intersection.worldnormal,shadowworldrayinfo.direction); if(d > 0) { for(int j=0; j<scene->num_geometries();j++) { Matrix4 shadowinversematrix; make_inverse_transformation_matrix(&shadowinversematrix, geometry[j]->position, geometry[j]->orientation, geometry[j]->scale ); RayInfo shadowlocalrayinfo; shadowlocalrayinfo.origin = shadowinversematrix.transform_point(shadowworldrayinfo.origin); shadowlocalrayinfo.direction = shadowinversematrix.transform_vector(shadowworldrayinfo.direction); bool check = geometry[j]->check_geometry(shadowlocalrayinfo,shadowintersection); if(check == true) { hit = true; break; } } if(hit == false) { color = color + intersection.material.diffuse*light[i].color*d; } } } RayInfo reflectionworldrayinfo; reflectionworldrayinfo.origin = intersection.worldposition; Vector3 r = ray.direction - 2*dot(ray.direction,intersection.worldnormal)*intersection.worldnormal; reflectionworldrayinfo.direction = normalize(r); n++; if(intersection.material.refractive_index != 0) { real_t judge = dot(ray.direction,intersection.worldnormal); real_t c; RayInfo refractionworldrayinfo; refractionworldrayinfo.origin = intersection.worldposition; real_t refractiveratio = scene->refractive_index/intersection.material.refractive_index; if(judge<0) { refract(ray, intersection.worldnormal, refractiveratio,refractionworldrayinfo); c = -dot(ray.direction,intersection.worldnormal); } else { if(refract(ray, -intersection.worldnormal, 1/refractiveratio,refractionworldrayinfo)) { c = dot(refractionworldrayinfo.direction,intersection.worldnormal); } else { if(n<=MAXNUMBER) { return intersection.material.specular*raycolor(scene,reflectionworldrayinfo,n); } } } real_t R0 = (intersection.material.refractive_index-1)*(intersection.material.refractive_index-1)/(intersection.material.refractive_index+1)/(intersection.material.refractive_index+1); real_t R = R0 + (1-R0)*pow(1-c,5); if(n<=MAXNUMBER) { return intersection.material.specular*(R*raycolor(scene,reflectionworldrayinfo,n) + (1-R)*raycolor(scene,refractionworldrayinfo,n)); } } else { if(n<=MAXNUMBER) { color = color + intersection.material.specular*raycolor(scene,reflectionworldrayinfo,n); } } return color; } return scene->background_color; }
void RefractShader::generateDir(const SurfacePoint & sp, const glm::vec3 & out, unsigned numSamples, BSDFSamples & samples) const { samples.resize (numSamples); // assume refraction index 1.0 for outer medium glm::float_t n1 = 1.0f; glm::float_t n2 = m_index; // normal should point to medium n1 glm::vec3 normal = sp.normal; const glm::vec3 incident = -out; // Flip normal and count new n if the ray is coming from // inside the surface (ie. from n2 to n1) if (sp.cos_theta(out) < 0) { normal = -normal; std::swap(n1, n2); } // n = n1 / n2 where ray comes from n1 to n2 /*const glm::float_t n = n1 / n2; const glm::float_t cosI = glm::dot(normal, -incident);*/ for (unsigned i = 0; i < numSamples; ++i) { glm::vec3 result, value; glm::vec3 refracted; glm::float_t refl; if(refract(n1, n2, normal, incident, refracted, refl)) { // always reflect //refl = 1.0f; // always transmit //refl = 0.0f; assert(0 <= refl && refl <= 1); // choose between refracted and reflected rays based on fresnel term const glm::float_t roulette = Sampling::uniform(); if(roulette < refl) { // reflect result = reflect(normal, incident); value = (1 / refl) * (refl) * m_reflectance / sp.cos_theta(result); } else { const real cos_theta = glm::dot(normal, result); // transmit result = refracted; value = (1 / (1 - refl)) * (1 - refl) * m_transmittance / sp.cos_theta(result); } } else { result = reflect(normal, incident); value = m_reflectance / sp.cos_theta(result); } samples[i] = BSDFSample(result, value, 1); } }