Note
Go to the end to download the full example code.
Physically-Based Rendering (PBR) on spheres#
PBR engines aim to simulate properties of light when it interacts with objects in the scene in a physically plausible way. The interaction of light with an object depends on the material the object is made of. In computer graphics, materials are usually divided in 2 main categories based on their conductive properties: dielectrics and metals.
This tutorial, illustrates how to model some material properties in FURY by using the PBR material.
Let’s start by importing the necessary modules:
import numpy as np
import fury
Now set up a new scene.
scene = fury.window.Scene()
scene.background((0.9, 0.9, 0.9))
Let’s define the parameters we are going to showcase in this tutorial. These subset of parameters have their values constrained in the 0 to 1 range.
material_params = [
[[1, 1, 0], {"metallic": 0, "roughness": 0}],
[(0, 0, 1), {"roughness": 0}],
[(1, 0, 1), {"anisotropy": 0, "metallic": 0.25, "roughness": 0.5}],
[
(1, 0, 1),
{"anisotropy_rotation": 0, "anisotropy": 1, "metallic": 0.25, "roughness": 0.5},
],
[(0, 1, 1), {"coat_strength": 0, "roughness": 0}],
[(0, 1, 1), {"coat_roughness": 0, "coat_strength": 1, "roughness": 0}],
]
Now we can start to add our actors to the scene and see how different values of the parameters produce interesting effects. For the purpose of this tutorial, we will see the effect of 11 different values of each parameter.
num_values = 11
for i, mp in enumerate(material_params):
color = mp[0]
params = mp[1]
center = [[0, -5 * i, 0]]
for j in range(num_values):
center[0][0] = -25 + 5 * j
sphere = fury.actor.sphere(center, color, radii=2, theta=32, phi=32)
normals = fury.utils.normals_from_actor(sphere)
tangents = fury.utils.tangents_from_direction_of_anisotropy(
normals, (0, 1, 0.5)
)
fury.utils.tangents_to_actor(sphere, tangents)
keys = list(params)
params[keys[0]] = np.round(0.1 * j, decimals=1)
fury.material.manifest_pbr(sphere, **params)
scene.add(sphere)
For interpretability purposes we will add some labels to guide us through our visualization.
labels = [
"Metallic",
"Roughness",
"Anisotropy",
"Anisotropy Rotation",
"Coat Strength",
"Coat Roughness",
]
for i, name in enumerate(labels):
pos = [-40, -5 * i, 0]
label = fury.actor.vector_text(
text=name, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)
)
scene.add(label)
for j in range(num_values):
pos = [-26 + 5 * j, 3, 0]
label = fury.actor.vector_text(
text=str(np.round(j * 0.1, decimals=1)),
pos=pos,
scale=(0.8, 0.8, 0.8),
color=(0, 0, 0),
)
scene.add(label)
Some parameters of this material have their values constrained to be between 1 and 2.3. These parameters are the Base Index of Refraction (IOR) and the Clear coat Index of Refraction (IOR). Therefore, we will interpolate some values within this range and see how they affect the rendering.
iors = np.round(np.linspace(1, 2.3, num=num_values), decimals=2)
ior_params = [
[(0, 1, 1), {"base_ior": iors[0], "roughness": 0}],
[
(0, 1, 1),
{
"coat_ior": iors[0],
"coat_roughness": 0.1,
"coat_strength": 1,
"roughness": 0,
},
],
]
for i, iorp in enumerate(ior_params):
color = iorp[0]
params = iorp[1]
center = [[0, -35 - (5 * i), 0]]
for j in range(num_values):
center[0][0] = -25 + 5 * j
sphere = fury.actor.sphere(center, color, radii=2, theta=32, phi=32)
keys = list(params)
params[keys[0]] = iors[j]
fury.material.manifest_pbr(sphere, **params)
scene.add(sphere)
Let’s add the respective labels to the scene.
labels = ["Base IoR", "Coat IoR"]
for i, name in enumerate(labels):
pos = [-40, -35 - (5 * i), 0]
label = fury.actor.vector_text(
text=name, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)
)
scene.add(label)
for j in range(num_values):
pos = [-26 + 5 * j, -32, 0]
label = fury.actor.vector_text(
text="{:.02f}".format(iors[j]), pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)
)
scene.add(label)
Finally, let’s visualize our tutorial.
interactive = False
if interactive:
fury.window.show(scene)
fury.window.record(scene=scene, size=(600, 600), out_path="viz_pbr_spheres.png")