init_code
This commit is contained in:
199
pygarment/meshgen/render/pythonrender.py
Normal file
199
pygarment/meshgen/render/pythonrender.py
Normal file
@@ -0,0 +1,199 @@
|
||||
import os
|
||||
import platform
|
||||
if platform.system() == 'Linux':
|
||||
os.environ["PYOPENGL_PLATFORM"] = "egl"
|
||||
import numpy as np
|
||||
import trimesh
|
||||
import pyrender
|
||||
from PIL import Image
|
||||
|
||||
from pygarment.meshgen.sim_config import PathCofig
|
||||
|
||||
|
||||
def rotate_matrix_y(matrix, angle_deg):
|
||||
rotation_angle = angle_deg * (np.pi / 180)
|
||||
|
||||
# Define the rotation matrix for 180-degree rotation around the y-axis
|
||||
rotation_matrix = np.array([
|
||||
[np.cos(rotation_angle), 0, np.sin(rotation_angle), 0],
|
||||
[0, 1, 0, 0],
|
||||
[-np.sin(rotation_angle), 0, np.cos(rotation_angle), 0],
|
||||
[0, 0, 0, 1]
|
||||
])
|
||||
|
||||
# Apply the rotation to the mesh vertices
|
||||
rot_matrix = np.dot(rotation_matrix, matrix)
|
||||
return rot_matrix
|
||||
|
||||
def rotate_matrix_x(matrix, angle_deg):
|
||||
rotation_angle = angle_deg * (np.pi / 180)
|
||||
|
||||
# Define the rotation matrix for 180-degree rotation around the y-axis
|
||||
rotation_matrix = np.array([
|
||||
[1, 0, 0, 0],
|
||||
[0, np.cos(rotation_angle), -np.sin(rotation_angle), 0],
|
||||
[0, np.sin(rotation_angle), np.cos(rotation_angle), 0],
|
||||
[0, 0, 0, 1]
|
||||
])
|
||||
|
||||
# Apply the rotation to the mesh vertices
|
||||
rot_matrix = np.dot(rotation_matrix, matrix)
|
||||
return rot_matrix
|
||||
|
||||
def get_bounding_box_edges(mesh):
|
||||
# Calculate the bounding box of the mesh
|
||||
min_coords = mesh.bounds[0]
|
||||
max_coords = mesh.bounds[1]
|
||||
|
||||
# Compute the corner points of the bounding box
|
||||
corners = [
|
||||
min_coords,
|
||||
[max_coords[0], min_coords[1], min_coords[2]],
|
||||
[min_coords[0], max_coords[1], min_coords[2]],
|
||||
[max_coords[0], max_coords[1], min_coords[2]],
|
||||
[min_coords[0], min_coords[1], max_coords[2]],
|
||||
[max_coords[0], min_coords[1], max_coords[2]],
|
||||
[min_coords[0], max_coords[1], max_coords[2]],
|
||||
max_coords
|
||||
]
|
||||
|
||||
return corners
|
||||
|
||||
def create_camera(pyrender, pyrender_body_mesh, scene, side, camera_location=None):
|
||||
|
||||
# Create a camera
|
||||
y_fov = np.pi / 6.
|
||||
camera = pyrender.PerspectiveCamera(yfov=y_fov)
|
||||
|
||||
|
||||
if camera_location is None:
|
||||
# Evaluate w.r.t. body
|
||||
|
||||
fov = 50 # Set your desired field of view in degrees
|
||||
|
||||
# # Calculate the bounding box center of the mesh
|
||||
bounding_box_center = pyrender_body_mesh.bounds.mean(axis=0)
|
||||
|
||||
# Calculate the diagonal length of the bounding box
|
||||
diagonal_length = np.linalg.norm(pyrender_body_mesh.bounds[1] - pyrender_body_mesh.bounds[0])
|
||||
|
||||
# Calculate the distance of the camera from the object based on the diagonal length
|
||||
distance = 1.5 * diagonal_length / (2 * np.tan(np.radians(fov / 2)))
|
||||
|
||||
camera_location = bounding_box_center
|
||||
camera_location[-1] += distance
|
||||
|
||||
# Calculate the camera pose
|
||||
camera_pose = np.array([
|
||||
[1.0, 0.0, 0.0, camera_location[0]],
|
||||
[0.0, 1.0, 0.0, camera_location[1]],
|
||||
[0.0, 0.0, 1.0, camera_location[2]],
|
||||
[0.0, 0.0, 0.0, 1.0]
|
||||
])
|
||||
|
||||
camera_pose = rotate_matrix_x(camera_pose, -15)
|
||||
camera_pose = rotate_matrix_y(camera_pose, 20)
|
||||
if side == 'back':
|
||||
camera_pose = rotate_matrix_y(camera_pose, 180)
|
||||
|
||||
# Set camera's pose in the scene
|
||||
scene.add(camera, pose=camera_pose)
|
||||
|
||||
def create_lights(scene, intensity=30.0):
|
||||
light_positions = [
|
||||
np.array([1.60614, 1.5341, 1.23701]),
|
||||
np.array([1.31844, 1.92831, -2.52238]),
|
||||
np.array([-2.80522, 1.2594, 2.34624]),
|
||||
np.array([0.160261, 1.81789, 3.52215]),
|
||||
np.array([-2.65752, 1.41194, -1.26328])
|
||||
]
|
||||
light_colors = [
|
||||
[1.0, 1.0, 1.0],
|
||||
[1.0, 1.0, 1.0],
|
||||
[1.0, 1.0, 1.0],
|
||||
[1.0, 1.0, 1.0],
|
||||
[1.0, 1.0, 1.0]
|
||||
]
|
||||
|
||||
# Add lights to the scene
|
||||
for i in range(5):
|
||||
light = pyrender.PointLight(color=light_colors[i], intensity=intensity)
|
||||
light_pose = np.eye(4)
|
||||
light_pose[:3, 3] = light_positions[i]
|
||||
scene.add(light, pose=light_pose)
|
||||
|
||||
def render(
|
||||
pyrender_garm_mesh, pyrender_body_mesh,
|
||||
side,
|
||||
paths: PathCofig,
|
||||
render_props=None
|
||||
):
|
||||
if render_props and 'resolution' in render_props:
|
||||
view_width, view_height = render_props['resolution']
|
||||
else:
|
||||
view_width, view_height = 1080, 1080
|
||||
# Create a pyrender scene
|
||||
scene = pyrender.Scene(bg_color=(1., 1., 1., 0.)) # Transparent!
|
||||
|
||||
# Create a pyrender mesh object from the trimesh object
|
||||
# Add the mesh to the scene
|
||||
scene.add(pyrender_garm_mesh)
|
||||
scene.add(pyrender_body_mesh)
|
||||
|
||||
camera_location=render_props['front_camera_location'] if 'front_camera_location' in render_props else None
|
||||
create_camera(
|
||||
pyrender, pyrender_body_mesh, scene, side,
|
||||
camera_location=camera_location
|
||||
)
|
||||
|
||||
create_lights(scene, intensity=80.)
|
||||
|
||||
# Create a renderer
|
||||
renderer = pyrender.OffscreenRenderer(viewport_width=view_width, viewport_height=view_height)
|
||||
|
||||
# Render the scene
|
||||
color, _ = renderer.render(scene, flags=pyrender.RenderFlags.RGBA)
|
||||
|
||||
image = Image.fromarray(color)
|
||||
image.save(paths.render_path(side), "PNG")
|
||||
|
||||
def load_meshes(paths:PathCofig, body_v, body_f):
|
||||
# Load body mesh
|
||||
body_mesh = trimesh.Trimesh(body_v, body_f)
|
||||
body_mesh.vertices = body_mesh.vertices / 100
|
||||
# Color body mesh
|
||||
body_material = pyrender.MetallicRoughnessMaterial(
|
||||
baseColorFactor=(0.0, 0.0, 0.0, 1.0), # RGB color, Alpha
|
||||
metallicFactor=0.658, # Range: [0.0, 1.0]
|
||||
roughnessFactor=0.5 # Range: [0.0, 1.0]
|
||||
)
|
||||
pyrender_body_mesh = pyrender.Mesh.from_trimesh(body_mesh, material=body_material)
|
||||
|
||||
|
||||
#Load garment mesh
|
||||
garm_mesh = trimesh.load_mesh(str(paths.g_sim)) # NOTE: Includes the texture
|
||||
garm_mesh.vertices = garm_mesh.vertices / 100 # scale to m
|
||||
|
||||
# Material adjustments
|
||||
material = garm_mesh.visual.material.to_pbr()
|
||||
material.baseColorFactor = [1., 1., 1., 1.]
|
||||
material.doubleSided = True # color both face sides
|
||||
# NOTE remove transparency -- add white background just in case
|
||||
white_back = Image.new('RGBA', material.baseColorTexture.size, color=(255, 255, 255, 255))
|
||||
white_back.paste(material.baseColorTexture)
|
||||
material.baseColorTexture = white_back.convert('RGB')
|
||||
|
||||
garm_mesh.visual.material = material
|
||||
|
||||
pyrender_garm_mesh = pyrender.Mesh.from_trimesh(garm_mesh, smooth=True)
|
||||
|
||||
return pyrender_garm_mesh, pyrender_body_mesh
|
||||
|
||||
def render_images(paths: PathCofig, body_v, body_f, render_props):
|
||||
|
||||
pyrender_garm_mesh, pyrender_body_mesh = load_meshes(paths, body_v, body_f)
|
||||
|
||||
for side in render_props['sides']:
|
||||
render(pyrender_garm_mesh, pyrender_body_mesh, side, paths, render_props)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user