Skip to content

Instantly share code, notes, and snippets.

@promto-c
Last active March 4, 2024 06:27
Show Gist options
  • Select an option

  • Save promto-c/2af74c97a86de519533cf2c0200e1fd7 to your computer and use it in GitHub Desktop.

Select an option

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.
"""
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