diff --git a/example_workflows/LowPoly.json b/example_workflows/LowPoly.json index 15f3e61..ed74ffe 100644 --- a/example_workflows/LowPoly.json +++ b/example_workflows/LowPoly.json @@ -1,15 +1,15 @@ { "id": "38599de0-fbb1-45b3-85bd-350be4be0b99", "revision": 0, - "last_node_id": 171, - "last_link_id": 341, + "last_node_id": 172, + "last_link_id": 343, "nodes": [ { "id": 119, "type": "Trellis2PreProcessImage", "pos": [ - 1357.4879980485002, - 810.1374066063063 + 1357.4880522655158, + 810.1377432913037 ], "size": [ 338.1875, @@ -49,15 +49,15 @@ "id": 10, "type": "Preview3D", "pos": [ - 2599.176159559729, - 977.848167140974 + 2599.179449827363, + 977.8483761282848 ], "size": [ - 839.375, - 804.34375 + 831.375, + 757.8125 ], "flags": {}, - "order": 16, + "order": 17, "mode": 0, "inputs": [ { @@ -87,7 +87,7 @@ "ver": "0.4.0", "Node name for S&R": "Preview3D", "widget_ue_connectable": {}, - "Last Time Model File": "Demon_5K_T2_Textured_00001_.glb", + "Last Time Model File": "BattleAxe_Skull_5K_T2_Textured_00001_.glb", "Scene Config": { "showGrid": true, "backgroundColor": "#282828", @@ -99,14 +99,14 @@ "fov": 35, "state": { "position": { - "x": -0.2648644520735538, - "y": 1.9130744008751, - "z": 8.533725216410774 + "x": 1.3746484182480285, + "y": 3.7115237021120526, + "z": 8.609243944537441 }, "target": { - "x": 0, - "y": 2.3652262901077714, - "z": 0 + "x": 0.06851264618030543, + "y": 2.774695192748069, + "z": -0.05880120407407445 }, "zoom": 1, "cameraType": "perspective" @@ -122,7 +122,7 @@ } }, "widgets_values": [ - "Demon_5K_T2_Textured_00001_.glb", + "BattleAxe_Skull_5K_T2_Textured_00001_.glb", "" ] }, @@ -130,8 +130,8 @@ "id": 45, "type": "Trellis2MeshWithVoxelAdvancedGenerator", "pos": [ - 1767.1635346146618, - -114.10762047499145 + 1767.1639555715703, + -114.10767101742454 ], "size": [ 495.8125, @@ -205,8 +205,8 @@ "id": 19, "type": "Trellis2ExportMesh", "pos": [ - 3722.217621150304, - -56.84392071302864 + 3722.219143756678, + -56.84392538923839 ], "size": [ 324, @@ -255,12 +255,12 @@ "id": 69, "type": "Trellis2LoadImageWithTransparency", "pos": [ - 892.153606196694, - 939.1705127098218 + 892.153671159438, + 939.1711468794934 ], "size": [ 788.875, - 908.875 + 938.875 ], "flags": {}, "order": 0, @@ -292,7 +292,7 @@ "widget_ue_connectable": {} }, "widgets_values": [ - "Image_04163_.png", + "battle_axe_with_embedded_skull_3d_game.png", "image" ] }, @@ -300,8 +300,8 @@ "id": 159, "type": "Trellis2Remesh", "pos": [ - 2326.5177834519413, - -99.42783755262815 + 2326.5176031841925, + -99.42788615598494 ], "size": [ 316.625, @@ -346,8 +346,8 @@ "id": 160, "type": "Trellis2SimplifyMesh", "pos": [ - 2703.839515971472, - -90.52389517286747 + 2703.839854715736, + -90.523939391573 ], "size": [ 270, @@ -395,8 +395,8 @@ "id": 161, "type": "Trellis2FillHolesWithMeshlib", "pos": [ - 3035.359019307043, - -85.97360391310178 + 3035.359166460096, + -85.97365143678927 ], "size": [ 249.28125, @@ -438,8 +438,8 @@ "id": 162, "type": "Trellis2MeshWithVoxelToTrimesh", "pos": [ - 3354.195926179601, - -83.69827956007441 + 3354.196116941102, + -83.69832440291476 ], "size": [ 349.40625, @@ -479,8 +479,8 @@ "id": 163, "type": "Trellis2MeshTexturing", "pos": [ - 1740.73846876078, - 1041.36221739427 + 1740.7385238714119, + 1041.3627089428724 ], "size": [ 419.125, @@ -511,7 +511,7 @@ "name": "trimesh", "type": "TRIMESH", "links": [ - 332 + 342 ] }, { @@ -554,8 +554,8 @@ "id": 164, "type": "Trellis2Continue", "pos": [ - 2294.2022484986333, - 811.4789025291578 + 2294.202369111298, + 811.4790325208386 ], "size": [ 225, @@ -602,21 +602,21 @@ "id": 165, "type": "Trellis2ExportMesh", "pos": [ - 2229.6069455613165, - 1072.7520781608714 + 2202.473699765833, + 1181.2855867420053 ], "size": [ 324, 146 ], "flags": {}, - "order": 15, + "order": 16, "mode": 0, "inputs": [ { "name": "trimesh", "type": "TRIMESH", - "link": 332 + "link": 343 }, { "name": "filename_prefix", @@ -652,8 +652,8 @@ "id": 166, "type": "PrimitiveString", "pos": [ - 900.2336795609519, - 552.6948153015276 + 900.2335947425305, + 552.694956150639 ], "size": [ 331.40625, @@ -681,15 +681,15 @@ "widget_ue_connectable": {} }, "widgets_values": [ - "Demon_5K_T2" + "BattleAxe_Skull_5K_T2" ] }, { "id": 167, "type": "StringConcatenate", "pos": [ - 3727.674396199132, - -122.64888891371209 + 3727.6751710278695, + -122.64888950302634 ], "size": [ 225, @@ -735,8 +735,8 @@ "id": 168, "type": "StringConcatenate", "pos": [ - 2219.6067824341803, - 1012.752082375349 + 2219.606967655262, + 1012.7523448008801 ], "size": [ 225, @@ -782,8 +782,8 @@ "id": 170, "type": "Trellis2LoadModel", "pos": [ - 1364.3321561875382, - -17.707215885147775 + 1364.3322312258001, + -17.707259679385793 ], "size": [ 283.34375, @@ -823,8 +823,8 @@ "id": 171, "type": "PrimitiveInt", "pos": [ - 902.6554675309226, - 696.7032007064956 + 902.6554561677136, + 696.7034727830761 ], "size": [ 270, @@ -854,6 +854,44 @@ 5000, "fixed" ] + }, + { + "id": 172, + "type": "Trellis2SmoothNormals", + "pos": [ + 2226.9685287459724, + 1078.936735793132 + ], + "size": [ + 225, + 47.328125 + ], + "flags": {}, + "order": 15, + "mode": 0, + "inputs": [ + { + "name": "trimesh", + "type": "TRIMESH", + "link": 342 + } + ], + "outputs": [ + { + "name": "trimesh", + "type": "TRIMESH", + "links": [ + 343 + ] + } + ], + "properties": { + "aux_id": "visualbruno/ComfyUI-Trellis2", + "ver": "f1e883cdb34689b410e1c0286597a51751be50b2", + "widget_ue_connectable": {}, + "Node name for S&R": "Trellis2SmoothNormals" + }, + "widgets_values": [] } ], "links": [ @@ -945,14 +983,6 @@ 2, "TRIMESH" ], - [ - 332, - 163, - 0, - 165, - 0, - "TRIMESH" - ], [ 333, 165, @@ -1016,6 +1046,22 @@ 160, 1, "INT" + ], + [ + 342, + 163, + 0, + 172, + 0, + "TRIMESH" + ], + [ + 343, + 172, + 0, + 165, + 0, + "TRIMESH" ] ], "groups": [ @@ -1064,10 +1110,10 @@ "workflowRendererVersion": "Vue", "ue_links": [], "ds": { - "scale": 0.35049389948139287, + "scale": 0.5131581182307069, "offset": [ - -68.06044491324586, - 549.777275684317 + -556.7203315201916, + -227.11759657774516 ] }, "links_added_by_ue": [], diff --git a/nodes.py b/nodes.py index e5e9d79..00af183 100644 --- a/nodes.py +++ b/nodes.py @@ -545,7 +545,7 @@ class Trellis2ProgressiveSimplify: def INPUT_TYPES(s): return { "required": { - "max_edge_length": ("FLOAT",{"default":2.64,"min":0.01,"max":99999.99,"step":0.01}), + "max_edge_length": ("FLOAT",{"default":0.00,"min":0.00,"max":99999.99,"step":0.01}), "max_triangle_aspect_ratio": ("FLOAT",{"default":20.00,"min":0.01,"max":99999.99,"step":0.01}), "strategy": (["Minimal Error First","Shortest Edge First"],{"default":"Minimal Error First"}), "stabilizer": ("FLOAT",{"default":0.000001,"min":0.0,"max":0.999999,"step":0.000001}), @@ -599,17 +599,27 @@ class Trellis2ProgressiveSimplify: else: settings.strategy = mrmeshpy.DecimateStrategy.ShortestEdgeFirst - settings.maxEdgeLen = max_edge_length settings.maxTriangleAspectRatio = max_triangle_aspect_ratio settings.stabilizer = stabilizer settings.touchNearBdEdges = touch_near_boundary_edges settings.optimizeVertexPos = optimize_vertex_positions - settings.angleWeightedDistToPlane = angle_based_weights - settings.maxError = max_edge_length / 1000 + settings.angleWeightedDistToPlane = angle_based_weights settings.packMesh = True print('Generating Meshlib Mesh ...') mesh = mrmeshnumpy.meshFromFacesVerts(faces, vertices) + + if max_edge_length == 0.0: + max_edge_length = 2.0 + # for edge_id in mesh.topology.allValidEdges(): + # edge_len = mesh.computeEdgeLen(edge_id) + # if edge_len > max_edge_length: + # max_edge_length = edge_len + # print(f"Calculated Max Edge Length: {max_edge_length}") + + settings.maxEdgeLen = max_edge_length + settings.maxError = max_edge_length / 1000 + print('Packing Optimally ...') mesh.packOptimally() print('Decimating ...') @@ -697,19 +707,19 @@ class Trellis2PostProcessMesh: return { "required": { "mesh": ("MESHWITHVOXEL",), - "fill_holes": ("BOOLEAN", {"default":True}), + "fill_holes": ("BOOLEAN", {"default":False}), "fill_holes_max_perimeter": ("FLOAT",{"default":0.03,"min":0.001,"max":99.999,"step":0.001}), - "remove_duplicate_faces": ("BOOLEAN",{"default":True}), - "repair_non_manifold_edges": ("BOOLEAN", {"default":True}), - "remove_non_manifold_faces": ("BOOLEAN", {"default":True}), - "remove_small_connected_components": ("BOOLEAN", {"default":True}), + "remove_duplicate_faces": ("BOOLEAN",{"default":False}), + "repair_non_manifold_edges": ("BOOLEAN", {"default":False}), + "remove_non_manifold_faces": ("BOOLEAN", {"default":False}), + "remove_small_connected_components": ("BOOLEAN", {"default":False}), "remove_small_connected_components_size": ("FLOAT", {"default":0.00001,"min":0.00001,"max":9.99999,"step":0.00001}), - "unify_faces_orientation": ("BOOLEAN", {"default":True}), - "remove_floaters": ("BOOLEAN",{"default":True}), - "remove_infinite_vertices": ("BOOLEAN",{"default":True}), - "merge_vertices": ("BOOLEAN",{"default":True}), + "unify_faces_orientation": ("BOOLEAN", {"default":False}), + "remove_floaters": ("BOOLEAN",{"default":False}), + "remove_infinite_vertices": ("BOOLEAN",{"default":False}), + "merge_vertices": ("BOOLEAN",{"default":False}), "merge_distance": ("FLOAT",{"default":0.0010,"min":0.0001,"max":999.9999,"step":0.0001}), - "remove_nan_vertices": ("BOOLEAN",{"default":True}), + "remove_nan_vertices": ("BOOLEAN",{"default":False}), }, } @@ -2095,7 +2105,7 @@ class Trellis2PostProcess2: if fill_holes: print('Filling holes ...') - trimesh.fill_holes() + trimesh.fill_holes() new_vertices = torch.from_numpy(trimesh.vertices).float() new_faces = torch.from_numpy(trimesh.faces).int() @@ -2299,7 +2309,29 @@ class Trellis2FillHolesWithMeshlib: mesh_copy.vertices = torch.from_numpy(new_vertices).float().to(mesh_copy.device) mesh_copy.faces = torch.from_numpy(new_faces).int().to(mesh_copy.device) - return (mesh_copy, holes_filled) + return (mesh_copy, holes_filled) + +class Trellis2SmoothNormals: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "trimesh": ("TRIMESH",), + }, + } + + RETURN_TYPES = ("TRIMESH",) + RETURN_NAMES = ("trimesh",) + FUNCTION = "process" + CATEGORY = "Trellis2Wrapper" + + def process(self, trimesh): + new_mesh = trimesh.copy() + new_mesh.vertex_normals = Trimesh.smoothing.get_vertices_normals(new_mesh) + + return (new_mesh,) + + NODE_CLASS_MAPPINGS = { "Trellis2LoadModel": Trellis2LoadModel, @@ -2326,6 +2358,7 @@ NODE_CLASS_MAPPINGS = { "Trellis2ReconstructMesh": Trellis2ReconstructMesh, "Trellis2MeshWithVoxelToMeshlibMesh": Trellis2MeshWithVoxelToMeshlibMesh, "Trellis2FillHolesWithMeshlib": Trellis2FillHolesWithMeshlib, + "Trellis2SmoothNormals": Trellis2SmoothNormals, } @@ -2354,4 +2387,5 @@ NODE_DISPLAY_NAME_MAPPINGS = { "Trellis2ReconstructMesh": "Trellis2 - Reconstruct Mesh", "Trellis2MeshWithVoxelToMeshlibMesh": "Trellis2 - Mesh with Voxel to Meshlib Mesh", "Trellis2FillHolesWithMeshlib": "Trellis2 - Fill Holes with Meshlib", + "Trellis2SmoothNormals": "Trellis2 - Smooth Normals", }