Skip to content

Instantly share code, notes, and snippets.

@Norod
Created October 8, 2024 09:28
Show Gist options
  • Save Norod/ebb5946cfe4f2edf916005748f5f2669 to your computer and use it in GitHub Desktop.
Save Norod/ebb5946cfe4f2edf916005748f5f2669 to your computer and use it in GitHub Desktop.
Renders a mesh in different view angles and save them as a spritesheet image
import trimesh
from PIL import Image
import numpy as np
import io
# If you are running on Apple Silicon, you may need to comment out the
# following lines as described in this GitHub issue
# to avoid running into an issue with the trimesh library:
# https://github.com/mikedh/trimesh/issues/2084#issuecomment-1840072858
def render_mesh(mesh, angle, resolution=512):
"""
Render the mesh with a given view angle and other parameters.
Parameters
----------
mesh : trimesh.Scene or trimesh.Trimesh
The mesh to render.
angle : (3,) float
Euler angles (pitch, yaw, roll) in radians.
resolution : int
Resolution of the rendered image.
Returns
-------
image : PIL.Image
Rendered image as a PIL Image object.
"""
# Create the transform matrix from the angle and apply it to the mesh
transform = trimesh.transformations.euler_matrix(angle[0], angle[1], angle[2])
mesh.apply_transform(transform)
# Render the mesh with the camera and transform
scene = trimesh.Scene([mesh])
# Set the camera resolution
scene.camera.resolution = (resolution, resolution)
#print(scene.camera_transform)
# Render the image as a PNG byte buffer
image_data = scene.save_image()
image = Image.open(io.BytesIO(image_data))
return image
def create_spritesheet(mesh, angles, resolution=512):
# Number of images per row/column
num_images_per_side = int(np.sqrt(len(angles)))
if num_images_per_side ** 2 != len(angles):
raise ValueError("Spritesheet size must be a perfect square")
# Render each angle
rendered_images = [render_mesh(mesh, angle, resolution) for angle in angles]
# Calculate the dimensions of the spritesheet
image_width, image_height = rendered_images[0].size
spritesheet_width = num_images_per_side * image_width
spritesheet_height = num_images_per_side * image_height
# Create a new blank spritesheet image
spritesheet = Image.new('RGB', (spritesheet_width, spritesheet_height))
# Paste each rendered image into the spritesheet
for i, img in enumerate(rendered_images):
x = (i % num_images_per_side) * image_width
y = (i // num_images_per_side) * image_height
spritesheet.paste(img, (x, y))
return spritesheet
# Load the OBJ mesh
mesh = trimesh.load('humanmalepirateswashbuckler.obj')
# Define angles for rendering
angles = [
[0, -(np.pi / 2), 0], # Front
[np.pi / 2, 0, 0], # Top 90-degree angle
[np.pi, 0, 0], # Bottom 180-degree angle
[np.pi / 2, np.pi / 4, 0], # Side (45 degrees)
[0, np.pi / 4, 0],
[0, np.pi / 4, 0],
[0, np.pi / 4, 0],
[0, np.pi / 4, 0],
[0, np.pi / 4, 0],
]
# Create the spritesheet
spritesheet = create_spritesheet(mesh, angles)
# Save the spritesheet image
spritesheet.save('mesh_spritesheet.png')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment