Weird patch on reflective spheres on planes in raytracer

Viewed 81

I am writing a small raytracer in python , everything was working fine but when i implemented plane geometry then the reflective spheres are getting weird patches on lower bottom. image below:

I guess this is happening because of some error in calculating lighting with wrong normals? but i am unable to figure out exactly what.

EDIT: When I moved the plane a unit down this disappeared, could it be because of point light above the spheres? to check this I removed all the lights but still, I am getting this patch.

enter image description here

code to find palne-ray intersection:

class Plane(Shape):
    def __init__(self, color, y=0, specular=-1, reflective=0):
        self.specular = specular
        self.reflective = reflective
        self.center = Vec3(0,y,0)
        self.normal = Vec3(0,-1,0)
        self.color = color

    def intersect_at_point(self, origin, ray):

        denom = ray.dot(self.normal)

        if abs(denom) > 0.0001:
            diff  = self.center - ray
            t = diff.dot(self.normal) / denom

            if t > 0.0001:
                return t
        return None

trace ray function.

def trace_ray(self, origin, direction, t_min, t_max, depth):



    closest_object, closest_t = self.closest_intersection(origin, direction, t_min, t_max)

    if closest_object == None:
        return Vec3(173/255, 216/255, 230/255)

    # Compute local color
    P = origin + closest_t * direction  # Compute intersection
    N = P - closest_object.center  # Compute  normal at intersection
    N = N / N.mag()
    local_color = closest_object.color * self.compute_light(P, N)

    # If we hit the recursion limit or the object is not reflective, we're done
    r = closest_object.reflective
    if depth <= 0 or r <= 0:
        return local_color

    # Compute the reflected color
    R = self.reflect_ray(-1*direction, N)
    reflected_color = self.trace_ray(P, R, 0.001, math.inf, depth - 1)

    return local_color * (1 - r) + reflected_color * r

closest intersection method.

  def closest_intersection(self, O, D, t_min, t_max):
        closest_t = math.inf
        closest_object = None

        for object in self.world.objects:
            t1, t2 = object.intersect_at_point(O, D)

            if (t_min < t1 < t_max) and t1 < closest_t:
                closest_t = t1
                closest_object = object

            if (t_min < t2 < t_max) and t2 < closest_t:
                closest_t = t2
                closest_object = object

        for plane in self.world.planes:

            t = plane.intersect_at_point(O,D)

            if t and (t_min < t < t_max) and t < closest_t:
                    closest_t = t
                    closest_object = plane

        return closest_object, closest_t

Calculate light method.

def compute_light(self, Point, Normal):

    i = 0.0
    P = Point
    N = Normal

    for light in self.world.lights:
        if light.type == 'ambient':
            i += light.intensity
        else:
            if light.type == 'point':
                L = light.position - P
                t_max = 1

            if light.type == 'directional':
                L = light.direction
                t_max = math.inf

            # Shadow check
            shadow_sphere, shadow_t = self.closest_intersection(P, L, 0.001, t_max)
            if shadow_sphere != None:
                continue

            n_dot_l = N.dot(L)

            if n_dot_l > 0:
                # print(f'light intensity {light.intensity}')
                i+= light.intensity * n_dot_l / (N.mag() * L.mag())

    return i
0 Answers
Related