From d0a8e4935c4e0122bf45e78f909039ebd2b6a81e Mon Sep 17 00:00:00 2001 From: Makar Solomatin Date: Sun, 14 Feb 2021 16:49:56 +0300 Subject: [PATCH] Add recursive shade function --- main.py | 23 ++++++------ pyrt/renderer/simplert.py | 73 +++++++++++++++------------------------ 2 files changed, 41 insertions(+), 55 deletions(-) diff --git a/main.py b/main.py index 4cfc640..8103103 100644 --- a/main.py +++ b/main.py @@ -10,10 +10,11 @@ floormaterial = PhongMaterial(color=Vec3(0.5,0.5,0.5)) sphere0material = PhongMaterial(color=Vec3(1.,0.,0.), transparency=0.5) -sphere1material = PhongMaterial(color=Vec3(0.,0.,1.), transparency=0.7) +sphere1material = PhongMaterial(color=Vec3(0.,0.,1.), transparency=0.1, reflectivity=0.5) +sphere2material = PhongMaterial(color=Vec3(0.,1.,0.)) camera = PerspectiveCamera(640, 480, 45) -camera.setView(Vec3(0.,-10.,10.), Vec3(0.,0.,0.), Vec3(0.,0.,1.)) +camera.setView(Vec3(0.,-10.,0.0), Vec3(0.,0.,0.), Vec3(0.,0.,1.)) scene = Scene() scene.add(Triangle(Vertex(position=(0, 0, 0)), @@ -23,15 +24,17 @@ scene.addLight(PointLight(Vec3(0,0,15))) # Add "floor" -A = Vertex(position=(-5.0, -5.0, 0.0)) -B = Vertex(position=( 5.0, -5.0, 0.0)) -C = Vertex(position=( 5.0, 5.0, 0.0)) -D = Vertex(position=(-5.0, 5.0, 0.0)) -scene.add(Triangle(A,B,C, material=floormaterial)) +# A = Vertex(position=(-5.0, -5.0, 0.0)) +# B = Vertex(position=( 5.0, -5.0, 0.0)) +# C = Vertex(position=( 5.0, 5.0, 0.0)) +# D = Vertex(position=(-5.0, 5.0, 0.0)) +# scene.add(Triangle(A,B,C, material=floormaterial)) # Add spheres -scene.add(Sphere(center=Vec3(2,-3.5,1.75), radius=1, material=sphere0material)) -scene.add(Sphere(center=Vec3(2,-1.5,1.75), radius=1, material=sphere1material)) +scene.add(Sphere(center=Vec3(0,-5.5,0), radius=1, material=sphere0material)) +scene.add(Sphere(center=Vec3(0,-0.5,0), radius=1, material=sphere1material)) +scene.add(Sphere(center=Vec3(3,-0.5,0), radius=1, material=sphere2material)) +scene.add(Sphere(center=Vec3(-3,-0.5,0), radius=0.5, material=sphere2material)) -imgdata = SimpleRT(shadow=True, iterations=3).render(scene) +imgdata = SimpleRT(shadow=True, iterations=7).render(scene) imgdata.save('a.png') diff --git a/pyrt/renderer/simplert.py b/pyrt/renderer/simplert.py index 2da54e5..0fe9d0e 100644 --- a/pyrt/renderer/simplert.py +++ b/pyrt/renderer/simplert.py @@ -17,13 +17,14 @@ def __init__(self, shadow=False, iterations=1): Renderer.__init__(self, "Simple Raytracer") self.shadow = shadow self.iterations = iterations + self.background = (0, 0, 0) if self.shadow: print("# Shadow Enabled") if self.iterations>1: print("# Iterations: " + str(self.iterations)) def _shade(self, scene: Scene, ray: Ray, hitrecord: HitRecord) -> tuple: - r = g = b = 0 # background color + r, g, b = self.background hit = False for element in scene.nodes: if element.hit(ray, hitrecord): @@ -69,38 +70,39 @@ def _shadow(self, scene: Scene, hitrecord: HitRecord) -> tuple: fs /= 4. return fs,local_num_shadow_rays + + def _recurse_shade(self, scene: Scene, ray: Ray, iteration_num: int) -> tuple: + hitrecord = HitRecord() + hit, r, g, b = self._shade(scene, ray, hitrecord) - def _reflect(self, r: int, g: int, b: int, scene: Scene, ray: Ray, hitrecord: HitRecord) -> tuple: - reflect_ray = Ray(hitrecord.point, reflect3(hitrecord.normal_g, ray.direction)) - reflect_hitrecord = HitRecord() - - hit, rnew, gnew, bnew = self._shade(scene, reflect_ray, reflect_hitrecord) + if not hit or iteration_num == 0: + return r, g, b + + if hitrecord.material.reflectivity != 0.0: + reflect_ray = Ray(hitrecord.point, reflect3(hitrecord.normal_g, ray.direction)) + new_r, new_g, new_b = self._recurse_shade(scene, reflect_ray, iteration_num - 1) - if hit: ref1 = hitrecord.material.reflectivity ref2 = 1.-ref1 - rnew = int ( ref1 * rnew + ref2 * r) - gnew = int ( ref1 * gnew + ref2 * g) - bnew = int ( ref1 * bnew + ref2 * b) - return rnew, gnew, bnew, reflect_ray, reflect_hitrecord - else: - return r,g,b,None,None - - def _refract(self, r: int, g: int, b: int, scene: Scene, ray: Ray, hitrecord: HitRecord, eta: float) -> tuple: - refract_ray = Ray(hitrecord.point, refract3(hitrecord.normal_g, ray.direction, hitrecord.material.refraction)) - refract_hitrecord = HitRecord() + r = int ( ref1 * new_r + ref2 * r) + g = int ( ref1 * new_g + ref2 * g) + b = int ( ref1 * new_b + ref2 * b) - hit, rnew, gnew, bnew = self._shade(scene, refract_ray, refract_hitrecord) + self.num_secondary_rays += 1 + + if hitrecord.material.transparency != 0.0: + refract_ray = Ray(hitrecord.point + ray.direction * 0.01, refract3(hitrecord.normal_g, ray.direction, hitrecord.material.refraction)) + new_r, new_g, new_b = self._recurse_shade(scene, refract_ray, iteration_num - 1) - if hit: ref1 = hitrecord.material.transparency ref2 = 1.-ref1 - rnew = int ( ref1 * rnew + ref2 * r) - gnew = int ( ref1 * gnew + ref2 * g) - bnew = int ( ref1 * bnew + ref2 * b) - return rnew, gnew, bnew, refract_ray, refract_hitrecord - else: - return r,g,b,None,None + r = int ( ref1 * new_r + ref2 * r) + g = int ( ref1 * new_g + ref2 * g) + b = int ( ref1 * new_b + ref2 * b) + + self.num_secondary_rays += 1 + + return r, g, b def render(self, scene: Scene) -> RGBImage: if not scene.camera: @@ -125,26 +127,7 @@ def render(self, scene: Scene) -> RGBImage: self.num_rays += 1 # Primary Ray: - hit, r, g, b = self._shade(scene, ray, hitrecord) - - if hit and hitrecord.material.reflectivity != 0.0: - refhit = hitrecord.copy() - refray = ray.copy() - for i in range(self.iterations - 1): - r, g, b, refray, refhit = self._reflect(r,g,b, scene, refray, refhit) - self.num_secondary_rays += 1 - if refray is None: - break - - if hit and hitrecord.material.transparency != 0.0: - refhit = hitrecord.copy() - refray = ray.copy() - for i in range(self.iterations - 1): - r, g, b, refray, refhit = self._refract(r,g,b, scene, refray, refhit, 1) - self.num_secondary_rays += 1 - if refray is None: - break - + r, g, b = self._recurse_shade(scene, ray, self.iterations - 1) image.drawPixelFast8(x, y, r, g, b)