MotionGPT / mGPT /render /renderer.py
bill-jiang's picture
Init
4409449
"""
This script is borrowed from https://github.com/mkocabas/VIBE
Adhere to their licence to use this script
It has been modified
"""
import os
import math
import trimesh
import pyrender
import numpy as np
from pyrender.constants import RenderFlags
# os.environ['DISPLAY'] = ':0.0'
# os.environ['PYOPENGL_PLATFORM'] = 'egl'
# os.environ['PYOPENGL_PLATFORM'] = 'osmesa'
SMPL_MODEL_DIR = "data/smpl_data/"
def get_smpl_faces():
return np.load(os.path.join(SMPL_MODEL_DIR, "smplfaces.npy"))
class WeakPerspectiveCamera(pyrender.Camera):
def __init__(self,
scale,
translation,
znear=pyrender.camera.DEFAULT_Z_NEAR,
zfar=None,
name=None):
super(WeakPerspectiveCamera, self).__init__(
znear=znear,
zfar=zfar,
name=name,
)
self.scale = scale
self.translation = translation
def get_projection_matrix(self, width=None, height=None):
P = np.eye(4)
P[0, 0] = self.scale[0]
P[1, 1] = self.scale[1]
P[0, 3] = self.translation[0] * self.scale[0]
P[1, 3] = -self.translation[1] * self.scale[1]
P[2, 2] = -1
return P
class Renderer:
def __init__(self, background=None, resolution=(224, 224), bg_color=[0, 0, 0, 0.5], orig_img=False, wireframe=False, cam_pose=np.eye(4)):
width, height = resolution
self.background = np.zeros((height, width, 3))
self.resolution = resolution
self.faces = get_smpl_faces()
self.orig_img = orig_img
self.wireframe = wireframe
self.renderer = pyrender.OffscreenRenderer(
viewport_width=self.resolution[0],
viewport_height=self.resolution[1],
point_size=0.5
)
# set the scene
self.scene = pyrender.Scene(bg_color=bg_color, ambient_light=(0.4, 0.4, 0.4))
light = pyrender.PointLight(color=[1.0, 1.0, 1.0], intensity=4)
light_pose = np.eye(4)
light_pose[:3, 3] = [0, -1, 1]
self.scene.add(light, pose=np.dot(cam_pose,light_pose).copy())
light_pose[:3, 3] = [0, 1, 1]
self.scene.add(light, pose=np.dot(cam_pose,light_pose).copy())
light_pose[:3, 3] = [1, 1, 2]
self.scene.add(light, pose=np.dot(cam_pose,light_pose).copy())
"""ok
light_pose = np.eye(4)
light_pose[:3, 3] = [0, -1, 1]
self.scene.add(light, pose=light_pose)
light_pose[:3, 3] = [0, 1, 1]
self.scene.add(light, pose=light_pose)
light_pose[:3, 3] = [1, 1, 2]
self.scene.add(light, pose=light_pose)
"""
# light_pose[:3, 3] = [0, -2, 2]
# [droite, hauteur, profondeur camera]
"""
light_pose = np.eye(4)
light_pose[:3, 3] = [0, -1, 1]
self.scene.add(light, pose=light_pose)
light_pose[:3, 3] = [0, 1, 1]
self.scene.add(light, pose=light_pose)
light_pose[:3, 3] = [1, 1, 2]
self.scene.add(light, pose=light_pose)
"""
def render(self, img, verts, cam, angle=None, axis=None, mesh_filename=None, color=[1.0, 1.0, 0.9],
cam_pose=np.eye(4)):
mesh = trimesh.Trimesh(vertices=verts, faces=self.faces, process=False)
Rx = trimesh.transformations.rotation_matrix(math.radians(180), [1, 0, 0])
# Rx = trimesh.transformations.rotation_matrix(math.radians(-90), [1, 0, 0])
mesh.apply_transform(Rx)
if mesh_filename is not None:
mesh.export(mesh_filename)
if angle and axis:
R = trimesh.transformations.rotation_matrix(math.radians(angle), axis)
mesh.apply_transform(R)
sx, sy, tx, ty = cam
camera = WeakPerspectiveCamera(
scale=[sx, sy],
translation=[tx, ty],
zfar=100000.
)
material = pyrender.MetallicRoughnessMaterial(
metallicFactor=0.0, # 0.0 for no specular lighting
# metallicFactor=0.7, # 0.0 for no specular lighting
alphaMode='OPAQUE',
baseColorFactor=(color[0], color[1], color[2], 1.0)
)
mesh = pyrender.Mesh.from_trimesh(mesh, material=material)
mesh_node = self.scene.add(mesh, 'mesh')
cam_node = self.scene.add(camera, pose=cam_pose)
if self.wireframe:
render_flags = RenderFlags.RGBA | RenderFlags.ALL_WIREFRAME
else:
render_flags = RenderFlags.RGBA
rgb, _ = self.renderer.render(self.scene, flags=render_flags)
if rgb.shape[-1]==3:
# Debug
# 0 not distinguish alpha
valid_mask = (rgb[:, :, -1] > 0)[:, :, np.newaxis]
output_img = rgb * valid_mask + (1 - valid_mask) * img
elif rgb.shape[-1]==4:
# valid_mask = (rgb[:, :, -1] > 128)[:, :, np.newaxis]
# output_img = rgb[:, :, :-1] * valid_mask + (1 - valid_mask) * img
# # output alpha
valid_mask = (rgb[:, :, -1] > 128)[:, :]
output_img = np.copy(rgb)
output_img[:, :, -1] *= valid_mask
# output_img = img
else:
raise ValueError(f"rgb shape {rgb.shape[-1]} is not correct!")
image = output_img.astype(np.uint8)
self.scene.remove_node(mesh_node)
self.scene.remove_node(cam_node)
return image
def get_renderer(width, height, cam_pose):
renderer = Renderer(resolution=(width, height),
bg_color=[1, 1, 1, 0.5],
orig_img=False,
wireframe=False,
cam_pose=cam_pose)
return renderer