pythongraphicsmeshopenmesh

How to color faces in OpenMesh?


There is no example in OpenMesh documentation for coloring faces. Which function should I use to color fh0 to green? (I tried mesh.set_color but could not succeed. You can see my attempt on second part of code)

import openmesh as om
import numpy as np

mesh = om.TriMesh()

# add a a couple of vertices to the mesh
vh0 = mesh.add_vertex([0, 1, 0])
vh1 = mesh.add_vertex([1, 0, 0])
vh2 = mesh.add_vertex([2, 1, 0])
vh3 = mesh.add_vertex([0,-1, 0])
vh4 = mesh.add_vertex([2,-1, 0])

# add a couple of faces to the mesh
fh0 = mesh.add_face(vh0, vh1, vh2)
fh1 = mesh.add_face(vh1, vh3, vh4)
fh2 = mesh.add_face(vh0, vh3, vh1)

# add another face to the mesh, this time using a list
vh_list = [vh2, vh1, vh4]
fh3 = mesh.add_face(vh_list)

#  0 ==== 2
#  |\  0 /|
#  | \  / |
#  |2  1 3|
#  | /  \ |
#  |/  1 \|
#  3 ==== 4

for face in mesh.faces():
    mesh.set_color(face, [0.67578125, 0.296875, 0.3515625])

om.write_mesh('test.obj', mesh)

but this gives me

IndexError: index 3 is out of bounds for axis 0 with size 3

How can I add color to faces in OpenMesh?


Solution

  • There are several issues:

    1. mesh.request_face_colors() is required for the TriMesh object to support storing face colors.
    2. mesh.set_color expects an alpha channel, so your color is actually [0.67578125, 0.296875, 0.3515625, 1.]
    3. write_mesh requires face_color=True argument.
    4. .obj file format doesn't support vertex/face color. Color is saved in a separate .mtl file ("material"). You can use other formats instead, ie .ply.

    Full code:

    import openmesh as om
    
    mesh = om.TriMesh()
    
    # add a a couple of vertices to the mesh
    vh0 = mesh.add_vertex([0, 1, 0])
    vh1 = mesh.add_vertex([1, 0, 0])
    vh2 = mesh.add_vertex([2, 1, 0])
    vh3 = mesh.add_vertex([0,-1, 0])
    vh4 = mesh.add_vertex([2,-1, 0])
    
    # add a couple of faces to the mesh
    fh0 = mesh.add_face(vh0, vh1, vh2)
    fh1 = mesh.add_face(vh1, vh3, vh4)
    fh2 = mesh.add_face(vh0, vh3, vh1)
    
    # add another face to the mesh, this time using a list
    vh_list = [vh2, vh1, vh4]
    fh3 = mesh.add_face(vh_list)
    
    #  0 ==== 2
    #  |\  0 /|
    #  | \  / |
    #  |2  1 3|
    #  | /  \ |
    #  |/  1 \|
    #  3 ==== 4
    
    mesh.request_face_colors()
    
    for face in mesh.faces():
        mesh.set_color(face, [0.67578125, 0.296875, 0.3515625, 1.])
    
    for face in mesh.faces():
        print(mesh.color(face))
    
    om.write_mesh('test.obj', mesh, face_color=True)
    om.write_mesh('test.ply', mesh, face_color=True)
    

    Console output (color attribute was successfully added to the mesh):

    [0.67578125 0.296875   0.3515625  1.        ]
    [0.67578125 0.296875   0.3515625  1.        ]
    [0.67578125 0.296875   0.3515625  1.        ]
    [0.67578125 0.296875   0.3515625  1.        ]
    

    Content of test.obj:

    # 5 vertices, 4 faces
    mtllib test.mat
    v 0.000000 1.000000 0.000000
    v 1.000000 0.000000 0.000000
    v 2.000000 1.000000 0.000000
    v 0.000000 -1.000000 0.000000
    v 2.000000 -1.000000 0.000000
    usemtl mat0
    f 1 2 3
    f 2 4 5
    f 1 4 2
    f 3 2 5
    

    Content of test.mat (this file specifies what "mat0" in the test.obj file means):

    newmtl mat0
    Ka 0.5000 0.5000 0.5000
    Kd 0.67451 0.298039 0.352941
    illum 1
    

    Content of test.ply (everything in a single file):

    ply
    format ascii 1.0
    element vertex 5
    property float x
    property float y
    property float z
    element face 4
    property list uchar int vertex_indices
    property uchar red
    property uchar green
    property uchar blue
    end_header
    0 1 0
    1 0 0
    2 1 0
    0 -1 0
    2 -1 0
    3 0 1 2 172 76 90
    3 1 3 4 172 76 90
    3 0 3 1 172 76 90
    3 2 1 4 172 76 90