diff --git a/examples/16_textured_scene.py b/examples/16_textured_scene.py index a03e13d..49fd8c4 100644 --- a/examples/16_textured_scene.py +++ b/examples/16_textured_scene.py @@ -1,6 +1,6 @@ # Example 16: Textured raytracing # -# This time we render a triangle and scene +# This time we render a triangle and sphere from pyrt.light import PointLight from pyrt.scene import * @@ -38,11 +38,11 @@ Vertex(position=(0, 1, 5), texcoord=(1, 0)), Vertex(position=(5, 1, 0), texcoord=(1, 1)), material= - TextureMaterial(texturepath='tex16.png')) + TextureMaterial(texturepath=['tex16.png'])) s = Sphere(center=Vec3(0, -3, 0), radius=1, material= - TextureMaterial(texturepath='tex16.png')) + TextureMaterial(texturepath=['tex16.png'])) # Add triangle and sphere to the scene: scene.add(t) diff --git a/examples/17.gif b/examples/17.gif new file mode 100644 index 0000000..6849c3a Binary files /dev/null and b/examples/17.gif differ diff --git a/examples/17_mipmaps.py b/examples/17_mipmaps.py new file mode 100644 index 0000000..135a614 --- /dev/null +++ b/examples/17_mipmaps.py @@ -0,0 +1,67 @@ +# Example 17: Textured raytracing +# +# This time we render a triangle and scene with mipmaps +# Used textures contain funny digits +# Digit corresponds to level of detalization + +from pyrt.light import PointLight +from pyrt.scene import * +from pyrt.material.texturematerial import TextureMaterial +from pyrt.camera import PerspectiveCamera +from pyrt.renderer import SimpleRT + +from pyrt.renderer import RGBImage +from pyrt.math import Vec3 +from pyrt.geometry import Triangle, Vertex +import moviepy.editor as mpy + + +def make_frame(t): + w = 320 + h = 240 + + # Create a camera with width, height and field of view: + camera = PerspectiveCamera(w, h, 60) + + # Set View matrix of camera: define where to look at + camera.setView(Vec3(0, -t - 10, 0), Vec3(0, 0, 0), Vec3(0, 0, 1)) + + # Create view-projection matrix (right to left) + vp = camera.projection * camera.view + + # Create a scene + scene = Scene() + + # Add a light to the scene + scene.addLight(PointLight(Vec3(0, -2, 0))) + + # Create a triangle + t1 = Triangle(Vertex(position=(-5, -4, 5), texcoord=(0, 0)), + Vertex(position=(5, -4, 5), texcoord=(1, 0)), + Vertex(position=(5, -4, -5), texcoord=(1, 1)), + material= + TextureMaterial(texturepath=['tex17-1.png', 'tex17-2.png'])) + + t2 = Triangle(Vertex(position=(-5, -4, 5), texcoord=(0, 0)), + Vertex(position=(5, -4, -5), texcoord=(1, 1)), + Vertex(position=(-5,-4, -5), texcoord=(0, 1)), + material= + TextureMaterial(texturepath=['tex17-1.png', 'tex17-2.png'])) + + # Add triangle and sphere to the scene: + scene.add(t1) + scene.add(t2) + + # Now tell the scene which camera we use + scene.setCamera(camera) + + # Create a raytracer using "SimpleRT" + engine = SimpleRT() + + # Render the scene: + image = engine.render(scene) + return image.data + + +clip = mpy.VideoClip(make_frame, duration=7) +clip.write_gif("17.gif",fps=1) diff --git a/examples/tex17-1.png b/examples/tex17-1.png new file mode 100644 index 0000000..0e9926c Binary files /dev/null and b/examples/tex17-1.png differ diff --git a/examples/tex17-2.png b/examples/tex17-2.png new file mode 100644 index 0000000..d75efd0 Binary files /dev/null and b/examples/tex17-2.png differ diff --git a/pyrt/camera/camera.py b/pyrt/camera/camera.py index bcde383..0095c2f 100644 --- a/pyrt/camera/camera.py +++ b/pyrt/camera/camera.py @@ -46,3 +46,11 @@ def getMatrix(self) -> Mat4: :return: """ pass + + @abstractmethod + def getSize(self) -> tuple: + """ + Returns the resolution tuple (w, h) + :return: + """ + pass \ No newline at end of file diff --git a/pyrt/camera/orthographiccamera.py b/pyrt/camera/orthographiccamera.py index 19c2dd6..3c08c3a 100644 --- a/pyrt/camera/orthographiccamera.py +++ b/pyrt/camera/orthographiccamera.py @@ -27,3 +27,6 @@ def __init__(self, width=512, height=512): def primaryRay(self, x: float, y: float) -> Ray: r = Ray(Vec3(x, y, 0.), self.direction) return r + + def getSize(self) -> tuple: + return self.width, self.height diff --git a/pyrt/camera/perspectivecamera.py b/pyrt/camera/perspectivecamera.py index 45b3045..1b7acc9 100644 --- a/pyrt/camera/perspectivecamera.py +++ b/pyrt/camera/perspectivecamera.py @@ -89,7 +89,6 @@ def setProjection(self, fov: float, width: int, height: int, znear: float, zfar: self.matrix = self.projection * self.view self.matrixinv = inverse4(self.matrix) - def getMatrix(self) -> Mat4: """ Returns the view-projection matrix @@ -98,3 +97,5 @@ def getMatrix(self) -> Mat4: """ return self.matrix + def getSize(self) -> tuple: + return self.width, self.height diff --git a/pyrt/material/texturematerial.py b/pyrt/material/texturematerial.py index 82c96b2..5808912 100644 --- a/pyrt/material/texturematerial.py +++ b/pyrt/material/texturematerial.py @@ -7,6 +7,7 @@ from .material import Material from ..math import Vec3, Ray, HitRecord, dot3, reflect3, normalize3, clamp3 from ..camera import Camera +from math import log2, floor class TextureMaterial(Material): @@ -14,12 +15,14 @@ class TextureMaterial(Material): """Texture Material Class""" def __init__(self, color: Vec3 = Vec3(1.,1.,1.), shininess: float = 10.0, reflectivity: float = 0.0, refraction: float = 1.0, - texturepath: str = ''): + texturepath: list = None): Material.__init__(self, color, shininess, reflectivity, refraction) - self.texture = None if len(texturepath) == 0 else Texture(texturepath) + self.texture = None \ + if texturepath is None \ + else {i: Texture(texturepath[i]) for i in range(len(texturepath))} - def setTexture(self, texture: Texture): - self.texture = texture + def addTexture(self, lod: int, texture: Texture): + self.texture.update({lod: texture}) def shade(self, camera: Camera, ray: Ray, hitrecord: HitRecord, lights: list) -> Vec3: """ @@ -29,7 +32,13 @@ def shade(self, camera: Camera, ray: Ray, hitrecord: HitRecord, lights: list) - """ colorsum = Vec3(0.,0.,0.) - texcolor = self.texture.color(hitrecord.texcoord) + if self.texture is None or len(self.texture) == 0: + texcolor = self.color + else: + size = camera.getSize(); + resolution = size[0] * size[1]; + lod = floor(log2((hitrecord.point - camera.position).length() / resolution) + 14) + texcolor = self.texture[max(0, min(lod, len(self.texture) - 1))].color(hitrecord.texcoord) if len(lights) > 0: for light in lights: diff --git a/pyrt/renderer/simplert.py b/pyrt/renderer/simplert.py index 512d4ea..ab8aa85 100644 --- a/pyrt/renderer/simplert.py +++ b/pyrt/renderer/simplert.py @@ -17,6 +17,7 @@ def __init__(self, shadow=False, iterations=1): Renderer.__init__(self, "Simple Raytracer") self.shadow = shadow self.iterations = iterations + if self.shadow: print("# Shadow Enabled") if self.iterations>1: