Repository: Genesis-Embodied-AI/Genesis
File: genesis/utils/mesh.py (Python)

Code before:
def get_hashkey(*args):
    hasher = hashlib.sha256()
    for arg in (*args, gs.__version__.encode()):
        if isinstance(arg, Path):
            file_stats = arg.stat()
            arg = (str(arg).encode(), file_stats.st_size, file_stats.st_mtime)
        if isinstance(arg, str):
            arg = arg.encode()
        elif not isinstance(arg, bytes):
            try:
                arg = bytes(memoryview(arg))
            except TypeError:
                arg = marshal.dumps(arg)
        hasher.update(arg)
    return hasher.hexdigest()


def load_mesh(file, skip_texture=True):
    if isinstance(file, (str, Path)):
        return trimesh.load(file, force="mesh", skip_texture=skip_texture)
    return file


def compute_sdf_data(mesh, res):
    """
    Convert mesh to sdf voxels and a transformation matrix from mesh frame to voxel frame.
    """
    voxels_radius = 0.6
    x = np.linspace(-voxels_radius, voxels_radius, res)
    y = np.linspace(-voxels_radius, voxels_radius, res)
    z = np.linspace(-voxels_radius, voxels_radius, res)
    X, Y, Z = np.meshgrid(x, y, z, indexing="ij")
    query_points = np.stack([X, Y, Z], axis=-1).reshape((-1, 3))

    voxels, *_ = igl.signed_distance(query_points, mesh.vertices, mesh.faces)
    voxels = voxels.reshape((res, res, res)).astype(gs.np_float, copy=False)

    T_mesh_to_sdf = np.eye(4, dtype=gs.np_float)
    T_mesh_to_sdf[:3, :3] *= (res - 1) / (voxels_radius * 2)
    T_mesh_to_sdf[:3, 3] = (res - 1) / 2

    sdf_data = {
        "voxels": voxels,
        "T_mesh_to_sdf": T_mesh_to_sdf,
    }
    return sdf_data


def surface_uvs_to_trimesh_visual(surface, uvs=None, n_verts=None):
    texture = surface.get_rgba()


Review comment (bug):
Why skipping texture would make sense in the first place. This is weird. I would suggest to just load texture systematically, and if it fails, fallback to loading without texture, with a `gs.logger.warning` stating that texture will be skipped because they failed to load.

Code after:
def get_hashkey(*args):
    hasher = hashlib.sha256()
    for arg in (*args, gs.__version__.encode()):
        if isinstance(arg, Path):
            file_stats = arg.stat()
            arg = (str(arg).encode(), file_stats.st_size, file_stats.st_mtime)
        if isinstance(arg, str):
            arg = arg.encode()
        elif not isinstance(arg, bytes):
            try:
                arg = bytes(memoryview(arg))
            except TypeError:
                arg = marshal.dumps(arg)
        hasher.update(arg)
    return hasher.hexdigest()


def load_mesh(file):
    if isinstance(file, (str, Path)):
        try:
            return trimesh.load_mesh(file, force="mesh", skip_texture=False)
        except Exception as e:
            gs.logger.warning(f"Failed to load mesh with texture: {e}")
            # try loading without texture data
            return trimesh.load_mesh(file, force="mesh", skip_texture=True)
    return file


def compute_sdf_data(mesh, res):
    """
    Convert mesh to sdf voxels and a transformation matrix from mesh frame to voxel frame.
    """
    voxels_radius = 0.6
    x = np.linspace(-voxels_radius, voxels_radius, res)
    y = np.linspace(-voxels_radius, voxels_radius, res)
    z = np.linspace(-voxels_radius, voxels_radius, res)
    X, Y, Z = np.meshgrid(x, y, z, indexing="ij")
    query_points = np.stack([X, Y, Z], axis=-1).reshape((-1, 3))

    voxels, *_ = igl.signed_distance(query_points, mesh.vertices, mesh.faces)
    voxels = voxels.reshape((res, res, res)).astype(gs.np_float, copy=False)

    T_mesh_to_sdf = np.eye(4, dtype=gs.np_float)
    T_mesh_to_sdf[:3, :3] *= (res - 1) / (voxels_radius * 2)
    T_mesh_to_sdf[:3, 3] = (res - 1) / 2

    sdf_data = {
        "voxels": voxels,
        "T_mesh_to_sdf": T_mesh_to_sdf,
    }
    return sdf_data