mikedh / trimesh

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

Assigning new material to a Trimesh object does nothing #2243

Open MenachemBerkovich opened 3 months ago

MenachemBerkovich commented 3 months ago

Hey, I'm trying to apply some image as a texture on my Trimesh item, But the Trimesh always remains as before. Why?

import numpy as np
import trimesh
im = Image.open("/app/free.jpg")
texture = trimesh.visual.texture.TextureVisuals(image=im)
mat = trimesh.visual.material.PBRMaterial(image=texture)
item.visual.material = mat
item.show()
Tugdual-G commented 3 months ago

Hello, You should provide the uv mapping in the [0,1]x[0,1] range between your vertices coordinates and the texture coordinates. For example, to map a texture to a sphere:

#!/usr/bin/env python3
from PIL import Image
import trimesh
import numpy as np

# Type hint to supress warnings of the editor since load can
# return different subclass of geometry
mesh: trimesh.Trimesh = trimesh.load("meshes/sphere.ply")

vertices = mesh.vertices

def to_lonlat_to_uv(xyz):
    # convert from cartesian xyz coordinate to a
    # surface parametrized by lonlat coords.
    # These surface parametrization is then expressed the range [0,1]x[0,1]
    # rather than [0, 360]x[-90,90]
    ndim = False
    R = np.sqrt(np.sum(xyz**2, axis=1))
    latlon = np.zeros((xyz.shape[0], 2))
    latlon[:, 1] = 0.5 + np.arcsin(xyz[:, 2] / R[np.newaxis, :]) / (np.pi)
    latlon[:, 0] = 0.5 + np.arctan2(xyz[:, 1], xyz[:, 0]) / (2 * np.pi)
    return latlon

uv = to_lonlat_to_uv(vertices)
im = Image.open("meshes/grid.png")

material = trimesh.visual.texture.SimpleMaterial(image=im)
color_visuals = trimesh.visual.TextureVisuals(uv=uv, image=im, material=material)
mesh.visual = color_visuals
mesh.show()