Last active
March 4, 2024 06:27
-
-
Save promto-c/2af74c97a86de519533cf2c0200e1fd7 to your computer and use it in GitHub Desktop.
Python script to parse UV coordinates from an OBJ file and preview the UV map. This utility reads the UV texture coordinates ('vt') from a specified OBJ file and visualizes the UV map using Matplotlib, providing a quick and simple way to preview the UV unwrapping of 3D models.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| Copyright (C) 2024 promto-c | |
| Permission Notice: | |
| - You are free to use, copy, modify, and distribute this software for any purpose. | |
| - No restrictions are imposed on the use of this software. | |
| - You do not need to give credit or include this notice in your work. | |
| - Use at your own risk. | |
| - This software is provided "AS IS" without any warranty, either expressed or implied. | |
| """ | |
| from typing import List, Tuple | |
| import matplotlib.pyplot as plt | |
| def parse_obj_file(file_path: str) -> Tuple[List[Tuple[float, float]], List[List[int]]]: | |
| """Parse the OBJ file and return UV coordinates and faces. | |
| Args: | |
| file_path: A string path to the .obj file. | |
| Returns: | |
| A tuple containing a list of UV coordinates (each a tuple of floats (u, v)) | |
| and a list of faces (each a list of indices referring to the UV coordinates). | |
| """ | |
| uvs: List[Tuple[float, float]] = [] | |
| faces: List[List[int]] = [] | |
| with open(file_path, 'r') as file: | |
| for line in file: | |
| parts = line.split() | |
| if not parts: | |
| continue | |
| if parts[0] == 'vt': | |
| u = float(parts[1]) | |
| v = float(parts[2]) | |
| uvs.append((u, v)) | |
| elif parts[0] == 'f': | |
| # Assuming the face is defined with vertex/texture/normal indices | |
| face_uv_indices = [int(part.split('/')[1]) - 1 for part in parts[1:]] # OBJ indices start at 1 | |
| faces.append(face_uv_indices) | |
| return uvs, faces | |
| def plot_uv_map(uvs: List[Tuple[float, float]], faces: List[List[int]], is_render_edges: bool = True) -> None: | |
| """Plot the UV map, optionally with edges connecting the UV points. | |
| Args: | |
| uvs: A list of UV coordinates, each a tuple of (u, v) floats. | |
| faces: A list of faces, each a list of indices referring to the UV coordinates. | |
| is_render_edges: A boolean flag indicating whether to render edges. | |
| """ | |
| plt.figure(figsize=(6, 6)) | |
| if is_render_edges: | |
| # Initialize lists to store line segment end points | |
| line_segments_x = [] | |
| line_segments_y = [] | |
| # Collect line segments | |
| for face in faces: | |
| for i in range(len(face)): | |
| start_uv = uvs[face[i]] | |
| end_uv = uvs[face[(i + 1) % len(face)]] # Wrap around to the first vertex | |
| # Append start and end points for each line segment | |
| line_segments_x.extend([start_uv[0], end_uv[0], None]) # None to separate segments | |
| line_segments_y.extend([start_uv[1], end_uv[1], None]) | |
| # Plot all line segments at once | |
| plt.plot(line_segments_x, line_segments_y, color='blue') | |
| # Plot the UV points | |
| u_coords, v_coords = zip(*uvs) | |
| plt.scatter(u_coords, v_coords, marker='.', color='red' if is_render_edges else 'blue') | |
| plt.title('UV Map' + (' with Edges' if is_render_edges else '')) | |
| plt.xlabel('U') | |
| plt.ylabel('V') | |
| plt.axis('equal') | |
| plt.grid(True) | |
| plt.show() | |
| if __name__ == "__main__": | |
| obj_file_path = 'path_to_your_obj_file.obj' # Replace this with the path to your OBJ file | |
| uvs, faces = parse_obj_file(obj_file_path) | |
| plot_uv_map(uvs, faces, is_render_edges=True) # Set to False to not render edges |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment