def process(self): if not any(output.is_linked for output in self.outputs): return InVert, InEdge, InEdSel = self.inputs OutVert, OutEdg, OutFace, ONVert, ONEdg, ONFace, OOVert, OOEdg, OOFace = self.outputs vertices_s = InVert.sv_get() topo = InEdge.sv_get() if len(topo[0][0]) == 2: bmlist= [bmesh_from_pydata(v, e, [], normal_update=True) for v,e in zip(vertices_s,topo)] else: bmlist= [bmesh_from_pydata(v, [], e, normal_update=True) for v,e in zip(vertices_s,topo)] rev, ree, ref, riv, rie, rif, rsv, rse, rsf = [],[],[],[],[],[],[],[],[] if InEdSel.is_linked: if self.sel_mode == "index": useedges = [np.array(bm.edges[:])[idxs] for bm, idxs in zip(bmlist, InEdSel.sv_get())] elif self.sel_mode == "mask": useedges = [np.extract(mask, bm.edges[:]) for bm, mask in zip(bmlist, InEdSel.sv_get())] else: useedges = [bm.edges for bm in bmlist] for bm,ind in zip(bmlist,useedges): geom = subdivide_edges(bm, edges=ind, smooth=self.smooth, smooth_falloff=int(self.falloff_type), fractal=self.fractal, along_normal=self.along_normal, cuts=self.cuts, seed=self.seed, quad_corner_type=int(self.corner_type), use_grid_fill=self.grid_fill, use_single_edge=self.single_edge, use_only_quads=self.only_quads, use_smooth_even=self.smooth_even) new_verts, new_edges, new_faces = pydata_from_bmesh(bm) rev.append(new_verts) ree.append(new_edges) ref.append(new_faces) if self.show_new: geo1 = geom['geom_inner'] riv.append([tuple(v.co) for v in geo1 if isinstance(v, bmesh.types.BMVert)]) rie.append([[v.index for v in e.verts] for e in geo1 if isinstance(e, bmesh.types.BMEdge)]) rif.append([[v.index for v in f.verts] for f in geo1 if isinstance(f, bmesh.types.BMFace)]) if self.show_old: geo2 = geom['geom_split'] rsv.append([tuple(v.co) for v in geo2 if isinstance(v, bmesh.types.BMVert)]) rse.append([[v.index for v in e.verts] for e in geo2 if isinstance(e, bmesh.types.BMEdge)]) rsf.append([[v.index for v in f.verts] for f in geo2 if isinstance(f, bmesh.types.BMFace)]) bm.free() OutVert.sv_set(rev) OutEdg.sv_set(ree) OutFace.sv_set(ref) ONVert.sv_set(riv) ONEdg.sv_set(rie) ONFace.sv_set(rif) OOVert.sv_set(rsv) OOEdg.sv_set(rse) OOFace.sv_set(rsf)
def process(self): if not (self.outputs['Vers'].is_linked and self.inputs['Vers'].is_linked): return vertices = Vector_generate(self.inputs['Vers'].sv_get()) faces = self.inputs['Pols'].sv_get() offset = self.inputs['Offset'].sv_get()[0] nsides = self.inputs['N sides'].sv_get()[0][0] radius = self.inputs['Radius'].sv_get()[0] outv = [] oute = [] outo = [] outn = [] # for each object for verts_obj, faces_obj in zip(vertices, faces): fullList(offset, len(faces_obj)) fullList(radius, len(faces_obj)) verlen = set(range(len(verts_obj))) bm = bmesh_from_pydata(verts_obj, [], faces_obj, normal_update=True) result = self.Offset_pols(bm, offset, radius, nsides, verlen) outv.append(result[0]) oute.append(result[1]) outo.append(result[2]) outn.append(result[3]) self.outputs['Vers'].sv_set(outv) self.outputs['Edgs'].sv_set(oute) self.outputs['OutPols'].sv_set(outo) self.outputs['InPols'].sv_set(outn)
def modal(self, context, event): context.area.tag_redraw() scn = context.scene if event.type in {'MIDDLEMOUSE'}: return {'RUNNING_MODAL'} if event.type in {'RIGHTMOUSE', 'ESC'}: bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') return {'CANCELLED'} if event.type in {'RET'}: bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.modifier_apply(apply_as='DATA', modifier="sv_bool") context.active_object.show_wire = False context.active_object.show_all_edges = False bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} scalar = scn.BGL_OFFSET_SCALAR VB, PB = generate_boolean_geom(self.verts, self.normal, scalar) bm = bmesh_from_pydata(VB, [], PB) n_obj = new_obj(bm, "ExtractObject", "Extract_mesh") n_obj.hide = True obj = bpy.context.active_object attache_boolean_modifier(obj, n_obj) return {'PASS_THROUGH'}
def process(self): # достаём два слота - вершины и полики if 'Centers' in self.outputs and self.outputs['Centers'].links or self.outputs['Normals'].links: if 'Polygons' in self.inputs and 'Vertices' in self.inputs and self.inputs['Polygons'].links and self.inputs['Vertices'].links: #if type(self.inputs['Poligons'].links[0].from_socket) == StringsSocket: pols = SvGetSocketAnyType(self, self.inputs['Polygons']) #if type(self.inputs['Vertices'].links[0].from_socket) == VerticesSocket: vers = SvGetSocketAnyType(self, self.inputs['Vertices']) normalsFORout = [] for i, obj in enumerate(vers): """ mesh_temp = bpy.data.meshes.new('temp') mesh_temp.from_pydata(obj, [], pols[i]) mesh_temp.update(calc_edges=True) """ bm = bmesh_from_pydata(obj, [], pols[i]) bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:]) bm.verts.ensure_lookup_table() verts = bm.verts tempobj = [] for idx in range(len(verts)): tempobj.append(verts[idx].normal[:]) normalsFORout.append(tempobj) bm.free() #bpy.data.meshes.remove(mesh_temp) #print (normalsFORout) if 'Normals' in self.outputs and self.outputs['Normals'].links: SvSetSocketAnyType(self, 'Normals', normalsFORout)
def process(self): if not (self.inputs[0].is_linked and self.inputs[2].is_linked): return if not any(self.outputs[name].is_linked for name in ['Vertices', 'Edges', 'Polygons', 'NewPolys']): return out, result_bevel_faces = [], [] meshes = match_long_repeat(self.get_socket_data()) for vertices, edges, faces, bevel_edges, offset, segments, profile in zip(*meshes): bm = bmesh_from_pydata(vertices, edges, faces) b_edges = get_bevel_edges(bm, bevel_edges) geom = list(bm.verts) + list(b_edges) + list(bm.faces) bevel_faces = bmesh.ops.bevel( bm, geom=geom, offset=offset, offset_type=int(self.offsetType), segments=segments, profile=profile, vertex_only=self.vertexOnly, material=-1)['faces'] new_bevel_faces = [[v.index for v in face.verts] for face in bevel_faces] out.append(pydata_from_bmesh(bm)) bm.free() result_bevel_faces.append(new_bevel_faces) Vertices, Edges, Polygons, NewPolygons = self.outputs Vertices.sv_set([i[0] for i in out]) Edges.sv_set([i[1] for i in out]) Polygons.sv_set([i[2] for i in out]) NewPolygons.sv_set(result_bevel_faces)
def process(self): vers = self.inputs['Vertices'].sv_get() pols = self.inputs['Polygons'].sv_get() normalsFORout = [] for i, obj in enumerate(vers): """ mesh_temp = bpy.data.meshes.new('temp') mesh_temp.from_pydata(obj, [], pols[i]) mesh_temp.update(calc_edges=True) """ bm = bmesh_from_pydata(obj, [], pols[i]) bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:]) bm.verts.ensure_lookup_table() verts = bm.verts tempobj = [] for idx in range(len(verts)): tempobj.append(verts[idx].normal[:]) normalsFORout.append(tempobj) bm.free() if self.outputs['Normals'].is_linked: self.outputs['Normals'].sv_set(normalsFORout)
def line(p1=[(0,0,0)], p2=[(1,0,0)], nverts=2, mode='pydata'): ''' line(p1=[(0,0,0)], p2=[(1,0,0)], nverts=2, mode='pydata') not finished.. ''' nv = nverts if mode in {'pydata', 'bm'}: verts = [] edges = [] num_verts = 0 for v1, v2 in zip(p1, p2): if nv == 2: verts.extend([v1, v2]) elif nv > 2: x_seg = (v2[0] - v1[0]) / (nv-1) y_seg = (v2[1] - v1[1]) / (nv-1) z_seg = (v2[2] - v1[2]) / (nv-1) verts.append(v1) verts.extend([[v1[0] + (x_seg * i), v1[1] + (y_seg * i), v1[2] + (z_seg * i)] for i in range(1, nv-1)]) verts.append(v2) edges.extend([[i + num_verts, i + 1 + num_verts] for i in range(nv-1)]) num_verts = len(verts) if mode == 'pydata': return verts, edges else: return bmesh_from_pydata(verts, edges, []) if mode == 'np': pass
def rect(dim_x=1.0, dim_y=1.62, radius=0.0, nverts=5, matrix=None, mode='pydata'): xdim = dim_x / 2 ydim = dim_y / 2 if mode in {'pydata', 'bm'}: verts = [] if radius == 0.0 or nverts < 2: verts = [[-xdim, ydim, 0], [xdim, ydim, 0], [xdim, -ydim, 0], [-xdim, -ydim, 0]] elif radius > 0.0 and radius < min(abs(dim_x), abs(dim_y)) and nverts >= 2: theta = HALF_PI / (nverts-1) xdim = xdim - radius ydim = ydim - radius coords = [[xdim, ydim], [xdim, -ydim], [-xdim, -ydim], [-xdim, ydim]] for (x, y), corner in zip(coords, range(4)): for i in range(nverts): rad = theta * i verts.append(((math.sin(rad + (corner*HALF_PI)) * radius) + x, (math.cos(rad + (corner*HALF_PI)) * radius) + y, 0)) num_verts = len(verts) edges = [[i, i+1] for i in range(num_verts-1)] + [[num_verts-1, 0]] faces = [i for i in range(num_verts)] if mode == 'pydata': return verts, edges, [faces] else: return bmesh_from_pydata(verts, edges, [faces]) if mode == 'np': pass
def remove_doubles_from_edgenet(verts_in, edges_in, distance): bm = bmesh_from_pydata(verts_in, edges_in, []) bmesh.ops.remove_doubles(bm, verts=bm.verts[:], dist=distance) verts_out = [v.co.to_tuple() for v in bm.verts] edges_out = [[j.index for j in i.verts] for i in bm.edges] return verts_out, edges_out
def solidify(vertices, faces, t, verlen): if not faces or not vertices: return False if len(faces[0]) == 2: return False bm = bmesh_from_pydata(vertices, [], faces) geom_in = bm.verts[:]+bm.edges[:]+bm.faces[:] bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:]) bmesh.ops.solidify(bm, geom=geom_in, thickness=t[0]) edges = [] faces = [] newpols = [] bm.verts.index_update() bm.edges.index_update() bm.faces.index_update() for edge in bm.edges[:]: edges.append([v.index for v in edge.verts[:]]) verts = [vert.co[:] for vert in bm.verts[:]] for face in bm.faces: indexes = [v.index for v in face.verts[:]] faces.append(indexes) if not verlen.intersection(indexes): newpols.append(indexes) bm.clear() bm.free() return (verts, edges, faces, newpols)
def make_bmesh_geometry(node, context, geometry, idx, layers): scene = context.scene meshes = bpy.data.meshes objects = bpy.data.objects verts, edges, matrix, _, _ = geometry name = node.basemesh_name + '.' + str("%04d" % idx) # remove object if name in objects: obj = objects[name] # assign the object an empty mesh, this allows the current mesh # to be uncoupled and removed from bpy.data.meshes obj.data = assign_empty_mesh(idx) # remove uncoupled mesh, and add it straight back. if name in meshes: meshes.remove(meshes[name]) mesh = meshes.new(name) obj.data = mesh else: # this is only executed once, upon the first run. mesh = meshes.new(name) obj = objects.new(name, mesh) scene.objects.link(obj) # at this point the mesh is always fresh and empty obj['idx'] = idx obj['basename'] = node.basemesh_name data_layers = None if node.distance_doubles > 0.0: bm = bmesh_from_pydata(verts, edges, []) verts, edges, faces, d1, d2 = shrink_geometry(bm, node.distance_doubles, layers) data_layers = d1, d2 force_pydata(obj.data, verts, edges) obj.update_tag(refresh={'OBJECT', 'DATA'}) if node.live_updates: if 'sv_skin' in obj.modifiers: sk = obj.modifiers['sv_skin'] obj.modifiers.remove(sk) if 'sv_subsurf' in obj.modifiers: sd = obj.modifiers['sv_subsurf'] obj.modifiers.remove(sd) _ = obj.modifiers.new(type='SKIN', name='sv_skin') b = obj.modifiers.new(type='SUBSURF', name='sv_subsurf') b.levels = node.levels b.render_levels = node.render_levels if matrix: matrix = matrix_sanitizer(matrix) obj.matrix_local = matrix else: obj.matrix_local = Matrix.Identity(4) return obj, data_layers
def storage_set_data(self, storage): geom = storage['geom'] name = storage['params']["obj_name"] geom_dict = json.loads(geom) if not geom_dict: print(self.name, 'contains no flatten geom') return unrolled_geom = unflatten(geom_dict) verts = unrolled_geom['Vertices'] edges = unrolled_geom['Edges'] polygons = unrolled_geom['Polygons'] matrix = unrolled_geom['Matrix'] bm = bmesh_from_pydata(verts, edges, polygons) obj = generate_object(name, bm) obj.matrix_world = matrix # rename if obj existed if not obj.name == name: storage['params']["obj_name"] = obj.name self.id_data.freeze(hard=True) self.obj_name = obj.name self.id_data.unfreeze(hard=True)
def intersect_edges_3d(verts_in, edges_in, s_epsilon): bm = bmesh_from_pydata(verts_in, edges_in, []) edge_indices = [e.index for e in bm.edges] trim_indices = len(edge_indices) for edge in bm.edges: edge.select = True cm = CAD_ops(epsilon=s_epsilon) d = get_intersection_dictionary(cm, bm, edge_indices) unselect_nonintersecting(bm, d.keys(), edge_indices) # store non_intersecting edge sequencer add_back = [[i.index for i in edge.verts] for edge in bm.edges if not edge.select] update_mesh(bm, d) verts_out = [v.co.to_tuple() for v in bm.verts] edges_out = [[j.index for j in i.verts] for i in bm.edges] # optional correction, remove originals, add back those that are not intersecting. edges_out = edges_out[trim_indices:] edges_out.extend(add_back) bm.free() return verts_out, edges_out
def process(self): # bmesh operations verts = self.inputs['verts'].sv_get() faces = self.inputs['faces'].sv_get() face_masks = self.inputs['face_masks'].sv_get() out_verts, out_faces = [], [] for _verts, _faces, _face_mask in zip(verts, faces, face_masks): bm = bmesh_from_pydata(_verts, [], _faces, normal_update=True) sel = [] add_sell = sel.append for f in (f for f in bm.faces if f.index in set(_face_mask)): f.select = True add_sell(f) generated_data = perform_mextrude(self, bm, sel) if generated_data: outv, outf = generated_data out_verts.append(outv) out_faces.append(outf) self.outputs['verts'].sv_set(out_verts) self.outputs['faces'].sv_set(out_faces)
def fillet(verts, edges, adj, num_seg): bm = bmesh_from_pydata(verts[0], edges[0], []) this_fillet = fillet_op0(bm, adj, num_seg) verts_out = [v.co[:] for v in bm.verts] edges_out = [[i.index for i in p.verts] for p in bm.edges[:]] return verts_out, edges_out
def process(self): BML, Verts, Edges, Polys, vermask, edgmask, angllim = self.inputs o1,o2,o3,o4,o5 = self.outputs angle = angllim.sv_get()[0] ret = [] bmlist = BML.sv_get([]) if Verts.is_linked: bmlist.extend([bmesh_from_pydata(verts, edges, faces, normal_update=True) for verts, edges, faces in zip(*mlr([Verts.sv_get(), Edges.sv_get([[]]), Polys.sv_get([[]])]))]) if vermask.is_linked: verm = [np.array(bm.verts[:])[ma] for bm,ma in zip(bmlist,vermask.sv_get())] else: verm = [bm.verts for bm in bmlist] if edgmask.is_linked: edgm = [np.array(bm.edges[:])[ma] for bm,ma in zip(bmlist,edgmask.sv_get())] else: edgm = [bm.edges for bm in bmlist] udb, dlm = self.use_dissolve_boundaries, self.delimit for bm, ang, vm, em in zip(bmlist, safc(bmlist, angle), verm, edgm): # it's a little undocumented.. ret.append(dissolve_limit(bm, angle_limit=ang, use_dissolve_boundaries=udb, verts=vm, edges=em, delimit=dlm)['region']) if o1.is_linked: o1.sv_set([[v.co[:] for v in bm.verts]for bm in bmlist]) if o2.is_linked: o2.sv_set([[[i.index for i in e.verts] for e in bm.edges]for bm in bmlist]) if o3.is_linked: o3.sv_set([[[i.index for i in p.verts] for p in bm.faces]for bm in bmlist]) if o4.is_linked: o4.sv_set(ret) if o5.is_linked: o5.sv_set(bmlist)
def grid(dim_x=1.0, dim_y=1.62, nx=2, ny=2, anchor=0, matrix=None, mode='pydata'): ''' dim_x - total dimension on x side dim_y - total dimension on y side nx - num verts on x side ny - num verts on y side anchor - 1 --- 2 --- 3 - - 8 0 4 - - 7 --- 6 --- 5 default is centered (0) ''' xside = dim_x / 2 yside = dim_y / 2 nx = max(2, nx) ny = max(2, ny) anchors = { 1: (0, dim_x, 0, dim_y), 2: (-xside, xside, 0, dim_y), 3: (-dim_x, 0, 0, dim_y), 4: (-dim_x, 0, -yside, yside), 5: (-dim_x, 0, 0, -dim_y), 6: (-xside, xside, 0, -dim_y), 7: (0, dim_x, 0, -dim_y), 8: (0, dim_x, -yside, yside), 0: (-xside, xside, -yside, yside) }.get(anchor, (-xside, xside, -yside, yside)) if mode in {'pydata', 'bm'}: verts = [] faces = [] add_face = faces.append total_range = ((ny-1) * (nx)) a, b = anchors[:2] c, d = anchors[2:] x = np.linspace(a, b, nx) y = np.linspace(c, d, ny) f = np.vstack(np.meshgrid(x, y, 0)).reshape(3, -1).T verts = f.tolist() for i in range(total_range): if not ((i + 1) % nx == 0): # +1 is the shift add_face([i, i+nx, i+nx+1, i+1]) # clockwise if mode == 'pydata': return verts, [], faces else: return bmesh_from_pydata(vert, [], faces) if mode == 'np': pass
def circle(radius=1.0, phase=0, nverts=20, matrix=None, mode='pydata'): ''' parameters: radius: float phase: where to start the unit circle nverts: number of verts of the circle matrix: transformation matrix [not implemented yet] mode: 'np' or 'pydata' : 'pydata' usage: Verts, Edges, Faces = circle(nverts=20, radius=1.6, mode='pydata') info: Each return type will be a nested list. Verts: will generate [[x0,y0,z0],[x1,y1,z1], ....[xN,yN,zN]] Edges: will generate [[a,b],[b,c], ....[n,a]] Faces: a single wrapped polygon around the bounds of the shape : 'np' usage: Verts, Edges, Faces = circle(nverts=20, radius=1.6, mode='np') outputs Verts, Edges, Faces info: Each return type will be a numpy array Verts: generates [n*4] - Array([[x0,y0,z0,w0],[x1,y1,z1,w1], ....[xN,yN,zN,wN]]) Edges: will be a [n*2] - Array([[a,b],[b,c], ....[n,a]]) Faces: a single wrapped polygon around the bounds of the shape to convert to pydata please consult the numpy manual. ''' if mode in {'pydata', 'bm'}: verts = [] theta = TAU / nverts for i in range(nverts): rad = i * theta verts.append((math.sin(rad + phase) * radius, math.cos(rad + phase) * radius, 0)) edges = [[i, i+1] for i in range(nverts-1)] + [[nverts-1, 0]] faces = [i for i in range(nverts)] if mode == 'pydata': return verts, edges, [faces] else: return bmesh_from_pydata(verts, edges, [faces]) if mode == 'np': t = np.linspace(0, np.pi * 2 * (nverts - 1 / nverts), nverts) circ = np.array([np.cos(t + phase) * radius, np.sin(t + phase) * radius, np.zeros(nverts), np.zeros(nverts)]) verts = np.transpose(circ) edges = np.array([[i, i+1] for i in range(nverts-1)] + [[nverts-1, 0]]) faces = np.array([[i for i in range(nverts)]]) return verts, edges, faces
def quad(side=1.0, radius=0.0, nverts=5, matrix=None, mode='pydata'): ''' parameters: side: gives the length of side of the rect radius: gives the radius of the rounded corners. - If the passed radius is equal to side/2 then you'll get a circle - if the passed radius exceeds side/2, then you will get rect nverts: if nverts is equal or greater than 2 then you will get rounded courners if the above radius is smaller or equal to side/2. matrix: --- mode: --- outputs Verts, Edges, Faces info: Each return type will be a nested list. Verts: will generate [[x0,y0,z0],[x1,y1,z1], ....[xN,yN,zN]] Edges: will generate [[a,b],[b,c], ....[n,a]] Faces: a single wrapped polygon around the bounds of the shape ''' if mode in {'pydata', 'bm'}: dim = side / 2 edges, faces = [], [] if radius > 0.0 and radius < dim and nverts >= 2: verts = [] theta = HALF_PI / (nverts-1) ext = dim - radius coords = [[ext, ext], [ext, -ext], [-ext, -ext], [-ext, ext]] for (x, y), corner in zip(coords, range(4)): for i in range(nverts): rad = theta * i verts.append(((math.sin(rad + (corner*HALF_PI)) * radius) + x, (math.cos(rad + (corner*HALF_PI)) * radius) + y, 0)) elif radius > 0.0 and radius == dim and nverts >= 2: verts, edges, faces = circle(radius=dim, nverts=((nverts*4)-4)) else: verts = [[-dim, dim, 0], [dim, dim, 0], [dim, -dim, 0], [-dim, -dim, 0]] # elif radius == 0.0 or (radius > 0.0 and radius > dim): num_verts = len(verts) if not edges: edges = [[i, i+1] for i in range(num_verts-1)] + [[num_verts-1, 0]] faces = [i for i in range(num_verts)] if mode == 'pydata': return verts, edges, [faces] else: return bmesh_from_pydata(verts, edges, [faces]) if mode == 'np': pass
def process(self): inputs = self.inputs outputs = self.outputs try: verts_in = inputs['Verts_in'].sv_get(deepcopy=False)[0] edges_in = inputs['Edges_in'].sv_get(deepcopy=False)[0] linked = outputs['Verts_out'].is_linked except (IndexError, KeyError) as e: return bm = bmesh_from_pydata(verts_in, edges_in, []) edge_indices = [e.index for e in bm.edges] trim_indices = len(edge_indices) for edge in bm.edges: edge.select = True cm = CAD_ops(epsilon=self.epsilon) d = get_intersection_dictionary(cm, bm, edge_indices) unselect_nonintersecting(bm, d.keys(), edge_indices) # store non_intersecting edge sequencer add_back = [[i.index for i in edge.verts] for edge in bm.edges if not edge.select] update_mesh(bm, d) verts_out = [v.co.to_tuple() for v in bm.verts] edges_out = [[j.index for j in i.verts] for i in bm.edges] # optional correction, remove originals, add back those that are not intersecting. edges_out = edges_out[trim_indices:] edges_out.extend(add_back) bm.free() # post processing step to remove doubles if self.rm_switch: bm = bmesh_from_pydata(verts_out, edges=edges_out) bmesh.ops.remove_doubles(bm, verts=bm.verts[:], dist=self.rm_doubles) verts_out = [v.co.to_tuple() for v in bm.verts] edges_out = [[j.index for j in i.verts] for i in bm.edges] outputs['Verts_out'].sv_set([verts_out]) outputs['Edges_out'].sv_set([edges_out])
def process(self): if not (self.inputs['Vertices'].is_linked and self.inputs['Polygons'].is_linked): return if not (any(self.outputs[name].is_linked for name in ['Vertices', 'Edges', 'Polygons', 'NewEdges', 'NewPolys'])): return vertices_s = self.inputs['Vertices'].sv_get(default=[[]]) edges_s = self.inputs['Edges'].sv_get(default=[[]]) faces_s = self.inputs['Polygons'].sv_get(default=[[]]) mask_s = self.inputs['Mask'].sv_get(default=[[True]]) result_vertices = [] result_edges = [] result_faces = [] result_new_edges = [] result_new_faces = [] meshes = match_long_repeat([vertices_s, edges_s, faces_s, mask_s]) for vertices, edges, faces, mask in zip(*meshes): bm = bmesh_from_pydata(vertices, edges, faces) fullList(mask, len(faces)) b_faces = [] for m, face in zip(mask, bm.faces): if m: b_faces.append(face) res = bmesh.ops.triangulate( bm, faces=b_faces, quad_method=int(self.quad_mode), ngon_method=int(self.ngon_mode)) b_new_edges = [tuple(v.index for v in edge.verts) for edge in res['edges']] b_new_faces = [[v.index for v in face.verts] for face in res['faces']] new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) bm.free() result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_new_edges.append(b_new_edges) result_new_faces.append(b_new_faces) if self.outputs['Vertices'].is_linked: self.outputs['Vertices'].sv_set(result_vertices) if self.outputs['Edges'].is_linked: self.outputs['Edges'].sv_set(result_edges) if self.outputs['Polygons'].is_linked: self.outputs['Polygons'].sv_set(result_faces) if self.outputs['NewEdges'].is_linked: self.outputs['NewEdges'].sv_set(result_new_edges) if self.outputs['NewPolys'].is_linked: self.outputs['NewPolys'].sv_set(result_new_faces)
def calc_mesh_normals(vertices, edges, faces): bm = bmesh_from_pydata(vertices, edges, faces, normal_update=True) vertex_normals = [] face_normals = [] for vertex in bm.verts: vertex_normals.append(tuple(vertex.normal)) for face in bm.faces: face_normals.append(tuple(face.normal)) bm.free() return vertex_normals, face_normals
def process(self): if not (self.inputs['Vertices'].is_linked and self.inputs['Polygons'].is_linked): return if not (any(self.outputs[name].is_linked for name in ['Vertices', 'Edges', 'Polygons', 'NewPolys'])): return vertices_s = self.inputs['Vertices'].sv_get(default=[[]]) edges_s = self.inputs['Edges'].sv_get(default=[[]]) faces_s = self.inputs['Polygons'].sv_get(default=[[]]) offsets_s = self.inputs['Offset'].sv_get()[0] segments_s = self.inputs['Segments'].sv_get()[0] profiles_s = self.inputs['Profile'].sv_get()[0] bevel_edges_s = self.inputs['BevelEdges'].sv_get(default=[[]]) result_vertices = [] result_edges = [] result_faces = [] result_bevel_faces = [] meshes = match_long_repeat([vertices_s, edges_s, faces_s, bevel_edges_s, offsets_s, segments_s, profiles_s]) for vertices, edges, faces, bevel_edges, offset, segments, profile in zip(*meshes): bm = bmesh_from_pydata(vertices, edges, faces) if bevel_edges: b_edges = [] for edge in bevel_edges: b_edge = [e for e in bm.edges if set([v.index for v in e.verts]) == set(edge)] b_edges.append(b_edge[0]) else: b_edges = bm.edges geom = list(bm.verts) + list(b_edges) + list(bm.faces) bevel_faces = bmesh.ops.bevel(bm, geom=geom, offset=offset, offset_type=int(self.offsetType), segments=segments, profile=profile, vertex_only=self.vertexOnly, #clamp_overlap=self.clampOverlap, material=-1)['faces'] new_bevel_faces = [[v.index for v in face.verts] for face in bevel_faces] new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) bm.free() result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_bevel_faces.append(new_bevel_faces) self.outputs['Vertices'].sv_set(result_vertices) if self.outputs['Edges'].is_linked: self.outputs['Edges'].sv_set(result_edges) if self.outputs['Polygons'].is_linked: self.outputs['Polygons'].sv_set(result_faces) if self.outputs['NewPolys'].is_linked: self.outputs['NewPolys'].sv_set(result_bevel_faces)
def makecube(self, size, divx, divy, divz): if 0 in (divx, divy, divz): return [], [] b = size / 2.0 verts = [ [b, b, -b], [b, -b, -b], [-b, -b, -b], [-b, b, -b], [b, b, b], [b, -b, b], [-b, -b, b], [-b, b, b] ] faces = [[0, 1, 2, 3], [4, 7, 6, 5], [0, 4, 5, 1], [1, 5, 6, 2], [2, 6, 7, 3], [4, 0, 3, 7]] edges = [[0, 4], [4, 5], [5, 1], [1, 0], [5, 6], [6, 2], [2, 1], [6, 7], [7, 3], [3, 2], [7, 4], [0, 3]] if (divx, divy, divz) == (1, 1, 1): return verts, edges, faces bm = bmesh_from_pydata(verts, [], faces) dist = 0.0001 section_dict = {0: divx, 1: divy, 2: divz} for axis in range(3): num_sections = section_dict[axis] if num_sections == 1: continue step = 1 / num_sections v1 = Vector(tuple((b if (i == axis) else 0) for i in [0, 1, 2])) v2 = Vector(tuple((-b if (i == axis) else 0) for i in [0, 1, 2])) for section in range(num_sections): mid_vec = v1.lerp(v2, section * step) plane_no = v2 - mid_vec plane_co = mid_vec visible_geom = bm.faces[:] + bm.verts[:] + bm.edges[:] bmesh.ops.bisect_plane( bm, geom=visible_geom, dist=dist, plane_co=plane_co, plane_no=plane_no, use_snap_center=False, clear_outer=False, clear_inner=False) indices = lambda i: [j.index for j in i.verts] verts = [list(v.co.to_tuple()) for v in bm.verts] faces = [indices(face) for face in bm.faces] edges = [indices(edge) for edge in bm.edges] return verts, edges, faces
def make_bmesh_geometry(node, idx, context, verts, *topology): scene = context.scene meshes = bpy.data.meshes objects = bpy.data.objects edges, faces, matrix = topology name = node.basemesh_name + "_" + str(idx) if name in objects: sv_object = objects[name] else: temp_mesh = default_mesh(name) sv_object = objects.new(name, temp_mesh) scene.objects.link(sv_object) # book-keeping via ID-props!? even this is can be broken by renames sv_object['idx'] = idx sv_object['madeby'] = node.name sv_object['basename'] = node.basemesh_name mesh = sv_object.data current_count = len(mesh.vertices) propose_count = len(verts) difference = (propose_count - current_count) ''' With this mode you make a massive assumption about the constant state of geometry. Assumes the count of verts edges/faces stays the same, and only updates the locations node.fixed_verts is not suitable for initial object creation but if over time you find that the only change is going to be vertices, this mode can be switched to to increase efficiency ''' if node.fixed_verts and difference == 0: f_v = list(itertools.chain.from_iterable(verts)) mesh.vertices.foreach_set('co', f_v) mesh.update() else: ''' get bmesh, write bmesh to obj, free bmesh''' bm = bmesh_from_pydata(verts, edges, faces) bm.to_mesh(sv_object.data) bm.free() sv_object.hide_select = False if matrix: matrix = matrix_sanitizer(matrix) if node.extended_matrix: sv_object.data.transform(matrix) sv_object.matrix_local = Matrix.Identity(4) else: sv_object.matrix_local = matrix else: sv_object.matrix_local = Matrix.Identity(4)
def process(self): vers = self.inputs['Vertices'].sv_get() pols = self.inputs['Polygons'].sv_get() normalsFORout = [] for i, obj in enumerate(vers): bm = bmesh_from_pydata(obj, [], pols[i], normal_update=True) normalsFORout.append([v.normal[:] for v in bm.verts]) bm.free() self.outputs['Normals'].sv_set(normalsFORout)
def make_bmesh_geometry_merged(node, idx, context, yielder_object): scene = context.scene meshes = bpy.data.meshes objects = bpy.data.objects name = node.basemesh_name + "_" + str(idx) if name in objects: sv_object = objects[name] else: temp_mesh = default_mesh(name) sv_object = objects.new(name, temp_mesh) scene.objects.link(sv_object) # book-keeping via ID-props! sv_object['idx'] = idx sv_object['madeby'] = node.name sv_object['basename'] = node.basemesh_name vert_count = 0 big_verts = [] big_edges = [] big_faces = [] for result in yielder_object: verts, topology = result edges, faces, matrix = topology if matrix: matrix = matrix_sanitizer(matrix) verts = [matrix * Vector(v) for v in verts] big_verts.extend(verts) big_edges.extend([[a + vert_count, b + vert_count] for a, b in edges]) big_faces.extend([[j + vert_count for j in f] for f in faces]) vert_count += len(verts) if node.fixed_verts and len(sv_object.data.vertices) == len(big_verts): mesh = sv_object.data f_v = list(itertools.chain.from_iterable(big_verts)) mesh.vertices.foreach_set('co', f_v) mesh.update() else: ''' get bmesh, write bmesh to obj, free bmesh''' bm = bmesh_from_pydata(big_verts, big_edges, big_faces, normal_update=node.calc_normals) bm.to_mesh(sv_object.data) bm.free() sv_object.hide_select = False sv_object.matrix_local = Matrix.Identity(4)
def fill_holes(vertices, edges, s): if not edges and not vertices: return False if len(edges[0]) != 2: return False bm = bmesh_from_pydata(vertices, edges, []) bmesh.ops.holes_fill(bm, edges=bm.edges[:], sides=s) verts, edges, faces = pydata_from_bmesh(bm) return (verts, edges, faces)
def process(self): inputs = self.inputs outputs = self.outputs if not (inputs['Vertices'].is_linked and inputs['Polygons'].is_linked): return named = ['Vertices', 'Edges', 'Polygons'] if not (any(outputs[name].is_linked for name in named)): return vertices_s = inputs['Vertices'].sv_get(default=[[]]) faces_s = inputs['Polygons'].sv_get(default=[[]]) result_vertices = [] result_edges = [] result_faces = [] meshes = match_long_repeat([vertices_s, faces_s]) for vertices, faces in zip(*meshes): bm = bmesh_from_pydata(vertices, [], faces) new_edges = [] new_faces = [] for f in bm.faces: coords = [v.co for v in f.verts] indices = [v.index for v in f.verts] if len(coords) > 3: for pol in tessellate([coords]): new_faces.append([indices[i] for i in pol]) else: new_faces.append([v.index for v in f.verts]) result_vertices.append([v.co[:] for v in bm.verts]) result_edges.append(new_edges) result_faces.append(new_faces) output_list = [ ['Vertices', result_vertices], ['Edges', result_edges], ['Polygons', result_faces] ] for output_name, output_data in output_list: if outputs[output_name].is_linked: outputs[output_name].sv_set(output_data)
def get_lathed_geometry(node, verts, edges, cent, axis, dvec, angle, steps): bm = bmesh_from_pydata(verts, edges, []) geom = bm.verts[:] + bm.edges[:] spin(bm, geom=geom, cent=cent, axis=axis, dvec=dvec, angle=angle, steps=steps, use_duplicate=0) if node.remove_doubles: bmesh.ops.remove_doubles(bm, verts=bm.verts[:], dist=node.dist) v = [v.co[:] for v in bm.verts] p = [[i.index for i in p.verts] for p in bm.faces[:]] bm.free() return v, p
def process(self): if not (self.inputs['Vertices'].is_linked and self.inputs['Polygons'].is_linked): return if not (any( self.outputs[name].is_linked for name in ['Vertices', 'Edges', 'Polygons', 'NewEdges', 'NewPolys'])): return vertices_s = self.inputs['Vertices'].sv_get(default=[[]], deepcopy=False) edges_s = self.inputs['Edges'].sv_get(default=[[]], deepcopy=False) faces_s = self.inputs['Polygons'].sv_get(default=[[]], deepcopy=False) if 'FaceData' in self.inputs: face_data_s = self.inputs['FaceData'].sv_get(default=[[]], deepcopy=False) else: face_data_s = [[]] mask_s = self.inputs['Mask'].sv_get(default=[[True]], deepcopy=False) result_vertices = [] result_edges = [] result_faces = [] result_face_data = [] result_new_edges = [] result_new_faces = [] meshes = match_long_repeat( [vertices_s, edges_s, faces_s, face_data_s, mask_s]) for vertices, edges, faces, face_data, mask in zip(*meshes): if face_data: face_data_matched = repeat_last_for_length( face_data, len(faces)) bm = bmesh_from_pydata(vertices, edges, faces, markup_face_data=True) mask_matched = repeat_last_for_length(mask, len(faces)) b_faces = [] for m, face in zip(mask_matched, bm.faces): if m: b_faces.append(face) res = bmesh.ops.triangulate(bm, faces=b_faces, quad_method=self.quad_mode, ngon_method=self.ngon_mode) b_new_edges = [ tuple(v.index for v in edge.verts) for edge in res['edges'] ] b_new_faces = [[v.index for v in face.verts] for face in res['faces']] if face_data: new_vertices, new_edges, new_faces, new_face_data = pydata_from_bmesh( bm, face_data_matched) else: new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) new_face_data = [] bm.free() result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_face_data.append(new_face_data) result_new_edges.append(b_new_edges) result_new_faces.append(b_new_faces) self.outputs['Vertices'].sv_set(result_vertices) self.outputs['Edges'].sv_set(result_edges) self.outputs['Polygons'].sv_set(result_faces) if 'FaceData' in self.outputs: self.outputs['FaceData'].sv_set(result_face_data) self.outputs['NewEdges'].sv_set(result_new_edges) self.outputs['NewPolys'].sv_set(result_new_faces)
def process(self): if not any(output.is_linked for output in self.outputs): return vertices_s = self.inputs['Vertices'].sv_get() edges_s = self.inputs['Edges'].sv_get(default=[[]]) faces_s = self.inputs['Faces'].sv_get(default=[[]]) masks_s = self.inputs['VertMask'].sv_get(default=[[1]]) iterations_s = self.inputs['Iterations'].sv_get()[0] if not self.laplacian: clip_dist_s = self.inputs['ClipDist'].sv_get()[0] else: clip_dist_s = [0.0] factor_s = self.inputs['Factor'].sv_get()[0] if self.laplacian: border_factor_s = self.inputs['BorderFactor'].sv_get()[0] else: border_factor_s = [0.0] result_vertices = [] result_edges = [] result_faces = [] meshes = match_long_repeat([ vertices_s, edges_s, faces_s, masks_s, clip_dist_s, factor_s, border_factor_s, iterations_s ]) for vertices, edges, faces, masks, clip_dist, factor, border_factor, iterations in zip( *meshes): fullList(masks, len(vertices)) bm = bmesh_from_pydata(vertices, edges, faces, normal_update=True) bm.verts.ensure_lookup_table() bm.edges.ensure_lookup_table() bm.faces.ensure_lookup_table() selected_verts = [ vert for mask, vert in zip(masks, bm.verts) if mask ] for i in range(iterations): if self.laplacian: # for some reason smooth_laplacian_vert does not work properly if faces are not selected for f in bm.faces: f.select = True bmesh.ops.smooth_laplacian_vert( bm, verts=selected_verts, lambda_factor=factor, lambda_border=border_factor, use_x=self.use_x, use_y=self.use_y, use_z=self.use_z, preserve_volume=self.preserve_volume) else: bmesh.ops.smooth_vert(bm, verts=selected_verts, factor=factor, mirror_clip_x=self.mirror_clip_x, mirror_clip_y=self.mirror_clip_y, mirror_clip_z=self.mirror_clip_z, clip_dist=clip_dist, use_axis_x=self.use_x, use_axis_y=self.use_y, use_axis_z=self.use_z) new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) bm.free() result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) self.outputs['Vertices'].sv_set(result_vertices) self.outputs['Edges'].sv_set(result_edges) self.outputs['Faces'].sv_set(result_faces)
def section(cut_me_vertices, cut_me_edges, mx, pp, pno, FILL=False, TRI=True): """Finds the section mesh between a mesh and a plane cut_me: Blender Mesh - the mesh to be cut mx: Matrix - The matrix of object of the mesh for correct coordinates pp: Vector - A point on the plane pno: Vector - The cutting plane's normal Returns: Mesh - the resulting mesh of the section if any or Boolean - False if no section exists""" def equation_plane(point, normal_dest): # получаем коэффициенты уравнения плоскости по точке и нормали normal = normal_dest.normalized() A = normal.x B = normal.y C = normal.z D = (A*point.x+B*point.y+C*point.z)*-1 if A < 0.0: A *= -1 B *= -1 C *= -1 D *= -1 return (A, B, C, D) def point_on_plane(v1, ep): formula = ep[0]*v1.x+ep[1]*v1.y+ep[2]*v1.z+ep[3] if formula == 0.0: return True else: return False if not cut_me_edges or not cut_me_vertices: return False verts = [] ed_xsect = {} x_me = {} ep = equation_plane(pp, pno) cut_me_polygons = [] if len(cut_me_edges[0]) > 2: cut_me_polygons = cut_me_edges.copy() cut_me_edges = [] new_me = bpy.data.meshes.new('tempus') new_me.from_pydata(cut_me_vertices, cut_me_edges, cut_me_polygons) new_me.update(calc_edges=True) for ed_idx, ed in enumerate(new_me.edges): # getting a vector from each edge vertices to a point on the plane # first apply transformation matrix so we get the real section vert1 = ed.vertices[0] v1 = new_me.vertices[vert1].co @ mx.transposed() vert2 = ed.vertices[1] v2 = new_me.vertices[vert2].co @ mx.transposed() vec = v2-v1 mul = vec @ pno if mul == 0.0: if not point_on_plane(v1, ep): # parallel and not on plane continue epv = ep[0]*vec.x + ep[1]*vec.y + ep[2]*vec.z if epv == 0: t0 = 0 else: t0 = -(ep[0]*v1.x+ep[1]*v1.y+ep[2]*v1.z + ep[3]) / epv pq = vec*t0+v1 if (pq-v1).length <= vec.length and (pq-v2).length <= vec.length: verts.append(pq) ed_xsect[ed.key] = len(ed_xsect) edges = [] for f in new_me.polygons: # get the edges that the intersecting points form # to explain this better: # If a face has an edge that is proven to be crossed then use the # mapping we created earlier to connect the edges properly ps = [ed_xsect[key] for key in f.edge_keys if key in ed_xsect] if len(ps) == 2: edges.append(tuple(ps)) x_me['Verts'] = verts x_me['Edges'] = edges bpy.data.meshes.remove(new_me) if x_me: if edges and FILL: bm = bmesh_from_pydata(verts, edges, []) bmesh.ops.remove_doubles(bm, verts=bm.verts[:], dist=0.000002) fres = bmesh.ops.edgenet_prepare(bm, edges=bm.edges[:]) if not TRI: # Alt + F bmesh.ops.triangle_fill(bm, use_beauty=True, use_dissolve=False, edges=fres['edges']) else: # can generate N-Gons bmesh.ops.edgeloop_fill(bm, edges=fres['edges']) # in case there are islands generated by the above operations, and said islands have varying # normals (up/down flipped due to lack of surrounding information), then we force all faces # to conform to the normal as obtained by the Matrix that generates this cut. normal_consistent(bm, pno) bm.verts.index_update() bm.edges.index_update() bm.faces.index_update() verts, edges, faces = pydata_from_bmesh(bm) x_me['Verts'] = verts x_me['Edges'] = faces # edges -- this was outputting faces into edges when fill was ticked? bm.clear() bm.free() return x_me else: return False
def process(self): if not (self.inputs[0].is_linked and (self.inputs[2].is_linked or self.inputs[1].is_linked)): return if not any(self.outputs[name].is_linked for name in ['Vertices', 'Edges', 'Polygons', 'NewPolys']): return verts_out = [] edges_out = [] faces_out = [] face_data_out = [] result_bevel_faces = [] meshes = match_long_repeat(self.get_socket_data()) for vertices, edges, faces, face_data, mask, offset, segments, profile, bevel_face_data, spread in zip( *meshes): if face_data: face_data_matched = repeat_last_for_length( face_data, len(faces)) if bevel_face_data and isinstance(bevel_face_data, (list, tuple)): bevel_face_data = bevel_face_data[0] bm = bmesh_from_pydata(vertices, edges, faces, markup_face_data=True, normal_update=True) geom = self.create_geom(bm, mask) try: # we try the most likely blender binary compatible version first (official builds) bevel_faces = bmesh.ops.bevel( bm, geom=geom, offset=offset, offset_type=self.offsetType, segments=segments, profile=profile, vertex_only=self.vertexOnly, clamp_overlap=self.clamp_overlap, loop_slide=self.loop_slide, spread=spread, miter_inner=self.miter_inner, miter_outer=self.miter_outer, # strength= (float) # hnmode= (enum in ['NONE', 'FACE', 'ADJACENT', 'FIXED_NORMAL_SHADING'], default 'NONE') material=-1)['faces'] except TypeError as e: # if the "try" failed, we try the new form of bmesh.ops.bevel arguments.. affect_geom = 'VERTICES' if self.vertexOnly else 'EDGES' bevel_faces = bmesh.ops.bevel( bm, geom=geom, offset=offset, offset_type=self.offsetType, segments=segments, profile=profile, # profile_type= (enum: 'SUPERELLIPSE', 'CUSTOM' ), default super affect=affect_geom, clamp_overlap=self.clamp_overlap, loop_slide=self.loop_slide, spread=spread, miter_inner=self.miter_inner, miter_outer=self.miter_outer, material=-1)['faces'] except Exception as e: self.exception(e) new_bevel_faces = [[v.index for v in face.verts] for face in bevel_faces] if not face_data: verts, edges, faces = pydata_from_bmesh(bm) verts_out.append(verts) edges_out.append(edges) faces_out.append(faces) if bevel_face_data != []: new_face_data = [] for face in faces: if set(face) in map(set, new_bevel_faces): new_face_data.append(bevel_face_data) else: new_face_data.append(None) face_data_out.append(new_face_data) else: face_data_out.append([]) else: verts, edges, faces, new_face_data = pydata_from_bmesh( bm, face_data_matched) verts_out.append(verts) edges_out.append(edges) faces_out.append(faces) if bevel_face_data != []: new_face_data_m = [] for data, face in zip(new_face_data, faces): if set(face) in map(set, new_bevel_faces): new_face_data_m.append(bevel_face_data) else: new_face_data_m.append(data) face_data_out.append(new_face_data_m) else: face_data_out.append(new_face_data) bm.free() result_bevel_faces.append(new_bevel_faces) self.outputs['Vertices'].sv_set(verts_out) self.outputs['Edges'].sv_set(edges_out) self.outputs['Polygons'].sv_set(faces_out) if 'FaceData' in self.outputs: self.outputs['FaceData'].sv_set(face_data_out) self.outputs['NewPolys'].sv_set(result_bevel_faces)
def make_hull(vertices, params): if not vertices: return False verts, faces = [], [[]] # invoke the right convex hull function if params.hull_mode == '3D': bm = bmesh_from_pydata(vertices, [], []) res = bmesh.ops.convex_hull(bm, input=bm.verts[:], use_existing_faces=False) unused_v_indices = [v.index for v in res["geom_unused"]] if params.inside and params.outside: verts, _, faces = pydata_from_bmesh(bm) elif not params.inside and params.outside: bmesh.ops.delete(bm, geom=[bm.verts[i] for i in unused_v_indices], context='VERTS') verts, _, faces = pydata_from_bmesh(bm) elif not params.outside and params.inside: used_v_indices = set(range(len(vertices))) - set(unused_v_indices) bmesh.ops.delete(bm, geom=[bm.verts[i] for i in used_v_indices], context='VERTS') verts = [ v[:] for idx, v in enumerate(vertices) if idx in unused_v_indices ] elif params.hull_mode == '2D': vertices_2d = get2d(params.plane, vertices) used_v_indices = mathutils.geometry.convex_hull_2d(vertices_2d) unused_v_indices = set(range(len(vertices))) - set(used_v_indices) bm = bmesh_from_pydata(vertices, [], [used_v_indices]) if params.inside and params.outside: verts, _, faces = pydata_from_bmesh(bm) elif not params.inside and params.outside: bmesh.ops.delete(bm, geom=[bm.verts[i] for i in unused_v_indices], context='VERTS') if params.sort_edges: bm.faces.ensure_lookup_table() addv = verts.append _ = [addv(v.co[:]) for v in bm.faces[0].verts[:]] faces = [list(range(len(verts)))] else: verts, _, faces = pydata_from_bmesh(bm) elif not params.outside and params.inside: bmesh.ops.delete(bm, geom=[bm.verts[i] for i in used_v_indices], context='VERTS') verts, _, _ = pydata_from_bmesh(bm) bm.clear() bm.free() return (verts, faces)
def process(self): inputs, outputs = self.inputs, self.outputs if self.dont_process(): return result_vertices, result_edges, result_faces, result_face_data = [], [], [], [] r_inner_vertices, r_inner_edges, r_inner_faces = [], [], [] r_split_vertices, r_split_edges, r_split_faces = [], [], [] use_mask = inputs['EdgeMask'].is_linked show_new = self.show_new and any(s.is_linked for s in outputs[4:7]) show_old = self.show_old and any(s.is_linked for s in outputs[7:]) use_face_data = inputs['FaceData'].is_linked and outputs[ 'FaceData'].is_linked output_numpy = any(self.out_np) meshes = self.get_data() for vertices, edges, faces, face_data, masks, cuts, smooth, fractal, along_normal, seed in zip( *meshes): if cuts < 1: result_vertices.append(vertices) result_edges.append(edges) result_faces.append(faces) result_face_data.append(face_data) r_inner_vertices.append(vertices) r_inner_edges.append(edges) r_inner_faces.append(faces) r_split_vertices.append(vertices) r_split_edges.append(edges) r_split_faces.append(faces) continue if use_face_data and len(face_data) > 0: if isinstance(face_data, ndarray): face_data = numpy_full_list(face_data, len(faces)).tolist() else: fullList(face_data, len(faces)) bm = bmesh_from_pydata(vertices, edges, faces, markup_face_data=use_face_data, markup_edge_data=use_mask, normal_update=True) selected_edges = get_selected_edges(use_mask, masks, bm.edges) geom = subdivide_edges(bm, edges=selected_edges, smooth=smooth, smooth_falloff=self.falloff_type, fractal=fractal, along_normal=along_normal, cuts=cuts, seed=seed, quad_corner_type=self.corner_type, use_grid_fill=self.grid_fill, use_single_edge=self.single_edge, use_only_quads=self.only_quads, use_smooth_even=self.smooth_even) if output_numpy: new_verts, new_edges, new_faces, new_face_data = numpy_data_from_bmesh( bm, self.out_np, face_data) else: if use_face_data and len(face_data) > 0: new_verts, new_edges, new_faces, new_face_data = pydata_from_bmesh( bm, face_data) else: new_verts, new_edges, new_faces = pydata_from_bmesh(bm) new_face_data = [] result_vertices.append(new_verts) result_edges.append(new_edges) result_faces.append(new_faces) result_face_data.append(new_face_data) if show_new: inner_verts, inner_edges, inner_faces = get_partial_result_pydata( geom['geom_inner']) r_inner_vertices.append(inner_verts) r_inner_edges.append(inner_edges) r_inner_faces.append(inner_faces) if show_old: split_verts, split_edges, split_faces = get_partial_result_pydata( geom['geom_split']) r_split_vertices.append(split_verts) r_split_edges.append(split_edges) r_split_faces.append(split_faces) bm.free() outputs['Vertices'].sv_set(result_vertices) outputs['Edges'].sv_set(result_edges) outputs['Faces'].sv_set(result_faces) outputs['FaceData'].sv_set(result_face_data) outputs['NewVertices'].sv_set(r_inner_vertices) outputs['NewEdges'].sv_set(r_inner_edges) outputs['NewFaces'].sv_set(r_inner_faces) outputs['OldVertices'].sv_set(r_split_vertices) outputs['OldEdges'].sv_set(r_split_edges) outputs['OldFaces'].sv_set(r_split_faces)
def process(self): outputs = self.outputs if not outputs['Vertices'].is_linked: return IVerts, IFaces, IMask, Imatr = self.inputs vertices_s = IVerts.sv_get() faces_s = IFaces.sv_get() linked_extruded_polygons = outputs['ExtrudedPolys'].is_linked linked_other_polygons = outputs['OtherPolys'].is_linked result_vertices = [] result_edges = [] result_faces = [] result_extruded_faces = [] result_other_faces = [] bmlist = [ bmesh_from_pydata(verts, [], faces) for verts, faces in zip(vertices_s, faces_s) ] trans = Imatr.sv_get() if IMask.is_linked: flist = [ np.extract(mask, bm.faces[:]) for bm, mask in zip(bmlist, IMask.sv_get()) ] else: flist = [bm.faces for bm in bmlist] for bm, selfaces in zip(bmlist, flist): extrfaces = extrude_discrete_faces(bm, faces=selfaces)['faces'] fullList(trans, len(extrfaces)) new_extruded_faces = [] for face, ma in zip(extrfaces, trans): normal = face.normal if normal[0] == 0 and normal[1] == 0: m_r = Matrix() if normal[2] >= 0 else Matrix.Rotation( pi, 4, 'X') else: z_axis = normal x_axis = Vector( (z_axis[1] * -1, z_axis[0], 0)).normalized() y_axis = z_axis.cross(x_axis).normalized() m_r = Matrix(list([*zip(x_axis[:], y_axis[:], z_axis[:]) ])).to_4x4() m = (Matrix.Translation(face.calc_center_median()) @ m_r).inverted() transform(bm, matrix=ma, space=m, verts=face.verts) if linked_extruded_polygons or linked_other_polygons: new_extruded_faces.append([v.index for v in face.verts]) new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) bm.free() new_other_faces = [ f for f in new_faces if f not in new_extruded_faces ] if linked_other_polygons else [] result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_extruded_faces.append(new_extruded_faces) result_other_faces.append(new_other_faces) outputs['Vertices'].sv_set(result_vertices) outputs['Edges'].sv_set(result_edges) outputs['Polygons'].sv_set(result_faces) outputs['ExtrudedPolys'].sv_set(result_extruded_faces) outputs['OtherPolys'].sv_set(result_other_faces)
def make_bmesh_geometry(node, obj_index, context, verts, *topology): collection = context.scene.collection meshes = bpy.data.meshes objects = bpy.data.objects islands = None edges, faces, materials, matrix = topology name = f'{node.basedata_name}.{obj_index:04d}' if name in objects: sv_object = objects[name] else: temp_mesh = default_mesh(name) sv_object = objects.new(name, temp_mesh) collection.objects.link(sv_object) # book-keeping via ID-props!? even this is can be broken by renames sv_object['idx'] = obj_index sv_object['madeby'] = node.name sv_object['basedata_name'] = node.basedata_name mesh = sv_object.data current_count = len(mesh.vertices) propose_count = len(verts) difference = (propose_count - current_count) ''' With this mode you make a massive assumption about the constant state of geometry. Assumes the count of verts edges/faces stays the same, and only updates the locations node.fixed_verts is not suitable for initial object creation but if over time you find that the only change is going to be vertices, this mode can be switched to to increase efficiency ''' if node.fixed_verts and difference == 0: f_v = list(itertools.chain.from_iterable(verts)) mesh.vertices.foreach_set('co', f_v) mesh.update() else: ''' get bmesh, write bmesh to obj, free bmesh''' bm = bmesh_from_pydata(verts, edges, faces, normal_update=node.calc_normals) if materials: for face, material in zip(bm.faces[:], materials): if material is not None: face.material_index = material bm.to_mesh(sv_object.data) if node.randomize_vcol_islands: islands = find_islands_treemap(bm) bm.free() sv_object.hide_select = False if node.randomize_vcol_islands: set_vertices(sv_object, islands) if matrix: # matrix = matrix_sanitizer(matrix) if node.extended_matrix: sv_object.data.transform(matrix) sv_object.matrix_local = Matrix.Identity(4) else: sv_object.matrix_local = matrix else: sv_object.matrix_local = Matrix.Identity(4)
def voronoi3d_layer(n_src_sites, all_sites, make_regions, do_clip, clipping, skip_added=True): diagram = Voronoi(all_sites) src_sites = all_sites[:n_src_sites] region_verts = dict() region_verts_map = dict() n_sites = n_src_sites if skip_added else len(all_sites) for site_idx in range(n_sites): region_idx = diagram.point_region[site_idx] region = diagram.regions[region_idx] vertices = [tuple(diagram.vertices[i,:]) for i in region] region_verts[site_idx] = vertices region_verts_map[site_idx] = {vert_idx: i for i, vert_idx in enumerate(region)} open_sites = set() region_faces = defaultdict(list) for ridge_idx, sites in enumerate(diagram.ridge_points): site_from, site_to = sites ridge = diagram.ridge_vertices[ridge_idx] if -1 in ridge: open_sites.add(site_from) open_sites.add(site_to) site_from_ok = not skip_added or site_from < n_src_sites site_to_ok = not skip_added or site_to < n_src_sites if make_regions: if site_from_ok: face_from = [region_verts_map[site_from][i] for i in ridge] region_faces[site_from].append(face_from) if site_to_ok: face_to = [region_verts_map[site_to][i] for i in ridge] region_faces[site_to].append(face_to) else: if site_from_ok and site_to_ok: face_from = [region_verts_map[site_from][i] for i in ridge] region_faces[site_from].append(face_from) face_to = [region_verts_map[site_to][i] for i in ridge] region_faces[site_to].append(face_to) verts = [region_verts[i] for i in range(n_sites) if i not in open_sites] faces = [region_faces[i] for i in range(n_sites) if i not in open_sites] empty_faces = [len(f) == 0 for f in faces] verts = [vs for vs, mask in zip(verts, empty_faces) if not mask] faces = [fs for fs, mask in zip(faces, empty_faces) if not mask] edges = polygons_to_edges(faces, True) if not make_regions: verts_n, edges_n, faces_n = [], [], [] for verts_i, edges_i, faces_i in zip(verts, edges, faces): used_verts = set(sum(faces_i, [])) mask = [i in used_verts for i in range(len(verts_i))] verts_i, edges_i, faces_i = mask_vertices(verts_i, edges_i, faces_i, mask) verts_n.append(verts_i) edges_n.append(edges_i) faces_n.append(faces_i) verts, edges, faces = verts_n, edges_n, faces_n if do_clip: verts_n, edges_n, faces_n = [], [], [] bounds = calc_bounds(src_sites, clipping) for verts_i, edges_i, faces_i in zip(verts, edges, faces): bm = bmesh_from_pydata(verts_i, edges_i, faces_i) bmesh_clip(bm, bounds, fill=True) verts_i, edges_i, faces_i = pydata_from_bmesh(bm) bm.free() verts_n.append(verts_i) edges_n.append(edges_i) faces_n.append(faces_i) verts, edges, faces = verts_n, edges_n, faces_n return verts, edges, faces
def voronoi3d_regions(sites, closed_only=True, recalc_normals=True, do_clip=False, clipping=1.0): diagram = Voronoi(sites) faces_per_site = defaultdict(list) nsites = len(diagram.point_region) nridges = len(diagram.ridge_points) open_sites = set() for ridge_idx in range(nridges): site_idx_1, site_idx_2 = diagram.ridge_points[ridge_idx] face = diagram.ridge_vertices[ridge_idx] if -1 in face: open_sites.add(site_idx_1) open_sites.add(site_idx_2) continue faces_per_site[site_idx_1].append(face) faces_per_site[site_idx_2].append(face) new_verts = [] new_edges = [] new_faces = [] for site_idx in sorted(faces_per_site.keys()): if closed_only and site_idx in open_sites: continue done_verts = dict() bm = bmesh.new() add_vert = bm.verts.new add_face = bm.faces.new for face in faces_per_site[site_idx]: face_bm_verts = [] for vertex_idx in face: if vertex_idx not in done_verts: bm_vert = add_vert(diagram.vertices[vertex_idx]) done_verts[vertex_idx] = bm_vert else: bm_vert = done_verts[vertex_idx] face_bm_verts.append(bm_vert) add_face(face_bm_verts) bm.verts.index_update() bm.verts.ensure_lookup_table() bm.faces.index_update() bm.edges.index_update() if closed_only and any (v.is_boundary for v in bm.verts): bm.free() continue if recalc_normals: bm.normal_update() bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:]) region_verts, region_edges, region_faces = pydata_from_bmesh(bm) bm.free() new_verts.append(region_verts) new_edges.append(region_edges) new_faces.append(region_faces) if do_clip: verts_n, edges_n, faces_n = [], [], [] bounds = calc_bounds(sites, clipping) for verts_i, edges_i, faces_i in zip(new_verts, new_edges, new_faces): bm = bmesh_from_pydata(verts_i, edges_i, faces_i) bmesh_clip(bm, bounds, fill=True) bm.normal_update() bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:]) verts_i, edges_i, faces_i = pydata_from_bmesh(bm) bm.free() verts_n.append(verts_i) edges_n.append(edges_i) faces_n.append(faces_i) new_verts, new_edges, new_faces = verts_n, edges_n, faces_n return new_verts, new_edges, new_faces
def process(self): # inputs if not self.inputs['Vertices'].is_linked: return vertices_s = self.inputs['Vertices'].sv_get(deepcopy=False) edges_s = self.inputs['Edges'].sv_get(default=[[]], deepcopy=False) faces_s = self.inputs['Polygons'].sv_get(default=[[]], deepcopy=False) masks_s = self.inputs['Mask'].sv_get(default=[[1]], deepcopy=False) if self.transform_mode == "Matrix": matrices_s = [ self.inputs['Matrices'].sv_get(default=[Matrix()], deepcopy=False) ] heights_s = [0.0] scales_s = [1.0] else: matrices_s = [[]] heights_s = self.inputs['Height'].sv_get(deepcopy=False) scales_s = self.inputs['Scale'].sv_get(deepcopy=False) if 'FaceData' in self.inputs: face_data_s = self.inputs['FaceData'].sv_get(default=[[]], deepcopy=False) else: face_data_s = [[]] need_mask_out = 'Mask' in self.outputs and self.outputs[ 'Mask'].is_linked result_vertices = [] result_edges = [] result_faces = [] result_ext_vertices = [] result_ext_edges = [] result_ext_faces = [] result_face_data = [] result_mask = [] meshes = match_long_repeat([ vertices_s, edges_s, faces_s, masks_s, matrices_s, heights_s, scales_s, face_data_s ]) for vertices, edges, faces, masks, matrix_per_iteration, height_per_iteration, scale_per_iteration, face_data in zip( *meshes): if self.transform_mode == "Matrix": if not matrix_per_iteration: matrix_per_iteration = [Matrix()] if self.multiple: if self.transform_mode == "Matrix": n_iterations = len(matrix_per_iteration) else: n_iterations = max(len(height_per_iteration), len(scale_per_iteration)) height_per_iteration_matched = repeat_last_for_length( height_per_iteration, n_iterations) scale_per_iteration_matched = repeat_last_for_length( scale_per_iteration, n_iterations) else: n_iterations = 1 matrix_per_iteration = [matrix_per_iteration] mask_matched = repeat_last_for_length(masks, len(faces)) if face_data: face_data_matched = repeat_last_for_length( face_data, len(faces)) bm = bmesh_from_pydata(vertices, edges, faces, normal_update=True, markup_face_data=True) mask_layer = bm.faces.layers.int.new('mask') bm.faces.ensure_lookup_table() #fill_faces_layer(bm, masks, 'mask', int, MASK, invert_mask=True) b_faces = [] b_edges = set() b_verts = set() for mask, face in zip(mask_matched, bm.faces): if mask: b_faces.append(face) for edge in face.edges: b_edges.add(edge) for vert in face.verts: b_verts.add(vert) extrude_geom = b_faces + list(b_edges) + list(b_verts) extruded_verts_last = [] extruded_bm_verts_all = set() extruded_edges_last = [] extruded_faces_last = [] extruded_bm_faces_last = [] matrix_spaces = [Matrix()] for idx in range(n_iterations): for item in extrude_geom: if isinstance(item, bmesh.types.BMFace): item[mask_layer] = OUT if is_290: kwargs = { 'use_dissolve_ortho_edges': self.dissolve_ortho_edges } else: kwargs = {} new_geom = bmesh.ops.extrude_face_region( bm, geom=extrude_geom, edges_exclude=set(), use_keep_orig=self.keep_original, **kwargs)['geom'] extruded_verts = [ v for v in new_geom if isinstance(v, bmesh.types.BMVert) ] extruded_faces = [ f for f in new_geom if isinstance(f, bmesh.types.BMFace) ] if self.transform_mode == "Matrix": matrices = matrix_per_iteration[idx] if isinstance(matrices, Matrix): matrices = [matrices] matrix_spaces_matched = repeat_last_for_length( matrix_spaces, len(extruded_verts)) for vertex_idx, (vertex, matrix) in enumerate( zip(*match_long_repeat([extruded_verts, matrices ]))): bmesh.ops.transform( bm, verts=[vertex], matrix=matrix, space=matrix_spaces_matched[vertex_idx]) matrix_spaces_matched[vertex_idx] = matrix.inverted( ) @ matrix_spaces_matched[vertex_idx] else: height = height_per_iteration_matched[idx] scale = scale_per_iteration_matched[idx] normal = get_avg_normal(extruded_faces) dr = normal * height center = get_faces_center(extruded_faces) translation = Matrix.Translation(center) rotation = normal.rotation_difference( (0, 0, 1)).to_matrix().to_4x4() m = translation @ rotation bmesh.ops.scale(bm, vec=(scale, scale, scale), space=m.inverted(), verts=extruded_verts) bmesh.ops.translate(bm, verts=extruded_verts, vec=dr) extruded_bm_verts_all.update(extruded_verts) extruded_verts_last = [tuple(v.co) for v in extruded_verts] extruded_edges = [ e for e in new_geom if isinstance(e, bmesh.types.BMEdge) ] extruded_edges_last = [ tuple(v.index for v in edge.verts) for edge in extruded_edges ] extruded_bm_faces_last = extruded_faces extruded_faces_last = [[v.index for v in face.verts] for face in extruded_faces] extrude_geom = new_geom if face_data: new_vertices, new_edges, new_faces, new_face_data = pydata_from_bmesh( bm, face_data_matched) else: new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) new_face_data = [] if need_mask_out: new_mask = self.get_out_mask(bm, extruded_bm_faces_last, extruded_bm_verts_all) result_mask.append(new_mask) bm.free() result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_ext_vertices.append(extruded_verts_last) result_ext_edges.append(extruded_edges_last) result_ext_faces.append(extruded_faces_last) result_face_data.append(new_face_data) self.outputs['Vertices'].sv_set(result_vertices) self.outputs['Edges'].sv_set(result_edges) self.outputs['Polygons'].sv_set(result_faces) self.outputs['NewVertices'].sv_set(result_ext_vertices) self.outputs['NewEdges'].sv_set(result_ext_edges) self.outputs['NewFaces'].sv_set(result_ext_faces) if 'Mask' in self.outputs: self.outputs['Mask'].sv_set(result_mask) if 'FaceData' in self.outputs: self.outputs['FaceData'].sv_set(result_face_data)
def process(self): if not any(output.is_linked for output in self.outputs): return InVert, InEdge, InEdSel = self.inputs OutVert, OutEdg, OutFace, ONVert, ONEdg, ONFace, OOVert, OOEdg, OOFace = self.outputs vertices_s = InVert.sv_get(deepcopy=False) topo = InEdge.sv_get(deepcopy=False) if len(topo[0][0]) == 2: bmlist = [ bmesh_from_pydata(v, e, [], normal_update=True) for v, e in zip(vertices_s, topo) ] else: bmlist = [ bmesh_from_pydata(v, [], e, normal_update=True) for v, e in zip(vertices_s, topo) ] rev, ree, ref, riv, rie, rif, rsv, rse, rsf = [],[],[],[],[],[],[],[],[] if InEdSel.is_linked: if self.sel_mode == "index": useedges = [ np.array(bm.edges[:])[idxs] for bm, idxs in zip(bmlist, InEdSel.sv_get(deepcopy=False)) ] elif self.sel_mode == "mask": useedges = [ np.extract(mask, bm.edges[:]) for bm, mask in zip(bmlist, InEdSel.sv_get(deepcopy=False)) ] else: useedges = [bm.edges for bm in bmlist] for bm, ind in zip(bmlist, useedges): geom = subdivide_edges(bm, edges=ind, smooth=self.smooth, smooth_falloff=self.falloff_type, fractal=self.fractal, along_normal=self.along_normal, cuts=self.cuts, seed=self.seed, quad_corner_type=self.corner_type, use_grid_fill=self.grid_fill, use_single_edge=self.single_edge, use_only_quads=self.only_quads, use_smooth_even=self.smooth_even) new_verts, new_edges, new_faces = pydata_from_bmesh(bm) rev.append(new_verts) ree.append(new_edges) ref.append(new_faces) if self.show_new: geo1 = geom['geom_inner'] riv.append([ tuple(v.co) for v in geo1 if isinstance(v, bmesh.types.BMVert) ]) rie.append([[v.index for v in e.verts] for e in geo1 if isinstance(e, bmesh.types.BMEdge)]) rif.append([[v.index for v in f.verts] for f in geo1 if isinstance(f, bmesh.types.BMFace)]) if self.show_old: geo2 = geom['geom_split'] rsv.append([ tuple(v.co) for v in geo2 if isinstance(v, bmesh.types.BMVert) ]) rse.append([[v.index for v in e.verts] for e in geo2 if isinstance(e, bmesh.types.BMEdge)]) rsf.append([[v.index for v in f.verts] for f in geo2 if isinstance(f, bmesh.types.BMFace)]) bm.free() OutVert.sv_set(rev) OutEdg.sv_set(ree) OutFace.sv_set(ref) ONVert.sv_set(riv) ONEdg.sv_set(rie) ONFace.sv_set(rif) OOVert.sv_set(rsv) OOEdg.sv_set(rse) OOFace.sv_set(rsf)
def process(self): if not any(s.is_linked for s in self.outputs): return verts_in = self.inputs['Vertices'].sv_get() edges_in = self.inputs['Edges'].sv_get() offset_in = self.inputs['Offset'].sv_get() step_in = self.inputs['Step'].sv_get() n_connections_in = self.inputs['NConnections'].sv_get() max_rhos_in = self.inputs['MaxRho'].sv_get() count_in = self.inputs['Count'].sv_get() length_in = self.inputs['Length'].sv_get() if self.z_mode == 'CURVE': curves_in = self.inputs['Curve'].sv_get() else: curves_in = [[]] verts_out = [] edges_out = [] faces_out = [] Z = self.get_orientation_vector() if self.z_mode == 'AXIS': z_idx = 'XYZ'.index(self.orient_axis) else: z_idx = None objects = match_long_repeat([ verts_in, edges_in, offset_in, step_in, n_connections_in, max_rhos_in, count_in, length_in, curves_in ]) for verts, edges, offsets, steps, n_connections, max_rhos, counts, lengths, curves in zip( *objects): nverts = len(verts) offsets = cycle_for_length(offsets, nverts) steps = cycle_for_length(steps, nverts) n_connections = cycle_for_length(n_connections, nverts) max_rhos = cycle_for_length(max_rhos, nverts) if self.len_mode == 'COUNT': counts = cycle_for_length(counts, nverts) lengths = [None for i in range(nverts)] else: counts = [None for i in range(nverts)] lengths = cycle_for_length(lengths, nverts) if curves: curves = cycle_for_length(curves, nverts) bm = bmesh.new() bm.verts.ensure_lookup_table() verts_bm = [] for i, v in enumerate(verts): if self.z_mode == 'AXIS': verts_line = make_verts_axis(v, Z, self.make_basis, steps[i] * offsets[i], steps[i], counts[i], lengths[i]) else: verts_line = make_verts_curve(v, curves[i]) verts_line_bm = [] prev_bm_vert = None new_vert = bm.verts.new new_edge = bm.edges.new for v in verts_line: bm_vert = new_vert(v) verts_line_bm.append(bm_vert) bm.verts.ensure_lookup_table() if prev_bm_vert is not None: new_edge((prev_bm_vert, bm_vert)) prev_bm_vert = bm_vert verts_bm.append(verts_line_bm) for i, j in edges: process_edge(bm, z_idx, verts_bm[i], verts_bm[j], steps[i], steps[j], n_connections[i], n_connections[j], max_rhos[i], max_rhos[j]) verts_new, edges_new, _ = pydata_from_bmesh(bm) bm.free() verts_new, edges_new = intersect_edges_3d(verts_new, edges_new, 1e-3) verts_new, edges_new, _ = remove_doubles(verts_new, edges_new, [], 1e-3) if self.outputs['Faces'].is_linked: bm = bmesh_from_pydata(verts_new, edges_new, [], normal_update=True) if self.z_mode == 'AXIS': for i, j in edges: side_edges = [] v_i = Vector(verts[i]) v_j = Vector(verts[j]) #self.info("Check: [%s - %s]", v_i, v_j) for bm_edge in bm.edges: bm_v1 = bm_edge.verts[0].co bm_v2 = bm_edge.verts[1].co if self.is_same_edge(bm_v1, bm_v2, v_i, v_j): side_edges.append(bm_edge) #self.info("Yes: [%s - %s]", bm_v1, bm_v2) else: pass #self.info("No: [%s - %s]", bm_v1, bm_v2) bmesh.ops.holes_fill(bm, edges=side_edges, sides=4) bm.edges.ensure_lookup_table() bm.faces.ensure_lookup_table() else: bmesh.ops.holes_fill(bm, edges=bm.edges[:], sides=4) verts_new, edges_new, faces_new = pydata_from_bmesh(bm) bm.free() else: faces_new = [] verts_out.append(verts_new) edges_out.append(edges_new) faces_out.append(faces_new) self.outputs['Vertices'].sv_set(verts_out) self.outputs['Edges'].sv_set(edges_out) self.outputs['Faces'].sv_set(faces_out)
def process(self): # inputs if not (self.inputs['Vertices'].is_linked): return vertices_s = self.inputs['Vertices'].sv_get() edges_s = self.inputs['Edg_Pol'].sv_get(default=[[]]) #faces_s = self.inputs['Polygons'].sv_get(default=[[]]) matrices_s = self.inputs['Matrices'].sv_get(default=[[]]) if is_matrix(matrices_s[0]): matrices_s = [Matrix_generate(matrices_s)] else: matrices_s = [Matrix_generate(matrices) for matrices in matrices_s] #extrude_edges_s = self.inputs['ExtrudeEdges'].sv_get(default=[[]]) result_vertices = [] result_edges = [] result_faces = [] result_ext_vertices = [] result_ext_edges = [] result_ext_faces = [] meshes = match_long_repeat([vertices_s, edges_s, matrices_s]) #, extrude_edges_s]) for vertices, edges, matrices in zip(*meshes): if len(edges[0]) == 2: faces = [] else: faces = edges.copy() edges = [] if not matrices: matrices = [Matrix()] bm = bmesh_from_pydata(vertices, edges, faces) # better to do it in separate node, not integrate by default. #if extrude_edges: # b_edges = [] # for edge in extrude_edges: # b_edge = [e for e in bm.edges if set([v.index for v in e.verts]) == set(edge)] # b_edges.append(b_edge[0]) #else: b_edges = bm.edges new_geom = bmesh.ops.extrude_edge_only(bm, edges=b_edges, use_select_history=False)['geom'] extruded_verts = [v for v in new_geom if isinstance(v, bmesh.types.BMVert)] for vertex, matrix in zip(*match_long_repeat([extruded_verts, matrices])): bmesh.ops.transform(bm, verts=[vertex], matrix=matrix, space=Matrix()) extruded_verts = [tuple(v.co) for v in extruded_verts] extruded_edges = [e for e in new_geom if isinstance(e, bmesh.types.BMEdge)] extruded_edges = [tuple(v.index for v in edge.verts) for edge in extruded_edges] extruded_faces = [f for f in new_geom if isinstance(f, bmesh.types.BMFace)] extruded_faces = [[v.index for v in edge.verts] for edge in extruded_faces] new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) bm.free() result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_ext_vertices.append(extruded_verts) result_ext_edges.append(extruded_edges) result_ext_faces.append(extruded_faces) if self.outputs['Vertices'].is_linked: self.outputs['Vertices'].sv_set(result_vertices) if self.outputs['Edges'].is_linked: self.outputs['Edges'].sv_set(result_edges) if self.outputs['Polygons'].is_linked: self.outputs['Polygons'].sv_set(result_faces) if self.outputs['NewVertices'].is_linked: self.outputs['NewVertices'].sv_set(result_ext_vertices) if self.outputs['NewEdges'].is_linked: self.outputs['NewEdges'].sv_set(result_ext_edges) if self.outputs['NewFaces'].is_linked: self.outputs['NewFaces'].sv_set(result_ext_faces)
def process(self): if not any(socket.is_linked for socket in self.outputs): return obj_vertices_s = self.inputs['ObjVertices'].sv_get() obj_edges_s = self.inputs['ObjEdges'].sv_get(default=[[]]) obj_faces_s = self.inputs['ObjFaces'].sv_get() surf_vertices_s = self.inputs['SurfVertices'].sv_get() surf_edges_s = self.inputs['SurfEdges'].sv_get(default=[[]]) surf_faces_s = self.inputs['SurfFaces'].sv_get() fill_sides_s = self.inputs['FillSides'].sv_get() def remember_connection(edges_by_face, bm_edge, bm_intersection): for face in bm_edge.link_faces: edges_by_face[face].append((bm_intersection, bm_edge.index)) cut_verts_out = [] cut_edges_out = [] cut_faces_out = [] obj_verts_out = [] obj_edges_out = [] obj_faces_out = [] inputs = zip_long_repeat(obj_vertices_s, obj_edges_s, obj_faces_s, surf_vertices_s, surf_edges_s, surf_faces_s, fill_sides_s) for obj_vertices, obj_edges, obj_faces, surf_vertices, surf_edges, surf_faces, fill_sides in inputs: if self.fill: if isinstance(fill_sides, (list, tuple)): fill_sides = fill_sides[0] # We are using bvh's raycast to calculate intersections of object's edges # with the surface. bvh = mathutils.bvhtree.BVHTree.FromPolygons(surf_vertices, surf_faces) bm_obj = bmesh_from_pydata(obj_vertices, obj_edges, obj_faces) bm_cut = bmesh.new() edges_by_face = defaultdict(list) bm_obj.verts.index_update() bm_obj.edges.index_update() for bm_edge in bm_obj.edges: v1, v2 = bm_edge.verts edge = v1.co - v2.co # Distance restriction is used to find only intersections which are within the edge, # not anywhere on the ray. distance = edge.length # Since raycast's ray is single-directioned, we have to check for intersections # twice: from V1 to V2 and from V2 to V1. cast = bvh.ray_cast(v1.co, -edge, distance) #self.debug("Edge %s: %s -> %s, Cast 0: %s", bm_edge.index, v1.co, edge, cast) intersection = cast[0] if intersection is not None: bm_intersection = bm_cut.verts.new(intersection) remember_connection(edges_by_face, bm_edge, bm_intersection) else: cast = bvh.ray_cast(v2.co, edge, distance) #self.debug("Edge %s: %s -> %s, Cast 1: %s", bm_edge.index, v2.co, -edge, cast) intersection = cast[0] if intersection is not None: bm_intersection = bm_cut.verts.new(intersection) remember_connection(edges_by_face, bm_edge, bm_intersection) bm_cut.verts.index_update() # Make "cut surface" object. # Of each object's face we are cutting, make an edge. bm_cut_edges = [] for intersections in edges_by_face.values(): if len(intersections) == 1: self.debug("Only one of object face's edges intersects the surface") continue if len(intersections) > 2: # Some day we may support splitting the face in more than two pieces; # but the algorithm will be more complicated then. raise Exception("Unsupported: more than two edges of the face intersect the surface") v1, v2 = intersections[0][0], intersections[1][0] bm_edge = bm_cut.edges.new((v1, v2)) bm_cut_edges.append(bm_edge) if len(bm_cut.verts) > 0: if self.fill: bmesh.ops.holes_fill(bm_cut, edges=bm_cut_edges, sides=fill_sides) new_verts_cut, new_edges_cut, new_faces_cut = pydata_from_bmesh(bm_cut) if self.make_pieces: new_verts_by_old_edge = dict() new_verts_by_old_face = dict() for old_obj_face in edges_by_face: intersections = edges_by_face[old_obj_face] if len(intersections) == 1: continue int1, int2 = intersections intersection1, intersection2 = int1[0].co, int2[0].co old_edge1, old_edge2 = int1[1], int2[1] # Create a vertex in the "object" mesh at each intersection of # it's edge with the surface. # Remember which of new vertices corresponds to which edge. if old_edge1 not in new_verts_by_old_edge: new_vert_1 = bm_obj.verts.new(intersection1) new_verts_by_old_edge[old_edge1] = new_vert_1 else: new_vert_1 = new_verts_by_old_edge[old_edge1] if old_edge2 not in new_verts_by_old_edge: new_vert_2 = bm_obj.verts.new(intersection2) new_verts_by_old_edge[old_edge2] = new_vert_2 else: new_vert_2 = new_verts_by_old_edge[old_edge2] new_verts_by_old_face[old_obj_face] = (new_vert_1, new_vert_2) bm_obj.verts.index_update() faces_to_remove = [] edges_to_remove = [] for old_obj_face in edges_by_face: intersections = edges_by_face[old_obj_face] if len(intersections) == 1: continue # Walk through the edges of each face we are cutting, in order. # Of each such face, we are making two. So in this loop we have # two states: new_face_state == True means we are on the one side of # the cut, False means we are on the another. Note that we do not know # which is which (for example, which one is "inside" the surface); but # it does not matter for us. # So new_face_verts[True] will contain vertices of one piece, # new_face_verts[False] - of another one. new_face_verts = defaultdict(list) new_face_side = True old_vert_pairs = list(zip(old_obj_face.verts, old_obj_face.verts[1:])) + [(old_obj_face.verts[-1], old_obj_face.verts[0])] need_split = False for old_vert_1, old_vert_2 in old_vert_pairs: old_edge = bm_obj.edges.get((old_vert_1, old_vert_2)) if old_edge.index in new_verts_by_old_edge: edges_to_remove.append((old_edge.verts[0], old_edge.verts[1])) need_split = True new_vert_1 = new_verts_by_old_edge[old_edge.index] self.debug("Old edge %s - %s is to be split; use new vert %s", old_vert_1.index, old_vert_2.index, new_vert_1.index) new_face_verts[new_face_side].append(new_vert_1) # if this edge is to be split, then we are stepping from one piece of # the face to another new_face_side = not new_face_side new_face_verts[new_face_side].append(new_vert_1) new_face_verts[new_face_side].append(old_vert_2) else: self.debug("Old edge %s - %s is not to be split", old_vert_1.index, old_vert_2.index) new_face_verts[new_face_side].append(old_vert_2) if need_split: faces_to_remove.append(old_obj_face) self.debug("Splitting face: %s", [v.index for v in old_obj_face.verts]) for new_face_list in new_face_verts.values(): bm_obj.faces.new(new_face_list) # remove old faces and edges (ones we cut in two) for old_face in faces_to_remove: bm_obj.faces.remove(old_face) for old_v1, old_v2 in edges_to_remove: # we can't just remember BMEdge instances themselves, # since they will be invalidated when we remove faces. old_edge = bm_obj.edges.get((old_v1, old_v2)) if old_edge: bm_obj.edges.remove(old_edge) edges_to_split = [] for new_vert_1, new_vert_2 in new_verts_by_old_face.values(): edge = bm_obj.edges.get((new_vert_1, new_vert_2)) edges_to_split.append(edge) # Split "object" by remembered cut edges. There will be "holes" # at places we cut. split_result = bmesh.ops.split_edges(bm_obj, edges=edges_to_split) if self.fill: bmesh.ops.holes_fill(bm_obj, edges = split_result['edges'], sides=fill_sides) new_verts_obj, new_edges_obj, new_faces_obj = pydata_from_bmesh(bm_obj) else: new_verts_obj, new_edges_obj, new_faces_obj = [], [], [] bm_cut.free() bm_obj.free() cut_verts_out.append(new_verts_cut) cut_edges_out.append(new_edges_cut) cut_faces_out.append(new_faces_cut) obj_verts_out.append(new_verts_obj) obj_edges_out.append(new_edges_obj) obj_faces_out.append(new_faces_obj) self.outputs['CutVertices'].sv_set(cut_verts_out) self.outputs['CutEdges'].sv_set(cut_edges_out) self.outputs['CutFaces'].sv_set(cut_faces_out) self.outputs['ObjVertices'].sv_set(obj_verts_out) self.outputs['ObjEdges'].sv_set(obj_edges_out) self.outputs['ObjFaces'].sv_set(obj_faces_out)
def process(self): # inputs if not (self.inputs['Vertices'].is_linked and self.inputs['Polygons'].is_linked): return if not any( self.outputs[name].is_linked for name in ['Vertices', 'Edges', 'Polygons', 'ExtrudedPolys', 'OtherPolys']): return vertices_s = self.inputs['Vertices'].sv_get() edges_s = self.inputs['Edges'].sv_get(default=[[]]) faces_s = self.inputs['Polygons'].sv_get(default=[[]]) masks_s = self.inputs['Mask'].sv_get(default=[[1]]) heights_s = self.inputs['Height'].sv_get() scales_s = self.inputs['Scale'].sv_get() result_vertices = [] result_edges = [] result_faces = [] result_extruded_faces = [] result_other_faces = [] meshes = match_long_repeat( [vertices_s, edges_s, faces_s, masks_s, heights_s, scales_s]) offset = 0 for vertices, edges, faces, masks, heights, scales in zip(*meshes): fullList(heights, len(faces)) fullList(scales, len(faces)) fullList(masks, len(faces)) bm = bmesh_from_pydata(vertices, edges, faces) extruded_faces = bmesh.ops.extrude_discrete_faces( bm, faces=bm.faces)['faces'] new_extruded_faces = [] for face, mask, height, scale in zip(extruded_faces, masks, heights, scales): if not mask: continue dr = face.normal * height center = face.calc_center_median() translation = Matrix.Translation(center) rotation = face.normal.rotation_difference( (0, 0, 1)).to_matrix().to_4x4() #rotation = autorotate(z, face.normal).inverted() m = translation * rotation bmesh.ops.scale(bm, vec=(scale, scale, scale), space=m.inverted(), verts=face.verts) bmesh.ops.translate(bm, verts=face.verts, vec=dr) new_extruded_faces.append([v.index for v in face.verts]) new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) bm.free() new_other_faces = [ f for f in new_faces if f not in new_extruded_faces ] result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_extruded_faces.append(new_extruded_faces) result_other_faces.append(new_other_faces) self.outputs['Vertices'].sv_set(result_vertices) if self.outputs['Edges'].is_linked: self.outputs['Edges'].sv_set(result_edges) if self.outputs['Polygons'].is_linked: self.outputs['Polygons'].sv_set(result_faces) if self.outputs['ExtrudedPolys'].is_linked: self.outputs['ExtrudedPolys'].sv_set(result_extruded_faces) if self.outputs['OtherPolys'].is_linked: self.outputs['OtherPolys'].sv_set(result_other_faces)
def process(self): # inputs if not self.inputs['Vertices'].is_linked: return vertices_s = self.inputs['Vertices'].sv_get() edges_s = self.inputs['Edges'].sv_get(default=[[]]) faces_s = self.inputs['Polygons'].sv_get(default=[[]]) masks_s = self.inputs['Mask'].sv_get(default=[[1]]) if self.transform_mode == "Matrix": matrices_s = [self.inputs['Matrices'].sv_get(Matrix())] heights_s = [0.0] scales_s = [1.0] else: matrices_s = [[]] heights_s = self.inputs['Height'].sv_get() scales_s = self.inputs['Scale'].sv_get() result_vertices = [] result_edges = [] result_faces = [] result_ext_vertices = [] result_ext_edges = [] result_ext_faces = [] meshes = match_long_repeat([ vertices_s, edges_s, faces_s, masks_s, matrices_s, heights_s, scales_s ]) for vertices, edges, faces, masks, matrix_per_iteration, height_per_iteration, scale_per_iteration in zip( *meshes): if self.transform_mode == "Matrix": if not matrix_per_iteration: matrix_per_iteration = [Matrix()] if self.multiple: if self.transform_mode == "Matrix": n_iterations = len(matrix_per_iteration) else: n_iterations = max(len(height_per_iteration), len(scale_per_iteration)) fullList(height_per_iteration, n_iterations) fullList(scale_per_iteration, n_iterations) else: n_iterations = 1 matrix_per_iteration = [matrix_per_iteration] fullList(masks, len(faces)) bm = bmesh_from_pydata(vertices, edges, faces, normal_update=True) b_faces = [] b_edges = set() b_verts = set() for mask, face in zip(masks, bm.faces): if mask: b_faces.append(face) for edge in face.edges: b_edges.add(edge) for vert in face.verts: b_verts.add(vert) extrude_geom = b_faces + list(b_edges) + list(b_verts) extruded_verts_last = [] extruded_edges_last = [] extruded_faces_last = [] matrix_spaces = [Matrix()] for idx in range(n_iterations): new_geom = bmesh.ops.extrude_face_region( bm, geom=extrude_geom, edges_exclude=set(), use_keep_orig=self.keep_original)['geom'] extruded_verts = [ v for v in new_geom if isinstance(v, bmesh.types.BMVert) ] extruded_faces = [ f for f in new_geom if isinstance(f, bmesh.types.BMFace) ] if self.transform_mode == "Matrix": matrices = matrix_per_iteration[idx] if isinstance(matrices, Matrix): matrices = [matrices] fullList(matrix_spaces, len(extruded_verts)) for vertex_idx, (vertex, matrix) in enumerate( zip(*match_long_repeat([extruded_verts, matrices ]))): bmesh.ops.transform(bm, verts=[vertex], matrix=matrix, space=matrix_spaces[vertex_idx]) matrix_spaces[vertex_idx] = matrix.inverted( ) @ matrix_spaces[vertex_idx] else: height = height_per_iteration[idx] scale = scale_per_iteration[idx] normal = get_avg_normal(extruded_faces) dr = normal * height center = get_faces_center(extruded_faces) translation = Matrix.Translation(center) rotation = normal.rotation_difference( (0, 0, 1)).to_matrix().to_4x4() m = translation @ rotation bmesh.ops.scale(bm, vec=(scale, scale, scale), space=m.inverted(), verts=extruded_verts) bmesh.ops.translate(bm, verts=extruded_verts, vec=dr) extruded_verts_last = [tuple(v.co) for v in extruded_verts] extruded_edges = [ e for e in new_geom if isinstance(e, bmesh.types.BMEdge) ] extruded_edges_last = [ tuple(v.index for v in edge.verts) for edge in extruded_edges ] extruded_faces_last = [[v.index for v in edge.verts] for edge in extruded_faces] extrude_geom = new_geom new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) bm.free() result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_ext_vertices.append(extruded_verts_last) result_ext_edges.append(extruded_edges_last) result_ext_faces.append(extruded_faces_last) self.outputs['Vertices'].sv_set(result_vertices) self.outputs['Edges'].sv_set(result_edges) self.outputs['Polygons'].sv_set(result_faces) self.outputs['NewVertices'].sv_set(result_ext_vertices) self.outputs['NewEdges'].sv_set(result_ext_edges) self.outputs['NewFaces'].sv_set(result_ext_faces)
def process(self): inputs = self.inputs outputs = self.outputs if not (inputs['Vertices'].is_linked and inputs['Polygons'].is_linked): return if not any(socket.is_linked for socket in outputs): return need_mask_out = 'Mask' in outputs and outputs['Mask'].is_linked vector_in = self.scale_socket_type vertices_s = inputs['Vertices'].sv_get(deepcopy=False) edges_s = inputs['Edges'].sv_get(default=[[]], deepcopy=False) faces_s = inputs['Polygons'].sv_get(default=[[]], deepcopy=False) masks_s = inputs['Mask'].sv_get(default=[[1]], deepcopy=False) heights_s = inputs['Height'].sv_get(deepcopy=False) scales_s = inputs['Scale'].sv_get(deepcopy=False) if 'Matrix' in inputs: matrixes_s = inputs['Matrix'].sv_get(default=[[Matrix()]], deepcopy=False) else: matrixes_s = [[Matrix()]] if 'FaceData' in inputs: face_data_s = self.inputs['FaceData'].sv_get(default=[[]], deepcopy=False) else: face_data_s = [[]] if type(matrixes_s[0]) == Matrix: matrixes_s = [matrixes_s] linked_extruded_polygons = outputs['ExtrudedPolys'].is_linked linked_other_polygons = outputs['OtherPolys'].is_linked result_vertices = [] result_edges = [] result_faces = [] result_extruded_faces = [] result_other_faces = [] result_mask = [] result_face_data = [] meshes = match_long_repeat([vertices_s, edges_s, faces_s, masks_s, heights_s, scales_s, matrixes_s, face_data_s]) for vertices, edges, faces, masks_, heights_, scales_, matrixes_, face_data in zip(*meshes): new_extruded_faces = [] new_extruded_faces_append = new_extruded_faces.append heights, scales, matrixes = make_repeaters([heights_, scales_, matrixes_]) masks = repeat_last_for_length(masks_, len(faces)) if face_data: face_data_matched = repeat_last_for_length(face_data, len(faces)) bm = bmesh_from_pydata(vertices, edges, faces, markup_face_data=True, normal_update=True) mask_layer = bm.faces.layers.int.new('mask') bm.faces.ensure_lookup_table() fill_faces_layer(bm, masks, 'mask', int, OUT) if self.mask_mode == 'NOEXTRUDE': faces_to_extrude = [face for face, mask in zip(bm.faces, masks) if mask] else: faces_to_extrude = bm.faces extruded_faces = bmesh.ops.extrude_discrete_faces(bm, faces=faces_to_extrude)['faces'] if self.mask_mode == 'NOEXTRUDE': extruded_face_items = zip(extruded_faces, heights, scales, matrixes) else: extruded_face_items = [(face, height, scale, matrix) for (face, mask, height, scale, matrix) in zip(extruded_faces, masks, heights, scales, matrixes) if mask] for face, height, scale, matrix in extruded_face_items: vec = scale if vector_in else (scale, scale, scale) # preparing matrix normal = face.normal if normal[0] == 0 and normal[1] == 0: m_r = Matrix() if normal[2] >= 0 else Matrix.Rotation(pi, 4, 'X') else: z_axis = normal x_axis = (Vector((z_axis[1] * -1, z_axis[0], 0))).normalized() y_axis = (z_axis.cross(x_axis)).normalized() m_r = Matrix(list([*zip(x_axis[:], y_axis[:], z_axis[:])])).to_4x4() dr = face.normal * height center = face.calc_center_median() translation = Matrix.Translation(center) space = (translation @ m_r).inverted() if self.extrude_mode == 'NORMAL': # inset, scale and push operations bmesh.ops.scale(bm, vec=vec, space=space, verts=face.verts) bmesh.ops.translate(bm, verts=face.verts, vec=dr) else: bmesh.ops.transform(bm, matrix=matrix, space=space, verts=face.verts) if linked_extruded_polygons or linked_other_polygons: new_extruded_faces_append([v.index for v in face.verts]) if face_data: new_vertices, new_edges, new_faces, new_face_data = pydata_from_bmesh(bm, face_data_matched) else: new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) new_face_data = [] new_other_faces = [f for f in new_faces if f not in new_extruded_faces] if linked_other_polygons else [] if need_mask_out: new_mask = self.get_out_mask(bm, extruded_faces) result_mask.append(new_mask) bm.free() result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_extruded_faces.append(new_extruded_faces) result_other_faces.append(new_other_faces) result_face_data.append(new_face_data) outputs['Vertices'].sv_set(result_vertices) outputs['Edges'].sv_set(result_edges) outputs['Polygons'].sv_set(result_faces) outputs['ExtrudedPolys'].sv_set(result_extruded_faces) outputs['OtherPolys'].sv_set(result_other_faces) if need_mask_out: outputs['Mask'].sv_set(result_mask) if 'FaceData' in outputs: outputs['FaceData'].sv_set(result_face_data)
def process(self): # достаём два слота - вершины и полики if all(s.is_linked for s in self.inputs[:-1]): if self.inputs['Z_Coef'].is_linked: z_coef = self.inputs['Z_Coef'].sv_get()[0] else: z_coef = [] polsR = self.inputs['PolsR'].sv_get()[ 0] # recipient one object [0] versR = self.inputs['VersR'].sv_get()[0] # recipient polsD = self.inputs['PolsD'].sv_get() # donor many objects [:] versD_ = self.inputs['VersD'].sv_get() # donor versD = Vector_generate(versD_) polsR, polsD, versD = match_long_repeat([polsR, polsD, versD]) bm = bmesh_from_pydata(versR, [], polsR, normal_update=True) bm.verts.ensure_lookup_table() new_ve = bm.verts vers_out = [] pols_out = [] i = 0 for vD, pR in zip(versD, polsR): # part of donor to make limits j = i pD = polsD[i] xx = [x[0] for x in vD] x0 = (self.width_coef) / (max(xx) - min(xx)) yy = [y[1] for y in vD] y0 = (self.width_coef) / (max(yy) - min(yy)) zz = [z[2] for z in vD] zzz = (max(zz) - min(zz)) if zzz: z0 = 1 / zzz else: z0 = 0 # part of recipient polygons to reciev donor last = len(pR) - 1 vs = [new_ve[v] for v in pR] # new_ve - temporery data if z_coef: if j < len(z_coef): z1 = z0 * z_coef[j] else: z1 = z0 new_vers = [] new_pols = [] for v in vD: new_vers.append( self.lerp3(vs[0], vs[1], vs[2], vs[last], v, x0, y0, z1)) for p in pD: new_pols.append([id for id in p]) pols_out.append(new_pols) vers_out.append(new_vers) i += 1 bm.free() output = Vector_degenerate(vers_out) self.outputs['Vertices'].sv_set(output) self.outputs['Poligons'].sv_set(pols_out)
def process(self): if not (self.inputs['Vertices'].is_linked and self.inputs['Polygons'].is_linked): return if not (any( self.outputs[name].is_linked for name in ['Vertices', 'Edges', 'Polygons', 'NewEdges', 'NewPolys'])): return vertices_s = self.inputs['Vertices'].sv_get(default=[[]]) edges_s = self.inputs['Edges'].sv_get(default=[[]]) faces_s = self.inputs['Polygons'].sv_get(default=[[]]) mask_s = self.inputs['Mask'].sv_get(default=[[True]]) result_vertices = [] result_edges = [] result_faces = [] result_new_edges = [] result_new_faces = [] meshes = match_long_repeat([vertices_s, edges_s, faces_s, mask_s]) for vertices, edges, faces, mask in zip(*meshes): bm = bmesh_from_pydata(vertices, edges, faces) fullList(mask, len(faces)) b_faces = [] for m, face in zip(mask, bm.faces): if m: b_faces.append(face) res = bmesh.ops.triangulate(bm, faces=b_faces, quad_method=int(self.quad_mode), ngon_method=int(self.ngon_mode)) b_new_edges = [ tuple(v.index for v in edge.verts) for edge in res['edges'] ] b_new_faces = [[v.index for v in face.verts] for face in res['faces']] new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) bm.free() result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_new_edges.append(b_new_edges) result_new_faces.append(b_new_faces) if self.outputs['Vertices'].is_linked: self.outputs['Vertices'].sv_set(result_vertices) if self.outputs['Edges'].is_linked: self.outputs['Edges'].sv_set(result_edges) if self.outputs['Polygons'].is_linked: self.outputs['Polygons'].sv_set(result_faces) if self.outputs['NewEdges'].is_linked: self.outputs['NewEdges'].sv_set(result_new_edges) if self.outputs['NewPolys'].is_linked: self.outputs['NewPolys'].sv_set(result_new_faces)
def process(self): # достаём два слота - вершины и полики if 'Vertices' in self.outputs and self.outputs['Vertices'].links: if (self.inputs['PolsR'].links and self.inputs['VersR'].links and self.inputs['VersD'].links and self.inputs['PolsD'].links): if self.inputs['Z_Coef'].links: z_coef = SvGetSocketAnyType(self, self.inputs['Z_Coef'])[0] else: z_coef = [] polsR = SvGetSocketAnyType( self, self.inputs['PolsR'])[0] # recipient one object [0] versR = SvGetSocketAnyType( self, self.inputs['VersR'])[0] # recipient polsD = SvGetSocketAnyType( self, self.inputs['PolsD']) # donor many objects [:] versD_ = SvGetSocketAnyType(self, self.inputs['VersD']) # donor versD = Vector_generate(versD_) ##### it is needed for normals of vertices bm = bmesh_from_pydata(versR, [], polsR) bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:]) bm.verts.ensure_lookup_table() new_ve = bm.verts #new_me = bpy.data.meshes.new('recepient') #new_me.from_pydata(versR, [], polsR) #new_me.update(calc_edges=True) #new_ve = new_me.vertices #print (new_ve[0].normal, 'normal') for i, vD in enumerate(versD): pD = polsD[i] n_verts = len(vD) n_faces = len(pD) xx = [x[0] for x in vD] x0 = (self.width_coef) / (max(xx) - min(xx)) yy = [y[1] for y in vD] y0 = (self.width_coef) / (max(yy) - min(yy)) zz = [z[2] for z in vD] zzz = (max(zz) - min(zz)) if zzz: z0 = 1 / zzz else: z0 = 0 #print (x0, y0, z0) vers_out = [] pols_out = [] for j, pR in enumerate(polsR): last = len(pR) - 1 vs = [new_ve[v] for v in pR] # new_ve - temporery data if z_coef: if j < len(z_coef): z1 = z0 * z_coef[j] else: z1 = z0 new_vers = [] new_pols = [] for v in vD: new_vers.append( self.lerp3(vs[0], vs[1], vs[2], vs[last], v, x0, y0, z1)) for p in pD: new_pols.append([id for id in p]) pols_out.append(new_pols) vers_out.append(new_vers) #bpy.data.meshes.remove(new_me) # cleaning and washing bm.free() #print (Vector_degenerate(vers_out)) output = Vector_degenerate(vers_out) #print (output) if 'Vertices' in self.outputs and self.outputs[ 'Vertices'].links: SvSetSocketAnyType(self, 'Vertices', output) if 'Poligons' in self.outputs and self.outputs[ 'Poligons'].links: SvSetSocketAnyType(self, 'Poligons', pols_out)
def process(self): if not any(output.is_linked for output in self.outputs): return vertices_s = self.inputs['Vertices'].sv_get() edges_s = self.inputs['Edges'].sv_get(default=[[]]) faces_s = self.inputs['Faces'].sv_get(default=[[]]) masks_s = self.inputs['EdgeMask'].sv_get(default=[[1]]) cuts_s = self.inputs['Cuts'].sv_get()[0] smooth_s = self.inputs['Smooth'].sv_get()[0] fractal_s = self.inputs['Fractal'].sv_get()[0] along_normal_s = self.inputs['AlongNormal'].sv_get()[0] seed_s = self.inputs['Seed'].sv_get()[0] result_vertices = [] result_edges = [] result_faces = [] r_inner_vertices = [] r_inner_edges = [] r_inner_faces = [] r_split_vertices = [] r_split_edges = [] r_split_faces = [] meshes = match_long_repeat([ vertices_s, edges_s, faces_s, masks_s, cuts_s, smooth_s, fractal_s, along_normal_s, seed_s ]) for vertices, edges, faces, masks, cuts, smooth, fractal, along_normal, seed in zip( *meshes): fullList(masks, len(edges)) bm = bmesh_from_pydata(vertices, edges, faces, normal_update=True) selected_edges = [] for m, edge in zip(masks, edges): if not m: continue found = False for bmesh_edge in bm.edges: if set(v.index for v in bmesh_edge.verts) == set(edge): found = True break if found: selected_edges.append(bmesh_edge) else: print("Cant find edge: " + str(edge)) geom = bmesh.ops.subdivide_edges( bm, edges=selected_edges, smooth=smooth, smooth_falloff=int(self.falloff_type), fractal=fractal, along_normal=along_normal, cuts=cuts, seed=seed, quad_corner_type=int(self.corner_type), use_grid_fill=self.grid_fill, use_single_edge=self.single_edge, use_only_quads=self.only_quads, use_smooth_even=self.smooth_even) new_verts, new_edges, new_faces = pydata_from_bmesh(bm) inner_verts, inner_edges, inner_faces = self.get_result_pydata( geom['geom_inner']) split_verts, split_edges, split_faces = self.get_result_pydata( geom['geom_split']) bm.free() result_vertices.append(new_verts) result_edges.append(new_edges) result_faces.append(new_faces) r_inner_vertices.append(inner_verts) r_inner_edges.append(inner_edges) r_inner_faces.append(inner_faces) r_split_vertices.append(split_verts) r_split_edges.append(split_edges) r_split_faces.append(split_faces) self.outputs['Vertices'].sv_set(result_vertices) self.outputs['Edges'].sv_set(result_edges) self.outputs['Faces'].sv_set(result_faces) self.outputs['NewVertices'].sv_set(r_inner_vertices) self.outputs['NewEdges'].sv_set(r_inner_edges) self.outputs['NewFaces'].sv_set(r_inner_faces) self.outputs['OldVertices'].sv_set(r_split_vertices) self.outputs['OldEdges'].sv_set(r_split_edges) self.outputs['OldFaces'].sv_set(r_split_faces)
def calc_mesh_normals(vertices, edges, faces): bm = bmesh_from_pydata(vertices, edges, faces, normal_update=True) vertex_normals = [v.normal[:] for v in bm.verts] bm.free() return vertex_normals
def process(self): inputs = self.inputs outputs = self.outputs if not (inputs['Vertices'].is_linked and inputs['Polygons'].is_linked): return if not any(socket.is_linked for socket in outputs): return vector_in = self.scale_socket_type vertices_s = inputs['Vertices'].sv_get() edges_s = inputs['Edges'].sv_get(default=[[]]) faces_s = inputs['Polygons'].sv_get(default=[[]]) masks_s = inputs['Mask'].sv_get(default=[[1]]) heights_s = inputs['Height'].sv_get() scales_s = inputs['Scale'].sv_get() linked_extruded_polygons = outputs['ExtrudedPolys'].is_linked linked_other_polygons = outputs['OtherPolys'].is_linked result_vertices = [] result_edges = [] result_faces = [] result_extruded_faces = [] result_other_faces = [] meshes = match_long_repeat( [vertices_s, edges_s, faces_s, masks_s, heights_s, scales_s]) for vertices, edges, faces, masks, heights, scales in zip(*meshes): new_extruded_faces = [] new_extruded_faces_append = new_extruded_faces.append fullList(heights, len(faces)) fullList(scales, len(faces)) fullList(masks, len(faces)) bm = bmesh_from_pydata(vertices, edges, faces) extruded_faces = bmesh.ops.extrude_discrete_faces( bm, faces=bm.faces)['faces'] for face, mask, height, scale in zip(extruded_faces, masks, heights, scales): if not mask: continue vec = scale if vector_in else (scale, scale, scale) # preparing matrix normal = face.normal if normal[0] == 0 and normal[1] == 0: m_r = Matrix() if normal[2] >= 0 else Matrix.Rotation( pi, 4, 'X') else: z_axis = normal x_axis = (Vector( (z_axis[1] * -1, z_axis[0], 0))).normalized() y_axis = (z_axis.cross(x_axis)).normalized() m_r = Matrix(list([*zip(x_axis[:], y_axis[:], z_axis[:]) ])).to_4x4() dr = face.normal * height center = face.calc_center_median() translation = Matrix.Translation(center) m = (translation @ m_r).inverted() # inset, scale and push operations bmesh.ops.scale(bm, vec=vec, space=m, verts=face.verts) bmesh.ops.translate(bm, verts=face.verts, vec=dr) if linked_extruded_polygons or linked_other_polygons: new_extruded_faces_append([v.index for v in face.verts]) new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) bm.free() new_other_faces = [ f for f in new_faces if f not in new_extruded_faces ] if linked_other_polygons else [] result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_extruded_faces.append(new_extruded_faces) result_other_faces.append(new_other_faces) outputs['Vertices'].sv_set(result_vertices) outputs['Edges'].sv_set(result_edges) outputs['Polygons'].sv_set(result_faces) outputs['ExtrudedPolys'].sv_set(result_extruded_faces) outputs['OtherPolys'].sv_set(result_other_faces)
def process(self): bmL, V, E, P = self.inputs Val = bmL.sv_get() if bmL.is_linked else [] o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15, o16, o17, o18, o19, o20, o21, o22, o23, o24, o25 = self.outputs if V.is_linked: for v, e, f in zip(*match_long_repeat( [V.sv_get(), E.sv_get([[]]), P.sv_get([[]])])): bm = bmesh_from_pydata(v, e, f) Val.append(bm) if self.mode1: for bm in Val: bm.normal_update() if o1.is_linked: o1.sv_set([[bm.calc_volume(signed=False) for bm in Val]]) if o2.is_linked: o2.sv_set([[vert.calc_edge_angle(-1) for vert in bm.verts] for bm in Val]) if o3.is_linked: o3.sv_set([[vert.calc_shell_factor() for vert in bm.verts] for bm in Val]) if o4.is_linked: o4.sv_set([[vert.is_boundary for vert in bm.verts] for bm in Val]) if o5.is_linked: o5.sv_set([[vert.is_manifold for vert in bm.verts] for bm in Val]) if o6.is_linked: o6.sv_set([[vert.is_wire for vert in bm.verts] for bm in Val]) if o7.is_linked: o7.sv_set([[vert.normal[:] for vert in bm.verts] for bm in Val]) if o8.is_linked: o8.sv_set([[edge.calc_face_angle_signed(0) for edge in bm.edges] for bm in Val]) if o9.is_linked: o9.sv_set([[edge.calc_length() for edge in bm.edges] for bm in Val]) if o10.is_linked: o10.sv_set([[edge.is_boundary for edge in bm.edges] for bm in Val]) if o11.is_linked: o11.sv_set([[edge.is_contiguous for edge in bm.edges] for bm in Val]) if o12.is_linked: o12.sv_set([[edge.is_convex for edge in bm.edges] for bm in Val]) if o13.is_linked: o13.sv_set([[edge.is_manifold for edge in bm.edges] for bm in Val]) if o14.is_linked: o14.sv_set([[edge.is_wire for edge in bm.edges] for bm in Val]) if o15.is_linked: o15.sv_set([[face.calc_area() for face in bm.faces] for bm in Val]) if o16.is_linked: o16.sv_set([[face.calc_center_bounds()[:] for face in bm.faces] for bm in Val]) if o17.is_linked: o17.sv_set([[face.calc_center_median()[:] for face in bm.faces] for bm in Val]) if o18.is_linked: o18.sv_set( [[face.calc_center_median_weighted()[:] for face in bm.faces] for bm in Val]) if o19.is_linked: o19.sv_set([[face.calc_perimeter() for face in bm.faces] for bm in Val]) if o20.is_linked: o20.sv_set([[face.calc_tangent_edge()[:] for face in bm.faces] for bm in Val]) if o21.is_linked: o21.sv_set( [[face.calc_tangent_edge_diagonal()[:] for face in bm.faces] for bm in Val]) if o22.is_linked: o22.sv_set( [[face.calc_tangent_edge_pair()[:] for face in bm.faces] for bm in Val]) if o23.is_linked: o23.sv_set( [[face.calc_tangent_vert_diagonal()[:] for face in bm.faces] for bm in Val]) if o24.is_linked: o24.sv_set([[face.normal[:] for face in bm.faces] for bm in Val]) if o25.is_linked: o25.sv_set(Val)
def process(self): if not any(socket.is_linked for socket in self.outputs): return vertices_s = self.inputs['Vertices'].sv_get() edges_s = self.inputs['Edges'].sv_get() faces_s = self.inputs['Faces'].sv_get() vertex_weight_s = self.inputs['VertexWeight'].sv_get() edge_weight_s = self.inputs['EdgeWeight'].sv_get() face_weight_s = self.inputs['FaceWeight'].sv_get() tangent_weight_s = self.inputs['TangentWeight'].sv_get() degree_u_s = self.inputs['DegreeU'].sv_get() degree_v_s = self.inputs['DegreeV'].sv_get() surface_out = [] control_points_out = [] weights_out = [] inputs = zip_long_repeat(vertices_s, edges_s, faces_s, degree_u_s, degree_v_s, vertex_weight_s, edge_weight_s, face_weight_s, tangent_weight_s) for vertices, edges, faces, degree_u, degree_v, vertex_weights, edge_weights, face_weights, tangent_weights in inputs: fullList(degree_u, len(faces)) fullList(degree_v, len(faces)) if not edges: edges = polygons_to_edges([faces], True)[0] fullList(vertex_weights, len(vertices)) fullList(tangent_weights, len(vertices)) fullList(edge_weights, len(edges)) fullList(face_weights, len(faces)) bm = bmesh_from_pydata(vertices, edges, faces, normal_update=True, markup_edge_data=True) normals = [vertex.normal for vertex in bm.verts] edge_planes_dict = dict() for edge in bm.edges: edge_v = edge.verts[1].co - edge.verts[0].co edge_c = (edge.verts[0].co + edge.verts[1].co) / 2.0 edge_ort_plane = PlaneEquation.from_normal_and_point( edge_v, edge_c) face_normals = [face.normal for face in edge.link_faces] faces_normal = sum(face_normals, Vector()) projected_faces_normal = edge_ort_plane.projection_of_point( faces_normal) #print("EV: %s, No.sum: %s, Pr.N: %s" % (edge_v, faces_normal, projected_faces_normal)) edge_plane = PlaneEquation.from_normal_and_point( projected_faces_normal, edge_c) edge_planes_dict[(edge.verts[0].index, edge.verts[1].index)] = edge_plane edge_planes_dict[(edge.verts[1].index, edge.verts[0].index)] = edge_plane bm.free() vert_planes = [ PlaneEquation.from_normal_and_point(normal, point) for normal, point in zip(normals, vertices) ] edge_weights_dict = dict() #edge_planes_dict = dict() for (i, j), edge_weight in zip(edges, edge_weights): edge_weights_dict[(i, j)] = edge_weight edge_weights_dict[(j, i)] = edge_weight #edge_planes_dict[(i, j)] = edge_plane #edge_planes_dict[(j, i)] = edge_plane for i, (face, degree_u, degree_v, face_weight) in enumerate( zip(faces, degree_u, degree_v, face_weights)): if len(face) != 4: self.info("Face #%s is not a Quad, skip it", i) continue face_verts = [vertices[i] for i in face] face_planes = [vert_planes[i] for i in face] face_vert_weights = [vertex_weights[i] for i in face] face_tangent_weights = [tangent_weights[i] for i in face] #face_edges = list(zip(face, face[1:])) + [(face[-1], face[0])] #face_edge_weights = [edge_weights_dict[edge] for edge in face_edges] surface, ctrlpts, weights = self.make_surface( face, degree_u, degree_v, face_verts, face_planes, face_vert_weights, face_tangent_weights, face_weight, edge_weights_dict, edge_planes_dict) surface_out.append(surface) control_points_out.append(list(map(tuple, ctrlpts))) weights_out.append(weights) self.outputs['Surfaces'].sv_set(surface_out) self.outputs['ControlPoints'].sv_set(control_points_out) self.outputs['Weights'].sv_set(weights_out)
def make_bmesh_geometry_merged(node, obj_index, context, yielder_object): scene = context.scene collection = scene.collection meshes = bpy.data.meshes objects = bpy.data.objects name = f'{node.basedata_name}.{obj_index:04d}' if name in objects: sv_object = objects[name] else: temp_mesh = default_mesh(name) sv_object = objects.new(name, temp_mesh) collection.objects.link(sv_object) # book-keeping via ID-props! sv_object['idx'] = obj_index sv_object['madeby'] = node.name sv_object['basedata_name'] = node.basedata_name vert_count = 0 big_verts = [] big_edges = [] big_faces = [] big_materials = [] for result in yielder_object: verts, topology = result edges, faces, materials, matrix = topology if matrix: # matrix = matrix_sanitizer(matrix) verts = [matrix @ Vector(v) for v in verts] big_verts.extend(verts) big_edges.extend([[a + vert_count, b + vert_count] for a, b in edges]) big_faces.extend([[j + vert_count for j in f] for f in faces]) big_materials.extend(materials) vert_count += len(verts) if node.fixed_verts and len(sv_object.data.vertices) == len(big_verts): mesh = sv_object.data f_v = list(itertools.chain.from_iterable(big_verts)) mesh.vertices.foreach_set('co', f_v) mesh.update() else: ''' get bmesh, write bmesh to obj, free bmesh''' bm = bmesh_from_pydata(big_verts, big_edges, big_faces, normal_update=node.calc_normals) if materials: for face, material in zip(bm.faces[:], big_materials): if material is not None: face.material_index = material bm.to_mesh(sv_object.data) bm.free() sv_object.hide_select = False sv_object.matrix_local = Matrix.Identity(4)
def get_vertex_normals(vecs, polygons): mesh = bmesh_from_pydata(vecs, [], polygons, normal_update=True) return [Vector(vert.normal) for vert in mesh.verts]
def process(self): if not (self.inputs['Vertices'].is_linked and self.inputs['Polygons'].is_linked): return if not (any( self.outputs[name].is_linked for name in ['Vertices', 'Edges', 'Polygons', 'NewPolys'])): return vertices_s = self.inputs['Vertices'].sv_get(default=[[]]) edges_s = self.inputs['Edges'].sv_get(default=[[]]) faces_s = self.inputs['Polygons'].sv_get(default=[[]]) offsets_s = self.inputs['Offset'].sv_get()[0] segments_s = self.inputs['Segments'].sv_get()[0] profiles_s = self.inputs['Profile'].sv_get()[0] bevel_edges_s = self.inputs['BevelEdges'].sv_get(default=[[]]) result_vertices = [] result_edges = [] result_faces = [] result_bevel_faces = [] meshes = match_long_repeat([ vertices_s, edges_s, faces_s, bevel_edges_s, offsets_s, segments_s, profiles_s ]) for vertices, edges, faces, bevel_edges, offset, segments, profile in zip( *meshes): bm = bmesh_from_pydata(vertices, edges, faces) if bevel_edges: b_edges = [] for edge in bevel_edges: b_edge = [ e for e in bm.edges if set([v.index for v in e.verts]) == set(edge) ] b_edges.append(b_edge[0]) else: b_edges = bm.edges geom = list(bm.verts) + list(b_edges) + list(bm.faces) bevel_faces = bmesh.ops.bevel( bm, geom=geom, offset=offset, offset_type=int(self.offsetType), segments=segments, profile=profile, vertex_only=self.vertexOnly, #clamp_overlap=self.clampOverlap, material=-1)['faces'] new_bevel_faces = [[v.index for v in face.verts] for face in bevel_faces] new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) bm.free() result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_bevel_faces.append(new_bevel_faces) self.outputs['Vertices'].sv_set(result_vertices) if self.outputs['Edges'].is_linked: self.outputs['Edges'].sv_set(result_edges) if self.outputs['Polygons'].is_linked: self.outputs['Polygons'].sv_set(result_faces) if self.outputs['NewPolys'].is_linked: self.outputs['NewPolys'].sv_set(result_bevel_faces)