Vector3D Ray::Trace(Environment &env, int recursion) { if(recursion > MAX_RECURSION) return BACKGROUND_COLOR; Intersection inter = FindClosestIntersection(env); if(inter.obj == NULL) return BACKGROUND_COLOR; Vector3D position = source + direction * inter.dist, normal = inter.obj->Normal(position); if(normal * direction > 0) normal = -normal; Vector3D reflect_direction = direction - 2 *(normal * direction) * normal; Vector3D half_reflect = (direction + normal).Normalize(); Ray reflected_ray = Ray(position, reflect_direction); Vector3D object_color = inter.obj->GetColorAt(position), ambient_color = env.ambient_light->Color(), diffuse_color = LightTrace(position, normal, env, recursion), specular_color = reflected_ray.Trace(env, recursion + 1), refraction_color = Refract(inter, env, recursion); Vector3D total_color = ambient_color * inter.obj->surface().ambiente + diffuse_color * inter.obj->surface().difusao; total_color = combine_colors(total_color, object_color); total_color = total_color + specular_color * inter.obj->surface().especular * pow(std::max(0.0, normal * half_reflect), inter.obj->surface().brilho) + refraction_color * inter.obj->surface().transmissao; return clamp_color(total_color); }
Spectrum FresnelSpecular::Sample_f(const Vector3f &wo, Vector3f *wi, const Point2f &u, Float *pdf, BxDFType *sampledType) const { Float F = FrDielectric(CosTheta(wo), etaA, etaB); if (u[0] < F) { // Compute specular reflection for _FresnelSpecular_ // Compute perfect specular reflection direction *wi = Vector3f(-wo.x, -wo.y, wo.z); if (sampledType) *sampledType = BxDFType(BSDF_SPECULAR | BSDF_REFLECTION); *pdf = F; return F * R / AbsCosTheta(*wi); } else { // Compute specular transmission for _FresnelSpecular_ // Figure out which $\eta$ is incident and which is transmitted bool entering = CosTheta(wo) > 0; Float etaI = entering ? etaA : etaB; Float etaT = entering ? etaB : etaA; // Compute ray direction for specular transmission if (!Refract(wo, Faceforward(Normal3f(0, 0, 1), wo), etaI / etaT, wi)) return 0; Spectrum ft = T * (1 - F); // Account for non-symmetry with transmission to different medium if (mode == TransportMode::Radiance) ft *= (etaI * etaI) / (etaT * etaT); if (sampledType) *sampledType = BxDFType(BSDF_SPECULAR | BSDF_TRANSMISSION); *pdf = 1 - F; return ft / AbsCosTheta(*wi); } }
void RealisticCamera::DrawRayPathFromScene(const Ray &r, bool arrow, bool toOpticalIntercept) const { Float elementZ = LensFrontZ() * -1; // Transform _ray_ from camera to lens system space static const Transform CameraToLens = Scale(1, 1, -1); Ray ray = CameraToLens(r); for (size_t i = 0; i < elementInterfaces.size(); ++i) { const LensElementInterface &element = elementInterfaces[i]; bool isStop = (element.curvatureRadius == 0); // Compute intersection of ray with lens element Float t; Normal3f n; if (isStop) t = -(ray.o.z - elementZ) / ray.d.z; else { Float radius = element.curvatureRadius; Float zCenter = elementZ + element.curvatureRadius; if (!IntersectSphericalElement(radius, zCenter, ray, &t, &n)) return; } Assert(t >= 0.f); printf("Line[{{%f, %f}, {%f, %f}}],", ray.o.z, ray.o.x, ray(t).z, ray(t).x); // Test intersection point against element aperture Point3f pHit = ray(t); Float r2 = pHit.x * pHit.x + pHit.y * pHit.y; Float apertureRadius2 = element.apertureRadius * element.apertureRadius; if (r2 > apertureRadius2) return; ray.o = pHit; // Update ray path for from-scene element interface interaction if (!isStop) { Vector3f wt; Float etaI = (i == 0 || elementInterfaces[i - 1].eta == 0.f) ? 1.f : elementInterfaces[i - 1].eta; Float etaT = (elementInterfaces[i].eta != 0.f) ? elementInterfaces[i].eta : 1.f; if (!Refract(Normalize(-ray.d), n, etaI / etaT, &wt)) return; ray.d = wt; } elementZ += element.thickness; } // go to the film plane by default { Float ta = -ray.o.z / ray.d.z; if (toOpticalIntercept) { ta = -ray.o.x / ray.d.x; printf("Point[{%f, %f}], ", ray(ta).z, ray(ta).x); } printf("%s[{{%f, %f}, {%f, %f}}]", arrow ? "Arrow" : "Line", ray.o.z, ray.o.x, ray(ta).z, ray(ta).x); } }
Spectrum MicrofacetTransmission::Sample_f(const Vector3f &wo, Vector3f *wi, const Point2f &u, Float *pdf, BxDFType *sampledType) const { Vector3f wh = distribution->Sample_wh(wo, u); Float eta = CosTheta(wo) > 0 ? (etaA / etaB) : (etaB / etaA); if (!Refract(wo, (Normal3f)wh, eta, wi)) return 0; *pdf = Pdf(wo, *wi); return f(wo, *wi); }
Point3D RayScene::GetColor(Ray3D ray,int rDepth,Point3D cLimit){ if (rDepth == 0) {return Point3D();} if (cLimit[0] > 1 && cLimit[1] > 1 && cLimit[2] > 1) {return Point3D();} RayIntersectionInfo iInfo; double resp = group->intersect(ray, iInfo, -1); if (resp > 0) { //Calculating reflection values. Point3D reflectedDirection = Reflect(ray.direction, iInfo.normal); Ray3D reflectedRay(iInfo.iCoordinate+(reflectedDirection.unit()*0.0001), reflectedDirection.unit()); //Calculating and finding the refraction values. Point3D refractedDirection; double refIndex; if (ray.direction.dot(iInfo.normal) < 0) { refIndex = iInfo.material->refind; } else { refIndex = 1/iInfo.material->refind; } int refract = Refract(ray.direction.unit(), iInfo.normal.unit(), refIndex, refractedDirection); Ray3D refractedRay(iInfo.iCoordinate+(refractedDirection.unit()*0.0001), refractedDirection.unit()); Point3D refractedTransparency = iInfo.material->transparent; //Calculating light contributions to the point. Point3D diffuse = Point3D(0,0,0); Point3D specular = Point3D(0,0,0); for (int i=0; i<lightNum; i++) { RayIntersectionInfo iInfo2 = iInfo; int iSectCount = 0; Point3D diffuseResp = lights[i]->getDiffuse(camera->position, iInfo2); Point3D specularResp = lights[i]->getSpecular(camera->position, iInfo2); Point3D transparency = lights[i]->transparency(iInfo2, group, cLimit); diffuse += diffuseResp*transparency; specular += specularResp*transparency; } Point3D response = iInfo.material->ambient*ambient+iInfo.material->emissive + diffuse + specular + GetColor(reflectedRay, rDepth-1, cLimit/iInfo.material->specular) + GetColor(refractedRay, rDepth-1, cLimit/iInfo.material->specular)*refractedTransparency; for (int i = 0; i <3; i++) { if (response[i] < 0) { response[i] = 0; } if (response[i] > 1) { response[i] = 1; } } return response; } else if (ray.position[0]==camera->position[0] && ray.position[1]==camera->position[1] && ray.position[2]==camera->position[2]) { return background; } else return Point3D(); }
bool RealisticCamera::TraceLensesFromScene(const Ray &rCamera, Ray *rOut) const { Float elementZ = -LensFrontZ(); // Transform _rCamera_ from camera to lens system space static const Transform CameraToLens = Scale(1, 1, -1); Ray rLens = CameraToLens(rCamera); for (size_t i = 0; i < elementInterfaces.size(); ++i) { const LensElementInterface &element = elementInterfaces[i]; // Compute intersection of ray with lens element Float t; Normal3f n; bool isStop = (element.curvatureRadius == 0); if (isStop) t = (elementZ - rLens.o.z) / rLens.d.z; else { Float radius = element.curvatureRadius; Float zCenter = elementZ + element.curvatureRadius; if (!IntersectSphericalElement(radius, zCenter, rLens, &t, &n)) return false; } Assert(t >= 0); // Test intersection point against element aperture Point3f pHit = rLens(t); Float r2 = pHit.x * pHit.x + pHit.y * pHit.y; if (r2 > element.apertureRadius * element.apertureRadius) return false; rLens.o = pHit; // Update ray path for from-scene element interface interaction if (!isStop) { Vector3f wt; Float etaI = (i == 0 || elementInterfaces[i - 1].eta == 0) ? 1 : elementInterfaces[i - 1].eta; Float etaT = (elementInterfaces[i].eta != 0) ? elementInterfaces[i].eta : 1; if (!Refract(Normalize(-rLens.d), n, etaI / etaT, &wt)) return false; rLens.d = wt; } elementZ += element.thickness; } // Transform _rLens_ from lens system space back to camera space if (rOut != nullptr) { static const Transform LensToCamera = Scale(1, 1, -1); *rOut = LensToCamera(rLens); } return true; }
bool DielectricMaterial::Scatter( const Ray& ray, const HitRecord& record, Vector3& attenuation, Ray& scattered ) const { attenuation = Vector3( 1.f, 1.f, 1.f ); const float dirDotNormal = ray.Direction().Dot( record.normal ); Vector3 outwardNormal; float niOverNt; float cosine; if ( dirDotNormal > 0.f ) { outwardNormal = -record.normal; niOverNt = refractionIndex; //cosine = refractionIndex * dirDotNormal / ray.Direction().Length(); cosine = dirDotNormal / ray.Direction().Length(); cosine = std::sqrt( 1.f - refractionIndex * refractionIndex * ( 1.f - cosine * cosine ) ); } else { outwardNormal = record.normal; niOverNt = 1.f / refractionIndex; cosine = -dirDotNormal / ray.Direction().Length(); } const Vector3 reflected = Reflect( ray.Direction(), record.normal ); float reflectProbability; Vector3 refracted; if ( Refract( ray.Direction(), outwardNormal, niOverNt, refracted ) ) { reflectProbability = Schlick( cosine, refractionIndex ); } else { reflectProbability = 1.f; } if ( Rand01() < reflectProbability ) { scattered = Ray( record.point, reflected ); } else { scattered = Ray( record.point, refracted ); } return true; }
Spectrum SpecularTransmission::Sample_f(const Vector3f &wo, Vector3f *wi, const Point2f &sample, Float *pdf, BxDFType *sampledType) const { // Figure out which $\eta$ is incident and which is transmitted bool entering = CosTheta(wo) > 0; Float etaI = entering ? etaA : etaB; Float etaT = entering ? etaB : etaA; // Compute ray direction for specular transmission if (!Refract(wo, Faceforward(Normal3f(0, 0, 1), wo), etaI / etaT, wi)) return 0; *pdf = 1; Spectrum ft = T * (Spectrum(1.) - fresnel.Evaluate(CosTheta(*wi))); // Account for non-symmetry with transmission to different medium if (mode == TransportMode::Radiance) ft *= (etaI * etaI) / (etaT * etaT); return ft / AbsCosTheta(*wi); }
/********** * DESCRIPTION: calculate pixel color * INPUT: x x position * y y position * normal surface normal * OUTPUT: - **********/ void PREVIEW::CalcPixel(int x, int y, VECTOR *normal) { PREVIEW_TEXTURE *ptexture; float costheta; float cosalpha,intens; VECTOR refl, newdir, norm, pos; float t; COLOR color, map; float x1,y1; norm = *normal; pos = norm; ptexture = texture_root; while(ptexture) { ptexture->Work(this, &pos, &norm); ptexture = (PREVIEW_TEXTURE*)ptexture->GetNext(); } color.r = ambient.r * global.ambient.r; color.g = ambient.g * global.ambient.g; color.b = ambient.b * global.ambient.b; if(surf->flags & SURF_BRIGHT) { color.r += diffuse.r; color.g += diffuse.g; color.b += diffuse.b; } else { t = -2.f*norm.z; refl.x = t*norm.x; refl.y = t*norm.y; refl.z = 1.f + t*norm.z; costheta = -dotp(&norm, &light); if(costheta <= 0.f) { /* Light source is on opposite side of surface, hence light must be * transmitted through ... */ if(translucency > EPSILON) { color.r += -costheta * difftrans.r; color.g += -costheta * difftrans.g; color.b += -costheta * difftrans.b; if(transphong > EPSILON) { /* calculate reflected ray direction */ cosalpha = -dotp(&refl, &light); if(cosalpha > EPSILON) { /* Specular highlight = cosine of the angle raised to the * appropriate power */ intens = pow(cosalpha, transphong) * translucency; color.r += intens * spectrans.r; color.g += intens * spectrans.g; color.b += intens * spectrans.b; } } } } else { if(costheta > EPSILON) { color.r += costheta * diffuse.r; color.g += costheta * diffuse.g; color.b += costheta * diffuse.b; } if(refphong > EPSILON) { /* calculate reflected ray direction */ cosalpha = -dotp(&refl, &light); if(cosalpha > EPSILON) { intens = pow(cosalpha, refphong); color.r += intens * specular.r; color.g += intens * specular.g; color.b += intens * specular.b; } } } if(transpar.r > EPSILON || transpar.g > EPSILON || transpar.b > EPSILON) { if(!Refract(&newdir, 1.f/refrindex, &norm, norm.z)) { color.r = color.r * (1.-transpar.r); color.g = color.g * (1.-transpar.g); color.b = color.b * (1.-transpar.b); t = (pos.z + .5f) / newdir.z; x1 = (pos.x + newdir.x * t) * 4.f; y1 = (pos.y + newdir.y * t) * 4.f; if(x1 < 0.f) x1 -= 1.f; if(y1 < 0.f) y1 -= 1.f; if(((int)x1 + (int)y1) & 1) { color.r += transpar.r; color.g += transpar.g; color.b += transpar.b; } } } if(reflect.r > EPSILON || reflect.g > EPSILON || reflect.b > EPSILON) { ApplyReflMap(&norm, &map); color.r += reflect.r * map.r; color.g += reflect.g * map.g; color.b += reflect.b * map.b; } } if(texture_root) { ambient = surf->ambient; diffuse = surf->diffuse; specular = surf->specular; reflect = surf->reflect; transpar = surf->transpar; difftrans = surf->difftrans; spectrans = surf->spectrans; refphong = refphong; transphong = transphong; foglength = foglength; refrindex = refrindex; translucency = translucency; } if(color.r > 1.f) { t = 1.f/color.r; color.r = 1.f; color.g *= t; color.b *= t; } if(color.g > 1.f) { t = 1.f/color.g; color.r *= t; color.g = 1.f; color.b *= t; } if(color.b > 1.f) { t = 1.f/color.b; color.r *= t; color.g *= t; color.b = 1.f; } line[x + y*xres].r = (UBYTE)(color.r*255.f); line[x + y*xres].g = (UBYTE)(color.g*255.f); line[x + y*xres].b = (UBYTE)(color.b*255.f); }
void RealisticCamera::DrawRayPathFromFilm(const Ray &r, bool arrow, bool toOpticalIntercept) const { Float elementZ = 0; // Transform _ray_ from camera to lens system space static const Transform CameraToLens = Scale(1, 1, -1); Ray ray = CameraToLens(r); printf("{ "); if (!TraceLensesFromFilm(r, nullptr)) printf("Dashed, "); for (int i = elementInterfaces.size() - 1; i >= 0; --i) { const LensElementInterface &element = elementInterfaces[i]; elementZ -= element.thickness; bool isStop = (element.curvatureRadius == 0); // Compute intersection of ray with lens element Float t; Normal3f n; if (isStop) t = -(ray.o.z - elementZ) / ray.d.z; else { Float radius = element.curvatureRadius; Float zCenter = elementZ + element.curvatureRadius; if (!IntersectSphericalElement(radius, zCenter, ray, &t, &n)) goto done; } Assert(t >= 0); printf("Line[{{%f, %f}, {%f, %f}}],", ray.o.z, ray.o.x, ray(t).z, ray(t).x); // Test intersection point against element aperture Point3f pHit = ray(t); Float r2 = pHit.x * pHit.x + pHit.y * pHit.y; Float apertureRadius2 = element.apertureRadius * element.apertureRadius; if (r2 > apertureRadius2) goto done; ray.o = pHit; // Update ray path for element interface interaction if (!isStop) { Vector3f wt; Float etaI = element.eta; Float etaT = (i > 0 && elementInterfaces[i - 1].eta != 0) ? elementInterfaces[i - 1].eta : 1; if (!Refract(Normalize(-ray.d), n, etaI / etaT, &wt)) goto done; ray.d = wt; } } ray.d = Normalize(ray.d); { Float ta = std::abs(elementZ / 4); if (toOpticalIntercept) { ta = -ray.o.x / ray.d.x; printf("Point[{%f, %f}], ", ray(ta).z, ray(ta).x); } printf("%s[{{%f, %f}, {%f, %f}}]", arrow ? "Arrow" : "Line", ray.o.z, ray.o.x, ray(ta).z, ray(ta).x); // overdraw the optical axis if needed... if (toOpticalIntercept) printf(", Line[{{%f, 0}, {%f, 0}}]", ray.o.z, ray(ta).z * 1.05f); } done: printf("}"); }
void Scene::BuildCornellBoxScene(std::vector<Shape*> &objects) { camera = new Camera( Point(-260, 0, 90), Point(-199, 0, 90) ); float lightEnergy = 35e8; lights.push_back(new SphereLight(Point(0, 0, 160), 3, Color(lightEnergy,lightEnergy,lightEnergy),1)); Color walls(0.1f,0.1f,0.1f); Material* white = new Material(Ambient(0.3,0.3,0.3),Diffuse(0.9, 0.9, 0.9),walls); AddObject("files\\cornell_box\\cornell_box_floor.3ds", new Material(Color(0.3,0.3,0.3),Color(0.9,0.9,0.9),walls, Reflect(0.2, 0.2, 0.2)), objects); AddObject("files\\cornell_box\\cornell_box_ceil.3ds", white, objects); AddObject("files\\cornell_box\\cornell_box_right_wall.3ds", new Material(Color(0.,0.1,0.),Color(0.4,1,0.4),walls), objects); AddObject("files\\cornell_box\\cornell_box_back.3ds", white, objects); AddObject("files\\cornell_box\\cornell_box_left_wall.3ds", new Material(Color(0.1,0.,0.),Color(1,0.4,0.4),walls), objects); AddObject("files\\cornell_box\\cornell_box_box1.3ds", white, objects); AddObject("files\\cornell_box\\cornell_box_box2.3ds", white, objects); objects.push_back(new Sphere(Point(-35,-45,20),15,new Material(Ambient(0,0,0),Diffuse(0,0,0),Specular(0,0,0), Reflect(0,0,0), Refract(1,1,1), 1.51, 1), Shape::GetUniqueID())); objects.push_back(new Sphere(Point(-50,50,15),15,new Material(Ambient(0,0,0),Diffuse(0,0,0),Specular(0,0,0), Reflect(1,1,1)), Shape::GetUniqueID() )); }