Spaces:
Sleeping
Sleeping
Patch trellis2/representations/mesh/base.py: guard cumesh and flex_gemm imports
Browse filescumesh and flex_gemm C++ extensions are compiled against torch 2.6.0 and fail
to load under torch 2.8.0 (ABI symbol mismatch). Both imports now have
try/except guards:
- cumesh: fill_holes/remove_faces/simplify become no-ops when unavailable.
o_voxel handles its own decimation; mesh may have minor holes but exports fine.
- flex_gemm grid_sample_3d: query_attrs raises RuntimeError if called, but
it is not invoked in the generation → GLB export pipeline path.
TRELLIS.2/trellis2/representations/mesh/base.py
CHANGED
|
@@ -1,8 +1,24 @@
|
|
| 1 |
from typing import *
|
| 2 |
import torch
|
| 3 |
from ..voxel import Voxel
|
| 4 |
-
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
|
| 8 |
class Mesh:
|
|
@@ -33,10 +49,12 @@ class Mesh:
|
|
| 33 |
return self.to('cpu')
|
| 34 |
|
| 35 |
def fill_holes(self, max_hole_perimeter=3e-2):
|
|
|
|
|
|
|
| 36 |
vertices = self.vertices.cuda()
|
| 37 |
faces = self.faces.cuda()
|
| 38 |
-
|
| 39 |
-
mesh =
|
| 40 |
mesh.init(vertices, faces)
|
| 41 |
mesh.get_edges()
|
| 42 |
mesh.get_boundary_info()
|
|
@@ -52,31 +70,37 @@ class Mesh:
|
|
| 52 |
return
|
| 53 |
mesh.fill_holes(max_hole_perimeter=max_hole_perimeter)
|
| 54 |
new_vertices, new_faces = mesh.read()
|
| 55 |
-
|
| 56 |
self.vertices = new_vertices.to(self.device)
|
| 57 |
self.faces = new_faces.to(self.device)
|
| 58 |
|
| 59 |
def remove_faces(self, face_mask: torch.Tensor):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
vertices = self.vertices.cuda()
|
| 61 |
faces = self.faces.cuda()
|
| 62 |
-
|
| 63 |
-
mesh =
|
| 64 |
mesh.init(vertices, faces)
|
| 65 |
mesh.remove_faces(face_mask)
|
| 66 |
new_vertices, new_faces = mesh.read()
|
| 67 |
-
|
| 68 |
self.vertices = new_vertices.to(self.device)
|
| 69 |
self.faces = new_faces.to(self.device)
|
| 70 |
|
| 71 |
def simplify(self, target=1000000, verbose: bool=False, options: dict={}):
|
|
|
|
|
|
|
| 72 |
vertices = self.vertices.cuda()
|
| 73 |
faces = self.faces.cuda()
|
| 74 |
-
|
| 75 |
-
mesh =
|
| 76 |
mesh.init(vertices, faces)
|
| 77 |
mesh.simplify(target, verbose=verbose, options=options)
|
| 78 |
new_vertices, new_faces = mesh.read()
|
| 79 |
-
|
| 80 |
self.vertices = new_vertices.to(self.device)
|
| 81 |
self.faces = new_faces.to(self.device)
|
| 82 |
|
|
@@ -221,7 +245,7 @@ class MeshWithVoxel(Mesh, Voxel):
|
|
| 221 |
|
| 222 |
def query_attrs(self, xyz):
|
| 223 |
grid = ((xyz - self.origin) / self.voxel_size).reshape(1, -1, 3)
|
| 224 |
-
vertex_attrs =
|
| 225 |
self.attrs,
|
| 226 |
torch.cat([torch.zeros_like(self.coords[..., :1]), self.coords], dim=-1),
|
| 227 |
self.voxel_shape,
|
|
|
|
| 1 |
from typing import *
|
| 2 |
import torch
|
| 3 |
from ..voxel import Voxel
|
| 4 |
+
|
| 5 |
+
# cumesh and flex_gemm are compiled against torch 2.6.0; they fail to load
|
| 6 |
+
# under torch 2.8.0+ due to C++ ABI changes. Guard both and provide minimal
|
| 7 |
+
# stubs so the rest of the module (and the generation pipeline) still works.
|
| 8 |
+
try:
|
| 9 |
+
import cumesh as _cumesh
|
| 10 |
+
_HAS_CUMESH = True
|
| 11 |
+
except Exception:
|
| 12 |
+
_cumesh = None
|
| 13 |
+
_HAS_CUMESH = False
|
| 14 |
+
|
| 15 |
+
try:
|
| 16 |
+
from flex_gemm.ops.grid_sample import grid_sample_3d as _grid_sample_3d
|
| 17 |
+
_HAS_FLEX_GRID = True
|
| 18 |
+
except Exception:
|
| 19 |
+
_HAS_FLEX_GRID = False
|
| 20 |
+
def _grid_sample_3d(*_a, **_kw):
|
| 21 |
+
raise RuntimeError("flex_gemm grid_sample_3d unavailable (ABI mismatch)")
|
| 22 |
|
| 23 |
|
| 24 |
class Mesh:
|
|
|
|
| 49 |
return self.to('cpu')
|
| 50 |
|
| 51 |
def fill_holes(self, max_hole_perimeter=3e-2):
|
| 52 |
+
if not _HAS_CUMESH:
|
| 53 |
+
return # skip; mesh may have small holes but GLB export still works
|
| 54 |
vertices = self.vertices.cuda()
|
| 55 |
faces = self.faces.cuda()
|
| 56 |
+
|
| 57 |
+
mesh = _cumesh.CuMesh()
|
| 58 |
mesh.init(vertices, faces)
|
| 59 |
mesh.get_edges()
|
| 60 |
mesh.get_boundary_info()
|
|
|
|
| 70 |
return
|
| 71 |
mesh.fill_holes(max_hole_perimeter=max_hole_perimeter)
|
| 72 |
new_vertices, new_faces = mesh.read()
|
| 73 |
+
|
| 74 |
self.vertices = new_vertices.to(self.device)
|
| 75 |
self.faces = new_faces.to(self.device)
|
| 76 |
|
| 77 |
def remove_faces(self, face_mask: torch.Tensor):
|
| 78 |
+
if not _HAS_CUMESH:
|
| 79 |
+
keep = ~face_mask.bool().to(self.faces.device)
|
| 80 |
+
self.faces = self.faces[keep]
|
| 81 |
+
return
|
| 82 |
vertices = self.vertices.cuda()
|
| 83 |
faces = self.faces.cuda()
|
| 84 |
+
|
| 85 |
+
mesh = _cumesh.CuMesh()
|
| 86 |
mesh.init(vertices, faces)
|
| 87 |
mesh.remove_faces(face_mask)
|
| 88 |
new_vertices, new_faces = mesh.read()
|
| 89 |
+
|
| 90 |
self.vertices = new_vertices.to(self.device)
|
| 91 |
self.faces = new_faces.to(self.device)
|
| 92 |
|
| 93 |
def simplify(self, target=1000000, verbose: bool=False, options: dict={}):
|
| 94 |
+
if not _HAS_CUMESH:
|
| 95 |
+
return # skip; o_voxel.postprocess handles its own decimation
|
| 96 |
vertices = self.vertices.cuda()
|
| 97 |
faces = self.faces.cuda()
|
| 98 |
+
|
| 99 |
+
mesh = _cumesh.CuMesh()
|
| 100 |
mesh.init(vertices, faces)
|
| 101 |
mesh.simplify(target, verbose=verbose, options=options)
|
| 102 |
new_vertices, new_faces = mesh.read()
|
| 103 |
+
|
| 104 |
self.vertices = new_vertices.to(self.device)
|
| 105 |
self.faces = new_faces.to(self.device)
|
| 106 |
|
|
|
|
| 245 |
|
| 246 |
def query_attrs(self, xyz):
|
| 247 |
grid = ((xyz - self.origin) / self.voxel_size).reshape(1, -1, 3)
|
| 248 |
+
vertex_attrs = _grid_sample_3d(
|
| 249 |
self.attrs,
|
| 250 |
torch.cat([torch.zeros_like(self.coords[..., :1]), self.coords], dim=-1),
|
| 251 |
self.voxel_shape,
|