def intersect(self, ray): ''' Implement intersection between the ray and the current object and return IntersectionResult variable (isect) which will store the intersection point, the normal at the intersection and material of the object at the intersection point. The variable isect should contain the nearest intersection point and all its properties. ''' isect = IntersectionResult() transformedRay = Ray() # Eyepoint transformed transformedRay.eyePoint = np.dot(self.Minv, np.append(ray.eyePoint, [1])) transformedRay.eyePoint = transformedRay.eyePoint[: 3] / transformedRay.eyePoint[ 3] # Ray transformed, since it's a vector not from origin need to do this calc ray_tip = ray.eyePoint + ray.viewDirection trans_ray_tip = np.dot(self.Minv, np.append(ray_tip, [1])) trans_ray_tip = trans_ray_tip[:3] / trans_ray_tip[3] transformedRay.viewDirection = GT.normalize(trans_ray_tip - transformedRay.eyePoint) global EPS_DISTANCE # use this for testing if a variable is close to 0 # TODO ===== BEGIN SOLUTION HERE ===== intersections = [] # Get all the intersections for child in self.children: intersection = child.intersect(transformedRay) if intersection.t == np.inf: continue # Point transformed intersection.p = np.dot(self.M, np.append(intersection.p, [1])) intersection.p = intersection.p[:3] / intersection.p[3] # Distance in world coords intersection.t = np.linalg.norm(intersection.p - ray.eyePoint) # Normal, inverse transpose because it's a normal to remove scale issues intersection.n = GT.normalize( np.dot(np.transpose(self.Minv), np.append(intersection.n, [0]))[:3]) intersections.append(intersection) min_isect = isect # Get the closest intersection for iss in intersections: if (iss.t < min_isect.t): min_isect = iss isect = min_isect # ===== END SOLUTION HERE ===== return isect
def create_ray(self,row,col): ''' Create ray (i.e. origin and direction) from a pixel specified by (row, col). The ray originates at the camera's eye and goes through the point in space that corresponds to the image pixel coordinate (row, col). Take a look at the Camera class to see the variables that can be used here. ''' ray = Ray() # construct an empty ray ''' The ray origin is set in this starter code. You need to compute and set the ray.viewDirection variable inside the solution block below. Note: GeomTransform.py implements a function called normalize for normalizing vectors (with appropriate check for division by zero). For a vector v, you can get the normalized vector as: normalized_v = GT.normalize(v) ''' cam = self.render.camera # use a local variable to save some typing ray.eyePoint = cam.pointFrom # origin of the ray # ====== BEGIN SOLUTION ====== dx = col / cam.imageWidth dy = row / cam.imageHeight stepx = dx * (cam.right - cam.left) stepy = dy * (cam.top - cam.bottom) ray.viewDirection = GT.normalize(cam.lookat + [cam.left + stepx, cam.top - stepy, 0]) # ====== END SOLUTION ======= return ray
def get_visible_lights(self, isect): ''' isect is variable of type IntersectionResult. isect.p contains the intersection point. This function should return a python list containing all the lights that are "visible" from isect.p position. A light source is visible if there are no objects between the point and the light source. All light sources are of type Light (Light class is defined in HelperClasses.py). The light sources in the scene is stored in the variable Scene.lights (accessed using self.lights). Your returned list should be a subset of self.lights ''' #you need to loop over the lights and return those that are visible from the position in result visibleLights = [] #====== BEGIN SOLUTION ===== for l in self.lights: ray = Ray() ray.eyePoint = isect.p ray.viewDirection = GT.normalize(l.pointFrom - ray.eyePoint) d = np.linalg.norm(l.pointFrom - ray.eyePoint) i = self.get_nearest_object_intersection(ray) if i.material is None or i.t >= d - 1e-9: visibleLights.append(l) # ===== END SOLUTION HERE ===== return visibleLights
def create_ray(self, row, col): ''' Create ray (i.e. origin and direction) from a pixel specified by (row, col). The ray originates at the camera's eye and goes through the point in space that corresponds to the image pixel coordinate (row, col). Take a look at the Camera class to see the variables that can be used here. ''' ray = Ray() # construct an empty ray ''' The ray origin is set in this starter code. You need to compute and set the ray.viewDirection variable inside the solution block below. Note: GeomTransform.py implements a function called normalize for normalizing vectors (with appropriate check for division by zero). For a vector v, you can get the normalized vector as: normalized_v = GT.normalize(v) ''' cam = self.render.camera # use a local variable to save some typing ray.eyePoint = cam.pointFrom # origin of the ray # TODO ====== BEGIN SOLUTION ====== # Get pixel center positions normalized_x = (2.0*float(col))/(cam.imageWidth) - 1.0 normalized_y = 1.0 - (2.0*float(row))/(cam.imageHeight) # Get other factors ch = cam.top / cam.near cw = ch * cam.aspect cx = cam.cameraXAxis * cw cy = cam.cameraYAxis * ch ray.viewDirection = GT.normalize((cam.lookat + normalized_x*cx + normalized_y*cy)) # ===== END SOLUTION ===== return ray
def get_visible_lights(self, isect): ''' isect is variable of type IntersectionResult. isect.p contains the intersection point. This function should return a python list containing all the lights that are "visible" from isect.p position. A light source is visible if there are no objects between the point and the light source. All light sources are of type Light (Light class is defined in HelperClasses.py). The light sources in the scene is stored in the variable Scene.lights (accessed using self.lights). Your returned list should be a subset of self.lights ''' # you need to loop over the lights and return those that are visible from the position in result visibleLights = [] # TODO ====== BEGIN SOLUTION ===== for l in self.lights: ray = Ray() ray.eyePoint = isect.p ray.viewDirection = GT.normalize(l.pointFrom - isect.p) nearest_isect = self.get_nearest_object_intersection(ray) # PLEASE NOTE: while i used to have # np.fabs(nearest_isect.t - np.linalg.norm(l.pointFrom - isect.p)) <= EPS_DISTANCE # This gave more different results than the solution images, as such # I kept this which gave a closer version to what scene4 gave # As was said in the forums, this shouldn't matter for grading as it only gives # slightly different shading results if nearest_isect.t == np.inf or nearest_isect.t >= np.linalg.norm(l.pointFrom - isect.p): # no further intersection than to the given point visibleLights.append(l) # ===== END SOLUTION HERE ===== return visibleLights
def create_ray(self,row,col): ''' Create ray (i.e. origin and direction) from a pixel specified by (row, col). The ray originates at the camera's eye and goes through the point in space that corresponds to the image pixel coordinate (row, col). Take a look at the Camera class to see the variables that can be used here. ''' ray = Ray() # construct an empty ray ''' The ray origin is set in this starter code. You need to compute and set the ray.viewDirection variable inside the solution block below. Note: GeomTransform.py implements a function called normalize for normalizing vectors (with appropriate check for division by zero). For a vector v, you can get the normalized vector as: normalized_v = GT.normalize(v) ''' cam = self.render.camera # use a local variable to save some typing ray.eyePoint = cam.pointFrom # origin of the ray #TODO ====== BEGIN SOLUTION ====== # get the camera coordinates cam_x = col*(cam.right-cam.left)/cam.imageWidth + cam.left cam_y = row*-(cam.top-cam.bottom)/cam.imageHeight + cam.top cam_z = cam.near xa = cam.cameraXAxis ya = cam.cameraYAxis za = cam.cameraZAxis R = [ [xa[0], ya[0], za[0], 0], [xa[1], ya[1], za[1], 0], [xa[2], ya[2], za[2], 0], [0, 0, 0, 1] ] T = [ [1, 0, 0, -cam.pointFrom[0]], [0, 1, 0, -cam.pointFrom[1]], [0, 0, 1, -cam.pointFrom[2]], [0, 0, 0, 1] ] cam_to_world = np.linalg.inv(np.dot(np.transpose(R),T)) world_pixels = np.dot( cam_to_world, [cam_x, cam_y, cam_z, 1] ) #world_pixels = world_pixels/world_pixels[3] ray.viewDirection = GT.normalize(world_pixels[0:3] - ray.eyePoint) # ===== END SOLUTION ===== return ray