Note
Go to the end to download the full example code.
Loading with MTL Properties#
import os
import numpy as np
import mirage as mr
obj_name = 'cube.obj'
obj_path = os.path.join(os.environ['MODELDIR'], obj_name)
Let’s take a look at what the obj file looks like
with open(obj_path, 'r') as f:
print(f.read())
# Blender v2.92.0 OBJ File: ''
# www.blender.org
mtllib cube.mtl
o Cube_Cube.003
v 1.000000 1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 -1.000000 1.000000
vt 0.625000 0.000000
vt 0.375000 0.250000
vt 0.375000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.500000
vt 0.625000 0.500000
vt 0.375000 0.750000
vt 0.625000 0.750000
vt 0.375000 1.000000
vt 0.125000 0.750000
vt 0.125000 0.500000
vt 0.875000 0.500000
vt 0.625000 1.000000
vt 0.875000 0.750000
vn 1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
usemtl None
s off
f 2/1/1 3/2/1 1/3/1
f 4/4/2 7/5/2 3/2/2
f 8/6/3 5/7/3 7/5/3
f 6/8/4 1/9/4 5/7/4
f 7/5/5 1/10/5 3/11/5
f 4/12/6 6/8/6 8/6/6
f 2/1/1 4/4/1 3/2/1
f 4/4/2 8/6/2 7/5/2
f 8/6/3 6/8/3 5/7/3
f 6/8/4 2/13/4 1/9/4
f 7/5/5 5/7/5 1/10/5
f 4/12/6 2/14/6 6/8/6
And the mtl file
with open(os.path.join(os.path.split(obj_path)[0], 'cube.mtl'), 'r') as f:
print(f.read())
# Blender MTL File: 'None'
# Material Count: 1
newmtl None
Ns 500
Ka 0.8 0.8 0.8
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2
We interpret:
The red channel of Kd (in Blender this is the red channel of the base color) as \(C_d\)
The blue channel of Kd as \(C_s\)
The index of refraction Ni (IOR in Blender) as the specular exponent \(n\)
For more information on making an mesh in blender with per-face materials, see this documentation page
mr.tic('Pure python load time')
obj = mr.load_obj(obj_path)
mr.toc()
Pure python load time: 4.30e-04 seconds
We can print the the cd, cs, and n attributes of the object, each of which should now have one entry per face
print(f'{obj.cd=}')
print(f'{obj.cs=}')
print(f'{obj.n=}')
obj.cd=array([[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8]])
obj.cs=array([[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8],
[0.8]])
obj.n=array([[10.],
[10.],
[10.],
[10.],
[10.],
[10.],
[10.],
[10.],
[10.],
[10.],
[10.],
[10.]])
Let’s build a BRDF with these attributes. Note if validate=True, the BRDF initialization procedure will check for energy conservation
brdf = mr.Brdf('phong', cd=obj.cd, cs=obj.cs, n=obj.n, validate=False)
Now the BRDF will apply the material properties of each face when computing a convex LC
npts = int(100)
L = mr.rand_unit_vectors(npts)
O = mr.rand_unit_vectors(npts)
mr.tic('lc')
lc1 = obj.convex_light_curve(brdf, L, O)
mr.toc()
lc: 2.68e-04 seconds
Notice that you can also mix and match uniform and varying properties. Here \(C_d\) has one entry per face, but the other two properties are uniform
brdf.cd = np.tile(brdf.cd[[0]], brdf.cd.shape)
brdf.cs = 0.9
brdf.n = 1
lc2 = obj.convex_light_curve(brdf, L, O)
Total running time of the script: (0 minutes 0.004 seconds)