From f429c80bbfed5857f1aacf79748dfeb3f8927521 Mon Sep 17 00:00:00 2001 From: Mark McArdle Date: Wed, 7 Oct 2020 18:56:22 +0100 Subject: [PATCH] Add multiprocessing renderer --- pyrt/renderer/__init__.py | 1 + pyrt/renderer/mprt.py | 90 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 pyrt/renderer/mprt.py diff --git a/pyrt/renderer/__init__.py b/pyrt/renderer/__init__.py index 6fbfd9d..a7e2fdd 100644 --- a/pyrt/renderer/__init__.py +++ b/pyrt/renderer/__init__.py @@ -6,4 +6,5 @@ from .renderer import Renderer from .simplert import SimpleRT +from .mprt import MultiProcessRT from .rgbimage import RGBImage, loadimage diff --git a/pyrt/renderer/mprt.py b/pyrt/renderer/mprt.py new file mode 100644 index 0000000..c072aa2 --- /dev/null +++ b/pyrt/renderer/mprt.py @@ -0,0 +1,90 @@ +""" +A multi processing ray tracer +""" + +from .rgbimage import * +from .renderer import Renderer +from ..scene import Scene +from ..math import * + +from .simplert import SimpleRT + +from multiprocessing import Pool +import time + + +class MultiProcessRT(SimpleRT): + + def __init__(self, shadow=False, iterations=1): + Renderer.__init__(self, "MP Raytracer") + self.shadow = shadow + self.iterations = iterations + if self.shadow: + print("# Shadow Enabled") + if self.iterations>1: + print("# Iterations: " + str(self.iterations)) + + + def trace_ray_multiprocess(engine, scene, x, y): + ray = scene.camera.primaryRay(x, y) + hitrecord = HitRecord() + engine.num_rays += 1 + + # Reset shadow rays for the process + engine.num_shadow_rays = 0 + + num_secondary_rays = 0 + + # Primary Ray: + hit, r, g, b = engine._shade(scene, ray, hitrecord) + + if hit and hitrecord.material.reflectivity != 0.0: + refhit = hitrecord.copy() + refray = ray.copy() + for i in range(engine.iterations - 1): + r, g, b, refray, refhit = engine._reflect(r,g,b, scene, refray, refhit) + num_secondary_rays += 1 + if refray is None: + break + + return x, y, r, g, b, num_secondary_rays, engine.num_shadow_rays + + def render(self, scene: Scene) -> RGBImage: + if not scene.camera: + print("Warning: Can't render: there is no (active) camera in the scene!") + return None + + time_start = time.time() + self.num_shadow_rays = 0 + self.num_secondary_rays = 0 + + w = scene.camera.width + h = scene.camera.height + + self.num_rays = w * h + + image = RGBImage(w,h) + + args = [] + for y in range(0, h): + for x in range(0, w): + args.append([scene, x, y]) + + with Pool() as p: + for result in p.starmap(self.trace_ray_multiprocess, args): + x, y, r, g, b, secondary_rays, shadow_rays = result + image.drawPixelFast8(x, y, r, g, b) + self.num_secondary_rays += secondary_rays + self.num_shadow_rays += shadow_rays + + time_end = time.time() + print("# RENDER STATISTICS" + 31 * "#") + time_total = time_end - time_start + print("TIME FOR RENDERING: " + str(time_total) + "s") + print("NUMBER OF PRIMARY RAYS: " + str(self.num_rays)) + print("NUMBER OF SECONDARY RAYS: " + str(self.num_secondary_rays)) + print("NUMBER OF SHADOW RAYS: " + str(self.num_shadow_rays)) + print("RAYS/s: " + str((self.num_rays + self.num_secondary_rays + self.num_shadow_rays) / time_total)) + print(50 * "#") + + return image