def construct_matrices(self): """ Construct FEM matrices """ V = p2e(self.vertices) F = p2e(self.faces) # Compute gradient operator: #F*3 by #V G = igl.eigen.SparseMatrixd() L = igl.eigen.SparseMatrixd() M = igl.eigen.SparseMatrixd() N = igl.eigen.MatrixXd() A = igl.eigen.MatrixXd() igl.grad(V, F, G) igl.cotmatrix(V, F, L) igl.per_face_normals(V, F, N) igl.doublearea(V, F, A) igl.massmatrix(V, F, igl.MASSMATRIX_TYPE_VORONOI, M) G = e2p(G) L = e2p(L) N = e2p(N) A = e2p(A) M = e2p(M) M = M.data # Compute latitude and longitude directional vector fields NS = np.reshape(G.dot(self.lat), [self.nf, 3], order='F') EW = np.cross(NS, N) # Compute F2V matrix (weigh by area) # adjacency i = self.faces.ravel() j = np.arange(self.nf).repeat(3) one = np.ones(self.nf * 3) adj = sparse.csc_matrix((one, (i, j)), shape=(self.nv, self.nf)) tot_area = adj.dot(A) norm_area = A.ravel().repeat(3) / np.squeeze(tot_area[i]) F2V = sparse.csc_matrix((norm_area, (i, j)), shape=(self.nv, self.nf)) # Compute interpolation matrix if self.level > 0: intp = self.intp[self.nv_prev:] i = np.concatenate( (np.arange(self.nv), np.arange(self.nv_prev, self.nv))) j = np.concatenate((np.arange(self.nv_prev), intp[:, 0], intp[:, 1])) ratio = np.concatenate( (np.ones(self.nv_prev), 0.5 * np.ones(2 * intp.shape[0]))) intp = sparse.csc_matrix((ratio, (i, j)), shape=(self.nv, self.nv_prev)) else: intp = sparse.csc_matrix(np.eye(self.nv)) # Compute vertex mean matrix self.G = G # gradient matrix self.L = L # laplacian matrix self.N = N # normal vectors (per-triangle) self.NS = NS # north-south vectors (per-triangle) self.EW = EW # east-west vectors (per-triangle) self.F2V = F2V # map face quantities to vertices self.M = M # mass matrix (area of voronoi cell around node. for integration) self.Seq = self._rotseq(self.vertices) self.Intp = intp
def grad_fun(index, gt_transient, transient, v, f, opt): mesh = MESH() mesh.v = igl.eigen.MatrixXd(v) mesh.f = igl.eigen.MatrixXi(f) igl.per_face_normals(mesh.v, mesh.f, mesh.fn) igl.doublearea(mesh.v, mesh.f, mesh.doublearea) gradient = grad_collocate(index, gt_transient, transient, mesh, opt) return gradient
def render_all_fun(i, v, f, opt): mesh = MESH() mesh.v = igl.eigen.MatrixXd(v) mesh.f = igl.eigen.MatrixXi(f) igl.per_face_normals(mesh.v, mesh.f, mesh.fn) igl.doublearea(mesh.v, mesh.f, mesh.doublearea) transient = mesh_sampling_collocate(mesh, opt.lighting[i,:], opt.lighting_normal[i,:], opt) return transient
def render_all_fun(i, v, f, vn, opt): mesh = MESH() mesh.v = igl.eigen.MatrixXd(v) mesh.f = igl.eigen.MatrixXi(f) mesh.vn = vn igl.per_face_normals(mesh.v, mesh.f, mesh.fn) igl.doublearea(mesh.v, mesh.f, mesh.doublearea) if opt.method == 'n': transient = mesh_sampling_collocate(mesh, opt.lighting[int(i),:], opt.lighting_normal[int(i),:], opt) else: transient = stratified_mesh_sampling_collocate(mesh, opt.lighting[int(i),:], opt.lighting_normal[int(i),:], opt) return transient
def initialize(self): self.vertices = igl.eigen.MatrixXd() self.faces = igl.eigen.MatrixXi() try: if not igl.read_triangle_mesh(self.mesh_path, self.vertices, self.faces): print("failed to read mesh\n") except: traceback.print_exc(file=sys.stdout) sys.exit(-1) self.face_normals = igl.eigen.MatrixXd() igl.per_face_normals(self.vertices, self.faces, self.face_normals) self.vertex_normals = igl.eigen.MatrixXd() igl.per_vertex_normals(self.vertices, self.faces, igl.PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA, self.vertex_normals) self.vertex_data = e2p(self.vertices).astype(dtype=np.float32, order='C') self.index_data = e2p(self.faces).astype(dtype=np.uint32, order='C') self.face_normal_data = e2p(self.face_normals).astype(dtype=np.float32, order='C') self.vertex_normal_data = e2p(self.vertex_normals).astype( dtype=np.float32, order='C') self.num_faces = self.index_data.shape[0] self.num_vertices = self.vertex_data.shape[0] self.center = np.mean(self.vertex_data, axis=0) self.max_vals = np.max(self.vertex_data, axis=0) self.min_vals = np.min(self.vertex_data, axis=0) self.extents = self.max_vals - self.min_vals print("min = %s, max = %s, extents = %s" % (self.min_vals, self.max_vals, self.extents)) self.vertex_data = (self.vertex_data - self.center) / self.extents self.vertex_byte_count = ArrayDatatype.arrayByteCount(self.vertex_data) self.vertex_normal_byte_count = ArrayDatatype.arrayByteCount( self.vertex_normal_data) self.index_byte_count = ArrayDatatype.arrayByteCount(self.index_data)
return True elif key == ord('2'): viewer.data.set_normals(N_vertices) return True elif key == ord('3'): viewer.data.set_normals(N_corners) return True return False # Load a mesh in OFF format igl.readOFF(TUTORIAL_SHARED_PATH + "fandisk.off", V, F) # Compute per-face normals N_faces = igl.eigen.MatrixXd() igl.per_face_normals(V, F, N_faces) # Compute per-vertex normals N_vertices = igl.eigen.MatrixXd() igl.per_vertex_normals(V, F, igl.PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA, N_vertices) # Compute per-corner normals, |dihedral angle| > 20 degrees --> crease N_corners = igl.eigen.MatrixXd() igl.per_corner_normals(V, F, 20, N_corners) # Plot the mesh viewer = igl.viewer.Viewer() viewer.callback_key_pressed = key_pressed viewer.core.show_lines = False viewer.data.set_mesh(V, F) viewer.data.set_normals(N_faces)
print("Press [space] to toggle showing surface.") print("Press '.'/',' to push back/pull forward slicing plane.") # Load mesh: (V,T) tet-mesh of convex hull, F contains original surface triangles igl.readMESH(TUTORIAL_SHARED_PATH + "bunny.mesh", V, T, F) # Call to point_mesh_squared_distance to determine bounds sqrD = igl.eigen.MatrixXd() I = igl.eigen.MatrixXi() C = igl.eigen.MatrixXd() igl.point_mesh_squared_distance(V, V, F, sqrD, I, C) max_distance = math.sqrt(sqrD.maxCoeff()) # Precompute signed distance AABB tree tree.init(V, F) # Precompute vertex, edge and face normals igl.per_face_normals(V, F, FN) igl.per_vertex_normals(V, F, igl.PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE, FN, VN) igl.per_edge_normals(V, F, igl.PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM, FN, EN, E, EMAP) # Plot the generated mesh update_visualization(viewer) viewer.callback_key_down = key_down viewer.data().show_lines = False viewer.launch()
#device = torch.device('cuda:1') device = torch.device('cpu') folder_name = os.getcwd() + '/progress-%f/' % args.lr if not os.path.isdir(folder_name): os.mkdir(folder_name) filename = os.getcwd() + '/setup.mat' setup = scipy.io.loadmat(filename) gt_transient = setup['gt_transient'] #mesh_location = '../mesh_processing/data/bunny.obj' gt_mesh = MESH() gt_mesh.v = igl.eigen.MatrixXd(torch.from_numpy(setup['gt_v']).numpy()) gt_mesh.f = igl.eigen.MatrixXi(torch.from_numpy(setup['gt_f']).numpy()) igl.per_face_normals(gt_mesh.v, gt_mesh.f, gt_mesh.fn) opt = OPT(5000) render_opt = OPT(50000) space_carving_location = os.getcwd() + '/space_carving_mesh.obj' space_carving_mesh = MESH() igl.readOBJ(space_carving_location, space_carving_mesh.v, space_carving_mesh.f) mesh = MESH() #mesh.v = space_carving_mesh.v #mesh.f = space_carving_mesh.f mesh.v = np.array(gt_mesh.v) #mesh.v[:,2] -= 0.1 #mesh.v += np.random.normal(0,0.1,mesh.v.shape) mesh.v = igl.eigen.MatrixXd(mesh.v)
update_visualization(viewer) return True print("Press [space] to toggle showing surface.") print("Press '.'/',' to push back/pull forward slicing plane.") # Load mesh: (V,T) tet-mesh of convex hull, F contains original surface triangles igl.readMESH(TUTORIAL_SHARED_PATH + "bunny.mesh", V, T, F) # Call to point_mesh_squared_distance to determine bounds sqrD = igl.eigen.MatrixXd() I = igl.eigen.MatrixXi() C = igl.eigen.MatrixXd() igl.point_mesh_squared_distance(V, V, F, sqrD, I, C) max_distance = math.sqrt(sqrD.maxCoeff()) # Precompute signed distance AABB tree tree.init(V, F) # Precompute vertex, edge and face normals igl.per_face_normals(V, F, FN) igl.per_vertex_normals(V, F, igl.PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE, FN, VN) igl.per_edge_normals(V, F, igl.PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM, FN, EN, E, EMAP) # Plot the generated mesh update_visualization(viewer) viewer.callback_key_down = key_down viewer.core.show_lines = False viewer.launch()
if __name__ == "__main__": mesh_path = sys.argv[1] print("mesh_path = %s\n" % mesh_path) vertices = igl.eigen.MatrixXd() faces = igl.eigen.MatrixXi() try: if not igl.read_triangle_mesh(mesh_path, vertices, faces): print("failed to read mesh\n") except: traceback.print_exc(file=sys.stdout) sys.exit(-1) face_normals = igl.eigen.MatrixXd() igl.per_face_normals(vertices, faces, face_normals) vertex_normals = igl.eigen.MatrixXd() igl.per_vertex_normals(vertices, faces, igl.PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA, vertex_normals) vertex_data = e2p(vertices).flatten('C').astype(dtype=np.float32, order='C') index_data = e2p(faces).flatten('C').astype(dtype=np.uint32, order='C') face_normal_data = e2p(face_normals).flatten('C').astype(dtype=np.float32, order='C') vertex_normal_data = e2p(vertex_normals).flatten('C').astype( dtype=np.float32, order='C') num_faces = len(index_data) / 3 num_vertices = len(vertex_data) / 3
import pyigl as igl class MESH: v = igl.eigen.MatrixXd() f = igl.eigen.MatrixXi() fn = igl.eigen.MatrixXd() mesh_location = os.getcwd() + '/space_carving_mesh.obj' space_carving_mesh = MESH() read_file = igl.readOBJ(mesh_location, space_carving_mesh.v, space_carving_mesh.f) igl.per_face_normals(space_carving_mesh.v, space_carving_mesh.f, space_carving_mesh.fn) P = igl.eigen.MatrixXd([[0,0,0], [0,0,0.2], [0,0.1,2]]) print(P) S = igl.eigen.MatrixXd() I = igl.eigen.MatrixXi() C = igl.eigen.MatrixXd() N = igl.eigen.MatrixXd() igl.signed_distance(P, space_carving_mesh.v, space_carving_mesh.f, igl.SignedDistanceType(0), S,I,C,N) for x in list(compress(range(P.rows()), S>0)): P.setRow(x, C.row(x)) print(P)
from utils import save_to_stl import trimesh import stl if len(sys.argv) < 2: print( "Usage: verify_feasibility.py [filename] (Optional: robot name in XML file)" ) exit() FNAME = sys.argv[1] # Step 0: Load in an XML file robot as CSG csg_graph, last_name = parse_csg_graph(FNAME) robot_name = last_name VLast, FLast = csg_graph[robot_name] # Face normals FN = igl.eigen.MatrixXd() igl.per_face_normals(VLast, FLast, FN) ## Vertices V = np.array(VLast) ## Faces F = np.array(FLast, dtype=np.int32) ## Face Normals FN = np.array(FN) ## Making the mesh robot = trimesh.base.Trimesh(V, F, FN) # Step 1: Show the robot design to the user (using libigl to show triangle mesh) robot.show()
def optimization(lr): folder_name = os.getcwd() + '/progress3-%f/' % lr if not os.path.isdir(folder_name): os.mkdir(folder_name) filename = os.getcwd() + '/setup_4.mat' setup = scipy.io.loadmat(filename) gt_transient = setup['gt_transient'] gt_mesh = MESH() gt_mesh.v = igl.eigen.MatrixXd(torch.from_numpy(setup['gt_v']).numpy()) gt_mesh.f = igl.eigen.MatrixXi(torch.from_numpy(setup['gt_f']).numpy()) igl.per_face_normals(gt_mesh.v, gt_mesh.f, gt_mesh.fn) igl.doublearea(gt_mesh.v, gt_mesh.f, gt_mesh.doublearea) opt = OPT(5000) render_opt = OPT(50000) smooth_opt = SMOOTH_OPT() opt.space_carving_projection = 1 space_carving_location = os.getcwd() + '/space_carving_mesh4.obj' space_carving_mesh = MESH() igl.readOBJ(space_carving_location, space_carving_mesh.v, space_carving_mesh.f) mesh = MESH() mesh_init_location = os.getcwd() + '/cnlos_5.obj' igl.readOBJ(mesh_init_location, mesh.v, mesh.f) #rendering.space_carving_initialization(mesh, space_carving_mesh, opt) igl.per_face_normals(mesh.v, mesh.f, mesh.fn) igl.doublearea(mesh.v, mesh.f, mesh.doublearea) mesh_optimization = MESH() mesh_optimization.v = torch.from_numpy(np.array(mesh.v)) mesh_optimization.v.requires_grad_() l2, transient, original_l2 = rendering.evaluate_smooth_L2_collocate( gt_transient, mesh, render_opt, smooth_opt) print('%05d update time: %5.5f L2 loss: %5.5f old L2 loss: %5.5f' % (0, 0, l2, original_l2)) filename = folder_name + 'init.mat' scipy.io.savemat(filename, mdict={ 'f': np.array(mesh.f), 'v': np.array(mesh.v), 'optim_v': mesh_optimization.v.data.numpy(), 'gt_v': np.array(gt_mesh.v), 'transient': transient, 'l2': l2, 'gt_transient': gt_transient }) optimizer = optim.Adam([mesh_optimization.v], lr=lr) dummy_loss = torch.sum(mesh_optimization.v) dummy_loss.backward() T = 10 l2_record = np.empty(T) for t in range(T): if t % 30 == 0: if opt.w_width >= 10: opt.w_width -= 10 render_opt.w_width -= 10 opt.sample_num += 500 render_opt.sample_num += 5000 tic = time.time() optimizer.zero_grad() #grad = np.zeros((mesh.v.rows(),3)) #for index in range(opt.lighting.shape[0]): # grad += rendering.grad_collocate(index, gt_transient, transient, mesh, opt) grad = rendering.grad_parallel(gt_transient, transient, mesh, opt) grad += rendering.smooth_grad(mesh, smooth_opt) mesh_optimization.v.grad.data = torch.from_numpy(grad) optimizer.step() if opt.space_carving_projection == 1: mesh.v = rendering.space_carving_projection( mesh_optimization, space_carving_mesh) else: mesh.v = igl.eigen.MatrixXd(mesh_optimization.v.data.numpy()) igl.per_face_normals(mesh.v, mesh.f, mesh.fn) igl.doublearea(mesh.v, mesh.f, mesh.doublearea) l2, transient, original_l2 = rendering.evaluate_smooth_L2_collocate( gt_transient, mesh, render_opt, smooth_opt) print('%05d update time: %5.5f L2 loss: %5.5f old L2 loss: %5.5f' % (t, time.time() - tic, l2, original_l2)) l2_record[t] = l2 filename = folder_name + '%05d.mat' % (t) scipy.io.savemat(filename, mdict={ 'v': np.array(mesh.v), 'transient': transient, 'l2': l2, 'origin_v': mesh_optimization.v.data.numpy(), 'grad': mesh_optimization.v.grad.data.numpy(), 'w_width': opt.w_width }) mesh_optimization.v.data = torch.from_numpy(np.array(mesh.v)) filename = folder_name + 'loss_val.mat' scipy.io.savemat(filename, mdict={'l2': l2_record})