fixed output mesh
This commit is contained in:
@@ -337,7 +337,7 @@ class PartCrafterPipeline(DiffusionPipeline, TransformerDiffusionMixin):
|
||||
max_num_expanded_coords=max_num_expanded_coords,
|
||||
# verbose=True
|
||||
)
|
||||
mesh = trimesh.Trimesh(mesh_v_f[0].astype(np.float32), mesh_v_f[1])
|
||||
mesh = trimesh.Trimesh(mesh_v_f[0].astype(np.float32), mesh_v_f[1], process=True)
|
||||
except:
|
||||
mesh_v_f = None
|
||||
mesh = None
|
||||
|
||||
@@ -10,9 +10,60 @@ from diffusers.utils import export_to_video
|
||||
from diffusers.utils.loading_utils import load_video
|
||||
import torch
|
||||
from torchvision.utils import make_grid
|
||||
import math
|
||||
|
||||
os.environ['PYOPENGL_PLATFORM'] = 'egl'
|
||||
|
||||
def explode_mesh(mesh, explosion_scale=0.4):
|
||||
# ensure we have a Scene
|
||||
if isinstance(mesh, trimesh.Trimesh):
|
||||
scene = trimesh.Scene(mesh)
|
||||
elif isinstance(mesh, trimesh.Scene):
|
||||
scene = mesh
|
||||
else:
|
||||
raise ValueError(f"Expected Trimesh or Scene, got {type(mesh)}")
|
||||
|
||||
if len(scene.geometry) <= 1:
|
||||
print("Nothing to explode")
|
||||
return scene
|
||||
|
||||
# 1) collect (name, geom, world_center)
|
||||
parts = []
|
||||
for name, geom in scene.geometry.items():
|
||||
# ← get(name) returns (4×4 world‐space matrix, parent_frame)
|
||||
world_tf, _ = scene.graph.get(name)
|
||||
pts = trimesh.transformations.transform_points(geom.vertices, world_tf)
|
||||
center = pts.mean(axis=0)
|
||||
parts.append((name, geom, center))
|
||||
|
||||
# compute global center
|
||||
all_centers = np.stack([c for _,_,c in parts], axis=0)
|
||||
global_center = all_centers.mean(axis=0)
|
||||
|
||||
exploded = trimesh.Scene()
|
||||
for name, geom, center in parts:
|
||||
dir_vec = center - global_center
|
||||
norm = np.linalg.norm(dir_vec)
|
||||
if norm < 1e-6:
|
||||
dir_vec = np.random.randn(3)
|
||||
dir_vec /= np.linalg.norm(dir_vec)
|
||||
else:
|
||||
dir_vec /= norm
|
||||
|
||||
offset = dir_vec * explosion_scale
|
||||
|
||||
# fetch the same 4×4, then bump just the translation
|
||||
world_tf, _ = scene.graph.get(name)
|
||||
world_tf = world_tf.copy()
|
||||
world_tf[:3, 3] += offset
|
||||
|
||||
exploded.add_geometry(geom, transform=world_tf, geom_name=name)
|
||||
print(f"[explode] {name} moved by {np.linalg.norm(offset):.4f}")
|
||||
|
||||
return exploded
|
||||
|
||||
|
||||
|
||||
def render(
|
||||
scene: pyrender.Scene,
|
||||
renderer: pyrender.Renderer,
|
||||
@@ -123,13 +174,22 @@ def render_views_around_mesh(
|
||||
Tuple[List[Image.Image], List[Image.Image]],
|
||||
Tuple[List[np.ndarray], List[np.ndarray]]
|
||||
]:
|
||||
|
||||
meshes = []
|
||||
scenes = []
|
||||
|
||||
if not isinstance(mesh, (trimesh.Trimesh, trimesh.Scene)):
|
||||
raise ValueError("mesh must be a trimesh.Trimesh or trimesh.Scene object")
|
||||
if isinstance(mesh, trimesh.Trimesh):
|
||||
mesh = trimesh.Scene(mesh)
|
||||
|
||||
scene = pyrender.Scene.from_trimesh_scene(mesh)
|
||||
for i in range(num_views):
|
||||
scenes.append(pyrender.Scene.from_trimesh_scene(trimesh.Scene(mesh)))
|
||||
else:
|
||||
for i in range(num_views):
|
||||
value = math.sin(math.pi * (i - 1) / num_views)
|
||||
scenes.append(pyrender.Scene.from_trimesh_scene(explode_mesh(mesh, 0.2 * value),
|
||||
ambient_light=[0.02, 0.02, 0.02],
|
||||
bg_color=[0.0, 0.0, 0.0, 1.0]))
|
||||
|
||||
light = pyrender.DirectionalLight(
|
||||
color=np.ones(3),
|
||||
intensity=light_intensity
|
||||
@@ -149,9 +209,9 @@ def render_views_around_mesh(
|
||||
)
|
||||
|
||||
images, depths = [], []
|
||||
for pose in camera_poses:
|
||||
for i, pose in enumerate(camera_poses):
|
||||
image, depth = render(
|
||||
scene, renderer, camera, pose, light,
|
||||
scenes[i], renderer, camera, pose, light,
|
||||
normalize_depth=normalize_depth,
|
||||
flags=flags,
|
||||
return_type=return_type
|
||||
|
||||
+117
-200
@@ -1,84 +1,22 @@
|
||||
{
|
||||
"id": "8fb4df3a-d3bc-4b42-95f2-434fb48a8992",
|
||||
"revision": 0,
|
||||
"last_node_id": 9,
|
||||
"last_link_id": 7,
|
||||
"last_node_id": 12,
|
||||
"last_link_id": 12,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "[Comfy3D] Load PartCrafter Pipeline",
|
||||
"pos": [
|
||||
2233.307861328125,
|
||||
1132.6119384765625
|
||||
],
|
||||
"size": [
|
||||
197.09921264648438,
|
||||
26
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "partcrafter_pipe",
|
||||
"type": "DIFFUSERS_PIPE",
|
||||
"links": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "[Comfy3D] Load PartCrafter Pipeline"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "[Comfy3D] Preview 3DMesh",
|
||||
"pos": [
|
||||
3333.187744140625,
|
||||
1183.9188232421875
|
||||
],
|
||||
"size": [
|
||||
600,
|
||||
500
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "mesh_file_path",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "mesh_file_path"
|
||||
},
|
||||
"link": 6
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"Node name for S&R": "[Comfy3D] Preview 3DMesh"
|
||||
},
|
||||
"widgets_values": [
|
||||
"",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
2161.17333984375,
|
||||
1232.0296630859375
|
||||
2166.6142578125,
|
||||
1234.06982421875
|
||||
],
|
||||
"size": [
|
||||
353.18182373046875,
|
||||
489.7575378417969
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
@@ -105,12 +43,101 @@
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"type": "[Comfy3D] Load PartCrafter Pipeline",
|
||||
"pos": [
|
||||
2166.07470703125,
|
||||
1154.1156005859375
|
||||
],
|
||||
"size": [
|
||||
346.0396423339844,
|
||||
28.720361709594727
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "partcrafter_pipe",
|
||||
"type": "DIFFUSERS_PIPE",
|
||||
"links": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "[Comfy3D] Load PartCrafter Pipeline"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"type": "[Comfy3D] Preview 3DMesh",
|
||||
"pos": [
|
||||
2927.549072265625,
|
||||
1245.26904296875
|
||||
],
|
||||
"size": [
|
||||
600,
|
||||
500
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "mesh_file_path",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "mesh_file_path"
|
||||
},
|
||||
"link": 12
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"Node name for S&R": "[Comfy3D] Preview 3DMesh"
|
||||
},
|
||||
"widgets_values": [
|
||||
"",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "PreviewAny",
|
||||
"pos": [
|
||||
2927.620361328125,
|
||||
1096.464111328125
|
||||
],
|
||||
"size": [
|
||||
342.048828125,
|
||||
88
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "source",
|
||||
"type": "*",
|
||||
"link": 7
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"Node name for S&R": "PreviewAny"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "[Comfy3D] PartCrafter Generate",
|
||||
"pos": [
|
||||
2550.86669921875,
|
||||
1193.7396240234375
|
||||
2569.100341796875,
|
||||
1241.7021484375
|
||||
],
|
||||
"size": [
|
||||
318.76953125,
|
||||
@@ -140,18 +167,16 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "merged_mesh",
|
||||
"type": "MESH",
|
||||
"name": "glb_mesh_path",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
5
|
||||
12
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "processed_image",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
3
|
||||
]
|
||||
"links": []
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
@@ -159,108 +184,16 @@
|
||||
},
|
||||
"widgets_values": [
|
||||
4,
|
||||
228764490511818,
|
||||
836283434168025,
|
||||
"randomize",
|
||||
1024,
|
||||
50,
|
||||
7,
|
||||
1000000000,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "PreviewAny",
|
||||
"pos": [
|
||||
2912.02490234375,
|
||||
1048.1806640625
|
||||
],
|
||||
"size": [
|
||||
350.2099609375,
|
||||
88
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "source",
|
||||
"type": "*",
|
||||
"link": 7
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"Node name for S&R": "PreviewAny"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "[Comfy3D] Save 3D Mesh",
|
||||
"pos": [
|
||||
2933.991943359375,
|
||||
1229.566162109375
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "mesh",
|
||||
"type": "MESH",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "save_path",
|
||||
"type": "STRING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
6
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "[Comfy3D] Save 3D Mesh"
|
||||
},
|
||||
"widgets_values": [
|
||||
"PartCrafter_Test/mesh.glb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "PreviewImage",
|
||||
"pos": [
|
||||
2928.69384765625,
|
||||
1368.6041259765625
|
||||
],
|
||||
"size": [
|
||||
321.450439453125,
|
||||
394.6763916015625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"Node name for S&R": "PreviewImage"
|
||||
},
|
||||
"widgets_values": []
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
@@ -280,30 +213,6 @@
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
3,
|
||||
2,
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
5,
|
||||
2,
|
||||
1,
|
||||
7,
|
||||
0,
|
||||
"MESH"
|
||||
],
|
||||
[
|
||||
6,
|
||||
7,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"STRING"
|
||||
],
|
||||
[
|
||||
7,
|
||||
2,
|
||||
@@ -311,23 +220,31 @@
|
||||
9,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
12,
|
||||
2,
|
||||
1,
|
||||
12,
|
||||
0,
|
||||
"STRING"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.9070294784580498,
|
||||
"scale": 1.0292706480615603,
|
||||
"offset": [
|
||||
-2140.713805878563,
|
||||
-975.661308705606
|
||||
-2024.039719890923,
|
||||
-1063.3672924124076
|
||||
]
|
||||
},
|
||||
"node_versions": {
|
||||
"ComfyUI-3D-Pack": "aedee80e370321bd78221b086445fe8a5f2f8906",
|
||||
"comfy-core": "0.3.44"
|
||||
},
|
||||
"frontendVersion": "1.23.4",
|
||||
"node_versions": {
|
||||
"comfy-core": "0.3.44",
|
||||
"ComfyUI-3D-Pack": "6fa0039ad586bdc6bc4f43af6be92ea3ebd479cb"
|
||||
},
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0,
|
||||
"VHS_MetadataImage": true,
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 452 KiB |
@@ -126,7 +126,7 @@ from Gen_3D_Modules.Hunyuan3D_2_1.hy3dpaint.utils.torchvision_fix import apply_f
|
||||
apply_fix()
|
||||
from Gen_3D_Modules.PartCrafter.partcrafter_src.pipelines.pipeline_partcrafter import PartCrafterPipeline
|
||||
from Gen_3D_Modules.PartCrafter.partcrafter_src.utils.data_utils import get_colored_mesh_composition
|
||||
from Gen_3D_Modules.PartCrafter.partcrafter_src.utils.image_utils import prepare_image
|
||||
from Gen_3D_Modules.PartCrafter.partcrafter_src.utils.render_utils import explode_mesh
|
||||
import zipfile
|
||||
|
||||
|
||||
@@ -262,12 +262,15 @@ class Preview_3DMesh:
|
||||
mesh_folder_path, filename = os.path.split(mesh_file_path)
|
||||
|
||||
if not os.path.isabs(mesh_file_path):
|
||||
mesh_file_path = os.path.join(comfy_paths.output_directory, mesh_folder_path)
|
||||
mesh_file_path = os.path.join(comfy_paths.output_directory, mesh_folder_path, filename)
|
||||
|
||||
if not filename.lower().endswith(SUPPORTED_3D_EXTENSIONS):
|
||||
cstr(f"[{self.__class__.__name__}] File name {filename} does not end with supported 3D file extensions: {SUPPORTED_3D_EXTENSIONS}").error.print()
|
||||
mesh_file_path = ""
|
||||
|
||||
print(f"[Preview_3DMesh] Final mesh path: {mesh_file_path}")
|
||||
print(f"[Preview_3DMesh] File exists: {os.path.exists(mesh_file_path) if mesh_file_path else False}")
|
||||
|
||||
previews = [
|
||||
{
|
||||
"filepath": mesh_file_path,
|
||||
@@ -5584,8 +5587,7 @@ class Hunyuan3D_21_TexGen:
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
# --------------------- PARTCRAFTER ---------------------
|
||||
|
||||
class Load_PartCrafter_Pipeline:
|
||||
"""Load PartCrafter Pipeline"""
|
||||
@@ -5644,12 +5646,13 @@ class Load_PartCrafter_Pipeline:
|
||||
print(f"PartCrafter pipeline loaded")
|
||||
return (pipeline,)
|
||||
|
||||
|
||||
class PartCrafter_Generate:
|
||||
"""PartCrafter Generation"""
|
||||
"""PartCrafter Generation - Creates multi-part 3D scenes with colored components"""
|
||||
|
||||
CATEGORY = "Comfy3D/Algorithm/PartCrafter"
|
||||
RETURN_TYPES = ("STRING", "MESH", "IMAGE")
|
||||
RETURN_NAMES = ("parts_zip_path", "merged_mesh", "processed_image")
|
||||
RETURN_TYPES = ("STRING", "STRING", "IMAGE")
|
||||
RETURN_NAMES = ("parts_zip_path", "glb_mesh_path", "processed_image")
|
||||
FUNCTION = "generate"
|
||||
|
||||
@classmethod
|
||||
@@ -5704,37 +5707,38 @@ class PartCrafter_Generate:
|
||||
use_flash_decoder=use_flash_decoder,
|
||||
).meshes
|
||||
|
||||
# Process results
|
||||
for i in range(len(outputs)):
|
||||
if outputs[i] is None:
|
||||
# If mesh is None (decoding error), use dummy mesh
|
||||
outputs[i] = trimesh.Trimesh(vertices=[[0, 0, 0]], faces=[[0, 0, 0]])
|
||||
# Ensure no None outputs
|
||||
for i, mesh in enumerate(outputs):
|
||||
if mesh is None:
|
||||
outputs[i] = trimesh.Trimesh(vertices=[[0,0,0]], faces=[[0,0,0]])
|
||||
print(f"Replaced None mesh at index {i} with dummy mesh")
|
||||
|
||||
# Create merged mesh
|
||||
merged_mesh_trimesh = get_colored_mesh_composition(outputs)
|
||||
split_mesh = explode_mesh(merged_mesh_trimesh)
|
||||
|
||||
# Debug logging
|
||||
print(f"Merged mesh type: {type(merged_mesh_trimesh)}")
|
||||
print(f"Merged mesh attributes: {dir(merged_mesh_trimesh)}")
|
||||
print(f"PartCrafter result type: {type(merged_mesh_trimesh)}")
|
||||
if hasattr(merged_mesh_trimesh, 'geometry'):
|
||||
print(f"Scene geometry keys: {list(merged_mesh_trimesh.geometry.keys())}")
|
||||
print(f"Scene contains {len(merged_mesh_trimesh.geometry)} parts: {list(merged_mesh_trimesh.geometry.keys())}")
|
||||
|
||||
# Create ZIP with individual parts
|
||||
parts_output_dir = "output/partcrafter_parts"
|
||||
os.makedirs(parts_output_dir, exist_ok=True)
|
||||
|
||||
zip_path = os.path.join(parts_output_dir, f"parts_seed_{seed}.zip")
|
||||
zip_path = os.path.join(parts_output_dir, f"parts.zip")
|
||||
parts = []
|
||||
|
||||
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
||||
for i, part in enumerate(outputs):
|
||||
print(f"Part {i} type: {type(part)}")
|
||||
if part is not None:
|
||||
for idx, mesh in enumerate(outputs):
|
||||
print(f"Part {idx} type: {type(mesh)}")
|
||||
if mesh is not None:
|
||||
# Save part as GLB file
|
||||
part_path = os.path.join(parts_output_dir, f"part_{i:02d}.glb")
|
||||
part.export(part_path)
|
||||
part_path = os.path.join(parts_output_dir, f"part_{idx:02d}.glb")
|
||||
mesh.export(part_path)
|
||||
parts.append(part_path)
|
||||
|
||||
# Add to ZIP
|
||||
zipf.write(part_path, f"part_{i:02d}.glb")
|
||||
zipf.write(part_path, f"part_{idx:02d}.glb")
|
||||
|
||||
# Clean up temporary file
|
||||
try:
|
||||
@@ -5742,56 +5746,48 @@ class PartCrafter_Generate:
|
||||
except:
|
||||
pass
|
||||
|
||||
print(f"Created parts ZIP: {zip_path}")
|
||||
print(f"Created parts ZIP: {zip_path} with {len(parts)} parts")
|
||||
|
||||
# Handle Scene vs Mesh for merged result
|
||||
# Save merged mesh
|
||||
scene_output_dir = "output/partcrafter_scenes"
|
||||
os.makedirs(scene_output_dir, exist_ok=True)
|
||||
scene_file_path = os.path.join(scene_output_dir, f"scene.glb")
|
||||
|
||||
# For Preview_3DMesh, return relative path from ComfyUI output directory
|
||||
relative_scene_path = "partcrafter_scenes/scene.glb"
|
||||
|
||||
# Export the merged mesh (same as app.py: merged.export(merged_path))
|
||||
merged_mesh_trimesh.export(scene_file_path)
|
||||
print(f"Saved merged colored mesh to: {scene_file_path}")
|
||||
|
||||
# Debug: check what was saved
|
||||
if isinstance(merged_mesh_trimesh, trimesh.Scene):
|
||||
print("Merged result is Scene, combining all geometries")
|
||||
if merged_mesh_trimesh.geometry:
|
||||
# Combine all geometries into one mesh
|
||||
all_meshes = []
|
||||
for geom_name in merged_mesh_trimesh.geometry:
|
||||
geom = merged_mesh_trimesh.geometry[geom_name]
|
||||
print(f"Geometry {geom_name}: {type(geom)}, vertices: {len(geom.vertices)}, faces: {len(geom.faces)}")
|
||||
all_meshes.append(geom)
|
||||
|
||||
# Combine all meshes into one
|
||||
if len(all_meshes) > 1:
|
||||
combined_mesh = trimesh.util.concatenate(all_meshes)
|
||||
print(f"Combined mesh: vertices: {len(combined_mesh.vertices)}, faces: {len(combined_mesh.faces)}")
|
||||
else:
|
||||
combined_mesh = all_meshes[0]
|
||||
|
||||
merged_mesh = Mesh.load_trimesh(given_mesh=combined_mesh)
|
||||
else:
|
||||
print("Scene has no geometry, creating dummy mesh")
|
||||
# Create a dummy mesh if scene is empty
|
||||
dummy_trimesh = trimesh.Trimesh(vertices=[[0, 0, 0]], faces=[[0, 0, 0]])
|
||||
merged_mesh = Mesh.load_trimesh(given_mesh=dummy_trimesh)
|
||||
print(f"Exported Scene with {len(merged_mesh_trimesh.geometry)} parts")
|
||||
for geom_name in merged_mesh_trimesh.geometry:
|
||||
geom = merged_mesh_trimesh.geometry[geom_name]
|
||||
print(f" Part {geom_name}: vertices: {len(geom.vertices)}, faces: {len(geom.faces)}")
|
||||
if hasattr(geom.visual, 'vertex_colors') and geom.visual.vertex_colors is not None:
|
||||
print(f" Has vertex colors: {geom.visual.vertex_colors.shape}")
|
||||
else:
|
||||
print("Merged result is Mesh, loading directly")
|
||||
merged_mesh = Mesh.load_trimesh(given_mesh=merged_mesh_trimesh)
|
||||
print(f"Exported single mesh: vertices: {len(merged_mesh_trimesh.vertices)}, faces: {len(merged_mesh_trimesh.faces)}")
|
||||
|
||||
merged_mesh.auto_normal()
|
||||
|
||||
# Save debug merged result
|
||||
# Debug info about the scene
|
||||
try:
|
||||
debug_dir = "output/partcrafter_debug"
|
||||
os.makedirs(debug_dir, exist_ok=True)
|
||||
|
||||
# Save merged result for debugging
|
||||
if isinstance(merged_mesh_trimesh, trimesh.Scene):
|
||||
merged_mesh_trimesh.export(os.path.join(debug_dir, f"merged_scene_seed_{seed}.glb"))
|
||||
print(f"Scene file saved successfully: {scene_file_path}")
|
||||
if os.path.exists(scene_file_path):
|
||||
file_size = os.path.getsize(scene_file_path) / (1024 * 1024) # MB
|
||||
print(f"Scene file size: {file_size:.2f} MB")
|
||||
print(f"Relative path for Preview_3DMesh: {relative_scene_path}")
|
||||
else:
|
||||
merged_mesh_trimesh.export(os.path.join(debug_dir, f"merged_mesh_seed_{seed}.obj"))
|
||||
|
||||
print(f"Debug merged file saved to {debug_dir}")
|
||||
print(f"Warning: Scene file was not created properly")
|
||||
except Exception as e:
|
||||
print(f"Failed to save debug files: {e}")
|
||||
print(f"Error checking scene file: {e}")
|
||||
|
||||
# Processed image
|
||||
processed_image_tensor = pils_to_torch_imgs([pil_image])
|
||||
|
||||
print(f"Generated {len(outputs)} parts")
|
||||
print(f"PartCrafter: Generated {len(outputs)} parts with explode_mesh processing")
|
||||
print(f"GLB mesh path for Preview_3DMesh: {relative_scene_path}")
|
||||
|
||||
return (zip_path, merged_mesh, processed_image_tensor)
|
||||
return (zip_path, relative_scene_path, processed_image_tensor)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user