For materials without texture map, this function will create texture map based on Kd. For materials with texture map, this function will multiply the map with Kd value. Args: mtl_filepath: the path to obj material. This function will overwrite mtl and texture maps in the destin
(mtl_filepath: str)
| 151 | |
| 152 | |
| 153 | def map_kd_value_to_textures(mtl_filepath: str): |
| 154 | """ |
| 155 | For materials without texture map, this function will create texture map based on Kd. |
| 156 | For materials with texture map, this function will multiply the map with Kd value. |
| 157 | |
| 158 | Args: |
| 159 | mtl_filepath: the path to obj material. This function will overwrite mtl and texture maps in the destination |
| 160 | |
| 161 | Returns: |
| 162 | """ |
| 163 | with open(mtl_filepath, 'r+') as f: |
| 164 | mtl_dir, _ = os.path.split(mtl_filepath) |
| 165 | mtl_content = f.read().split('newmtl') |
| 166 | f.seek(0) |
| 167 | new_texture_id = 0 |
| 168 | for material in mtl_content: |
| 169 | material_lines = material.splitlines() |
| 170 | Kd_line_ids = [i for i, x in enumerate(material_lines) if x.lstrip().startswith('Kd')] |
| 171 | texture_lines = [x for x in material_lines if x.lstrip().startswith('map_Kd')] |
| 172 | if Kd_line_ids: # Kd_line is not empty, assume it is a valid material |
| 173 | material_lines[0] = 'newmtl' + material_lines[0] # add delimiter back |
| 174 | Kd_line = material_lines[Kd_line_ids[0]] |
| 175 | Kd_values = np.asarray(Kd_line.split()[1:], dtype='f4') # parse three Kd values |
| 176 | |
| 177 | texture_line = None |
| 178 | if texture_lines: |
| 179 | texture_line = texture_lines[0].lstrip() # ignore spaces begin |
| 180 | texture_line = texture_line[6:].replace(" ", "") # remove map_Kd and space |
| 181 | # some files may be missing, check first |
| 182 | if not os.path.exists(os.path.join(mtl_dir, texture_line)): |
| 183 | # remove the map line |
| 184 | material_lines.remove(texture_lines[0]) |
| 185 | texture_line = None |
| 186 | |
| 187 | if texture_line is None: |
| 188 | Kd_values = (Kd_values * 255).astype(np.uint8) |
| 189 | Kd_img = np.tile(np.reshape(Kd_values, [1, 1, 3]), (100, 100, 1)) |
| 190 | # for some reason, open3d would make texture boundary darker |
| 191 | # thus, use small textures (1x1 image) would make texture color non-uniform |
| 192 | # use 100x100 is more robust |
| 193 | Kd_img = Image.fromarray(Kd_img) # reshape to a 1x1 image |
| 194 | new_texture_path = f"new_textures/{new_texture_id}.png" |
| 195 | new_texture_dir = os.path.join(mtl_dir, 'new_textures') |
| 196 | if not os.path.exists(new_texture_dir): |
| 197 | os.makedirs(new_texture_dir) |
| 198 | Kd_img.save(os.path.join(mtl_dir, new_texture_path)) |
| 199 | material_lines[-1] = f"map_Kd ./{new_texture_path}" # replace last empty line by map_Kd |
| 200 | material_lines.append("") |
| 201 | new_texture_id += 1 |
| 202 | else: |
| 203 | with Image.open(os.path.join(mtl_dir, texture_line)) as Kd_img: |
| 204 | Kd_img_array = mesh_utils.clean_texture(np.asarray(Kd_img)) |
| 205 | Kd_img_array = Kd_img_array * Kd_values |
| 206 | Kd_img = Image.fromarray(Kd_img_array.astype(np.uint8)) |
| 207 | Kd_img.save(os.path.join(mtl_dir, texture_line)) |
| 208 | material_lines[Kd_line_ids[0]] = 'Kd 1 1 1' # no need for Kd values anymore |
| 209 | |
| 210 | for x in material_lines: |
no test coverage detected