mikedh / trimesh

Python library for loading and using triangular meshes.
https://trimesh.org
MIT License
3k stars 579 forks source link

face_colors doesn't color faces properly, but instead interpolates the colors #1997

Open coderforlife opened 1 year ago

coderforlife commented 1 year ago

If I draw a box with each triangle a solid color like so:

import trimesh
import numpy as np
mesh = trimesh.primitives.Box(extents=(5, 5, 5))
mesh.visual.face_colors = np.array([
    [255, 0, 0, 255],
    [255, 128, 0, 255],
    [255, 255, 0, 255],
    [128, 255, 0, 255],
    [0, 255, 0, 255],
    [0, 255, 128, 255],
    [0, 255, 255, 255],
    [0, 128, 255, 255],
    [0, 0, 255, 255],
    [128, 0, 255, 255],
    [255, 0, 255, 255],
    [255, 0, 128, 255],
])
mesh.show()

There are no solid colors anywhere on the cube, everything is a gradient. When doing a face-visual (instead of a vertex-visual) you need to be using flat colors for each triangle. This may require a geometry shader to do properly so that each triangle can emit the same color to each of its vertices (and each vertex is emitted by one triangle instead of shared between triangles).

It is even more severe than just making gradients as entire faces can miss the designated color. For example, in the box, there is no spot that is red (to make it really obvious, keep the first color red and set all other colors to black - the entire cube is black with no hint of red anywhere).

I was using the trimesh library to highlight particular faces with particular computed properties, but several faces weren't showing up because of this issue.

mikedh commented 1 year ago

Hey, I think you might want mesh.show(smooth=False) which should probably be the default if mesh.visual.kind == 'face', which produces this:

image
coderforlife commented 1 year ago

Exactly! Sorry I didn't find that option. Still a bit odd that with smoothing some face colors get completely dropped...

coderforlife commented 1 year ago

Reopening... smooth=False doesn't work in Jupyter notebook...

paireks commented 12 months ago

Yes, I have the same issue. Tried smooth=False and mesh.visual.kind == 'face', but it still keeps smoothing. 2023-11-01_17h21_10

paireks commented 12 months ago

Another interesting issue is the lack of transparency for faces: image

You can check source code there: https://github.com/paireks/dotbimpy/blob/master/dotbimpy/other/DotbimToTrimeshScene.ipynb

3d file is there: https://3dviewer.net/#model=https://raw.githubusercontent.com/paireks/dotbim/master/test/ExampleFiles/TestFilesFromArchicad/MulticolorHouse.bim

3d file from previous example is there: https://3dviewer.net/#model=https://raw.githubusercontent.com/paireks/dotbim/master/test/ExampleFiles/TestFilesFromC%23/CubesWithFaceColorsAndWithout_WithFixedNormals.bim

gtangg11 commented 3 months ago

Has this been resolved. It seems preventing interpolation in trimesh is just not possible.

ie this code still interpolates

mesh = Trimesh(mesh.vertices, mesh.faces, smooth=False, process=False)
mesh.visual.vertex_colors = None
mesh.visual.face_colors = np.random.randint(0, 255, (len(mesh.faces), 3))
mesh.visual.kind == 'face'
return mesh
gtangg11 commented 2 months ago

Ok, it seems the reason why face interpolation is happening is because openGL stores the data in vertex form as opposed to face form. Just run your mesh through this function, which preserves the number and index of faces but makes the vertices unique (and changes faces' vertex indexing)

def duplicate_verts(mesh: Trimesh):
    """
    """
    verts = mesh.vertices[mesh.faces.reshape(-1), :]
    faces = np.arange(0, verts.shape[0])
    faces = faces.reshape(-1, 3)
    return Trimesh(vertices=verts, faces=faces, process=False)

Wish this would have been made clear before, which would have saved a lot of time for everyone (only occurred to me reading the src code of mesh.show() as well as getting misled by Trimesh arguments such as process and smooth).

Before:

Screenshot 2024-08-01 at 7 40 18 AM

After:

Screenshot 2024-08-01 at 7 41 15 AM