Custom renderer in PythonΒΆ

This test demostrates how to create an custom renderer using component extension in Python.

[1]:
%load_ext autoreload
%autoreload 2
[2]:
import os
import imageio
import pandas as pd
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import lmfunctest as ft
import lmscene
import lightmetrica as lm
[3]:
os.getpid()
[3]:
659
[4]:
%load_ext lightmetrica_jupyter
[5]:
@lm.pylm_component('renderer::ao')
class Renderer_AO(lm.Renderer):
    """Simple ambient occlusion renderer"""

    def construct(self, prop):
        self.film = lm.Film.castFrom(lm.comp.get(prop['output']))
        if self.film is None:
            return False
        self.spp = prop['spp']
        return True

    def render(self, scene):
        w = self.film.size().w
        h = self.film.size().h
        rng = lm.Rng(42)
        lm.progress.start(w*h)
        def process(index, threadid):
            x = index % w
            y = int(index / w)
            rp = np.array([(x+.5)/w, (y+.5)/h])
            ray = scene.primaryRay(rp, self.film.aspectRatio())
            hit = scene.intersect(ray)
            if hit is None:
                return
            V = 0
            for i in range(self.spp):
                n, u, v = hit.geom.orthonormalBasis(-ray.d)
                d = lm.math.sampleCosineWeighted(rng)
                r = lm.Ray(hit.geom.p, np.dot(d, [u,v,n]))
                if scene.intersect(r, lm.Eps, .2) is None:
                    V += 1
            V /= self.spp
            self.film.setPixel(x, y, np.full(3, V))
            lm.progress.update(y*w+x)
        lm.parallel.foreach(w*h, process)
        lm.progress.end()
[6]:
lm.init('user::default', {})
[7]:
lm.parallel.init('parallel::openmp', {
    'numThreads': 1
})
[8]:
lm.log.init('logger::jupyter', {})
[9]:
lm.progress.init('progress::jupyter', {})
[10]:
lm.info()
[I|0.032|114@user  ] Lightmetrica -- Version 3.0.0 (rev. fe30e7c) Linux x64
[11]:
# Scene
lm.asset('film_output', 'film::bitmap', {
    'w': 640,
    'h': 360
})
lmscene.load(ft.env.scene_path, 'fireplace_room')
[I|0.050|48@assets ] Loading asset [name='film_output']
[I|0.060|48@assets ] Loading asset [name='camera_main']
[I|0.061|48@assets ] Loading asset [name='model_obj']
[I|0.061|29@objload]   Loading OBJ file [path='fireplace_room.obj']
[I|0.061|169@objloa]   Loading MTL file [path='fireplace_room.mtl']
[I|0.061|44@texture]   Loading texture [path='wood.ppm']
[I|0.165|44@texture]   Loading texture [path='leaf.ppm']
[I|0.168|44@texture]   Loading texture [path='picture8.ppm']
[I|0.208|44@texture]   Loading texture [path='wood5.ppm']
[12]:
lm.build('accel::sahbvh', {})
[I|0.666|246@scene ] Building acceleration structure [name='accel::sahbvh']
[I|0.666|131@accel_]   Flattening scene
[I|0.695|261@accel_]   Building
[13]:
lm.render('renderer::ao', {
    'output': lm.asset('film_output'),
    'spp': 5
})
[I|1.475|151@user  ] Starting render [name='renderer::ao']
[14]:
img = np.flip(np.copy(lm.buffer(lm.asset('film_output'))), axis=0)
[15]:
f = plt.figure(figsize=(15,15))
ax = f.add_subplot(111)
ax.imshow(np.clip(np.power(img,1/2.2),0,1))
plt.show()
../_images/executed_functest_func_py_custom_renderer_15_0.png