85 lines
2.7 KiB
Python
85 lines
2.7 KiB
Python
import trimesh
|
|
import numpy as np
|
|
import sys
|
|
import os
|
|
|
|
def trimesh_texture_split(glb_file, quantization_steps=1.0):
|
|
print(f"Loading {glb_file}...")
|
|
scene = trimesh.load(glb_file, force='scene')
|
|
|
|
geom_names = list(scene.geometry.keys())
|
|
if not geom_names:
|
|
print("No geometry found in the file.")
|
|
return []
|
|
|
|
geom_name = geom_names[0]
|
|
mesh = scene.geometry[geom_name]
|
|
|
|
if not hasattr(mesh, "visual") or not hasattr(mesh.visual, "material"):
|
|
print("Mesh has no visual or material.")
|
|
return []
|
|
|
|
mat = mesh.visual.material
|
|
pil_img = None
|
|
if getattr(mat, "baseColorTexture", None) is not None:
|
|
pil_img = mat.baseColorTexture
|
|
elif getattr(mat, "image", None) is not None:
|
|
pil_img = mat.image
|
|
|
|
if pil_img is None:
|
|
print("Material has no image texture.")
|
|
return []
|
|
img_np = np.array(pil_img.convert('RGB')) / 255.0
|
|
h, w = img_np.shape[:2]
|
|
|
|
print(f"Image Resolution: {w}x{h}")
|
|
face_uvs = mesh.visual.uv[mesh.faces].mean(axis=1)
|
|
|
|
u = face_uvs[:, 0] % 1.0
|
|
v = face_uvs[:, 1] % 1.0
|
|
|
|
pixel_x = np.clip((u * w).astype(int), 0, w - 1)
|
|
pixel_y = np.clip(((1.0 - v) * h).astype(int), 0, h - 1)
|
|
|
|
face_colors = img_np[pixel_y, pixel_x]
|
|
crushed_colors = np.round(face_colors * quantization_steps) / quantization_steps
|
|
unique_colors, face_color_indices = np.unique(crushed_colors, axis=0, return_inverse=True)
|
|
|
|
split_pieces = []
|
|
|
|
from trimesh.visual import material, TextureVisuals
|
|
|
|
for i, color in enumerate(unique_colors):
|
|
mask = (face_color_indices == i)
|
|
sub_mesh = mesh.submesh([mask], append=True)
|
|
r, g, b = (color * 255).astype(np.uint8)
|
|
|
|
# Solid PBR material export
|
|
mat = material.PBRMaterial(baseColorFactor=[r, g, b, 255])
|
|
sub_mesh.visual = TextureVisuals(material=mat)
|
|
|
|
split_pieces.append(sub_mesh)
|
|
|
|
print(f"Instantly mathematically sliced into {len(split_pieces)} independent pieces!")
|
|
return split_pieces
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) < 2:
|
|
print("Usage: python test_trimesh.py <mesh.glb>")
|
|
sys.exit(1)
|
|
|
|
in_file = sys.argv[1]
|
|
pieces = trimesh_texture_split(in_file, quantization_steps=1.0)
|
|
|
|
out_path = in_file.replace(".glb", "_single_split.glb")
|
|
if out_path == in_file:
|
|
out_path += "_single_split.glb"
|
|
|
|
scene_out = trimesh.Scene()
|
|
for i, piece in enumerate(pieces):
|
|
scene_out.add_geometry(piece, geom_name=f"part_{i}")
|
|
print(f"Packed part_{i} ({len(piece.faces)} faces)")
|
|
|
|
scene_out.export(out_path)
|
|
print(f"\nSuccessfully exported all pieces into ONE file: {out_path}")
|