static Ray3D GetGizmoAxisInWorldSpace( const APlaceable* pEntity, const EGizmoAxis eAxis ) { const Vec3D& origin = pEntity->GetOrigin(); const Matrix4 R = pEntity->GetOrientation().ToMat4(); const Vec3D axisX = R[0].ToVec3(); const Vec3D axisY = R[1].ToVec3(); const Vec3D axisZ = R[2].ToVec3(); switch( eAxis ) { case GizmoAxis_X : return Ray3D( origin, axisX ); case GizmoAxis_Y : return Ray3D( origin, axisY ); case GizmoAxis_Z : return Ray3D( origin, axisZ ); mxNO_SWITCH_DEFAULT; } return Ray3D(); }
int RayDirectionalLight::isInShadow(RayIntersectionInfo& iInfo,RayShape* shape,int& isectCount){ Point3D P = iInfo.iCoordinate; Point3D L = -direction; Ray3D temp = Ray3D(P,L); Ray3D tempRay = Ray3D(temp(.00001),L); RayIntersectionInfo info; double d = shape->intersect(tempRay, info, -1); //printf("hit distance:%f,%f,%f,%f\n",d,info.normal.p[0],info.normal.p[1],info.normal.p[2]); if (L.dot(info.normal) >= 0) return 1; if (d > 0) {return 0;} else return 1; }
Point3D RayDirectionalLight::transparency(RayIntersectionInfo& iInfo,RayShape* shape,Point3D cLimit){ Point3D trans = Point3D(1,1,1); Ray3D shadeRay = Ray3D(iInfo.iCoordinate, -direction); shadeRay.position = shadeRay(0.00001); RayIntersectionInfo info; Point3D Kt = Point3D(); while (Kt[0] < cLimit[0] && Kt[1] < cLimit[1] && Kt[2] < cLimit[2]) { double dis = shape->intersect(shadeRay, info, -1); Point3D N = info.normal; if (dis < 0 || -direction.dot(N) >= 0) return trans; Kt = info.material->transparent; shadeRay.position = info.iCoordinate; shadeRay.position = shadeRay(0.00001); cLimit /= Kt; trans -= Kt; } if(trans[0]<0) trans[0] =0; if(trans[1]<0) trans[1] =0; if(trans[2]<0) trans[2] =0; return trans; }
int RaySpotLight::isInShadow(RayIntersectionInfo& iInfo,RayShape* shape,int& isectCount){ Point3D temp = this->location - iInfo.iCoordinate; double dist = temp.length(); Ray3D newRay = Ray3D(); newRay.position = iInfo.iCoordinate; newRay.direction = temp.unit(); if(shape->intersect(newRay, iInfo, dist) > 0){ isectCount+=1; return 1; } return 0; }
int RayPointLight::isInShadow(RayIntersectionInfo& iInfo,RayShape* shape,int& isectCount){ Point3D temp = location - iInfo.iCoordinate; double dist = sqrt(temp.dot(temp)); double atten = 0; atten = (constAtten + (linearAtten*dist) + (quadAtten*pow(dist,2.0))); Ray3D testRay = Ray3D(); testRay.position = iInfo.iCoordinate; testRay.direction = temp.unit(); if(shape->intersect(testRay, iInfo, dist) != -1){ return 1; } //1 = inShadow, 0 = no shadow return 0; }
void Raytracer::render( int width, int height, Point3D eye, Vector3D view, Vector3D up, double fov, char* fileName, char mode ) { Matrix4x4 viewToWorld; _scrWidth = width; _scrHeight = height; double factor = (double(height)/2)/tan(fov*M_PI/360.0); initPixelBuffer(); viewToWorld = initInvViewMatrix(eye, view, up); // Construct a ray for each pixel. for (int i = 0; i < _scrHeight; i++) { for (int j = 0; j < _scrWidth; j++) { // Sets up ray origin and direction in view space, // image plane is at z = -1. Point3D origin(0, 0, 0); Point3D imagePlane; imagePlane[0] = (-double(width)/2 + 0.5 + j)/factor; imagePlane[1] = (-double(height)/2 + 0.5 + i)/factor; imagePlane[2] = -1; // TODO: Convert ray to world space and call // shadeRay(ray) to generate pixel colour. /////////////////////// OUR CODE /////////////////////////////// Vector3D d = Vector3D(imagePlane[0], imagePlane[1], imagePlane[2]); d = viewToWorld*d; origin = viewToWorld*origin; Ray3D ray = Ray3D( origin , d ); if (mode == 'd'){ (*(ray.intersection.mat)).specular = Colour(0,0,0); } Colour col; col = shadeRay(ray, mode); /////////////////////// OUR CODE /////////////////////////////// _rbuffer[i*width+j] = int(col[0]*255); _gbuffer[i*width+j] = int(col[1]*255); _bbuffer[i*width+j] = int(col[2]*255); } } flushPixelBuffer(fileName); }
Colour Raytracer::shadeRay( Ray3D& ray ) { Colour col(0.0, 0.0, 0.0); traverseScene(_root, ray); // Don't bother shading if the ray didn't hit // anything. if (!ray.intersection.none) { computeShading(ray); // You'll want to call shadeRay recursively (with a different ray, // of course) here to implement reflection/refraction effects. float dampFactor = 0.0; // Calculate reflection ray Vector3D N = ray.intersection.normal; Vector3D D = ray.dir; Vector3D reflectionDir = -2*(D.dot(N))*N + D; reflectionDir.normalize(); Point3D reflectionOrigin = ray.intersection.point + 0.01*reflectionDir; Ray3D reflectionRay = Ray3D(reflectionOrigin, reflectionDir); // calculate shade of reflected ray shadeRay(reflectionRay); // limit effective distance of reflections if (reflectionRay.intersection.t_value > 10.0 || reflectionRay.intersection.t_value <= 0.0) { col = ray.col; } else { dampFactor = fabs(1.0/reflectionRay.intersection.t_value); // contraint dampFactor to 0-0.9 dampFactor = fmax(0, fmin(dampFactor,0.9)); // Set colour to include reflection col = ray.col + dampFactor*reflectionRay.col; } col.clamp(); } return col; }
Point3D RayPointLight::transparency(RayIntersectionInfo& iInfo,RayShape* shape,Point3D cLimit){ Point3D temp = location - iInfo.iCoordinate; double dist = sqrt(temp.dot(temp)); double atten = 0; atten = (constAtten + (linearAtten*dist) + (quadAtten*pow(dist,2.0))); Ray3D testRay = Ray3D(); testRay.direction = temp.unit(); testRay.position = iInfo.iCoordinate + testRay.direction; Point3D out = Point3D(1,1,1); if(shape->intersect(testRay, iInfo, dist) != -1){ Point3D trans = iInfo.material->transparent; out = out * trans; out = out * transparency(iInfo, shape, cLimit / trans); } //1 = inShadow, 0 = no shadow return out; }
//---------------------------------------------------------------------------------------------------------------- bool UnitSquare::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // Implement intersection code for UnitSquare, which is // defined on the xy-plane, with vertices (0.5, 0.5, 0), // (-0.5, 0.5, 0), (-0.5, -0.5, 0), (0.5, -0.5, 0), and normal // (0, 0, 1). // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_value. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. // The original point is at 0,0,0 at its own model coordinates // Get ray direction in model coordinates Ray3D ObjectRay = Ray3D(worldToModel*ray.origin, worldToModel * ray.dir); Point3D origin(0,0,0); // always assume unitsquare is on x,y plane Vector3D squareNormal(0,0,1); double t_value; Point3D intersectionPoint; // If the ray is not moving towards the square, it means there is no intersection since // the square lies on the x and y axis, ray must move at some value on the z direction if (ObjectRay.dir[2] != 0) { t_value = -ObjectRay.origin[2]/ObjectRay.dir[2]; // Check for no self intersection if ((t_value )< 0.001) { return false; } } //the ray and the square are on the same plane else if (ObjectRay.dir[2] == 0 && ObjectRay.origin[2] == 0) { double temp1 = (-1.5 - ObjectRay.origin[0])/ObjectRay.dir[0]; double temp2 = (1.5 - ObjectRay.origin[0])/ObjectRay.dir[0]; double temp3 = (-1.5 - ObjectRay.origin[1])/ObjectRay.dir[1]; double temp4 = (1.5 - ObjectRay.origin[1])/ObjectRay.dir[1]; t_value = temp1; if (temp2 < t_value ) { t_value = temp2; } if (temp3 < t_value ) { t_value =temp3; } if (temp4< t_value ) { t_value = temp4; } } else { return false; } // Compute t_value from z intersection at z = 0 // If the ray already has an intersection at an earlier t_value, return but don't update // ray.intersection fields if(ray.intersection.none == false) { if(t_value > ray.intersection.t_value) { return false; } } // Compute coordinates Vector3D intersection(ObjectRay.origin[0] + ObjectRay.dir[0] * t_value, ObjectRay.origin[1] + ObjectRay.dir[1] * t_value, 0); double x = ObjectRay.origin[0] + ObjectRay.dir[0] * t_value; double y = ObjectRay.origin[1] + ObjectRay.dir[1] * t_value; // Test x if(x >= -0.5 && x <= 0.5) { // Text y if(y >= -0.5 && y <= 0.5) { // We have an intersection ray.intersection.t_value = t_value; ray.intersection.point = modelToWorld * Point3D(x, y, 0); ray.intersection.normal = Vector3D(0, 0, 1); // For Image Mapping ray.intersection.CenterPoint = modelToWorld * Point3D(0,0,0); // every model thinks it is in the center ray.intersection.normal = transNorm(worldToModel, ray.intersection.normal); ray.intersection.normal.normalize(); ray.intersection.none = false; // false means there is an intersection return true; } } return false; }
bool UnitSphere::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // TODO: implement intersection code for UnitSphere, which is centred // on the origin. // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_value. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. Ray3D ObjectRay = Ray3D(worldToModel * ray.origin, worldToModel * ray.dir); double a = pow(ObjectRay.dir[0], 2) + pow(ObjectRay.dir[1], 2) + pow(ObjectRay.dir[2], 2); double b = 2 * (ObjectRay.origin[0] * ObjectRay.dir[0] + ObjectRay.origin[1] * ObjectRay.dir[1] + ObjectRay.origin[2] * ObjectRay.dir[2]); double c = pow(ObjectRay.origin[0], 2) + pow(ObjectRay.origin[1], 2) + pow(ObjectRay.origin[2], 2) -1; double discriminant = pow(b, 2) - 4 * a * c; // No intersection since no real roots if(discriminant < 0) { return false; } else { double t_1 = (-1 * b + sqrt(discriminant)) / (2 * a); double t_2 = (-1 * b - sqrt(discriminant)) / (2 * a); double t_value = 0; if ( t_2 < 0 && t_1 < 0) return false; else if ( t_1 < 0 ) t_value = t_2; else if ( t_2 < 0 ) t_value = t_1; else t_value = fmin(t_1, t_2); // If the ray already has an intersection at an earlier t_value, return but don't update // ray.intersection fields if(ray.intersection.none == false) { if(t_value > ray.intersection.t_value) { return true; } } double x = ObjectRay.origin[0] + ObjectRay.dir[0]*t_value; double y = ObjectRay.origin[1] + ObjectRay.dir[1]*t_value; double z = ObjectRay.origin[2] + ObjectRay.dir[2]*t_value; Vector3D intersection = Vector3D(x, y, z); ray.intersection.t_value = t_value; ray.intersection.point = modelToWorld * Point3D(x, y, z); ray.intersection.normal = transNorm(worldToModel, intersection); ray.intersection.normal.normalize(); // FOR TEXTURE MAPPING! ray.intersection.CenterPoint = modelToWorld * Point3D(0,0,0); // every model thinks it is in the center ray.intersection.none = false; return true; } }
Ray3D RayScene::GetRay(RayCamera* camera,int i,int j,int width,int height){ return Ray3D(); }
int step_trace_ray::execute ( const pair & frame_fragment, ray_tracer & rt ) const { int current_frame = frame_fragment.first; int current_fragment = frame_fragment.second; // Consume std::vector<Primitive*> scene; std::vector<Primitive*> static_scene = rt.static_scene; std::vector<Luminaire*> luminaires = rt.luminaires; std::vector<Primitive*> dynamic_scene; rt.dynamic_scene.get(current_frame, dynamic_scene); scene.insert(scene.end(), static_scene.begin(), static_scene.end()); scene.insert(scene.end(), dynamic_scene.begin(), dynamic_scene.end()); std::vector<Point2D*> points; rt.pixel_locations.get(pair(current_frame, current_fragment), points); // Execute double duration; std::clock_t start = std::clock(); std::vector<Pixel*> pixels; double invWidth = 1/((double)rt.image_width); double invHeight = 1/((double)rt.image_height); int smaller = std::min(rt.image_width, rt.image_height); double fov = 30; double aspectratio = rt.image_width/((double)rt.image_height); double angle = tan(3.141592653589793 * 0.5 * fov / 180.0); for(int ij = 0; ij < points.size(); ij++) { double x = (double)points[ij]->i; double y = (double)points[ij]->j; double nSamp1D = sqrt(rt.number_pixel_samples); double duvSamp = 1.0/nSamp1D; Multispectral3D superSample = Multispectral3D(); for(int i = 0; i < nSamp1D; ++i) { for(int j = 0; j < nSamp1D; ++j) { double u = x + (i + 0.5 * duvSamp)/smaller; double v = y + (j + 0.5 * duvSamp)/smaller; double xx = (2 * (u * invWidth) - 1) * angle * aspectratio; double yy = (1 - 2 * (v * invHeight)) * angle; Vector3D raydir = Vector3D(xx, yy, -1).normalize(); Ray3D ray = Ray3D(Point3D(), raydir, NULL, 0); superSample = superSample + trace(ray, scene, luminaires); } } Multispectral3D rgb = superSample / rt.number_pixel_samples; pixels.push_back(new Pixel(points[ij]->i,points[ij]->j,rgb.r,rgb.g,rgb.b)); } duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC; // Produce rt.pixels.put(pair(current_frame, current_fragment), pixels); rt.execution_time.put(pair(current_frame, current_fragment), duration); return CnC::CNC_Success; };
//Comparison speed: 10.96 //Bounding Boxes: 5.89 //Ordering: 4.99 double RayGroup::intersect(Ray3D ray,RayIntersectionInfo& iInfo,double mx){ //printf("This runs\n"); bool ignoreMX = false; if (mx == -1) ignoreMX = true; Ray3D rayCopy = Ray3D(); rayCopy.position = ray.position; rayCopy.direction = ray.direction; double min_t = -1; RayShape* min_shape = NULL; RayIntersectionInfo tempInfo = RayIntersectionInfo(); double boxOut = bBox.intersect(ray); if (boxOut < mx || ignoreMX){ if(boxOut > -1){ Matrix4D matrix = getMatrix(); ray.position = getInverseMatrix().multPosition(ray.position); ray.direction = getInverseMatrix().multDirection(ray.direction); double scaler = ray.direction.length(); ray.direction = ray.direction.unit(); int count = 0; for (int i = 0; i < sNum; i++) { RayShape* temp = shapes[i]; double dist = temp->bBox.intersect(ray); if(dist < mx || ignoreMX) { if (dist > -1) { //Means we have a hit of the inner volume hits[count].shape = temp; hits[count].t = dist; count++; } } } qsort(hits,count,sizeof(RayShapeHit),RayShapeHit::Compare); //if (bBox.intersect(ray) > -1){ for (int i = 0; i < count; i++) { //printf("something got hit!\n"); //printf("i = %i\n",i); RayShape* temp = hits[i].shape; double t = -1; t = temp->intersect(ray, tempInfo, mx); if (t > 0) { t = t / scaler; if (min_t == -1 || t < min_t) { min_t = t; min_shape = temp; iInfo.iCoordinate = tempInfo.iCoordinate; iInfo.normal = tempInfo.normal; iInfo.material = tempInfo.material; break; } } //Checks if its a Static Ray Group with its own transform information /*StaticRayGroup* temp2 = dynamic_cast<StaticRayGroup*>(temp); if(temp2 != 0) { t = temp->intersect(rayCopy, tempInfo, mx); if (t > 0) { if (min_t == -1 || t < min_t) { iInfo.iCoordinate = tempInfo.iCoordinate; iInfo.normal = tempInfo.normal; iInfo.material = tempInfo.material; min_t = t; min_shape = temp; } } } else { ray.position = getInverseMatrix().multPosition(rayCopy.position); ray.direction = getInverseMatrix().multDirection(rayCopy.direction).unit(); t = temp->intersect(ray, tempInfo, mx); if (t > 0) { if (min_t == -1 || t < min_t) { iInfo.iCoordinate = matrix.multPosition(tempInfo.iCoordinate); iInfo.normal = getNormalMatrix().multNormal(tempInfo.normal); iInfo.material = tempInfo.material; min_t = t; min_shape = temp; } } }*/ } iInfo.iCoordinate = matrix.multPosition(iInfo.iCoordinate); iInfo.normal = getNormalMatrix().multDirection(iInfo.normal).unit(); //iInfo.material = iInfo.material; } } return min_t; }
Colour Raytracer::shadeRay( Ray3D& ray, char renderStyle ) { Colour col(0.0, 0.0, 0.0); traverseScene(_root, ray); // Don't bother shading if the ray didn't hit // anything. if (!ray.intersection.none) { //computeShading(ray); if (renderStyle != 's') { computeShading(ray, renderStyle); col = ray.col; #ifdef USE_REFLECTIONS if ((ray.intersection.mat->reflectivity >= 0.01) && (ray.reflections < MAX_REFLECTIONS) && (renderStyle != 'd')) { // emit another ray Vector3D n = ray.intersection.normal; n.normalize(); Vector3D d = ray.dir; d.normalize(); double dot = n.dot(d); Vector3D newdir = d - (2 * dot * n); Ray3D newRay = Ray3D(ray.intersection.point + 0.01*newdir, newdir, ray.reflections+1, ray.refractions, ray.cLight); Colour secondaryColour = shadeRay(newRay, renderStyle); double ref = ray.intersection.mat->reflectivity; col = (1-ref)*ray.col + ref*secondaryColour; } else { col = ray.col; } #else col = ray.col; #endif // Check for refractions // Don't check for refractions of reflected rays #ifdef USE_REFRACTIONS if((ray.intersection.mat->transitivity >= 0.1) && (ray.refractions < MAX_REFRACTIONS) && (renderStyle != 'd')) { double c1 = ray.cLight; double c2 = ray.intersection.mat->cLight; if (ray.cLight < 0.99) { //Ray leaves object to air/vacuum c2= 1; } Vector3D n = ray.intersection.normal; n.normalize(); Vector3D d = ray.dir; d.normalize(); double dot = n.dot(d); Vector3D reflDir = d - (2 * dot * n); reflDir.normalize(); //Now determine refraction direction //Depends on reflDir, c1, c2, n, as specified in the relation below double theta1 = acos( n.dot(-d) ); if(dot > 0 ) { //Ray is leaving object theta1 = acos( n.dot(d) ); } double theta2 = asin(c2*sin(theta1)/c1); //Check for critical angle // Compute refraction direction Vector3D refractDir = (c2/c1)*ray.dir + ( (c2/c1)*cos(theta1) - cos(theta2))*n; if(dot > 0 ) { //Ray is leaving object =====================changed sign refractDir = (c2/c1)*ray.dir - ( (c2/c1)*cos(theta1) - cos(theta2))*n; } refractDir.normalize(); Ray3D refractRay = Ray3D(ray.intersection.point + 0.0001*refractDir, refractDir,ray.reflections, ray.refractions+1, c2 ); Colour colRefract = shadeRay(refractRay, renderStyle); double matTran = ray.intersection.mat->transitivity; if(!refractRay.intersection.none) { //Refracted ray does not go off into space col = (1-matTran)*col + matTran*colRefract; } }//end of refractions #endif }//End of check if(renderStyle != 's') else { //renderStyle == 's' col = (*(ray.intersection.mat)).diffuse; } }//End of check if (!ray.intersection.none) return col; }// End of shadeRay
// Basically, this is an intersection with 3 different connected surfaces // The top disk, the bottom disk and the cylinder body. // Test the intersection of all 3 bodies and figure out which has the lowest t value bool UnitCylinder::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // Get the ray in the object coordinates Ray3D ObjectRay = Ray3D(worldToModel * ray.origin, worldToModel * ray.dir); // A reference to the origin point in object/model coordinates Point3D centerOfCylinder(0,0,0); // Center of cylinder // T Values // One to check for intersection with disks, one to check for intersection with sides double t_value; double t_valueTwo; double tempOne, tempTwo; double radius = 1.0; // the radius of the disk of the cylinder Vector3D normal; // The normal of the cylinder Disk as well as wall of cylinder // Gets reused Point3D intersectionPoint; // intersection point with the cylinder //--------------------------------------------------------------------------------- // Checking Intersection with Cylinder Disks //--------------------------------------------------------------------------------- // Note: Will only intersect the disks of the cylinder // if the direction value for z is not 0 // Getting the tValue for the closer base if (ObjectRay.dir[2] != 0) { // Tvalue to intersect bottom disk of cylinder (negative z axis) tempOne = (-0.5-ObjectRay.origin[2])/ObjectRay.dir[2]; // Tvalue to intersect top disk of cylinder (positive z axis) tempTwo = (0.5-ObjectRay.origin[2])/ObjectRay.dir[2]; // Update the normal depending on which disk is closer if (tempOne < tempTwo) { t_value = tempOne; // Construct the normal for the closer disk, which points on the negative z axis Point3D normal_temp(0,0,-1); normal = normal_temp - centerOfCylinder; normal.normalize(); } else { t_value = tempTwo; Point3D normal_temp(0,0,1); normal = normal_temp - centerOfCylinder; normal.normalize(); } } //--------------------------------------------------------------------------------- // Calculate the intersection point for the disk //--------------------------------------------------------------------------------- intersectionPoint = ObjectRay.origin + t_value * ObjectRay.dir; // Prevent self intersection if (t_value < 0.001) { return false; } // Base or top of cylinder // need make sure within the radius of the disk if (intersectionPoint[0]*intersectionPoint[0] + intersectionPoint[1] * intersectionPoint[1] <= (radius*radius)) { // If it intersection before and it's tvalue is lower then this, // means there is no intersection, return false. if (!ray.intersection.none && (t_value > ray.intersection.t_value)) { return false; } // Else, there is intersection, update and return true ray.intersection.point = intersectionPoint; ray.intersection.normal = normal; ray.intersection.t_value = t_value; ray.intersection.none = false; // Every model thinks it is in the center ray.intersection.CenterPoint = modelToWorld * Point3D(0,0,0); return true; } // No intersection with cylinder disk // Check for intersection with cylinder body //--------------------------------------------------------------------------------- // Checking Intersection with Cylinder Body //--------------------------------------------------------------------------------- // Source: http://www.csie.ntu.edu.tw/~cyy/courses/rendering/pbrt-2.00/html/cylinder_8cpp_source.html // Compute Quadratic Cylinder Coefficients double a = ObjectRay.dir[0]*ObjectRay.dir[0] + ObjectRay.dir[1]*ObjectRay.dir[1]; double b = (ObjectRay.origin[0]*ObjectRay.dir[0] + ObjectRay.origin[1]* ObjectRay.dir[1]); double c = ObjectRay.origin[0]*ObjectRay.origin[0] + ObjectRay.origin[1]*ObjectRay.origin[1] - radius*radius; double discriminant = b*b-a*c; // If ray is aligned with body of the cylinder, there is no intersection if (a == 0.0) { // return false } //If discrimant is < 0 => No real roots to the cylinder quadratic equation. if (discriminant<0) { // It means no intersection return false; } else { double rootOne = -b/a + sqrt(discriminant) / a; double rootTwo = -b/a - sqrt(discriminant) / a; if (rootOne< 0 && rootTwo < 0) { return false; } else if (rootOne> 0 && rootTwo < 0) { t_valueTwo = rootOne; } else { t_valueTwo = rootTwo; } } //--------------------------------------------------------------------------------- // Calculate the intersection point for the walls of the cylinder //--------------------------------------------------------------------------------- // There is no intersection with the base of the cylinder on x,y plane // Check if there is intersection with sides. // Get the intersection point for the sides intersectionPoint = ObjectRay.origin+ t_valueTwo * ObjectRay.dir; // Check for no self intersection if (t_valueTwo < 0.001) { return false; } // Get the coordinate of the normals for the sides of the cylinder normal[0] = intersectionPoint[0]; normal[1] = intersectionPoint[1]; normal[2] = 0; normal.normalize(); // If the intersection point is within the height of the cylinder if (intersectionPoint[2] < 0.5 && intersectionPoint[2] > -0.5) { // Ensure no previous intersection with lower t value if (!ray.intersection.none && t_value > ray.intersection.t_value) { return false; } // Update the intersection to the ray ray.intersection.point = modelToWorld * intersectionPoint; Point3D normalTemp; normalTemp[0] = intersectionPoint[0]; normalTemp[1] = intersectionPoint[1]; normalTemp[2] = 0; ray.intersection.normal = modelToWorld * (normalTemp - centerOfCylinder); ray.intersection.t_value = t_valueTwo; ray.intersection.none = false; // Every model thinks it is in the center ray.intersection.CenterPoint = modelToWorld * Point3D(0,0,0); return true; } // If the intersection is not within the height of the cylinder, // It means there wasn't really a cylinder intersection to begin with else { return false; } }
// Assume disk is flat on the x,y plane with radius 1 bool UnitDisk::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // Get the ray in the object coordinates Ray3D ObjectRay = Ray3D(worldToModel * ray.origin, worldToModel * ray.dir); // A reference to the origin point in object/model coordinates Point3D centerofDisk(0,0,0); // Center of cylinder // T Values // One to check for intersection with disks, one to check for intersection with sides double t_value; double t_valueTwo; double tempOne, tempTwo; double radius = 1.0; // the radius of the disk of the cylinder Vector3D normal; // The normal of the cylinder Disk as well as wall of cylinder // Gets reused Point3D intersectionPoint; // intersection point with the cylinder //--------------------------------------------------------------------------------- // Checking Intersection with Cylinder Disks //--------------------------------------------------------------------------------- // Note: Will only intersect the disks of the cylinder // if the direction value for z is not 0 // Getting the tValue for the closer base if (ObjectRay.dir[2] != 0) { // To know if intersect from top or bottom of disk, and set normal accordingly tempOne = (-0.0000001-ObjectRay.origin[2])/ObjectRay.dir[2]; // Tvalue tempTwo = (0.00000001-ObjectRay.origin[2])/ObjectRay.dir[2]; // Update the normal depending on which disk is closer if (tempOne < tempTwo) { t_value = tempOne; // Construct the normal for the closer disk, which points on the negative z axis Point3D normal_temp(0,0,-1); normal = normal_temp - centerofDisk; normal.normalize(); } else { t_value = tempTwo; Point3D normal_temp(0,0,1); normal = normal_temp - centerofDisk; normal.normalize(); } } //--------------------------------------------------------------------------------- // Calculate the intersection point for the disk //--------------------------------------------------------------------------------- intersectionPoint = ObjectRay.origin + t_value * ObjectRay.dir; // Prevent self intersection if (t_value < 0.001) { return false; } // Base or top of cylinder // need make sure within the radius of the disk if (intersectionPoint[0]*intersectionPoint[0] + intersectionPoint[1] * intersectionPoint[1] <= (radius*radius)) { // If it intersection before and it's tvalue is lower then this, // means there is no intersection, return false. if (!ray.intersection.none && (t_value > ray.intersection.t_value)) { return false; } // Else, there is intersection, update and return true ray.intersection.point = intersectionPoint; ray.intersection.normal = normal; ray.intersection.t_value = t_value; ray.intersection.none = false; // Every model thinks it is in the center ray.intersection.CenterPoint = modelToWorld * Point3D(0,0,0); return true; } return false; // no intersection with disk }
Point3D RayScene::GetColor(Ray3D ray,int rDepth,Point3D cLimit) { Point3D color; RayIntersectionInfo info; Ray3D reflection; Ray3D refraction; Ray3D reflectedRay; Point3D reflect, reflColor, refractColor; int shad; int numCrossed = 0; double dist; dist = group -> intersect(ray, info, -1); if (dist == -1) return background; color = ambient*info.material -> ambient + info.material -> emissive; if (ray.direction.dot(info.normal) < 0) { for (int j = 0; j < this->lightNum; j++) { shad = this->lights[j]->isInShadow(info, this->group, numCrossed); Point3D ts = lights[j]->transparency(info, group, cLimit); color += this->lights[j]->getDiffuse(ray.position, info) * ts; color += this->lights[j]->getSpecular(ray.position, info) * ts; } reflect = Reflect(ray.direction, info.normal); // Reflected ray reflectedRay = Ray3D(info.iCoordinate, reflect); reflectedRay.position = reflectedRay(0.0001); if (rDepth > 0 && (info.material->specular[0] > cLimit[0]) && (info.material->specular[1] > cLimit[1]) && (info.material->specular[2] > cLimit[2])) { reflColor = GetColor(reflectedRay, rDepth - 1, (cLimit / info.material->specular)); if (reflColor.p[0] == background.p[0] && reflColor.p[1] == background.p[1] && reflColor.p[2] == background.p[2]) reflColor = Point3D(); // reflected color added reflColor *= info.material -> specular; color += reflColor; } } // refraction if (this -> Refract(ray.direction, info.normal, info.material->refind, refraction.direction)) { refraction.position = info.iCoordinate; refraction.position = refraction(0.0001); refractColor = this -> GetColor(refraction, rDepth - 1, cLimit); if (refractColor.p[0] == background.p[0] && refractColor.p[1] == background.p[1] && refractColor.p[2] == background.p[2]) refractColor = Point3D(); refractColor *= info.material -> transparent; color += refractColor; } for (int i = 0; i < 3; i++) { if (color.p[i] > 1) color.p[i] = 1; } for (int i = 0; i < 3; i++) { if (color.p[i] < 0) color.p[i] = 0; } return color; }
void Raytracer::render( int width, int height, Point3D eye, Vector3D view, Vector3D up, double fov, int AA_level, char* fileName, char renderStyle ) { Matrix4x4 viewToWorld; _scrWidth = width; _scrHeight = height; double factor = (double(_scrHeight)/2)/tan(fov*M_PI/360.0); initPixelBuffer(); viewToWorld = initInvViewMatrix(eye, view, up); /** * Extension: Anti-aliasing level via supersampling method * Algorithm: * Generate an image of dimensions equal to a multiple of the original * dimensions (as specified by the AA level) * Then sample individual pixels and average them to compose a pixel * on the actual screen */ _aaLevel = AA_level; initSuperPixelBuffer(); /// A little print for the user fprintf(stderr, "Rendering %dx%d scene, AA-level %d\n", _scrWidth, _scrHeight, _aaLevel); int superi, superj; double offi, offj; // Construct a ray for each pixel. for (int i = 0; i < _scrHeight; i++) { for (int j = 0; j < _scrWidth; j++) { // Prepare to supersample for anti aliasing for (int m = 0; m < _aaLevel; m++) { for (int n = 0; n < _aaLevel; n++) { // Sets up ray origin and direction in view space, // image plane is at z = -1. Point3D origin(0, 0, 0); Point3D imagePlane; offj = double(1)/(0.5 * _aaLevel) + double(n)/_aaLevel; offi = double(1)/(0.5 * _aaLevel) + double(m)/_aaLevel; imagePlane[0] = (-double((_scrWidth))/2 + offj + j)/factor; imagePlane[1] = (-double((_scrHeight))/2 + offi + i)/factor; imagePlane[2] = -1; // Create the transformed ray and shoot it out (shadeRay) Vector3D pixelVector = Vector3D(imagePlane[0], imagePlane[1], imagePlane[2]); Vector3D transformedPixelVector = viewToWorld * pixelVector; Point3D transformedOrigin = viewToWorld * origin; Ray3D ray = Ray3D(transformedOrigin, transformedPixelVector); //Check for scene render style Colour col = shadeRay(ray, renderStyle); superi = i*_aaLevel + m; superj = j*_aaLevel + n; _superrbuffer[superi*(_aaLevel*_scrWidth)+superj] = int(col[0]*255); _supergbuffer[superi*(_aaLevel*_scrWidth)+superj] = int(col[1]*255); _superbbuffer[superi*(_aaLevel*_scrWidth)+superj] = int(col[2]*255); } }//End supersampling loop } }//finsihed pixel loop // Now average out the pixels from the super buffer (supersampling) factor = double(1)/(_aaLevel * _aaLevel); unsigned long rtemp; unsigned long gtemp; unsigned long btemp; for (int i = 0; i < _scrHeight; i++) { for (int j = 0; j < _scrWidth; j++) { rtemp = 0; gtemp = 0; btemp = 0; for (int m = 0; m < _aaLevel; m++) { superi = i*_aaLevel + m; for (int n = 0; n < _aaLevel; n++) { superj = j*_aaLevel + n; rtemp += _superrbuffer[superi*(_aaLevel*_scrWidth)+superj]; gtemp += _supergbuffer[superi*(_aaLevel*_scrWidth)+superj]; btemp += _superbbuffer[superi*(_aaLevel*_scrWidth)+superj]; } } _rbuffer[i*_scrWidth+j] = factor * rtemp; _gbuffer[i*_scrWidth+j] = factor * gtemp; _bbuffer[i*_scrWidth+j] = factor * btemp; } } flushPixelBuffer(fileName); }
Ray3D Ray3D::fromTo(const glm::vec3 & from, const glm::vec3 & to) { return Ray3D(from, to - from); }