def Sample2(self, p: Point3d, u: (float, float), Ns: Normal) -> Point3d: # Compute coordinate system for sphere sampling Pcenter = Point3d(0, 0, 0) * self.objectToWorld wc = (Pcenter - p).get_normalized() wcX, wcY = Transform.create_coordinateSystem(wc) # Sample uniformly on sphere if $\pt{}$ is inside it if (p - Pcenter).get_length_squared() - self.radius * self.radius < 1e-40: return self.Sample1(u, Ns) # Sample sphere uniformly inside subtended cone sinThetaMax2 = self.radius * self.radius / (p - Pcenter).get_length_squared() cosThetaMax = math.sqrt(max(0.0, 1.0 - sinThetaMax2)) dgSphere = DifferentialGeometry() thit = 1.0 r = Ray(p, UniformSampleCone2(u, cosThetaMax, wcX, wcY, wc), 1e-3) b, t = self.get_intersection(r, dgSphere) # if not b: #bug thit = Vector3d.dot(Pcenter - p, r.direction.get_normalized()) ps = r.get_at(thit) nn = (ps - Pcenter).get_normalized() Ns.Set(nn) # if (ReverseOrientation) *ns *= -1.f; return ps
def get_is_intersected(self, ray: Ray) -> bool: # Check ray against overall grid bounds if self.bounds.get_is_point_inside(ray.get_at(ray.min_t)): rayT = ray.min_t else: rayT, tmp = self.bounds.get_intersect(ray) if rayT is None: return False gridIntersect = ray.get_at(rayT) # Set up 3D DDA for ray NextCrossingT = [float] * 3 DeltaT = [float] * 3 Step = [int] * 3 Out = [int] * 3 Pos = [int] * 3 for axis in range(3): # Compute current voxel for axis Pos[axis] = self.get_pos_to_voxel(gridIntersect, axis) if ray.direction[axis] >= 0: # Handle ray with positive direction for voxel stepping NextCrossingT[axis] = rayT + (self.get_voxel_to_pos(Pos[axis] + 1, axis) - gridIntersect[axis]) / \ ray.direction[axis] DeltaT[axis] = self.width[axis] / ray.direction[axis] Step[axis] = 1 Out[axis] = self.nVoxels[axis] else: # Handle ray with negative direction for voxel stepping NextCrossingT[axis] = rayT + (self.get_voxel_to_pos(Pos[axis], axis) - gridIntersect[axis]) / \ ray.direction[axis] DeltaT[axis] = -self.width[axis] / ray.direction[axis] Step[axis] = -1 Out[axis] = -1 #Walk grid for shadow ray while True: o = self.get_offset(Pos[0], Pos[1], Pos[2]) voxel = self.voxels[o] if voxel is not None: if voxel.get_is_intersected(ray): return True # Advance to next voxel # Find _stepAxis_ for stepping to next voxel bits = ((NextCrossingT[0] < NextCrossingT[1]) << 2) + ((NextCrossingT[0] < NextCrossingT[2]) << 1) + ( (NextCrossingT[1] < NextCrossingT[2])) cmpToAxis = [2, 1, 2, 1, 2, 2, 0, 0] stepAxis = cmpToAxis[bits] if ray.max_t < NextCrossingT[stepAxis]: break Pos[stepAxis] += Step[stepAxis] if Pos[stepAxis] == Out[stepAxis]: break NextCrossingT[stepAxis] += DeltaT[stepAxis] return False
def generate_ray(self, sample:CameraSample)->Ray: point_camera = Point3d(sample.image_xy[0], sample.image_xy[1], 0.0) * self.rasterToCamera direction = Vector3d(0.0, 0.0, 1.0) r = Ray(point_camera, direction, 0.0, infinity_max_f) if self.lensRadius>0.0: pass #todo r.time = sample.time return r * self.camera_to_world
def generate_ray(self, sample:CameraSample)->Ray: camera_point = Point3d(sample.image_xy[0], sample.image_xy[1], 0.0) * self.rasterToCamera camera_direction = Vector3d(camera_point.x, camera_point.y, camera_point.z).get_normalized() r = Ray(camera_point, camera_direction, 0.0, infinity_max_f) if self.lensRadius>0.0: pass #todo r.time = sample.time return r * self.camera_to_world
def Pdf2(self, p: Point3d, wi: Vector3d)->float: # Intersect sample ray with area light geometry dgLight = DifferentialGeometry() ray = Ray(p, wi, 1e-3) ray.depth = -1 # temporary hack to ignore alpha mask b, thit =self.get_intersection(ray, dgLight) if not b: return 0.0 # Convert light sample weight to solid angle measure pdf = (p - ray.get_at(thit)).get_length_squared() / (math.fabs(Vector3d.dot(dgLight.normal, -wi) * self.Area())) if math.isinf(pdf): pdf = 0.0 return pdf
def scatter(self, ray, hit_record): target = hit_record.point + hit_record.normal + random_in_unit_sphere() self.scattered = Ray(hit_record.point, target - hit_record.point, ray.time) self.attenuation = self.albedo return True
def Sample1(self, p: Point3d, ls: LightSample, Ns: Normal)->Point3d: pdf, sn = self.areaDistribution.SampleDiscrete(ls.uComponent) pt = self.shapes[sn].Sample2(p, ls.uPos, Ns) # Find closest intersection of ray with shapes in _ShapeSet_ r = Ray(p, (pt-p).get_normalized(), 1e-3, infinity_max_f) anyHit = False thit = 1.0 dg = DifferentialGeometry() for i in range(len(self.shapes)): anyHit_b, thit_f = self.shapes[i].get_intersection(r, dg) if anyHit_b: anyHit = True thit = thit_f if anyHit: Ns.Set(dg.normal) return r.get_at(thit)
def scatter(self, ray, hit_record): reflected = reflect(unit_vector(ray.direction), hit_record.normal) self.scattered = Ray(hit_record.point, reflected + self.fuzzy * random_in_unit_sphere(), ray.time) self.attenuation = self.albedo return np.dot(self.scattered.direction, hit_record.normal) > 0.
def get_intersection(self, ray: Ray, intersection: Intersection) -> bool: hit, thit = self.shape.get_intersection(ray, intersection.differentialGeometry) if not hit: return False intersection.primitive = self intersection.WorldToObject = self.shape.objectToWorld intersection.ObjectToWorld = self.shape.objectToWorld ray.max_t = thit return True
def get_intersection(self, ray: Ray, dg: DifferentialGeometry) -> (bool, float): p1_index = self.mesh.index[self.triangle_index*3 + 0] p2_index = self.mesh.index[self.triangle_index*3 + 2] p3_index = self.mesh.index[self.triangle_index*3 + 1] p1 = self.mesh.points[p1_index] p2 = self.mesh.points[p2_index] p3 = self.mesh.points[p3_index] e1 = p2 - p1 e2 = p3 - p1 s1 = Vector3d.cross(ray.direction, e2) divisor = Vector3d.dot(s1, e1) if divisor == 0.0: return False, 0.0 invDivisor = 1.0 / divisor # Compute first barycentric coordinate d = ray.origin - p1 b1 = Vector3d.dot(d, s1) * invDivisor if b1 < 0.0 or b1 > 1.0: return False, 0.0 #Compute second barycentric coordinate s2 = Vector3d.cross(d, e1) b2 = Vector3d.dot(ray.direction, s2) * invDivisor if b2 < 0.0 or (b1 + b2) > 1.0: return False, 0.0 # Compute _t_ to intersection point t = Vector3d.dot(e2, s2) * invDivisor if t < ray.min_t or t > ray.max_t: return False, 0.0 dg.shape = self dg.point = ray.get_at(t) dg.normal = Normal.create_from_vector3d( Vector3d.cross(e1, e2).get_normalized()) return True, t