Rendering quad
This example describes how to render a simple scene containing a quad represented by two triangles. The code starts again with lm::init()
function.
[1]:
import lmenv
lmenv.load('.lmenv')
[1]:
Namespace(bin_path='/lightmetrica-v3/_build/bin', path='/lightmetrica-v3', scene_path='/lm3/scenes')
[2]:
import numpy as np
import imageio
%matplotlib inline
import matplotlib.pyplot as plt
import lightmetrica as lm
%load_ext lightmetrica_jupyter
[3]:
lm.init()
lm.log.init('jupyter')
lm.progress.init('jupyter')
lm.info()
[I|0.000] Lightmetrica -- Version 3.0.0 (rev. 70601db) Linux x64
Similarly we define the assets. In addition to film
, we define camera
, mesh
, and material
. Although the types of assets are different, we can use consistent interface to define the assets: lm::load_*()
functions. Here we prepare for a pinhole camera (camera::pinhole
), a raw mesh (mesh::raw
), and a diffuse material (material::diffuse
) with the corrsponding parameters. Please refer to Built-in component reference for the detailed description of the parameters.
[5]:
# Film for the rendered image
film = lm.load_film('film', 'bitmap', w=1920, h=1080)
# Pinhole camera
camera = lm.load_camera('camera', 'pinhole',
position=[0,0,5],
center=[0,0,0],
up=[0,1,0],
vfov=30,
aspect=16/9)
# Load mesh with raw vertex data
mesh = lm.load_mesh('mesh', 'raw',
ps=[-1,-1,-1,1,-1,-1,1,1,-1,-1,1,-1],
ns=[0,0,1],
ts=[0,0,1,0,1,1,0,1],
fs={
'p': [0,1,2,0,2,3],
'n': [0,0,0,0,0,0],
't': [0,1,2,0,2,3]
})
# Material
material = lm.load_material('material', 'diffuse', Kd=[1,1,1])
[I|0.016] Loading asset [name='film']
[I|0.094] Loading asset [name='camera']
[I|0.095] Loading asset [name='mesh']
[I|0.095] Loading asset [name='material']
Next we will create a scene asset. The scene asset can also be created load_scene()
function. Here, we will create scene::default
asset.
A scene internally uses acceleration structure for ray-scene intersections, which can be specified by accel
parameter.
[6]:
accel = lm.load_accel('accel', 'sahbvh')
scene = lm.load_scene('scene', 'default', accel=accel)
[I|0.102] Loading asset [name='accel']
[I|0.103] Loading asset [name='scene']
The scene of Lightmetrica is defined by a set of primitives
. A primitive specifies an object inside the scene by associating geometries and materials. We can define a primitive by lm::Scene::add_primitive()
function.
Note
If you need transformation applied to the geometry, you can use lm::Scene::add_transformed_primitive()
function. The transformation is given by 4x4 matrix.
In this example we define two pritimives; one for camera and the other for quad mesh with diffuse material. We don’t apply any transformation to the geometry, so we use lm::Scene::add_primitive()
function.
Note
Specifically, the scene is represented by a scene graph, a directed acyclic graph representing spatial structure and attributes of the scene. Each node of the scene graph describes either a primitive or a pritmive group. We provide a set of APIs to manipulate the structure of scene graph for advanced usage like instancing.
[7]:
scene.add_primitive(camera=camera)
scene.add_primitive(mesh=mesh, material=material)
After the configuration of the primitives, we must build the scene, which can be done by lm::Scene::build()
function.
[8]:
scene.build()
[I|0.115] Building acceleration structure [name='accel']
[I|0.115] .. Flattening scene
[I|0.115] .. Building
Nowe we are ready for rendering. Here we will use renderer::raycast
asset, which takes scene
as a parameter. The rendered image will out written in the film asset specified by output
parameter. We can also configure the background color with bg_color
parameter.
[9]:
renderer = lm.load_renderer('renderer', 'raycast',
scene=scene,
output=film,
bg_color=[0,0,0])
renderer.render()
[I|0.122] Loading asset [name='renderer']
[9]:
{'elapsed': 0.80884675}
[10]:
img = np.copy(film.buffer())
f = plt.figure(figsize=(15,15))
ax = f.add_subplot(111)
ax.imshow(np.clip(np.power(img,1/2.2),0,1), origin='lower')
plt.show()
