MeshPalettizer / src /__init__.py
dylanebert's picture
initial commit
346b70f
import numpy as np
from .palette import create_palette, PaletteMapper
from .atlas import create_atlas
from .mesh import apply_atlas
__all__ = ["convert_meshes", "ConversionConfig", "ConversionResult"]
class ConversionConfig:
def __init__(
self,
atlas_size=16,
face_sampling_ratio=0.1,
simplify_details=True,
detail_sensitivity=None,
):
self.atlas_size = atlas_size
self.face_sampling_ratio = face_sampling_ratio
self.simplify_details = simplify_details
self.detail_sensitivity = detail_sensitivity
self.total_palette_colors = atlas_size * atlas_size
class ConversionResult:
def __init__(self, meshes, atlas, palette, scene_metadata=None):
self.meshes = meshes
self.atlas = atlas
self.palette = palette
self.scene_metadata = scene_metadata
def convert_meshes(
mesh_list,
atlas_size=16,
face_sampling_ratio=0.1,
simplify_details=True,
detail_sensitivity=None,
scene_metadata=None,
):
if not mesh_list:
raise ValueError("No meshes provided")
config = ConversionConfig(
atlas_size, face_sampling_ratio, simplify_details, detail_sensitivity
)
print(
f"Processing {len(mesh_list)} mesh(es) with {config.total_palette_colors}-color palette"
)
all_sampled_colors = []
meshes_with_valid_geometry = []
mesh_face_colors = {}
for mesh_name, mesh_object in mesh_list:
if mesh_object is None or len(mesh_object.faces) == 0:
print(f"Skipping {mesh_name}: no valid geometry")
continue
print(
f"Analyzing {mesh_name}: {len(mesh_object.faces)} faces, {len(mesh_object.vertices)} vertices"
)
meshes_with_valid_geometry.append((mesh_name, mesh_object))
from .extraction.reader import get_face_colors
face_colors = get_face_colors(
mesh_object,
simplify_details=config.simplify_details,
detail_sensitivity=config.detail_sensitivity,
)
mesh_face_colors[mesh_name] = face_colors
from .extraction import sample_colors
face_areas = mesh_object.area_faces if hasattr(mesh_object, "area_faces") else None
sampled_colors = sample_colors(face_colors, config.face_sampling_ratio, face_areas)
all_sampled_colors.extend(sampled_colors)
if not meshes_with_valid_geometry:
raise ValueError("No valid meshes found")
combined_color_array = np.array(all_sampled_colors, dtype=np.uint8)
print(
f"Total sampled colors: {len(combined_color_array)} from {len(meshes_with_valid_geometry)} mesh(es)"
)
quantized_palette = create_palette(combined_color_array, size=config.atlas_size)
texture_atlas_image, color_to_uv_mapping = create_atlas(
quantized_palette, size=config.atlas_size
)
nearest_color_mapper = PaletteMapper(quantized_palette)
atlas_applied_meshes = []
for mesh_name, mesh_object in meshes_with_valid_geometry:
print(f"Applying atlas to {mesh_name}")
mesh_with_atlas_texture = apply_atlas(
mesh_object, texture_atlas_image, color_to_uv_mapping, nearest_color_mapper,
face_colors=mesh_face_colors[mesh_name]
)
atlas_applied_meshes.append((mesh_name, mesh_with_atlas_texture))
print(f"✓ Successfully processed {len(atlas_applied_meshes)} mesh(es)")
return ConversionResult(
atlas_applied_meshes, texture_atlas_image, quantized_palette, scene_metadata
)