Hit BVH::BVHNode::trace(const AABB_Ray & aabb_ray, const Ray & ray, Amount minT) { Hit retHit(ray); //First check to see if this hit intersects with this node. Amount thisT = getBox().intersect(aabb_ray); if(thisT > 0 && (thisT < minT || minT < 0)) { if(this->left != nullptr) { Hit hLeft = this->left->trace(aabb_ray,ray,minT); if(hLeft.didHit() && (hLeft.getT() < minT || minT < 0)) { retHit = hLeft; minT = hLeft.getT(); } } if(this->right != nullptr) { Hit hRight = this->right->trace(aabb_ray,ray,minT); if(hRight.didHit() && (hRight.getT() < minT || minT < 0)) { retHit = hRight; } } } return retHit; }
bool Face::plane_intersect(const Ray &r, Hit &h, bool intersect_backfacing, bool* backfacing_hit) { // insert the explicit equation for the ray into the implicit equation of the plane // equation for a plane // ax + by + cz = d; // normal . p + direction = 0 // plug in ray // origin + direction * t = p(t) // origin . normal + t * direction . normal = d; // t = d - origin.normal / direction.normal; Vec3f normal = computeNormal(); double d = normal.Dot3((*this)[0]->get()); double numer = d - r.getOrigin().Dot3(normal); double denom = r.getDirection().Dot3(normal); if (denom == 0) return 0; // parallel to plane if (!intersect_backfacing && normal.Dot3(r.getDirection()) >= 0) return 0; // hit the backside double t = numer / denom; if (t > EPSILON && t < h.getT()) { h.set(t,this->getMaterial(),normal,this); assert (h.getT() >= EPSILON); //hit the backside but that's okay in this case if (normal.Dot3(r.getDirection()) >= 0){ *backfacing_hit = true; } return 1; } return 0; }
Vec3f RayTracer::shadow(const Vec3f &point, const Vec3f &pointOnLight, const Face *f, const Ray &ray, const Hit &hit) const { const Vec3f normal(hit.getNormal()); const Material *m = hit.getMaterial(); Vec3f dirToLight = pointOnLight - point; dirToLight.Normalize(); /* If dot product < 0, surface is not facing light */ if (normal.Dot3(dirToLight) > 0) { Ray rayToLight(point, dirToLight); Hit hLight; bool blocked = CastRay(rayToLight, hLight, false); while (std::fabs(hLight.getT()) < SURFACE_EPSILON && std::fabs((pointOnLight - point).Length()) > SURFACE_EPSILON) { rayToLight = Ray(rayToLight.pointAtParameter(SURFACE_EPSILON), dirToLight); blocked = CastRay(rayToLight, hLight, false); } if (hLight.getT() == FLT_MAX || hLight.getMaterial() != f->getMaterial()) { return Vec3f(0, 0, 0); } const Vec3f lightColor = 0.2 * f->getMaterial()->getEmittedColor() * f->getArea(); return m->Shade(ray,hit,dirToLight,lightColor,args); } return Vec3f(0, 0, 0); }
bool Sphere::intersect(const Ray &r, Hit &h, float tmin) { Vec3f v = center - r.getOrigin(); float tp = v.Dot3(r.getDirection()); float det = tp*tp - v.Dot3(v) + radius*radius; //intersect if(det > 0) { //t' det = sqrtf(det); float t1 = tp - det; float t2 = tp + det; if(t1 > tmin && t1 < h.getT()) { Vec3f normal = (r.pointAtParameter(t1) - center); normal /= radius; normal.Normalize(); h.set(t1,material,normal,r); return 1; } else if(t2 > tmin && t2 < h.getT()) { //sphere's normal Vec3f normal = (r.pointAtParameter(t2) - center); normal /= radius; normal.Normalize(); h.set(t2,material,normal,r); return 1; } } return 0; }
bool Face::plane_intersect(const Ray &r, Hit &h, bool intersect_backfacing) const { // insert the explicit equation for the ray into the implicit equation of the plane // equation for a plane // ax + by + cz = d; // normal . p + direction = 0 // plug in ray // origin + direction * t = p(t) // origin . normal + t * direction . normal = d; // t = d - origin.normal / direction.normal; glm::vec3 normal = computeNormal(); float d = glm::dot(normal,(*this)[0]->get()); float numer = d - glm::dot(r.getOrigin(),normal); float denom = glm::dot(r.getDirection(),normal); if (denom == 0) return 0; // parallel to plane if (!intersect_backfacing && glm::dot(normal,r.getDirection()) >= 0) return 0; // hit the backside float t = numer / denom; if (t > EPSILON && t < h.getT()) { h.set(t,this->getMaterial(),normal); assert (h.getT() >= EPSILON); return 1; } return 0; }
bool Grid::intersect(const Ray &r, Hit &h, float tmin) { MarchingInfo march; initialRayMarch(march,r,tmin); int currentI = march.GetI(); int currentJ = march.GetJ(); int currentK = march.GetK(); float currentT = march.GetT(); int numObjects; //Object3DVector currentVector; 绝对不能新建一个Object3DVector,然后把isOpaque的值赋给这个Object3DVector,因为当这个函数结束时,会把Object3DVector销毁,对应的指针指向的对象也会被销毁。 //当然还有一种方法是定义一个Object3DVector指针 //printf("i:%d j:%d currentI:%d currentJ:%d currentK:%d\n",i,j,currentI,currentJ,currentK); Object3DVector isAlreadyIntersect; while(currentI>=0 && currentI<nx && currentJ>=0 && currentJ<ny && currentK>=0 && currentK<nz) { RayTracingStats::IncrementNumGridCellsTraversed(); Object3DVector* currentVector = &isOpaque[currentI][currentJ][currentK]; numObjects = currentVector->getNumObjects(); //printf("%d %d %d\n",currentI,currentJ,currentK); for(int i=0; i<numObjects; ++i) { //already intersected object don't need intersect again if(isAlreadyIntersect.isInside(currentVector->getObject(i))) continue; RayTracingStats::IncrementNumIntersections(); currentVector->getObject(i)->intersect(r,h,tmin); isAlreadyIntersect.addObject(currentVector->getObject(i)); } if(h.getMaterial()!=NULL && h.getT()>=currentT && h.getT()<=march.GetNext_x() && h.getT()<=march.GetNext_y() && h.getT()<=march.GetNext_z()) { return true; } march.nextCell(); currentI = march.GetI(); currentJ = march.GetJ(); currentK = march.GetK(); currentT = march.GetT(); //折射或反射,shadow时,光线圆点会在grid内 } numObjects = others.getNumObjects(); for(int i=0; i<numObjects; i++) { others.getObject(i)->intersect(r,h,tmin); } if(h.getMaterial()!=NULL) //这里有问题,因为如果没有和平面相交的话,h的material也有可能不是null return true; return false; }
bool Transform::Intersect(const Ray &r, Hit &h, float tmin) const { bool result = false; Matrix m = m_matrix; if ( m.Inverse() ) { Vec3f org = r.getOrigin(); Vec3f dir = r.getDirection(); m.Transform(org); m.TransformDirection(dir); Ray r2 (dir, org); result = m_pObject->Intersect(r2, h, tmin); if (result) { Matrix m1 = m; m1.Transpose(); Vec3f n = h.getNormal(); m1.TransformDirection(n); n.Normalize(); h.set(h.getT(), h.getMaterial(), n, r); } } return result; }
bool Plane::intersect(const Ray & r, Hit & h, float tmin) { assert (tmin >= 0.0f); Vec3f org = r.getOrigin(); Vec3f dir = r.getDirection(); if (dir.Dot3(normal) < 1.0e-7 && dir.Dot3(normal) > -1.0e-7) { return false; } // Appromately parrell to plane float tempT = (offset - org.Dot3(normal)) / dir.Dot3(normal); if (tempT <= 1e-6) { return false; } else if (tempT >= tmin && tempT < h.getT()) { // Update Hit Point normal.Normalize(); h.set(tempT, NULL, normal, color, r); return true; } return false; }
/* The intersect routine will first transform the ray, then delegate to the intersect routine of the contained object. Make sure to correctly transform the resulting normal according to the rule seen in lecture. You may choose to normalize the direction of the transformed ray or leave it un-normalized. If you decide not to normalize the direction, you might need to update some of your intersection code. */ bool Transform::intersect(const Ray &r, Hit &h, float tmin) { Vec3f r0 = r.getOrigin(); Vec3f rd = r.getDirection(); Matrix inv; matrix.Inverse(inv); inv.Transform(r0); inv.TransformDirection(rd); if (object != NULL) { //这里的h是有问题的,作如下修改: bool judge = object->intersect(Ray(r0,rd), h, tmin); Vec3f normal = h.getNormal(); //这里很奇怪,normal的方向没有修正,然而结果却是对的 //改了之后反而是错的!! //这里确定normal没有错,那么就是之后应用normal的 //问题 //好吧,就是这里的问题 //经过把图形摆正,发现求的法向量没有问题,但是没有单位化…………! matrix.TransformDirection(normal); normal.Normalize(); //or: //Matrix change,res; //matrix.Inverse(change); //change.Transpose(res); //res.TransformDirection(normal); h.set(h.getT(), h.getMaterial(), normal, r); return judge; } return false; }
bool Sphere::intersect(const Ray &r, Hit &h, float tmin) { //直线方程 P = t*D + R ① //圆方程 ||P||= raduis ② //将①带入②, 由点乘的性质(满足分配率,交换律),求得t^2+2RDt+R^2-r^2=0 //得t = -RD±sqrt(RD^2-R^2+r^2) //选择距离较近的那个点t = -RD-sqrt(RD^2-R^2+r^2) Vec3f D = r.getDirection(); Vec3f R = r.getOrigin()-center; float R2 = R.Dot3(R); float RD = R.Dot3(D); float b2_4ac = RD*RD-R2+radius*radius;//R2 RD RDRD这些其实可以存在ray里,但是算法研究以程序清晰为要 if(b2_4ac<0)return 0; float t; t = -RD - sqrt(b2_4ac); if(t<0){ t = -RD + sqrt(b2_4ac); if(t < 0)return 0; } if(t<h.getT()) { h.set(t, &color, r); } return 1; }
bool Sphere::intersect(const Ray &r, Hit &h, float tmin){ /*Vector equation for sphere P*P - r^2 = 0 ((R0-c) + td)*((R0-c) + td) - r^2 = 0 (td)^2 + 2R0-c)td + (R0-c)^2 - r^2 =0 Use quadratic equation solve for t a = (d^2) b = 2(R0-c)d c = ((R0-c)^2 - r^2) */ Vec3f rayOrigin, rayDirection,segment,Q; float tpos,tneg,a,b,c,discriminant; rayOrigin = r.getOrigin(); rayDirection = r.getDirection(); segment = rayOrigin - _center; a = rayDirection.Dot3(rayDirection); b = 2*segment.Dot3(rayDirection); c = segment.Dot3(segment) - _radius*_radius; discriminant = sqrt(b*b - 4*a*c); tpos = (-b + discriminant)/(2*a); tneg = (-b - discriminant)/(2*a); if (tneg > tmin && tneg < h.getT()){ Q = r.pointAtParameter(tneg); Q = Q - _center; Q.Normalize(); h.set(tneg, _material,Q,r); return true; } else if (tpos > tmin && tpos < h.getT()){ Q = r.pointAtParameter(tpos); Q = Q - _center; Q.Normalize(); h.set(tpos,_material,Q,r); return true; } return false; }
void PhotonMapping::TracePhoton(const Vec3f &position, const Vec3f &direction, const Vec3f &energy, int iter) { if(iter>args->num_bounces){ return; } Hit h = Hit(); Ray R = Ray(position, direction); bool intersect = raytracer->CastRay(R, h, false); if(!intersect){ return; } Material *m = h.getMaterial(); Vec3f normal = h.getNormal(); Vec3f point = R.pointAtParameter(h.getT()); Vec3f opDirec = direction; opDirec.Negate(); opDirec.Normalize(); Vec3f diffuse = m->getDiffuseColor(), reflec = m->getReflectiveColor(); double diffuseAnswer = diffuse.x()+diffuse.y()+diffuse.z(); double reflecAnswer = reflec.x()+reflec.y()+reflec.z(); double total = reflecAnswer+diffuseAnswer; diffuseAnswer /= total; reflecAnswer /= total; double seed = GLOBAL_mtrand.rand(); if(seed <= diffuseAnswer && seed >= 0){ Vec3f newEnergy = energy * diffuse; Vec3f newPosition = point; Vec3f newDirection = Vec3f(GLOBAL_mtrand.rand(),GLOBAL_mtrand.rand(),GLOBAL_mtrand.rand()); newDirection.Normalize(); Photon answer = Photon(point,opDirec,newEnergy,iter+1); kdtree->AddPhoton(answer); TracePhoton(newPosition, newDirection, newEnergy, iter+1); } else if(seed>diffuseAnswer && seed <= 1){ Vec3f newEnergy = energy * reflec; Vec3f newPosition = point; Vec3f newDirection = direction - 2 * direction.Dot3(normal) * normal; Photon answer = Photon(point,opDirec,newEnergy,iter+1); kdtree->AddPhoton(answer); TracePhoton(newPosition, newDirection, newEnergy, iter+1); } // ============================================== // ASSIGNMENT: IMPLEMENT RECURSIVE PHOTON TRACING // ============================================== // Trace the photon through the scene. At each diffuse or // reflective bounce, store the photon in the kd tree. // One optimization is to *not* store the first bounce, since that // direct light can be efficiently computed using classic ray // tracing. }
Vec3f RayTracer::shadows(const Ray &ray, const Hit &hit) const { Vec3f answer(0, 0, 0); const int num_lights = mesh->getLights().size(); if (args->num_shadow_samples == 0) { for (int i = 0; i < num_lights; ++i) { const Face *f = mesh->getLights()[i]; Vec3f pointOnLight = f->computeCentroid(); const Vec3f point(ray.pointAtParameter(hit.getT())); Vec3f dirToLight = pointOnLight - point; dirToLight.Normalize(); const Vec3f lightColor = 0.2 * f->getMaterial()->getEmittedColor() * f->getArea(); return hit.getMaterial()->Shade(ray,hit,dirToLight,lightColor,args); } } // ---------------------------------------------- // add contributions from each light that is not in shadow for (int i = 0; i < num_lights; i++) { const Face *f = mesh->getLights()[i]; Vec3f pointOnLight = f->computeCentroid(); const Vec3f point(ray.pointAtParameter(hit.getT())); double answerx = 0, answery = 0, answerz = 0; { for (int s = 0; s <= args->num_shadow_samples; ++s) { const Vec3f sh = shadow(point, pointOnLight, f, ray, hit); answerx += sh.x(); answery += sh.y(); answerz += sh.z(); pointOnLight = f->RandomPoint(); } } answer += Vec3f(answerx, answery, answerz); } answer *= static_cast<double>(1) / ((args->num_shadow_samples + 1) * num_lights); return answer; }
void PhotonMapping::TracePhoton(const Vec3f &position, const Vec3f &direction, const Vec3f &energy, int iter) { // ============================================== // ASSIGNMENT: IMPLEMENT RECURSIVE PHOTON TRACING // ============================================== // Trace the photon through the scene. At each diffuse or // reflective bounce, store the photon in the kd tree. // One optimization is to *not* store the first bounce, since that // direct light can be efficiently computed using classic ray // tracing. //do ray cast Ray r(position,direction*(1/direction.Length())); Hit h; raytracer->CastRay(r,h,true); if (h.getT()>1000) return; MTRand mtrand; Vec3f refl = h.getMaterial()->getReflectiveColor(); Vec3f diff = h.getMaterial()->getDiffuseColor(); double ran=mtrand.rand(); if (iter==0) ran= mtrand.rand(refl.Length()+diff.Length()); //std::cout<<iter<<" "<<h.getT()<<" "<<refl.Length()+diff.Length()<<std::endl; //send reflective photon if (iter<args->num_bounces&&ran<=refl.Length()) TracePhoton(r.pointAtParameter(h.getT()),r.getDirection()-2*(r.getDirection().Dot3(h.getNormal()))*h.getNormal(),energy,iter+1); else if (iter<args->num_bounces&&ran<=refl.Length()+diff.Length()) TracePhoton(r.pointAtParameter(h.getT()),RandomDiffuseDirection(h.getNormal()),energy,iter+1); else { Photon p(position,direction,energy,iter); kdtree->AddPhoton(p); } }
Vec3f RayTracer::reflection(const Ray &start_ray, int bounce_count) const { Ray ray(start_ray); Hit h; Vec3f answer = TraceRay(ray, h, bounce_count); while (h.getT() < SURFACE_EPSILON) { ray = Ray(ray.pointAtParameter(SURFACE_EPSILON), ray.getDirection()); answer = TraceRay(ray, h, bounce_count); } return answer; }
bool Triangle::intersect( const Ray& r , Hit& h , float tmin){ Vector3f R_o = r.getOrigin(); Vector3f R_d = r.getDirection(); Matrix3f A( this->a.x()-this->b.x() , this->a.x()-this->c.x() , R_d.x() , this->a.y()-this->b.y() , this->a.y()-this->c.y() , R_d.y() , this->a.z()-this->b.z() , this->a.z()-this->c.z() , R_d.z() ); Matrix3f BetaM( this->a.x()-R_o.x() , this->a.x()-this->c.x() , R_d.x() , this->a.y()-R_o.y() , this->a.y()-this->c.y() , R_d.y() , this->a.z()-R_o.z() , this->a.z()-this->c.z() , R_d.z() ); float beta = BetaM.determinant() / A.determinant(); Matrix3f GammaM( this->a.x()-this->b.x() , this->a.x()-R_o.x() , R_d.x() , this->a.y()-this->b.y() , this->a.y()-R_o.y() , R_d.y() , this->a.z()-this->b.z() , this->a.z()-R_o.z() , R_d.z() ); float gamma = GammaM.determinant() / A.determinant(); float alpha = 1.0f - beta - gamma; Matrix3f tM( this->a.x()-this->b.x() , this->a.x()-this->c.x() , this->a.x()-R_o.x() , this->a.y()-this->b.y() , this->a.y()-this->c.y() , this->a.y()-R_o.y() , this->a.z()-this->b.z() , this->a.z()-this->c.z() , this->a.z()-R_o.z() ); float t = tM.determinant() / A.determinant(); if (beta + gamma > 1){ return false; } if (beta < 0){ return false; } if (gamma < 0){ return false; } if (t > tmin && t < h.getT()){ Vector3f newNormal = (alpha*this->normals[0] + beta*this->normals[1] + gamma*this->normals[2]).normalized(); h.set(t, this->material, newNormal); Vector2f newTexCoord = (alpha*this->texCoords[0] + beta*this->texCoords[1] + gamma*this->texCoords[2]); h.setTexCoord(newTexCoord); return true; } else{ return false; } }
// trace a ray through pixel (i,j) of the image an return the color glm::vec3 TraceRay(double i, double j,tVals* arg) { // compute and set the pixel color int max_d = std::max(arg->args->width,arg->args->height); glm::vec3 color; if (arg->args->num_antialias_samples > 1) { for (int n = 0; n < arg->args->num_antialias_samples; n++) { //Random sampling WaitForSingleObject(*arg->ranLock,INFINITE); double x = (GLOBAL_MTRAND.rand()*2 + i - arg->args->width / 2.0) / double(max_d) + 0.5; double y = (GLOBAL_MTRAND.rand()*2 + j - arg->args->height / 2.0) / double(max_d) + 0.5; ReleaseMutex(*arg->ranLock); Ray r = arg->camera->generateRay(x, y); Hit hit; glm::vec3 part = arg->raytracer->TraceRay(r, hit, arg->args->num_bounces); part /= arg->args->num_antialias_samples; color += part; // add that ray for visualization RayTree::AddMainSegment(r, 0, hit.getT()); } } else { // Here's what we do with a single sample per pixel: // construct & trace a ray through the center of the pixel double x = (i - arg->args->width / 2.0) / double(max_d) + 0.5; double y = (j - arg->args->height / 2.0) / double(max_d) + 0.5; Ray r = arg->camera->generateRay(x, y); Hit hit; color = arg->raytracer->TraceRay(r, hit, arg->args->num_bounces); // add that ray for visualization RayTree::AddMainSegment(r, 0, hit.getT()); } // return the color return color; }
//normal.(r.origin + t*r.direction) +d = 0 bool Plane::intersect(const Ray &r, Hit &h, float tmin) { float isParallel = normal.Dot3(r.getDirection()); if(!Utility::isZero(isParallel)) { float dist = -(normal.Dot3(r.getOrigin())-d)/isParallel; //当时没有理解d的含义,构造是应该是ax+by+cz-d=0 if(dist > tmin && dist < h.getT()) { h.set(dist,material,normal,r); return 1; } } return 0; }
bool CylinderRing::intersect(const Ray &r, Hit &h) const { // intersect with the 4 parts of the ring double outer_t; Vec3f outer_normal; bool outer = IntersectFiniteCylinder(r,center,outer_radius,height,outer_t,outer_normal); double inner_t; Vec3f inner_normal; bool inner = IntersectFiniteCylinder(r,center,inner_radius,height,inner_t,inner_normal); double top_t; Vec3f top_normal; bool top = IntersectAnnulus(r,center+Vec3f(0,height/2.0,0),inner_radius,outer_radius,top_t,top_normal); double bottom_t; Vec3f bottom_normal; bool bottom = IntersectAnnulus(r,center-Vec3f(0,height/2.0,0),inner_radius,outer_radius,bottom_t,bottom_normal); bool answer = false; // return the closest intersection if (outer && (outer_t < h.getT())) { h.set(outer_t,this->getMaterial(),outer_normal,NULL); answer = true; } if (inner && (inner_t < h.getT())) { h.set(inner_t,this->getMaterial(),-inner_normal,NULL); answer = true; } if (top && (top_t < h.getT())) { h.set(top_t,this->getMaterial(),top_normal,NULL); answer = true; } if (bottom && (bottom_t < h.getT())) { h.set(bottom_t,this->getMaterial(),-bottom_normal,NULL); answer = true; } return answer; }
bool Face::triangle_intersect(const Ray &r, Hit &h, Vertex *a, Vertex *b, Vertex *c, bool intersect_backfacing) const { // compute the intersection with the plane of the triangle Hit h2 = Hit(h); if (!plane_intersect(r,h2,intersect_backfacing)) return 0; // figure out the barycentric coordinates: glm::vec3 Ro = r.getOrigin(); glm::vec3 Rd = r.getDirection(); // [ ax-bx ax-cx Rdx ][ beta ] [ ax-Rox ] // [ ay-by ay-cy Rdy ][ gamma ] = [ ay-Roy ] // [ az-bz az-cz Rdz ][ t ] [ az-Roz ] // solve for beta, gamma, & t using Cramer's rule glm::mat3 detA_mat(a->get().x-b->get().x,a->get().x-c->get().x,Rd.x, a->get().y-b->get().y,a->get().y-c->get().y,Rd.y, a->get().z-b->get().z,a->get().z-c->get().z,Rd.z); float detA = glm::determinant(detA_mat); if (fabs(detA) <= 0.000001) return 0; assert (fabs(detA) >= 0.000001); glm::mat3 beta_mat(a->get().x-Ro.x,a->get().x-c->get().x,Rd.x, a->get().y-Ro.y,a->get().y-c->get().y,Rd.y, a->get().z-Ro.z,a->get().z-c->get().z,Rd.z); glm::mat3 gamma_mat(a->get().x-b->get().x,a->get().x-Ro.x,Rd.x, a->get().y-b->get().y,a->get().y-Ro.y,Rd.y, a->get().z-b->get().z,a->get().z-Ro.z,Rd.z); float beta = glm::determinant(beta_mat) / detA; float gamma = glm::determinant(gamma_mat) / detA; if (beta >= -0.00001 && beta <= 1.00001 && gamma >= -0.00001 && gamma <= 1.00001 && beta + gamma <= 1.00001) { h = h2; // interpolate the texture coordinates float alpha = 1 - beta - gamma; float t_s = alpha * a->get_s() + beta * b->get_s() + gamma * c->get_s(); float t_t = alpha * a->get_t() + beta * b->get_t() + gamma * c->get_t(); h.setTextureCoords(t_s,t_t); assert (h.getT() >= EPSILON); return 1; } return 0; }
bool Plane::intersect( const Ray& r, Hit& h, float tmin ) const { float nd = this->m_normal.dot(r.getDirection()); if (nd == 0.0f) { return false; } float t = (this->m_d - (this->m_normal.dot(r.getOrigin())))/nd; if (t < h.getT() && t > tmin) { h.set(t, this->m_material, this->m_normal); return true; } return false; }
bool Transform::intersect(const Ray &r, Hit &h, float tmin) { Vec3f rTransOri = r.getOrigin(); Vec3f rTransDir = r.getDirection(); Matrix mInverse; m.Inverse(mInverse); mInverse.Transform(rTransOri); mInverse.TransformDirection(rTransDir); rTransDir.Normalize(); Ray rTrans(rTransDir,rTransOri); Hit hTrans(10000,NULL,Vec3f(0,0,0)); //need a new hit,because the x-y-z had changed 就因为这里没有使用一个新的hit导致了自己debug了两天 instance->intersect(rTrans,hTrans,tmin); if(hTrans.getT()<10000) { //world's t float t; //Vec3f hitPoint = rTransOri + rTransDir * hTrans.getT(); Vec3f hitPoint = rTrans.pointAtParameter(hTrans.getT()); m.Transform(hitPoint); Vec3f rOri = r.getOrigin(); Vec3f rDir = r.getDirection(); if((fabs(rDir[0])>=fabs(rDir[1]))&&(fabs(rDir[0])>=fabs(rDir[2]))){ t = (hitPoint[0] - rOri[0]) / rDir[0]; } else if((fabs(rDir[1])>=fabs(rDir[0]))&&(fabs(rDir[1])>=fabs(rDir[2]))){ t = (hitPoint[1] - rOri[1]) / rDir[1]; } else if((fabs(rDir[2])>=fabs(rDir[0]))&&(fabs(rDir[2])>=fabs(rDir[1]))){ t = (hitPoint[2] - rOri[2]) / rDir[2]; } //world's normal mInverse.Transpose(); Vec3f wNormal = hTrans.getNormal(); mInverse.TransformDirection(wNormal); wNormal.Normalize(); //need normalize //h.setNormal(wNormal); if(t>=tmin && t<=h.getT()) { h.set(t,hTrans.getMaterial(),wNormal,r); return 1; } } return 0; }
bool Face::triangle_intersect(const Ray &r, Hit &h, Vertex *a, Vertex *b, Vertex *c, bool intersect_backfacing, bool* backfacing_hit) { *backfacing_hit = false; // compute the intersection with the plane of the triangle Hit h2 = Hit(h); if (!plane_intersect(r,h2,intersect_backfacing, backfacing_hit)) return 0; // figure out the barycentric coordinates: Vec3f Ro = r.getOrigin(); Vec3f Rd = r.getDirection(); // [ ax-bx ax-cx Rdx ][ beta ] [ ax-Rox ] // [ ay-by ay-cy Rdy ][ gamma ] = [ ay-Roy ] // [ az-bz az-cz Rdz ][ t ] [ az-Roz ] // solve for beta, gamma, & t using Cramer's rule double detA = Matrix::det3x3(a->get().x()-b->get().x(),a->get().x()-c->get().x(),Rd.x(), a->get().y()-b->get().y(),a->get().y()-c->get().y(),Rd.y(), a->get().z()-b->get().z(),a->get().z()-c->get().z(),Rd.z()); if (fabs(detA) <= 0.000001) return 0; assert (fabs(detA) >= 0.000001); double beta = Matrix::det3x3(a->get().x()-Ro.x(),a->get().x()-c->get().x(),Rd.x(), a->get().y()-Ro.y(),a->get().y()-c->get().y(),Rd.y(), a->get().z()-Ro.z(),a->get().z()-c->get().z(),Rd.z()) / detA; double gamma = Matrix::det3x3(a->get().x()-b->get().x(),a->get().x()-Ro.x(),Rd.x(), a->get().y()-b->get().y(),a->get().y()-Ro.y(),Rd.y(), a->get().z()-b->get().z(),a->get().z()-Ro.z(),Rd.z()) / detA; //Case of an intersection if (beta >= -0.00001 && beta <= 1.00001 && gamma >= -0.00001 && gamma <= 1.00001 && beta + gamma <= 1.00001) { h = h2; // interpolate the texture coordinates double alpha = 1 - beta - gamma; double t_s = alpha * a->get_s() + beta * b->get_s() + gamma * c->get_s(); double t_t = alpha * a->get_t() + beta * b->get_t() + gamma * c->get_t(); h.setTextureCoords(t_s,t_t); assert (h.getT() >= EPSILON); return 1; } return 0; }
Vector3f Material::Shade( const Ray& ray, const Hit& hit, const Vector3f& dirToLight, const Vector3f& lightColor ) { Vector3f kd; if(t.valid() && hit.hasTex) { Vector2f texCoord = hit.texCoord; Vector3f texColor = t(texCoord[0],texCoord[1]); kd = texColor; } else { kd = this->diffuseColor; } //Diffuse Shading if(noise.valid()) { kd = noise.getColor(ray.getOrigin()+ray.getDirection()*hit.getT()); } Vector3f n = hit.getNormal().normalized(); Vector3f color = clampedDot( dirToLight ,n )*pointwiseDot( lightColor , kd); return color; }
bool Transform::intersect( const Ray& r , Hit& h , float tmin) { Matrix4f iMatrix=TMatrix_.inverse(); Matrix4f tMatrix=TMatrix_.transposed() ; //Ray newRay = Ray((iMatrix * Vector4f(r.getOrigin(), 1.0f)).xyz(), (iMatrix* Vector4f(r.getDirection(), 0.0f)).xyz().normalized()); Ray newRay = Ray((iMatrix * Vector4f(r.getOrigin(), 1.0f)).xyz(), (iMatrix* Vector4f(r.getDirection(), 0.0f)).xyz()); if(o->intersect(newRay, h , tmin)) { h.set(h.getT(), h.getMaterial(), (iMatrix.transposed() * Vector4f(h.getNormal(), 0.0f)).xyz().normalized()); return true; } return false; }
bool Triangle::any_intersect(const Ray& ray, Hit& hit, float tmin) { Vector3f direction = ray.getDirection(); Vector3f origin = ray.getOrigin(); float list[9] = { (a.x()) - (b.x()),(a.y()) - (b.y()),(a.z()) - (b.z()), (a.x()) - (c.x()),(a.y()) - (c.y()),(a.z()) - (c.z()), (a[0]) - (origin[0]),(a[1]) - (origin[1]),(a[2]) - (origin[2]), }; Matrix3f A = Matrix3f(list[0], list[3], direction[0], list[1], list[4], direction[1], list[2], list[5], direction[2]); float determinant = A.determinant(); if (determinant == 0) { return false; } float t = Matrix3f::determinant3x3(list[0], list[3], list[6], list[1], list[4], list[7], list[2], list[5], list[8]) / determinant; if (t <= tmin || t >= hit.getT()) { return false; } float beta = Matrix3f::determinant3x3(list[6], list[3], direction[0], list[7], list[4], direction[1], list[8], list[5], direction[2]) / determinant; float gamma = Matrix3f::determinant3x3(list[0], list[6], direction[0], list[1], list[7], direction[1], list[2], list[8], direction[2]) / determinant; if ((beta >= 0 && gamma >= 0 && beta + gamma <= 1)) { return true; } return false; }
bool Grid::intersectWithGridVisualization(const Ray & r, Hit & h, float tmin) const { RayTracing_Stats::IncrementNumIntersections(); MarchInfo mi; bool re = initializeRayMarch(mi, r, tmin); if ( re == false ) { return false; } int index_i, index_j, index_k; while ( IsCellValid(mi) ) { RayTracing_Stats::IncrementNumGridCellsTraversed(); index_i = mi.get_i(); index_j = mi.get_j(); index_k = mi.get_k(); Object3DVector & obj_array = cells[num_y * num_z * index_i + num_z * index_j + index_k].objs; int num_objs = obj_array.getNumOfObjects(); if ( num_objs > 0 ) { if ( mi.tmin < h.getT() ) { h.set(mi.tmin, selfRendering_m, mi.surfaceNormal, r); return true; } else return false; } else { mi.nextCell(); } } return false; }
Vec3f RayTracer::reflections(const Ray &ray, const Hit &hit, int bounce_count, double roughness) const { if (bounce_count <= 0) return Vec3f(0, 0, 0); const Vec3f point = ray.pointAtParameter(hit.getT()); /* Get mirror direction */ const Vec3f orig_dir = ray.getDirection(); Vec3f norm = hit.getNormal(); norm.Normalize(); const Vec3f new_dir = orig_dir - 2 * orig_dir.Dot3(norm) * norm; const Ray new_ray(point, new_dir); Vec3f rand_vec(0, 0, 0); double answerx = 0, answery = 0, answerz = 0; /* sphere projection, what if the center of the sphere misses the * object? */ { for (int i = 0; i <= args->num_glossy_samples; ++i) { /* Getting gloss ray */ Ray start_ray(new_ray.getOrigin(), new_ray.getDirection() + rand_vec); const Vec3f answer(reflection(start_ray, bounce_count - 1)); answerx += answer.x(); answery += answer.y(); answerz += answer.z(); rand_vec = Vec3f(roughness * (static_cast<double>(rand()) / RAND_MAX), roughness * (static_cast<double>(rand()) / RAND_MAX), roughness * (static_cast<double>(rand()) / RAND_MAX)); } } Vec3f answer = Vec3f(answerx, answery, answerz); answer *= static_cast<double>(1)/(args->num_glossy_samples + 1); return answer; }
bool Transform::intersect(const Ray &r, Hit &h, float tmin) { Vec3f original = r.getOrigin(); Vec3f dir = r.getDirection(); mReverseMat.Transform(original); mReverseMat.TransformDirection(dir); Ray transformedRay(original, dir); if (mObj->intersect(transformedRay, h, tmin)) { Vec3f normal = h.getNormal(); Matrix t; mReverseMat.Transpose(t); t.TransformDirection(normal); h.set(h.getT(), h.getMaterial(), normal, r); return true; } return false; }
bool Rectangle::intersect(const Ray& r, Hit& h, float tmin) { Vector3f a = vertex0; Vector3f b = vertex0 + side_1; Vector3f c = vertex0 + side_2; Vector3f direction = r.getDirection(); Vector3f origin = r.getOrigin(); float list[9] = { (a.x()) - (b.x()),(a.y()) - (b.y()),(a.z()) - (b.z()), (a.x()) - (c.x()),(a.y()) - (c.y()),(a.z()) - (c.z()), (a[0]) - (origin[0]),(a[1]) - (origin[1]),(a[2]) - (origin[2]), }; Matrix3f A = Matrix3f(list[0], list[3], direction[0], list[1], list[4], direction[1], list[2], list[5], direction[2]); float determinant = A.determinant(); if (determinant == 0) { return false; } float t = Matrix3f::determinant3x3(list[0], list[3], list[6], list[1], list[4], list[7], list[2], list[5], list[8]) / determinant; if (t <= tmin || t >= h.getT()) { return false; } float beta = Matrix3f::determinant3x3(list[6], list[3], direction[0], list[7], list[4], direction[1], list[8], list[5], direction[2]) / determinant; float gamma = Matrix3f::determinant3x3(list[0], list[6], direction[0], list[1], list[7], direction[1], list[2], list[8], direction[2]) / determinant; if ((beta >= 0 && gamma >= 0 && beta <= 1 && gamma <= 1)) { h.set(t, this->material, normal); return true; } return false; }