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)

Gallery generated by Sphinx-Gallery