Added the node "Smooth Normals" + Updated "Low Poly" workflow

This commit is contained in:
Bruno Fargnoli
2026-02-02 10:29:03 +01:00
parent f1e883cdb3
commit 2aa5f328cc
2 changed files with 160 additions and 80 deletions
+110 -64
View File
@@ -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": [],
+50 -16
View File
@@ -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",
}