def find_connect_point(self, iInfo, ray_proj, triangle_dic): """ find vector on intersection point, called in connect() """ #set small number for floating point problem small_num = 0.000001 ###find connecting point t = -1 triangle = self.model.triangles[iInfo.triangleID] rays=[euclid.Ray3(triangle.vertices[0],triangle.vertices[1]),\ euclid.Ray3(triangle.vertices[1],triangle.vertices[2]),\ euclid.Ray3(triangle.vertices[2],triangle.vertices[0])] #iterate edges in triangle to find closest intersection for ray_proj #and update iInfo ray_id = 0 for i, ray in enumerate(rays): print("ray" + str(i) + ":") (t_temp, iInfo_temp) = self.line_intersect(ray_proj, ray) if (t_temp < t or t < 0) and t_temp > small_num: print(t_temp) t = t_temp iInfo.icoordinate = iInfo_temp.icoordinate ray_id = i #iterate self.model.triangles to find next triangleID for i, tri_temp in enumerate(self.model.triangles): #find triangle that consists of two vertice to build ray #and find triangle whose ID is not yet in triangle_dic if triangle.vertex_indices[ ray_id] in tri_temp.vertex_indices and triangle.vertex_indices[ (ray_id + 1) % 3] in tri_temp.vertex_indices and i not in triangle_dic: iInfo.triangleID = i break return (t, ray_id)
def intersect_on_new_model(self): for prev_iInfo in self.prev_iInfos: ray = euclid.Ray3(prev_iInfo.icoordinate, -prev_iInfo.cutting_vector) iInfo = IntersectionInfo() mx = -1 iInfo_temp = IntersectionInfo() # ###find nearest intersection # for i,triangle in enumerate(self.model.triangles): # (isIntersect,iInfo_temp)=triangle.intersect(ray); # if isIntersect: # #print("intersection_temp in outer loop") # #print(iInfo_temp) # d=(iInfo_temp.icoordinate-ray.p).magnitude_squared(); # if mx==-1 or d<mx: # iInfo=iInfo_temp; # iInfo.triangleID=i; # mx=d; ###find farest intersection for i, triangle in enumerate(self.model.triangles): (isIntersect, iInfo_temp) = triangle.intersect(ray) if isIntersect: #print("intersection_temp in outer loop") #print(iInfo_temp) d = (iInfo_temp.icoordinate - ray.p).magnitude_squared() if d > mx: iInfo = iInfo_temp iInfo.triangleID = i mx = d if mx > -1: if len(self.iInfos) > 0: self.connect(self.iInfos[-1], iInfo) self.iInfos.append(iInfo) self.points.extend((iInfo.icoordinate[0], iInfo.icoordinate[1], iInfo.icoordinate[2]))
def build_ray(self, mouse_x, mouse_y, button, w, h): """ build ray: from mouse position to a 3D ray (in world coordinate) starting from camera eye position """ #viewport coordinates to normalized device coordinates x = 2 * mouse_x / w - 1 y = 2 * mouse_y / h - 1 #call projection matrix and model view matrix M_proj = (gl.GLfloat * 16)() M_modelview = (gl.GLfloat * 16)() gl.glGetFloatv(gl.GL_PROJECTION_MATRIX, M_proj) gl.glGetFloatv(gl.GL_MODELVIEW_MATRIX, M_modelview) M_proj = euclid.Matrix4.new(*(list(M_proj))) M_modelview = euclid.Matrix4.new(*(list(M_modelview))) M_proj_inversed = M_proj.inverse() M_modelview_inversed = M_modelview.inverse() #homogeneous clip coordinates vector_clip = euclid.Vector3(x, y, -1) #eye coordinates vector_eye = M_proj_inversed * vector_clip vector_eye = euclid.Vector3(vector_eye[0], vector_eye[1], -1) #world coordinates vector_world = M_modelview_inversed * vector_eye vector_world.normalize() # print(vector_world); # print(M_modelview_inversed); #build ray, starting point is camera eye position ray = euclid.Ray3( euclid.Point3(M_modelview_inversed[12], M_modelview_inversed[13], M_modelview_inversed[14]), vector_world) return ray
def getColor(self, intersect, obj, intensity): # DEBUG: no shadows #return RayColor(intensity, obj.getColor(intersect)) # get a ray from the intersect to the source of light vectorToLight = self.light - intersect rayToLight = euclid.Ray3(intersect, vectorToLight) for o in self.objects: i = o.intersect(rayToLight) if obj == o: if type(i) == euclid.Point3: # often means intercept with self continue elif not i: # is None continue # no intercept # otherwise find penetration lenI = abs(i) distances.append(lenI) if lenI < 0.2: continue if i: # intersect, so is in shadow return RayColor(intensity, (0, 0, 0)) # otherwise not in shadow # find intensity depending on angle to light. if type(obj) == RaycastingPlane: normal = obj.shape.n elif type(obj) == RaycastingSphere: normal = (intersect - obj.shape.c).normalize() strength = abs(vectorToLight.normalized().dot(normal)) return RayColor(intensity * strength, obj.getColor(intersect))
def reflect(point, obj, ray): if type(obj) == RaycastingSphere: n = (point - obj.c).normalized() v = -ray.v.normalized() elif type(obj) == RaycastingPlane: n = obj.shape.n v = -ray.v.normalized() else: raise TypeError("Unknown shape") return euclid.Ray3(point, 2 * n.dot(v) * n - v)
def selection_ray(self, x, y): self.setup() model_view = (GLdouble * 16)() glGetDoublev(GL_MODELVIEW_MATRIX, model_view) projection = (GLdouble * 16)() glGetDoublev(GL_PROJECTION_MATRIX, projection) viewport = (GLint * 4)() glGetIntegerv(GL_VIEWPORT, viewport) x1, y1, z1 = GLdouble(), GLdouble(), GLdouble() x2, y2, z2 = GLdouble(), GLdouble(), GLdouble() gluUnProject(x, y, 0, model_view, projection, viewport, x1, y1, z1) gluUnProject(x, y, 1, model_view, projection, viewport, x2, y2, z2) ray = euclid.Ray3(euclid.Point3(x1.value, y1.value, z1.value), euclid.Point3(x2.value, y2.value, z2.value)) ray.v.normalize() self.reset() return ray
def generateRays(self, startline=0, endline=None): """ generate all the rays for the pixels in the screen. each ray starts from the camera's position and goes through the screen. The camera is originally at 0,0,0; and the screen originally is at A(f, .5w, .5h); B(f, .5w, -.5h); C(f, -.5w, -.5h); D(f, -.5w, .5h); Apply the transformation matrix for rotation to easily get the actual screen position! don't do complex math if somebody already did it for you """ if not endline: endline = self.imageh A = Point3(self.focallength, 0.5 * self.screenw, 0.5 * self.screenh) B = Point3(self.focallength, 0.5 * self.screenw, -0.5 * self.screenh) # C = Point3(self.focallength, -0.5*self.screenw, -0.5*self.screenh) D = Point3(self.focallength, -0.5 * self.screenw, 0.5 * self.screenh) # rotate & translate the ABCD vectors A = self.rotation * A B = self.rotation * B D = self.rotation * D A += self.translation B += self.translation D += self.translation # unit vector for screen width, nx, is A to D divided by image width nx = D - A nx /= self.imagew # unit vector for screen height, ny, is A to B divided by image height ny = B - A ny /= self.imageh OA = A - self.translation # the first ray. will be modified to find the various rays for x in range(self.imagew): for y in range(startline, endline): # This is the initial ray for searching for collisions. vector = OA + (0.5 + x) * nx + (0.5 + y) * ny ray = euclid.Ray3(self.translation, vector) yield ray, x, y
def main(): T = int(raw_input()) for case in xrange(T): N = int(raw_input()) position = euclid.Vector3() velocity = euclid.Vector3() for _ in xrange(N): x, y, z, vx, vy, vz = map(float, raw_input().split()) position += euclid.Vector3(x, y, z) velocity += euclid.Vector3(vx, vy, vz) position /= N velocity /= N if velocity == euclid.Vector3(): d_min = abs(position - euclid.Point3()) t_min = 0. else: position = euclid.Point3(position.x, position.y, position.z) ray = euclid.Ray3(position, velocity) connection = ray.connect(euclid.Point3()) d_min = abs(connection) t_min = abs(connection.p1 - position) / abs(velocity) print 'Case #%d: %1.8f %1.8f' % (case + 1, d_min, t_min)
# elif data[0] == 'f': # vi_1, vi_2, vi_3 = data[1:4] # faces.extend((vi_1,vi_2,vi_3)) #point1=[0,0]; #point2=[0,1]; #point3=[1,1]; #point4=[1,0]; # #x=np.arange(4); #y=np.array([point1,point2,point3,point4]); #cs=interpolate.CubicSpline(x,y); #plt.plot(y[:,0],y[:,1]); #plt.plot(cs(xs)[:,0],cs(xs)[:,1]) #plt.show() ray1 = euclid.Ray3(euclid.Point3(0, 0, 0), euclid.Point3(1, 1, 1)) ray2 = euclid.Ray3(euclid.Point3(1, 1, 0), euclid.Point3(1, 1, -0.5)) def line_intersect(ray1, ray2): """ find intersection point between two lines """ small_num = 0.000001 den = ray2.v.cross(ray1.v) d = den.magnitude() t = -1 #if not paralleled if d > small_num: g = ray2.p - ray1.p num = ray2.v.cross(g)
def findLightedColor(self, obj, point): truecolor = obj.getColor(point) # these two for highlights angles = [] spectralAngles = [] # this for brightness distances = [] # this for intersection tests intersected = [] # normal vector Vn = obj.normal(point).normalize() # line to viewer Vv = (point - self.camera.translation).normalize() # Try to draw a line to a light source for light in self.lights: ray = euclid.Ray3(point, light.position - point) canDoLight = True for thing in self.objects: inter = thing.intersect(ray) # if it's an intersection, no light! if isinstance(inter, euclid.Point3): if inter: if thing != obj: canDoLight = False intersected.append(True) else: if inter and inter.length > 0.05: if thing.getTransparency() > 0.0: continue else: canDoLight = False intersected.append(True) break # spectral reflection stuff if canDoLight: intersected.append(False) N = obj.normal(point) N.normalize() dot = N.dot(ray.v.normalized()) angles.append(dot) # find reflection vector & viewer vector angle Vl = (light.position - point) distances.append(len(Vl)) Vl.normalize() # must rotate L around axis N x L, equal to angle. N_L_angle = math.acos(Vl.dot(N)) axis = Vl.cross(N) rot = euclid.Quaternion.new_rotate_axis(N_L_angle * 2, axis) Reflection = rot * Vl # get angle between viewer and reflection spectralAngles.append(Reflection.dot(Vv)) shadowed = True for tf in intersected: shadowed &= tf if shadowed: return (0, 0, 0) angle = max(angles) # The greatest angle wins distance = min(distances) # smallest distance # but wait, there's more! Find the spectral lighting angle spectral = max(spectralAngles) # lighted color lightedcolor = truecolor #lerp((0,0,0), truecolor, 7 / distance**2) # If the material is more reflective, the highlight is smaller & more intense # but for now, if the angle is above a threshold make it white if spectral < -0.985: return lerp(lightedcolor, (255, 255, 255), abs((spectral + 0.985) * 100)**3) return lerp((0, 0, 0), lightedcolor, angle)
def connect(self, iInfo_start, iInfo_end): """ find connecting points along surface """ #dictionay to keep track of triangle gone through triangle_dic = {} print("=========================") print("start ID is") print(iInfo_start.triangleID) print("end ID is") print(iInfo_end.triangleID) iInfo = iInfo_start.copy() iInfo_prev = iInfo.copy() counter = 0 while (iInfo.triangleID != iInfo_end.triangleID): triangle_dic[iInfo.triangleID] = counter print("triangle Info:") print("triangleID is " + str(iInfo.triangleID)) print("vertices:") print(self.model.triangles[iInfo.triangleID].vertex_indices) print(self.model.triangles[iInfo.triangleID].vertices) counter += 1 #check if triangle normal is too close to previous triangle normal #we want to continue the vector direction if the two normals are similar if iInfo_prev.normal.dot( iInfo.normal) / iInfo.normal.magnitude_squared() > 0.9: v = iInfo_end.icoordinate - iInfo_prev.icoordinate else: v = iInfo_end.icoordinate - iInfo.icoordinate #get projected vector of v on triangle v_proj = v - v.dot(iInfo.normal) / iInfo.normal.magnitude_squared( ) * (iInfo.normal) v_proj.normalize() #build ray with projected vector ray_proj = euclid.Ray3(iInfo.icoordinate, v_proj) print("ray_proj is:") print(ray_proj) #keep track of previous iInfo iInfo_prev = iInfo.copy() #find intersection with t and ray_id, iInfo passed by reference t, ray_id = self.find_connect_point(iInfo, ray_proj, triangle_dic) print('t is:') print(t) #check if t < 0, which is intersection in wrong direction if (t < 0): print("error: connecting point in wrong direction") break # #check if intersection is inside triangle # if not self.model.triangles[iInfo.triangleID].inside_check(iInfo.icoordinate): # print("error: connecting point is not in triangle") # print("wrong connecting point:") # print(iInfo.icoordinate) # break; #check if triangle found is correct if iInfo.triangleID in triangle_dic: print("error: wrong triangle found") break #update iInfo.normal iInfo.normal = self.model.triangles[iInfo.triangleID].plane.n print('connecting point' + str(counter) + " inside triangle" + str(iInfo.triangleID)) print(iInfo.icoordinate) iInfoTemp = iInfo.copy() self.iInfos.append(iInfoTemp) self.points.extend((iInfo.icoordinate[0], iInfo.icoordinate[1], iInfo.icoordinate[2]))
scene.objects.append(RaycastingSphere(euclid.Point3(-50, 0, 0), 2.0)) scene.objects[-1].reflectionIndex = 0.2 scene.objects.append(RaycastingSphere(euclid.Point3(-55, 2, 0), 1.0)) scene.objects[-1].reflectionIndex = 0.2 scene.objects.append(RaycastingSphere(euclid.Point3(-55, 8, -2), 3.0)) scene.objects[-1].reflectionIndex = 0.1 scene.objects.append(RaycastingSphere(euclid.Point3(-55, 2, -5), 2.0)) scene.objects[-1].color = (255, 0, 0) """scene.objects.append(RaycastingPlane((0,0,0), euclid.Point3(0, 0, 5))) scene.objects[-1].reflectionIndex = 0.2""" im = Image.new("RGB", (imgW, imgH), (0, 0, 255)) pixels = im.load() for x, y, point in scene.camera.getPixelCoords(imgW, imgH): color = scene.trace( euclid.Ray3(scene.camera.focus, point - scene.camera.focus), 1.0, 5) if color.__class__.__name__ == "RayColor": pixels[x, y] = color.toRGB() elif type(color) == tuple: pixels[x, y] = color else: raise TypeError("unknown color type: " + str(type(color)) + " containing:\n" + repr(color)) if not len(distances) < 2: print "average:" + str( reduce(lambda x, y: x + y, distances) / float(len(distances))) print "min:" + str(reduce(lambda x, y: x if x < y else y, distances)) distances.insert(0, 0.0) print "number of 0.0s:" + str( reduce(lambda x, y: x + 1 if y == 0.0 else x, distances))