目录
模型TRELLIS.2-4B:
File "/data/lbg/project/chaijian/TRELLIS.2-main/SegviGen-main/inference_full.py", line 302, in inference
with open("microsoft/TRELLIS.2-4B/pipeline.json", "r") as f:
glb2vxz
python
import torch
import trimesh
import os
os.environ['OPENCV_IO_ENABLE_OPENEXR'] = '1'
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
import sys
current_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(current_dir)
print('current_dir', current_dir)
paths = [current_dir, current_dir + '/../']
for path in paths:
sys.path.insert(0, path)
os.environ['PYTHONPATH'] = (os.environ.get('PYTHONPATH', '') + ':' + path).strip(':')
import o_voxel
from PIL import Image
def make_texture_square_pow2(img: Image.Image, target_size=None):
w, h = img.size
max_side = max(w, h)
pow2 = 1
while pow2 < max_side:
pow2 *= 2
if target_size is not None:
pow2 = target_size
pow2 = min(pow2, 2048)
return img.resize((pow2, pow2), Image.BILINEAR)
def preprocess_scene_textures(asset):
if not isinstance(asset, trimesh.Scene):
return asset
TEX_KEYS = ["baseColorTexture", "normalTexture", "metallicRoughnessTexture", "emissiveTexture", "occlusionTexture"]
for geom in asset.geometry.values():
visual = getattr(geom, "visual", None)
mat = getattr(visual, "material", None)
if mat is None:
continue
for key in TEX_KEYS:
if not hasattr(mat, key):
continue
tex = getattr(mat, key)
if tex is None:
continue
if isinstance(tex, Image.Image):
setattr(mat, key, make_texture_square_pow2(tex))
elif hasattr(tex, "image") and tex.image is not None:
img = tex.image
if not isinstance(img, Image.Image):
img = Image.fromarray(img)
tex.image = make_texture_square_pow2(img)
if hasattr(mat, "image") and mat.image is not None:
img = mat.image
if not isinstance(img, Image.Image):
img = Image.fromarray(img)
mat.image = make_texture_square_pow2(img)
return asset
def glb_to_vxz(glb_path, vxz_path):
asset = trimesh.load(glb_path, force='scene')
asset = preprocess_scene_textures(asset)
aabb = asset.bounding_box.bounds
center = (aabb[0] + aabb[1]) / 2
scale = 0.99999 / (aabb[1] - aabb[0]).max()
asset.apply_translation(-center)
asset.apply_scale(scale)
mesh = asset.to_mesh()
vertices = torch.from_numpy(mesh.vertices).float()
faces = torch.from_numpy(mesh.faces).long()
voxel_indices, dual_vertices, intersected = o_voxel.convert.mesh_to_flexible_dual_grid(
vertices, faces, grid_size=512, aabb=[[-0.5, -0.5, -0.5], [0.5, 0.5, 0.5]],
face_weight=1.0, boundary_weight=0.2, regularization_weight=1e-2, timing=False
)
vid = o_voxel.serialize.encode_seq(voxel_indices)
mapping = torch.argsort(vid)
voxel_indices = voxel_indices[mapping]
dual_vertices = dual_vertices[mapping]
intersected = intersected[mapping]
voxel_indices_mat, attributes = o_voxel.convert.textured_mesh_to_volumetric_attr(
asset, grid_size=512, aabb=[[-0.5, -0.5, -0.5], [0.5, 0.5, 0.5]], timing=False
)
vid_mat = o_voxel.serialize.encode_seq(voxel_indices_mat)
mapping_mat = torch.argsort(vid_mat)
attributes = {k: v[mapping_mat] for k, v in attributes.items()}
dual_vertices = dual_vertices * 512 - voxel_indices
dual_vertices = (torch.clamp(dual_vertices, 0, 1) * 255).type(torch.uint8)
intersected = (intersected[:, 0:1] + 2 * intersected[:, 1:2] + 4 * intersected[:, 2:3]).type(torch.uint8)
attributes['dual_vertices'] = dual_vertices
attributes['intersected'] = intersected
o_voxel.io.write(vxz_path, voxel_indices, attributes)
if __name__ == "__main__":
glb_path = "./assets/example.glb"
vxz_path = "./assets/input.vxz"
glb_to_vxz(glb_path, vxz_path)
拆子部件:
子部件是一个整体,只是颜色不一样,需要自行后处理
感谢提供详细的调试输出!现在问题很明确了:颜色来自纹理贴图(PBR材质),而不是顶点或面颜色。因为:
-
网格只有一个几何体(没有多个独立物体)。
-
有 UV坐标 (
visual.uv形状为 (65414, 2)),这是纹理映射的基础。 -
visual.material是 PBRMaterial 类型,说明材质很可能包含基础颜色纹理(baseColorTexture)。
这意味着 :模型的不同区域呈现出不同颜色,是因为纹理图像 上绘制了不同的颜色区域,而网格的所有面共享这一个纹理。要按"颜色"拆分部件,本质上是要根据纹理颜色将面分组,但这相当于对纹理图像做分割并映射回网格,非常复杂且容易出错。