in threestudio/models/exporters/mesh_exporter.py [0:0]
def export_obj_with_mtl(self, mesh: Mesh) -> List[ExporterOutput]:
params = {
"mesh": mesh,
"save_mat": True,
"save_normal": self.cfg.save_normal,
"save_uv": self.cfg.save_uv,
"save_vertex_color": False,
"map_Kd": None, # Base Color
"map_Ks": None, # Specular
"map_Bump": None, # Normal
# ref: https://en.wikipedia.org/wiki/Wavefront_.obj_file#Physically-based_Rendering
"map_Pm": None, # Metallic
"map_Pr": None, # Roughness
"map_format": self.cfg.texture_format,
}
if self.cfg.save_uv:
mesh.unwrap_uv(self.cfg.xatlas_chart_options, self.cfg.xatlas_pack_options)
if self.cfg.save_texture:
threestudio.info("Exporting textures ...")
assert self.cfg.save_uv, "save_uv must be True when save_texture is True"
# clip space transform
uv_clip = mesh.v_tex * 2.0 - 1.0
# pad to four component coordinate
uv_clip4 = torch.cat(
(
uv_clip,
torch.zeros_like(uv_clip[..., 0:1]),
torch.ones_like(uv_clip[..., 0:1]),
),
dim=-1,
)
# rasterize
rast, _ = self.ctx.rasterize_one(
uv_clip4, mesh.t_tex_idx, (self.cfg.texture_size, self.cfg.texture_size)
)
hole_mask = ~(rast[:, :, 3] > 0)
def uv_padding(image):
uv_padding_size = self.cfg.xatlas_pack_options.get("padding", 2)
inpaint_image = (
cv2.inpaint(
(image.detach().cpu().numpy() * 255).astype(np.uint8),
(hole_mask.detach().cpu().numpy() * 255).astype(np.uint8),
uv_padding_size,
cv2.INPAINT_TELEA,
)
/ 255.0
)
return torch.from_numpy(inpaint_image).to(image)
# Interpolate world space position
gb_pos, _ = self.ctx.interpolate_one(
mesh.v_pos, rast[None, ...], mesh.t_pos_idx
)
gb_pos = gb_pos[0]
# Sample out textures from MLP
geo_out = self.geometry.export(points=gb_pos)
mat_out = self.material.export(points=gb_pos, **geo_out)
threestudio.info(
"Perform UV padding on texture maps to avoid seams, may take a while ..."
)
if "albedo" in mat_out:
params["map_Kd"] = uv_padding(mat_out["albedo"])
else:
threestudio.warn(
"save_texture is True but no albedo texture found, using default white texture"
)
if "metallic" in mat_out:
params["map_Pm"] = uv_padding(mat_out["metallic"])
if "roughness" in mat_out:
params["map_Pr"] = uv_padding(mat_out["roughness"])
if "bump" in mat_out:
params["map_Bump"] = uv_padding(mat_out["bump"])
# TODO: map_Ks
return [
ExporterOutput(
save_name=f"{self.cfg.save_name}.obj", save_type="obj", params=params
)
]