def __init__(self, width=1200, height=800, use_offscreen=True): #super().__init__() self.width, self.height = width, height self.use_offscreen = use_offscreen self.render_wireframe = False self.mat_constructor = pyrender.MetallicRoughnessMaterial self.trimesh_to_pymesh = pyrender.Mesh.from_trimesh self.scene = pyrender.Scene(bg_color=colors['white'], ambient_light=(0.3, 0.3, 0.3)) pc = pyrender.PerspectiveCamera(yfov=np.pi / 3.0, aspectRatio=float(width) / height) camera_pose = np.eye(4) camera_pose[:3, 3] = np.array([0, 0, 3.0]) self.camera_node = self.scene.add(pc, pose=camera_pose, name='pc-camera') self.figsize = (width, height) if self.use_offscreen: self.viewer = pyrender.OffscreenRenderer(*self.figsize) self.use_raymond_lighting(4.) else: self.viewer = Viewer(self.scene, use_raymond_lighting=True, viewport_size=self.figsize, cull_faces=False, run_in_thread=True)
def start(self): if self._physics_client is None: self._physics_client = pybullet.connect(pybullet.DIRECT) pybullet.setGravity(0, 0, -GRAVITY_ACCEL, physicsClientId=self._physics_client) self._key_to_id = {} self._key_to_com = {} if self._debug: self._create_scene() self._viewer = Viewer(self._scene, use_raymond_lighting=True, run_in_thread=True)
def view_3d_scene(self): """ Render the scene in a 3D viewer. """ if self.state is None or self.camera is None: raise ValueError('Cannot render 3D scene before state is set! You can set the state with the reset() function') Viewer(self.scene, use_raymond_lighting=True)
def quick_color_visualize(): scene = Scene(bg_color=[0, 0, 0]) root = os.path.expanduser('~') mesh_path = '.keras/paz/datasets/ycb_models/035_power_drill/textured.obj' path = os.path.join(root, mesh_path) mesh = color_object(path) scene.add(mesh) Viewer(scene, use_raymond_lighting=True, flags=RenderFlags.FLAT)
def run(self): """ """ self.viewer = Viewer(self.scene, use_raymond_lighting=False, cull_faces=False, run_in_thread=True) threading.Thread(target=self.accept_messages).start()
def __init__(self, render_scene=None, viewport_size=None, render_flags=None, viewer_flags=None, registered_keys=None, run_in_thread=True, video_filename=None, **kwargs): """ Use render_scene to specify camera or lighting or additional geometries if required. """ _viewer_flags = { 'view_center': np.zeros(3), 'window_title': 'PyPhysX Scene Viewer', 'show_world_axis': True, 'show_mesh_axes': False, 'axes_scale': 0.5, 'use_raymond_lighting': True, 'plane_grid_spacing': 1., 'plane_grid_num_of_lines': 10, 'spheres_count': [8, 8], 'refresh_rate': 30.0, } if viewer_flags is not None: _viewer_flags.update(viewer_flags) fps = _viewer_flags['refresh_rate'] self.video_writer = imageio.get_writer(video_filename, fps=fps) if video_filename is not None else None PyRenderBase.__init__(self, render_scene=render_scene, plane_grid_spacing=_viewer_flags['plane_grid_spacing'], plane_grid_num_of_lines=_viewer_flags['plane_grid_num_of_lines'], spheres_count=_viewer_flags['spheres_count']) Viewer.__init__(self, scene=self.render_scene, viewport_size=viewport_size, render_flags=render_flags, viewer_flags=_viewer_flags, registered_keys=registered_keys, run_in_thread=run_in_thread, **kwargs)
def _run(kwargs): """Internal method that runs the viewer Parameters ---------- kwargs : dict Other keyword arguments for the Viewer instance. """ if 'use_raymond_lighting' not in kwargs: kwargs['use_raymond_lighting'] = True viewer = Viewer(Visualizer3D._scene, viewport_size=Visualizer3D._size, **kwargs) if viewer.viewer_flags['save_directory']: Visualizer3D._save_directory = viewer.viewer_flags[ 'save_directory'] Visualizer3D._kwargs = {} return viewer
def main(mesh_path): # rendering conf ambient_light = 0.8 directional_light = 1.0 img_res = 512 cam_f = 500 cam_c = img_res / 2.0 scene = Scene(ambient_light=np.array( [ambient_light, ambient_light, ambient_light, 1.0])) mesh_v, mesh_vc, mesh_f = load_ply_data(mesh_path) mesh_ = trimesh.Trimesh(vertices=mesh_v, faces=mesh_f, vertex_colors=mesh_vc) points_mesh = Mesh.from_trimesh(mesh_, smooth=True, material=None) mesh_node = scene.add(points_mesh) cam = IntrinsicsCamera(fx=cam_f, fy=cam_f, cx=cam_c, cy=cam_c) cam_pose = np.array([[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 2.0], [0.0, 0.0, 0.0, 1.0]]) direc_l = DirectionalLight(color=np.ones(3), intensity=directional_light) light_node_1 = scene.add(direc_l, pose=np.matmul(rotationy(30), rotationx(45))) direc_l = DirectionalLight(color=np.ones(3), intensity=directional_light) light_node_2 = scene.add(direc_l, pose=np.matmul(rotationy(-30), rotationx(45))) direc_l = DirectionalLight(color=np.ones(3), intensity=directional_light) light_node_3 = scene.add(direc_l, pose=np.matmul(rotationy(-180), rotationx(45))) direc_l = DirectionalLight(color=np.ones(3), intensity=(directional_light - 0.5)) light_node_4 = scene.add(direc_l, pose=np.matmul(rotationy(0), rotationx(-10))) ################ # rendering cam_node = scene.add(cam, pose=cam_pose) render_flags = { 'flip_wireframe': False, 'all_wireframe': False, 'all_solid': False, 'shadows': True, 'vertex_normals': False, 'face_normals': False, 'cull_faces': True, 'point_size': 1.0, } viewer_flags = { 'mouse_pressed': False, 'rotate': False, 'rotate_rate': np.pi / 6.0, 'rotate_axis': np.array([0.0, 1.0, 0.0]), 'view_center': np.array([0.0, 0.0, 0.0]), 'record': False, 'use_raymond_lighting': False, 'use_direct_lighting': False, 'lighting_intensity': 3.0, 'use_perspective_cam': True, 'window_title': 'DIT', 'refresh_rate': 25.0, 'fullscreen': False, 'show_world_axis': False, 'show_mesh_axes': False, 'caption': None, 'save_one_frame': False, } v = Viewer(scene, viewport_size=(512, 512), render_flags=render_flags, viewer_flags=viewer_flags, run_in_thread=False) v.close()
viewer_flags = { 'mouse_pressed': False, 'rotate': False, 'rotate_rate': np.pi / 6.0, 'rotate_axis': np.array([0.0, 1.0, 0.0]), 'view_center': np.array([0.0, 0.0, 0.0]), 'record': False, 'use_raymond_lighting': False, 'use_direct_lighting': False, 'lighting_intensity': 3.0, 'use_perspective_cam': True, 'save_directory': '/home/wanglz14/Desktop/video/', 'window_title': 'FOV Human', 'refresh_rate': 10.0, 'fullscreen': False, 'show_world_axis': False, 'show_mesh_axes': False, 'caption': None } v = Viewer(scene, viewport_size=(800, 800), render_flags=render_flags, viewer_flags=viewer_flags, run_in_thread=True) mesh = trimesh.load('../results/test/01.ply') points_mesh = Mesh.from_trimesh(mesh, smooth=True) v._render_lock.acquire() scene.remove_node(human_node) human_node = scene.add(points_mesh) v._render_lock.release()
from pyrender import Mesh, Scene, Viewer from io import BytesIO import numpy as np import trimesh import requests import time duck_source = "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb" duck = trimesh.load(BytesIO(requests.get(duck_source).content), file_type='glb') duckmesh = Mesh.from_trimesh(list(duck.geometry.values())[0]) scene = Scene(ambient_light=np.array([1.0, 1.0, 1.0, 1.0])) scene.add(duckmesh) orig_positions = duckmesh.primitives[0].positions vwr = Viewer(scene, run_in_thread=True, render_flags={ "cull_faces": False, "all_wireframe": False }, use_raymond_lighting=True, bg_color=[255, 0, 255]) while vwr.is_active: with vwr.render_lock: duckmesh.primitives[0].positions = orig_positions + np.random.randn( *orig_positions.shape) * 2 time.sleep(0.1)
scene.add_node(boxf_node) # ------------------------------------------------------------------------------ # By using the add() utility function # ------------------------------------------------------------------------------ drill_node = scene.add(drill_mesh, pose=drill_pose) bottle_node = scene.add(bottle_mesh, pose=bottle_pose) wood_node = scene.add(wood_mesh) direc_l_node = scene.add(direc_l, pose=cam_pose) spot_l_node = scene.add(spot_l, pose=cam_pose) # ============================================================================== # Using the viewer with a default camera # ============================================================================== v = Viewer(scene, shadows=True) # ============================================================================== # Using the viewer with a pre-specified camera # ============================================================================== cam_node = scene.add(cam, pose=cam_pose) v = Viewer(scene, central_node=drill_node) # ============================================================================== # Rendering offscreen from that camera # ============================================================================== r = OffscreenRenderer(viewport_width=640 * 2, viewport_height=480 * 2) color, depth = r.render(scene) import matplotlib.pyplot as plt
from io import BytesIO import numpy as np import requests import trimesh from pyrender import Mesh, Scene, Viewer duck_source = "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb" duck = trimesh.load(BytesIO(requests.get(duck_source).content), file_type="glb") duckmesh = Mesh.from_trimesh(list(duck.geometry.values())[0]) scene = Scene(ambient_light=np.array([1.0, 1.0, 1.0, 1.0])) scene.add(duckmesh) Viewer(scene)
file_type='glb') duckmesh = Mesh.from_trimesh(list(duck.geometry.values())[0]) # create all available backgrounds bg_idx = 0 bg_imgs = [ Image.open("./models/background.png"), Image.open("./models/wood_uv.png"), None ] background_texs = [ Texture(source=bg_img, source_channels="RGBA") if bg_img else None for bg_img in bg_imgs ] scene = Scene(ambient_light=np.array([1.0, 1.0, 1.0, 1.0]), bg_color=[255, 0, 255], background_texture=background_texs[0]) scene.add(duckmesh) def on_background_toggle(vwr): global bg_idx bg_idx = (bg_idx + 1) % 3 scene.background_texture = background_texs[bg_idx] Viewer(scene, registered_keys={"b": on_background_toggle}, run_in_thread=False, viewport_size=(640, 480))
#============================================================================== scene = Scene(ambient_light=np.array([0.02, 0.02, 0.02, 1.0])) cam_node = scene.add(cam, pose=cam_pose) scene.main_camera_node = cam_node #============================================================================== drill_node = scene.add(drill_mesh) r = OffscreenRenderer(viewport_width=640, viewport_height=480) rf = pyrender.RenderFlags.NONE rf |= pyrender.RenderFlags.USE_RAW_DEPTH color, raw_depth = r.render(scene, flags=rf) r.delete() # unproject to get point cloud pcd = unproj(inv_mvp, raw_depth) #============================================================================== #------------------------------------------------------------------------------ # Creating meshes from point clouds #------------------------------------------------------------------------------ points_mesh = Mesh.from_points(pcd, colors=np.array((0.0, 1.0, 0.0, 1.0))) pcd_node = scene.add(points_mesh) #============================================================================== # Using the viewer with a pre-specified camera #============================================================================== v = Viewer(scene, render_flags={'point_size': 5})
# at_x, at_y, at_z = 0,0,0 # Create camera pose and add it to the scene new_campose, _ = lookAt(distance=distance, alpha=alpha, beta=beta, at_x=at_x, at_y=at_y, at_z=at_z) cam_node = scene.add(camera, pose=new_campose) # A light pointing from the camera's perspective could also be added # point_l_node = scene.add(point_l_cam, pose=new_campose) #============================================================================== # Use viewer to display scene #============================================================================== # View the scene view_render_flags = {'cull_faces': False, 'vertex_normals': False} v = Viewer(scene, render_flags=view_render_flags, viewport_size=(IMAGE_WIDTH, IMAGE_HEIGHT)) #============================================================================== # Prepare for dataset generation #============================================================================== flags = RenderFlags.SKIP_CULL_FACES r = OffscreenRenderer(viewport_width=IMAGE_WIDTH, viewport_height=IMAGE_HEIGHT) # color, _ = r.render(scene, flags=flags) # Generate dataset ? choice = input("Generate dataset? [y/n]: ") accepted_inputs = ['y','n'] while (not (choice in accepted_inputs)): choice = input("Generate dataset? [y/n]: ")
class PybulletPhysicsEngine(PhysicsEngine): """Wrapper for pybullet physics engine that is tied to a single ID""" def __init__(self, urdf_cache_dir, debug=False): PhysicsEngine.__init__(self) self._physics_client = None self._debug = debug self._urdf_cache_dir = urdf_cache_dir if not os.path.isabs(self._urdf_cache_dir): self._urdf_cache_dir = os.path.join( os.getcwd(), self._urdf_cache_dir ) if not os.path.exists(os.path.join(self._urdf_cache_dir, "plane")): os.makedirs(os.path.join(self._urdf_cache_dir, "plane")) shutil.copy( pkg_resources.resource_filename( "sd_maskrcnn", "data/plane/plane.urdf" ), os.path.join(self._urdf_cache_dir, "plane", "plane.urdf"), ) shutil.copy( pkg_resources.resource_filename( "sd_maskrcnn", "data/plane/plane_convex_piece_0.obj" ), os.path.join( self._urdf_cache_dir, "plane", "plane_convex_piece_0.obj" ), ) def add(self, obj, static=False): # create URDF urdf_filename = os.path.join( self._urdf_cache_dir, KEY_SEP_TOKEN.join(obj.key.split(KEY_SEP_TOKEN)[:-1]), "{}.urdf".format( KEY_SEP_TOKEN.join(obj.key.split(KEY_SEP_TOKEN)[:-1]) ), ) urdf_dir = os.path.dirname(urdf_filename) if not os.path.exists(urdf_filename): try: os.makedirs(urdf_dir) except: self._logger.warning( "Failed to create dir %s. The object may have been created simultaneously by another process" % (urdf_dir) ) self._logger.info( "Exporting URDF for object {}".format( KEY_SEP_TOKEN.join(obj.key.split(KEY_SEP_TOKEN)[:-1]) ) ) # Fix center of mass (for rendering) and density and export geometry = obj.mesh.copy() geometry.apply_translation(-obj.mesh.center_mass) trimesh.exchange.export.export_urdf(geometry, urdf_dir) com = obj.mesh.center_mass pose = self._convert_pose(obj.pose, com) obj_t = pose.translation obj_q_wxyz = pose.quaternion obj_q_xyzw = np.roll(obj_q_wxyz, -1) try: obj_id = pybullet.loadURDF( urdf_filename, obj_t, obj_q_xyzw, useFixedBase=static, physicsClientId=self._physics_client, ) except: raise Exception("Failed to load %s" % (urdf_filename)) if self._debug: self._add_to_scene(obj) self._key_to_id[obj.key] = obj_id self._key_to_com[obj.key] = com def get_velocity(self, key): obj_id = self._key_to_id[key] return pybullet.getBaseVelocity( obj_id, physicsClientId=self._physics_client ) def get_pose(self, key): obj_id = self._key_to_id[key] obj_t, obj_q_xyzw = pybullet.getBasePositionAndOrientation( obj_id, physicsClientId=self._physics_client ) obj_q_wxyz = np.roll(obj_q_xyzw, 1) pose = RigidTransform( rotation=obj_q_wxyz, translation=obj_t, from_frame="obj", to_frame="world", ) pose = self._deconvert_pose(pose, self._key_to_com[key]) return pose def remove(self, key): obj_id = self._key_to_id[key] pybullet.removeBody(obj_id, physicsClientId=self._physics_client) self._key_to_id.pop(key) self._key_to_com.pop(key) if self._debug: self._remove_from_scene(key) def step(self): pybullet.stepSimulation(physicsClientId=self._physics_client) if self._debug: time.sleep(0.04) self._update_scene() def reset(self): if self._physics_client is not None: self.stop() self.start() def start(self): if self._physics_client is None: self._physics_client = pybullet.connect(pybullet.DIRECT) pybullet.setGravity( 0, 0, -GRAVITY_ACCEL, physicsClientId=self._physics_client ) self._key_to_id = {} self._key_to_com = {} if self._debug: self._create_scene() self._viewer = Viewer( self._scene, use_raymond_lighting=True, run_in_thread=True ) def stop(self): if self._physics_client is not None: pybullet.disconnect(self._physics_client) self._physics_client = None if self._debug: self._scene = None self._viewer.close_external() while self._viewer.is_active: pass def __del__(self): self.stop() del self def _convert_pose(self, pose, com): new_pose = pose.copy() new_pose.translation = pose.rotation.dot(com) + pose.translation return new_pose def _deconvert_pose(self, pose, com): new_pose = pose.copy() new_pose.translation = pose.rotation.dot(-com) + pose.translation return new_pose def _create_scene(self): self._scene = Scene() camera = PerspectiveCamera( yfov=0.833, znear=0.05, zfar=3.0, aspectRatio=1.0 ) cn = Node() cn.camera = camera pose_m = np.array( [ [0.0, 1.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0], [0.0, 0.0, -1.0, 0.88], [0.0, 0.0, 0.0, 1.0], ] ) pose_m[:, 1:3] *= -1.0 cn.matrix = pose_m self._scene.add_node(cn) self._scene.main_camera_node = cn def _add_to_scene(self, obj): self._viewer.render_lock.acquire() n = Node( mesh=Mesh.from_trimesh(obj.mesh), matrix=obj.pose.matrix, name=obj.key, ) self._scene.add_node(n) self._viewer.render_lock.release() def _remove_from_scene(self, key): self._viewer.render_lock.acquire() if self._scene.get_nodes(name=key): self._scene.remove_node( next(iter(self._scene.get_nodes(name=key))) ) self._viewer.render_lock.release() def _update_scene(self): self._viewer.render_lock.acquire() for key in self._key_to_id.keys(): obj_pose = self.get_pose(key).matrix if self._scene.get_nodes(name=key): next(iter(self._scene.get_nodes(name=key))).matrix = obj_pose self._viewer.render_lock.release()
class MeshViewer(object): def __init__(self, width=1200, height=800, use_offscreen=True): #super().__init__() self.width, self.height = width, height self.use_offscreen = use_offscreen self.render_wireframe = False self.mat_constructor = pyrender.MetallicRoughnessMaterial self.trimesh_to_pymesh = pyrender.Mesh.from_trimesh self.scene = pyrender.Scene(bg_color=colors['white'], ambient_light=(0.3, 0.3, 0.3)) pc = pyrender.PerspectiveCamera(yfov=np.pi / 3.0, aspectRatio=float(width) / height) camera_pose = np.eye(4) camera_pose[:3, 3] = np.array([0, 0, 3.0]) self.camera_node = self.scene.add(pc, pose=camera_pose, name='pc-camera') self.figsize = (width, height) if self.use_offscreen: self.viewer = pyrender.OffscreenRenderer(*self.figsize) self.use_raymond_lighting(4.) else: self.viewer = Viewer(self.scene, use_raymond_lighting=True, viewport_size=self.figsize, cull_faces=False, run_in_thread=True) def set_background_color(self, color=colors['white']): self.scene.bg_color = color def set_cam_trans(self, trans=[0, 0, 3.0]): if isinstance(trans, list): trans = np.array(trans) camera_pose = np.eye(4) camera_pose[:3, 3] = trans self.scene.set_pose(self.camera_node, pose=camera_pose) def update_camera_pose(self, camera_pose): self.scene.set_pose(self.camera_node, pose=camera_pose) def close_viewer(self): if self.viewer.is_active: self.viewer.close_external() def set_meshes(self, meshes, group_name='static', poses=[]): for node in self.scene.get_nodes(): if node.name is not None and '%s-mesh' % group_name in node.name: self.scene.remove_node(node) if len(poses) < 1: for mid, mesh in enumerate(meshes): if isinstance(mesh, trimesh.Trimesh): mesh = pyrender.Mesh.from_trimesh(mesh) self.scene.add(mesh, '%s-mesh-%2d' % (group_name, mid)) else: for mid, iter_value in enumerate(zip(meshes, poses)): mesh, pose = iter_value if isinstance(mesh, trimesh.Trimesh): mesh = pyrender.Mesh.from_trimesh(mesh) self.scene.add(mesh, '%s-mesh-%2d' % (group_name, mid), pose) def set_static_meshes(self, meshes, poses=[]): self.set_meshes(meshes, group_name='static', poses=poses) def set_dynamic_meshes(self, meshes, poses=[]): self.set_meshes(meshes, group_name='dynamic', poses=poses) def _add_raymond_light(self): from pyrender.light import DirectionalLight from pyrender.node import Node thetas = np.pi * np.array([1.0 / 6.0, 1.0 / 6.0, 1.0 / 6.0]) phis = np.pi * np.array([0.0, 2.0 / 3.0, 4.0 / 3.0]) nodes = [] for phi, theta in zip(phis, thetas): xp = np.sin(theta) * np.cos(phi) yp = np.sin(theta) * np.sin(phi) zp = np.cos(theta) z = np.array([xp, yp, zp]) z = z / np.linalg.norm(z) x = np.array([-z[1], z[0], 0.0]) if np.linalg.norm(x) == 0: x = np.array([1.0, 0.0, 0.0]) x = x / np.linalg.norm(x) y = np.cross(z, x) matrix = np.eye(4) matrix[:3, :3] = np.c_[x, y, z] nodes.append( Node(light=DirectionalLight(color=np.ones(3), intensity=1.0), matrix=matrix)) return nodes def use_raymond_lighting(self, intensity=1.0): if not self.use_offscreen: sys.stderr.write( 'Interactive viewer already uses raymond lighting!\n') return for n in self._add_raymond_light(): n.light.intensity = intensity / 3.0 if not self.scene.has_node(n): self.scene.add_node(n) #, parent_node=pc) def render(self, render_wireframe=None, RGBA=False): from pyrender.constants import RenderFlags flags = RenderFlags.SHADOWS_DIRECTIONAL if RGBA: flags |= RenderFlags.RGBA if render_wireframe is not None and render_wireframe == True: flags |= RenderFlags.ALL_WIREFRAME elif self.render_wireframe: flags |= RenderFlags.ALL_WIREFRAME color_img, depth_img = self.viewer.render(self.scene, flags=flags) return color_img def save_snapshot(self, fname): if not self.use_offscreen: sys.stderr.write( 'Currently saving snapshots only works with off-screen renderer!\n' ) return color_img = self.render() cv2.imwrite(fname, color_img)
e = subjectVertex if inside(e): if not inside(s): outputList.append(computeIntersection()) outputList.append(e) elif inside(s): outputList.append(computeIntersection()) s = e cp1 = cp2 return (outputList) # View the scene view_render_flags = {'cull_faces': False} v = Viewer(scene, viewport_size=(width, height), render_flags=view_render_flags) r = OffscreenRenderer(viewport_width=width, viewport_height=height) color, depth = r.render(scene, flags=RenderFlags.SKIP_CULL_FACES) # color = cvtColor(color, COLOR_RGB2BGR) def draw_point(img, imgpts): for point in imgpts: img = circle(img, tuple(point), 4, (255, 0, 0), 2) return img # draw the computed (x,y) coords on the image color = draw_point(color, points) plt.imshow(color)
obj_points_numpy) # Values close to 0 are 0 obj_points_numpy = obj_points_numpy.astype('float32') # Add spheres at the object points in obj_spoints # ball_trimesh = trimesh.creation.icosphere(subdivisions=3) # ball_mesh = Mesh.from_trimesh(ball_trimesh) # for row in obj_points: # scene.add(ball_mesh, pose=spatial_transform_Matrix(scale=0.005, t_x=row[0], t_y=row[1], t_z=row[2])) #============================================================================== # Attempt to convert 3D to 2D position #============================================================================== # View the scene view_render_flags = {'cull_faces': False} v = Viewer(scene, render_flags=view_render_flags) #============================================================================== # Rendering offscreen from that camera #============================================================================== dimensions = 600 # dimensions = 1280 r = OffscreenRenderer(viewport_width=dimensions, viewport_height=dimensions) # Generate dataset ? question_string = "Generate chess board dataset? (select no because it's already there) [y/n]: " choice = input(question_string) accepted_inputs = ['y', 'n'] while (not (choice in accepted_inputs)): choice = input(question_string)
vec = np.array([0, point_size_ndc]) vertices[0, 0:2] = vec vertices[1, 0:2] = _rot_mat(np.radians(120)) @ vec vertices[2, 0:2] = _rot_mat(np.radians(-120)) @ vec mat = MetallicRoughnessMaterial(doubleSided=True, baseColorFactor=[1.0, 0, 0, 1]) instances = [np.eye(4) for i in range(pts_2d.shape[0])] for i in range(pts_2d.shape[0]): instances[i][0, 3] = (2 * pts_2d[i][0] - width) / height instances[i][1, 3] = pts_2d[i][1] / height * 2 - 1 instances[i][2, 3] = -1 prim = Primitive(positions=vertices, mode=GLTF.TRIANGLES, material=mat, poses=instances) return Mesh(primitives=[prim]) pts_mesh = create_2d_point_mesh(640, 480, [[0, 0], [320, 240], [640, 480]], point_size_px=15) duck_node = scene.add(duckmesh) dn = scene.add_hud_node(Node(name="hud", mesh=pts_mesh)) Viewer(scene, run_in_thread=False, viewer_flags={"use_direct_lighting": True}, viewport_size=(640, 480))