class Eyes: def __init__(self, cross_eye=0.0, default_look_distance=200, eye_fov=40): self.default_look_target = Vector((0, default_look_distance, 0)) self.look_target = self.default_look_target self.rotation = Quaternion((1, 0, 0, 0)) self.position = Vector((0, 0, 0)) self.leye_pos = Vector((-5.96898, 6.09201, 3.69949)) self.reye_pos = Vector((5.96898, 6.09201, 3.69949)) self.leye_norm = Vector((cross_eye, 1, 0)) self.reye_norm = Vector((-cross_eye, 1, 0)) self.pupil_pos = np.zeros(4) # lx ly rx ry self.eye_fov = eye_fov def set_rotation(self, rotation): self.rotation = rotation def update(self): self.update_pupil_pos() new_look_target = self.update_look_target() if new_look_target: print("blonk") self.look_target = new_look_target self.update() else: print(self.pupil_pos) def update_pupil_pos(self): leye_pos = self.leye_pos.copy() leye_pos.rotate(self.rotation) leye_pos += self.position reye_pos = self.reye_pos.copy() reye_pos.rotate(self.rotation) reye_pos += self.position leye_beam = self.look_target.copy() - leye_pos reye_beam = self.look_target.copy() - reye_pos leye_beam.rotate(self.rotation.inverted()) leye_beam_angle = self.leye_norm.rotation_difference(leye_beam) reye_beam.rotate(self.rotation.inverted()) reye_beam_angle = self.reye_norm.rotation_difference(reye_beam) self.pupil_pos = -1*np.degrees([leye_beam_angle.z, leye_beam_angle.x, reye_beam_angle.z, reye_beam_angle.x]) def update_look_target(self, forced=False): fov = np.full(4, self.eye_fov) / np.array([2, 4, 2, 4]) if forced or np.any(self.pupil_pos < -1*fov) or np.any(self.pupil_pos > fov): new_look_target = self.default_look_target.copy() new_look_target.rotate(self.rotation) new_look_target += self.position return new_look_target else: return False
def compute_translation_rotation_bone_bond(self, old_bone, new_bond): # Translation v_old_atom_0, v_old_atom_1 = Vector([ old_bone.head.x, old_bone.head.y, old_bone.head.z ]), Vector([old_bone.tail.x, old_bone.tail.y, old_bone.tail.z]) center_old_bond = (v_old_atom_1 + v_old_atom_0) / 2 v_new_atom_0, v_new_atom_1 = Vector([ new_bond.atoms[0].x, new_bond.atoms[0].y, new_bond.atoms[0].z ]), Vector( [new_bond.atoms[1].x, new_bond.atoms[1].y, new_bond.atoms[1].z]) center_new_bond = (v_new_atom_1 + v_new_atom_0) / 2 translation = center_new_bond - center_old_bond # Rotation old_bond_vec = Vector([ old_bone.tail.x - old_bone.head.x, old_bone.tail.y - old_bone.head.y, old_bone.tail.z - old_bone.head.z ]) new_bond_vec = Vector([ new_bond.atoms[1].x - new_bond.atoms[0].x, new_bond.atoms[1].y - new_bond.atoms[0].y, new_bond.atoms[1].z - new_bond.atoms[0].z ]) rotation = old_bond_vec.rotation_difference(new_bond_vec).to_euler() return translation, rotation
def invoke(self, context, event): scene = context.scene active_object = bpy.context.view_layer.objects.active if active_object is None or active_object.mode != "SCULPT": return {'FINISHED'} to_object() mouse_pos = [event.mouse_region_x, event.mouse_region_y] region = context.region region3D = context.space_data.region_3d # Get intersection and create objects at this location if possible view_vector = view3d_utils.region_2d_to_vector_3d(region, region3D, mouse_pos) origin = view3d_utils.region_2d_to_origin_3d(region, region3D, mouse_pos) loc = view3d_utils.region_2d_to_location_3d(region, region3D, mouse_pos, view_vector) rot = (0,0,0) hit, loc_hit, norm, face, *_ = scene.ray_cast(context.view_layer, origin, view_vector) if hit: loc = loc_hit z = Vector((0,0,1)) rot = z.rotation_difference( norm ).to_euler() obj_type = context.scene.add_object_type # TODO: Add more init options here if obj_type == "Sphere": bpy.ops.mesh.primitive_uv_sphere_add(radius=1, enter_editmode=False, location=loc) elif obj_type == "Cube": bpy.ops.mesh.primitive_cube_add(enter_editmode=False, location=loc, rotation=rot) elif obj_type == "Cylinder": bpy.ops.mesh.primitive_cylinder_add(radius=1, depth=2, enter_editmode=False, location=loc, rotation=rot) elif obj_type == "Torus": bpy.ops.mesh.primitive_torus_add(align='WORLD', location=loc, rotation=rot, major_radius=1, minor_radius=0.25, abso_major_rad=1.25, abso_minor_rad=0.75) elif obj_type == "Scene": custom_obj = context.scene.add_scene_object if custom_obj: deselect_all() make_active(custom_obj) bpy.ops.object.duplicate(linked=True) clone_custom = bpy.context.view_layer.objects.active bpy.ops.object.make_single_user(object=True, obdata=True) clone_custom.location = loc clone_custom.rotation_euler = rot deselect_all() make_active(clone_custom) to_sculpt() return {'FINISHED'}
def execute(self, context): obj = bpy.context.edit_object me = obj.data # Get a BMesh representation bm = bmesh.from_edit_mesh(me) ef = bm.select_history.active aim = None cent = None if isinstance(ef, bmesh.types.BMFace): aim = ef.normal cent = ef.calc_center_bounds() elif isinstance(ef, bmesh.types.BMEdge): aim = Vector(ef.verts[1].co) - Vector(ef.verts[0].co) cent = .5 * (Vector(ef.verts[1].co) + Vector(ef.verts[0].co)) diff = aim.rotation_difference(self.p_axis_to_vector()).to_matrix() bmesh.ops.rotate(bm, cent=cent, matrix=diff, verts=[v for v in bm.verts if v.select]) # finalize bmesh.update_edit_mesh(me, True) return {'FINISHED'}
def _apply_planer_map(bm, uv_layer, size, offset, rotation, tex_aspect): scale = 1.0 / size sx = 1.0 * scale sy = 1.0 * scale ofx = offset[0] ofy = offset[1] rz = rotation * pi / 180.0 aspect = tex_aspect sel_faces = [f for f in bm.faces if f.select] # calculate average of normal n_ave = Vector((0.0, 0.0, 0.0)) for f in sel_faces: n_ave = n_ave + f.normal q = n_ave.rotation_difference(Vector((0.0, 0.0, 1.0))) # update UV coordinate for f in sel_faces: for l in f.loops: co = compat.matmul(q, l.vert.co) x = co.x * sx y = co.y * sy u = x * cos(rz) - y * sin(rz) + ofx v = -x * aspect * sin(rz) - y * aspect * cos(rz) + ofy l[uv_layer].uv = Vector((u, v))
def apply_planer_map(bm, uv_layer, size, offset, rotation, tex_aspect): scale = 1.0 / size sx = 1.0 * scale sy = 1.0 * scale ofx = offset[0] ofy = offset[1] rz = rotation * pi / 180.0 aspect = tex_aspect sel_faces = [f for f in bm.faces if f.select] # calculate average of normal n_ave = Vector((0.0, 0.0, 0.0)) for f in sel_faces: n_ave = n_ave + f.normal q = n_ave.rotation_difference(Vector((0.0, 0.0, 1.0))) # update UV coordinate for f in sel_faces: for l in f.loops: if common.check_version(2, 80, 0) >= 0: # pylint: disable=E0001 co = q @ l.vert.co else: co = q * l.vert.co x = co.x * sx y = co.y * sy u = x * cos(rz) - y * sin(rz) + ofx v = -x * aspect * sin(rz) - y * aspect * cos(rz) + ofy l[uv_layer].uv = Vector((u, v))
def vecscorrect(vecs, mats): out = [] lengthve = len(vecs)-1 for i, m in enumerate(mats): out_ = [] k = i if k > lengthve: k = lengthve vec_c = Vector((0, 0, 0)) for v in vecs[k]: vec = v*m out_.append(vec) vec_c += vec vec_c = vec_c / len(vecs[k]) v = out_[1]-out_[0] w = out_[2]-out_[0] A = v.y*w.z - v.z*w.y B = -v.x*w.z + v.z*w.x C = v.x*w.y - v.y*w.x #D = -out_[0].x*A - out_[0].y*B - out_[0].z*C norm = Vector((A, B, C)).normalized() vec0 = Vector((0, 0, 1)) mat_rot_norm = vec0.rotation_difference(norm).to_matrix().to_4x4() out_pre = [] for v in out_: v_out = (v-vec_c) * mat_rot_norm out_pre.append(v_out[:]) out.append(out_pre) return out
def createDimOffsetGiz(group,dim,objIndex): #Set Matrix k = Vector((0,0,1)) basisMatrix = Matrix.Translation(Vector((0,0,0))) rot = k.rotation_difference(dim.gizRotDir) rotMatrix = rot.to_matrix() rotMatrix.resize_4x4() basisMatrix = basisMatrix @ rotMatrix basisMatrix.translation = Vector(dim.gizLoc)+(Vector(dim.gizRotDir)*0.1) #Offset Gizmo dimOffsetGiz = group.gizmos.new("GIZMO_GT_arrow_3d") dimOffsetGiz.target_set_prop("offset", dim, "dimOffset") dimOffsetGiz.draw_style = "NORMAL" dimOffsetGiz.length = 0 dimOffsetGiz.matrix_basis = basisMatrix dimOffsetGiz.scale_basis = 0.8 dimOffsetGiz.color = (pow(dim.color[0],(1/2.2)),pow(dim.color[1],(1/2.2)),pow(dim.color[2],(1/2.2))) dimOffsetGiz.alpha = 0.3 dimOffsetGiz.color_highlight = (pow(dim.color[0],(1/2.2)),pow(dim.color[1],(1/2.2)),pow(dim.color[2],(1/2.2))) dimOffsetGiz.alpha_highlight = 1 #Button Gizmo #dimButton = group.gizmos.new("GIZMO_GT_button_2d") #dimButton.icon = 'PREFERENCES' #dimButton.scale_basis = 0.2 #dimButton.matrix_basis = basisMatrix # Add Gizmos to group group.offset_widget = dimOffsetGiz
def draw(self, context): selected_archetype = get_selected_archetype(context) selected_portal = get_selected_portal(context) portal = self.linked_portal asset = selected_archetype.asset self.color = 0, 0.6, 1 if selected_portal != portal: self.alpha = 0 if selected_portal == portal: self.alpha = 0.3 if portal and asset: corners = [ portal.corner1, portal.corner2, portal.corner3, portal.corner4 ] x = [p[0] for p in corners] y = [p[1] for p in corners] z = [p[2] for p in corners] centroid = Vector( (sum(x) / len(corners), sum(y) / len(corners), sum(z) / len(corners))) normal = -(corners[2] - corners[0] ).cross(corners[1] - corners[0]).normalized() default_axis = Vector((0, 0, 1)) rot = default_axis.rotation_difference(normal) arrow_mat = Matrix.LocRotScale(centroid, rot, Vector((0.3, 0.3, 0.3))) self.draw_preset_arrow(matrix=asset.matrix_world @ arrow_mat)
def vecscorrect(vecs, mats): out = [] lengthve = len(vecs) - 1 for i, m in enumerate(mats): out_ = [] k = i if k > lengthve: k = lengthve vec_c = Vector((0, 0, 0)) for v in vecs[k]: vec = v @ m out_.append(vec) vec_c += vec vec_c = vec_c / len(vecs[k]) v = out_[1] - out_[0] w = out_[2] - out_[0] A = v.y * w.z - v.z * w.y B = -v.x * w.z + v.z * w.x C = v.x * w.y - v.y * w.x #D = -out_[0].x*A - out_[0].y*B - out_[0].z*C norm = Vector((A, B, C)).normalized() vec0 = Vector((0, 0, 1)) mat_rot_norm = vec0.rotation_difference(norm).to_matrix().to_4x4() out_pre = [] for v in out_: v_out = (v - vec_c) @ mat_rot_norm out_pre.append(v_out[:]) out.append(out_pre) return out
def Comp(shape_type, param, name): # TODO use param global curr_obj ob = curr_obj if shape_type == "faces": # Check that it is indeed a mesh if not ob or ob.type != 'MESH': print(ob) assert (False) # If we are in edit mode, return to object mode bpy.ops.object.mode_set(mode='OBJECT') # Retrieve the mesh data mesh = ob.data polys = mesh.polygons for poly in polys: n = poly.normal verts = [mesh.vertices[i] for i in poly.vertices] # TODO use c = poly.center Push() state["location"] = cpy(c) up = Vector((0, 0, 1)) rdiff = up.rotation_difference(n) state["rotation"] = cpy(rdiff) Size((state["size"].x, state["size"].y, 0)) Symbol(name) Pop() if shape_type == "sideedges": if not ob or ob.type != 'MESH': print(ob) assert (False) # If we are in edit mode, return to object mode bpy.ops.object.mode_set(mode='OBJECT') mesh = ob.data edges = mesh.edges for edge in edges: v1 = Vector(mesh.vertices[edge.vertices[0]].co) v2 = Vector(mesh.vertices[edge.vertices[1]].co) # Assuming flat direction = Vector(v2) - Vector(v1) angle = Vector( (1, 0)).angle_signed(Vector((direction.x, direction.y))) rot = Quaternion((0, 0, 1), -angle) #rot = .rotation_difference(direction) print("RDIFF: ", rot, rot.angle, rot.axis) c = v1 / 2 + v2 / 2 Push() state["location"] = cpy(c) state["rotation"] = cpy(rot) Size((direction.magnitude, 0, 0)) Symbol(name) Pop()
def execute(self, context): # FIXME: Undo is inconsistent. # FIXME: Would be nicer if rotate could pick some object-local axis. from mathutils import Vector print_3d = context.scene.print_3d face_areas = print_3d.use_alignxy_face_area self.context = context mode_orig = context.mode skip_invalid = [] for obj in context.selected_objects: orig_loc = obj.location.copy() orig_scale = obj.scale.copy() # When in edit mode, do as the edit mode does. if mode_orig == 'EDIT_MESH': bm = bmesh.from_edit_mesh(obj.data) faces = [f for f in bm.faces if f.select] else: faces = [p for p in obj.data.polygons if p.select] if not faces: skip_invalid.append(obj.name) continue # Rotate object so average normal of selected faces points down. normal = Vector((0.0, 0.0, 0.0)) if face_areas: for face in faces: normal += (face.normal * face.calc_area()) else: for face in faces: normal += face.normal normal = normal.normalized() normal.rotate(obj.matrix_world) # local -> world. offset = normal.rotation_difference(Vector((0.0, 0.0, -1.0))) offset = offset.to_matrix().to_4x4() obj.matrix_world = offset @ obj.matrix_world obj.scale = orig_scale obj.location = orig_loc if len(skip_invalid) > 0: for name in skip_invalid: print( f"Align to XY: Skipping object {name}. No faces selected.") if len(skip_invalid) == 1: self.report( {'WARNING'}, f"Skipping object {skip_invalid[0]}. No faces selected.") else: self.report( {'WARNING'}, f"Skipping some objects. No faces selected. See terminal.") return {'FINISHED'}
def create_bond(pt1: Vector, pt2: Vector, atom_size): dir = pt2 - pt1 length = dir.length origin = (pt1 + dir / 2).to_tuple() up = Vector((0, 0, 1)) rotation = up.rotation_difference(dir).to_euler() bpy.ops.mesh.primitive_cylinder_add(radius=atom_size / 2, location=origin, depth=length, rotation=rotation, vertices=QUALITY) return bpy.context.object
def doodads(object1, mesh1, dmin, dmax): """function to generate the doodads""" global dVerts global dPolygons i = 0 # on parcoure cette boucle pour ajouter des doodads a toutes les polygons # english translation: this loops adds doodads to all polygons while(i < len(object1.data.polygons)): if object1.data.polygons[i].select is False: continue doods_nbr = random.randint(dmin, dmax) j = 0 while(j <= doods_nbr): origin_dood = randVertex(object1.data.polygons[i].vertices[0], object1.data.polygons[i].vertices[1], object1.data.polygons[i].vertices[2], object1.data.polygons[i].vertices[3], Verts) type_dood = random.randint(0, len(bpy.context.scene.discomb.DISC_doodads) - 1) polygons_add = [] verts_add = [] # First we have to apply scaling and rotation to the mesh bpy.ops.object.select_pattern(pattern=bpy.context.scene.discomb.DISC_doodads[type_dood], extend=False) bpy.context.scene.objects.active = bpy.data.objects[bpy.context.scene.discomb.DISC_doodads[type_dood]] bpy.ops.object.transform_apply(rotation=True, scale=True) for polygon in bpy.data.objects[bpy.context.scene.discomb.DISC_doodads[type_dood]].data.polygons: polygons_add.append(polygon.vertices) for vertex in bpy.data.objects[bpy.context.scene.discomb.DISC_doodads[type_dood]].data.vertices: verts_add.append(vertex.co.copy()) normal_original_polygon = object1.data.polygons[i].normal nor_def = Vector((0.0, 0.0, 1.0)) qr = nor_def.rotation_difference(normal_original_polygon.normalized()) if(test_v2_near_v1(nor_def, -normal_original_polygon)): qr = Quaternion((0.0, 0.0, 0.0, 0.0)) # qr = angle_between_nor(nor_def, normal_original_polygon) for vertex in verts_add: vertex.rotate(qr) vertex += origin_dood findex = len(dVerts) for polygon in polygons_add: dPolygons.append([polygon[0] + findex, polygon[1] + findex, polygon[2] + findex, polygon[3] + findex]) i_dood_type.append(bpy.data.objects[bpy.context.scene.discomb.DISC_doodads[type_dood]].name) for vertex in verts_add: dVerts.append(vertex) j += 1 i += 5
def doodads(object1, mesh1, dmin, dmax): """function to generate the doodads""" global dVerts global dPolygons i = 0 # on parcoure cette boucle pour ajouter des doodads a toutes les polygons # english translation: this loops adds doodads to all polygons while(i < len(object1.data.polygons)): if object1.data.polygons[i].select is False: continue doods_nbr = random.randint(dmin, dmax) j = 0 while(j <= doods_nbr): origin_dood = randVertex(object1.data.polygons[i].vertices[0], object1.data.polygons[i].vertices[1], object1.data.polygons[i].vertices[2], object1.data.polygons[i].vertices[3], Verts) type_dood = random.randint(0, len(self.DISC_doodads) - 1) polygons_add = [] verts_add = [] # First we have to apply scaling and rotation to the mesh bpy.ops.object.select_pattern(pattern=self.DISC_doodads[type_dood], extend=False) bpy.context.view_layer.objects.active = bpy.data.objects[self.DISC_doodads[type_dood]] bpy.ops.object.transform_apply(location=False, rotation=True, scale=True) for polygon in bpy.data.objects[self.DISC_doodads[type_dood]].data.polygons: polygons_add.append(polygon.vertices) for vertex in bpy.data.objects[self.DISC_doodads[type_dood]].data.vertices: verts_add.append(vertex.co.copy()) normal_original_polygon = object1.data.polygons[i].normal nor_def = Vector((0.0, 0.0, 1.0)) qr = nor_def.rotation_difference(normal_original_polygon.normalized()) if(test_v2_near_v1(nor_def, -normal_original_polygon)): qr = Quaternion((0.0, 0.0, 0.0, 0.0)) # qr = angle_between_nor(nor_def, normal_original_polygon) for vertex in verts_add: vertex.rotate(qr) vertex += origin_dood findex = len(dVerts) for polygon in polygons_add: dPolygons.append([polygon[0] + findex, polygon[1] + findex, polygon[2] + findex, polygon[3] + findex]) i_dood_type.append(bpy.data.objects[self.DISC_doodads[type_dood]].name) for vertex in verts_add: dVerts.append(vertex) j += 1 i += 5
def Rotation(self, context, vec): obj = bpy.context.active_object #obj.hide axis = Vector((0.0, 0.0, 1.0)) q = axis.rotation_difference(vec) loc, rot, scale = obj.matrix_world.decompose() mat_scale = Matrix() for i in range(3): mat_scale[i][i] = scale[i] obj.matrix_world = (Matrix.Translation(loc) * q.to_matrix().to_4x4() * mat_scale)
def createDimOffsetGiz(group, dim, objIndex, idx, dimStr): context = bpy.context dimProps = dim if dim.uses_style: for alignedDimStyle in context.scene.StyleGenerator.alignedDimensions: if alignedDimStyle.name == dim.style: dimProps = alignedDimStyle # Set Matrix k = Vector((0, 0, 1)) basisMatrix = Matrix.Translation(Vector((0, 0, 0))) rot = k.rotation_difference(dim.gizRotDir) rotMatrix = rot.to_matrix() rotMatrix.resize_4x4() basisMatrix.translation = Vector( dim.gizLoc) + (Vector(dim.gizRotDir) * 0.2) basisMatrix = basisMatrix @ rotMatrix # Offset Gizmo dimOffsetGiz = group.gizmos.new("GIZMO_GT_arrow_3d") op = dimOffsetGiz.target_set_operator("measureit_arch.dimesnion_offset") op.objIndex = objIndex op.idx = idx op.dimType = dimStr dimOffsetGiz.draw_style = "NORMAL" dimOffsetGiz.use_draw_modal = False dimOffsetGiz.length = 0 dimOffsetGiz.matrix_basis = basisMatrix dimOffsetGiz.use_draw_value = False dimOffsetGiz.scale_basis = 1 dimOffsetGiz.color = (pow(dimProps.color[0], (1 / 2.2)), pow(dimProps.color[1], (1 / 2.2)), pow(dimProps.color[2], (1 / 2.2))) dimOffsetGiz.alpha = 0.3 dimOffsetGiz.color_highlight = (pow(dimProps.color[0], (1 / 2.2)), pow(dimProps.color[1], (1 / 2.2)), pow(dimProps.color[2], (1 / 2.2))) dimOffsetGiz.alpha_highlight = 1 # Button Gizmo #dimButton = group.gizmos.new("GIZMO_GT_button_2d") #dimButton.icon = 'PREFERENCES' #dimButton.scale_basis = 0.2 #dimButton.matrix_basis = basisMatrix # Add Gizmos to group group.offset_widget = dimOffsetGiz
def execute(self, context): obj = context.active_object bm = bmesh.from_edit_mesh(obj.data) if common.check_version(2, 73, 0) >= 0: bm.faces.ensure_lookup_table() # get UV layer if not bm.loops.layers.uv: if self.assign_uvmap: bm.loops.layers.uv.new() else: self.report({'WARNING'}, "Object must have more than one UV map") return {'CANCELLED'} uv_layer = bm.loops.layers.uv.verify() scale = 1.0 / self.size sx = 1.0 * scale sy = 1.0 * scale ofx = self.offset[0] ofy = self.offset[1] rz = self.rotation * pi / 180.0 aspect = self.tex_aspect sel_faces = [f for f in bm.faces if f.select] # calculate average of normal n_ave = Vector((0.0, 0.0, 0.0)) for f in sel_faces: n_ave = n_ave + f.normal q = n_ave.rotation_difference(Vector((0.0, 0.0, 1.0))) # update UV coordinate for f in sel_faces: for l in f.loops: co = q * l.vert.co x = co.x * sx y = co.y * sy u = x * cos(rz) - y * sin(rz) + ofx v = -x * aspect * sin(rz) - y * aspect * cos(rz) + ofy l[uv_layer].uv = Vector((u, v)) bmesh.update_edit_mesh(obj.data) return {'FINISHED'}
def execute(self, context): orientation = get_orientation(context) if not orientation: return {'CANCELLED'} def normalize(vec, index): if vec.length == 0.0: vec[:] = [0.0] * 3 vec[index] = 1.0 else: vec.normalize() mat = orientation.matrix axes = ['XYZ'.index(s) for s in self.axes] i, j, k = axes vec1 = mat.col[i] normalize(vec1, i) vec2 = mat.col[j] normalize(vec2, j) vec3 = mat.col[k] normalize(vec3, k) if vec1 != vec2: if (i + 1) % 3 == j: vec3[:] = vec1.cross(vec2).normalized() vec2[:] = vec3.cross(vec1).normalized() else: vec3[:] = vec2.cross(vec1).normalized() vec2[:] = vec1.cross(vec3).normalized() elif vec1 != vec3: if (i + 1) % 3 != k: vec2[:] = vec1.cross(vec3).normalized() vec3[:] = vec2.cross(vec1).normalized() else: vec2[:] = vec3.cross(vec1).normalized() vec3[:] = vec1.cross(vec2).normalized() else: v = Vector([0.0] * 3) v[i] = 1.0 q = v.rotation_difference(vec1) m = q.to_matrix() for c in range(3): mat.col[c] = m.col[c] return {'FINISHED'}
def bead_instancing(context, group, bead, hair, position): print("instancing beads...") #only_render_in_display() new_instance = bpy.data.objects.new("Instance", None) new_instance.dupli_type = 'GROUP' new_instance.dupli_group = group new_instance.location = position v1 = get_hair_dir(hair) v0 = Vector((0, 0, 1)) rot = v0.rotation_difference(v1).to_euler() new_instance.rotation_euler = rot scene.objects.link(new_instance) print("got through bead instancing function")
def execute(self, context): obj = context.active_object bm = bmesh.from_edit_mesh(obj.data) if muv_common.check_version(2, 73, 0) >= 0: bm.faces.ensure_lookup_table() # get UV layer if not bm.loops.layers.uv: self.report( {'WARNING'}, "Object must have more than one UV map") return {'CANCELLED'} uv_layer = bm.loops.layers.uv.verify() scale = 1.0 / self.size sx = 1.0 * scale sy = 1.0 * scale ofx = self.offset[0] ofy = self.offset[1] rz = self.rotation * pi / 180.0 aspect = self.tex_aspect sel_faces = [f for f in bm.faces if f.select] # calculate average of normal n_ave = Vector((0.0, 0.0, 0.0)) for f in sel_faces: n_ave = n_ave + f.normal q = n_ave.rotation_difference(Vector((0.0, 0.0, 1.0))) # update UV coordinate for f in sel_faces: for l in f.loops: co = q * l.vert.co x = co.x * sx y = co.y * sy u = x * cos(rz) - y * sin(rz) + ofx v = -x * aspect * sin(rz) - y * aspect * cos(rz) + ofy l[uv_layer].uv = Vector((u, v)) bmesh.update_edit_mesh(obj.data) return {'FINISHED'}
def invoke(self, context, event): if context.object: click_placer = context.scene.click_placer mouse_pos = [event.mouse_region_x, event.mouse_region_y] viewport_region = context.region viewport_region_data = context.space_data.region_3d viewport_matrix = viewport_region_data.view_matrix.inverted() ray_start = viewport_matrix.to_translation() ray_depth = viewport_matrix @ Vector((0, 0, -1000)) ray_end = view3d_utils.region_2d_to_location_3d( viewport_region, viewport_region_data, mouse_pos, ray_depth) ray_dir = ray_end.normalized() despgraph = context.evaluated_depsgraph_get() self.cast = context.scene.ray_cast(despgraph, origin=ray_start, direction=ray_dir, distance=1000.0) if not self.cast[0]: return {'CANCELLED'} # linked copy bpy.ops.object.duplicate( { "object": context.object, "selected_objects": [context.object] }, linked=True) self.new_obj = bpy.context.object self.new_obj.location = self.cast[1] if click_placer.rotate_to_normal: axis = Vector(axis_dict[click_placer.up_axis]) rot = axis.rotation_difference(self.cast[2]).to_euler() self.new_obj.rotation_euler = rot return {'FINISHED'}
def draw_text(self, context, event): wm = context.window_manager region = bpy.context.region rv3d = bpy.context.space_data.region_3d self.circle_color = [0.102758, 0.643065, 1.000000, 1.000000] if event.ctrl and not self.f_key: self.circle_color = [1.000000, 0.202489, 0.401234, 1.000000] elif self.f_key: self.circle_color = [1.0, 1.0, 1.0, .7] ### draw brush size text if self.f_key or event.alt or self.f_key_shift or self.scale_stroke: bgl.glColor4f(1.0, 1.0, 1.0, .7) text_pos = bpy_extras.view3d_utils.location_3d_to_region_2d( region, rv3d, self.projected_mouse) if text_pos != None: blf.position(0, text_pos[0] - 30, text_pos[1] + 10, 0) blf.size(0, 18, 72) if self.f_key: blf.draw(0, "Size: " + str(round(wm.asset_sketcher.brush_size, 2))) elif self.f_key_shift: blf.draw(0, "Density: " + str(wm.asset_sketcher.brush_density)) elif event.alt: blf.draw(0, str(self.picked_asset_name)) if self.scale_stroke: vec = Vector((0, 1, 0)) # * self.ground_normal_mat angle = vec.rotation_difference( self.stroke_direction.normalized()).to_euler() #angle = self.stroke_direction.normalized().rotation_difference(Vector((0,1,0))).to_euler() text1 = "Scale: " + str(round(self.stroke_length, 2)) text2 = "Angle: " + str(round(math.degrees(angle[2]), 2)) blf.draw(0, text1) #blf.position(0, text_pos[0]-30, text_pos[1]+10+20, 0) #blf.draw(0, text2) restore_opengl_defaults()
def distribute_beads(ps, context, num_beads, bead): print("distributing beads...") bead.select = True #hairs = context.object.particle_systems[scene.particle_system_index].particles hairs = context.object.particle_systems[0].particles for i in range(0, num_beads): random_hair = hairs[random.randrange(len(hairs))] random_segment = random_hair.hair_keys[random.randrange( len(random_hair.hair_keys) - 1)] new_pos = random_segment.co new_bead = bead.copy() new_bead.data = bead.data.copy() new_bead.location = new_pos v1 = get_hair_dir(random_hair) v0 = Vector((0, 0, 1)) rot = v0.rotation_difference(v1).to_euler() new_bead.rotation_euler = rot scene.objects.link(new_bead)
def add_light(name, type, intensity, color, vector, angle): out_color = SRGBToLinear(color) if type == "SUN": light = bpy.data.lights.get(name) if light == None: light = bpy.data.lights.new(name=name, type='SUN') light.energy = intensity * 0.1 light.shadow_cascade_max_distance = 12000 light.color = out_color light.angle = angle elif type == "SPOT": light = bpy.data.lights.get(name) if light == None: light = bpy.data.lights.new(name=name, type='SPOT') light.energy = intensity * 750.0 light.shadow_buffer_clip_start = 4 light.color = out_color light.spot_size = angle light.spot_blend = 1.0 else: light = bpy.data.lights.get(name) if light == None: light = bpy.data.lights.new(name=name, type='POINT') light.energy = intensity * 750.0 light.shadow_buffer_clip_start = 4 light.color = out_color light.shadow_soft_size = angle obj_vec = Vector((0.0, 0.0, 1.0)) rotation_vec = Vector((vector[0], vector[1], vector[2])) obj = bpy.data.objects.get(name) if obj == None: obj = bpy.data.objects.new(name=name, object_data=light) bpy.context.collection.objects.link(obj) obj.rotation_euler = obj_vec.rotation_difference( rotation_vec).to_euler() return obj
def drawBone2(p1, p2, radiuses, material): length = dist(p1,p2) print('length :',length) v = Vector(diffv(p1, p2)) up = Vector((0,0,1)) if v!=-up: rot = up.rotation_difference(v) else: rot = Quaternion((1,0,0),math.pi) s1 = drawEllipsoid((0,0,-0.5*length),radiuses,material) s2 = drawEllipsoid((0,0,0.5*length),radiuses,material) c1 = drawCylinder(zero,radiuses,length,materials.blue) s1.select = True s2.select = True c1.select = True #bpy.ops.transform.translate(value=(0,0,length/2)) #bpy.ops.object.editmode_toggle() bpy.ops.transform.rotate(value=rot.angle, axis=rot.axis) #bpy.ops.object.editmode_toggle() #bpy.ops.transform.translate(value=Vector((0,0,-0.5*length))*rot.to_matrix()) rot.normalize(); bpy.ops.transform.translate(value=Vector((0,0,0.5*length))*rot.to_matrix()) bpy.ops.transform.translate(value=p1) return (s1,s2,c1)
def get_point_rotation(context, scene, curve_obj, index=0, spline_index=0): # Get curve attributes curve_mat = curve_obj.matrix_world curve = curve_obj.data points = get_spline_points(curve.splines[spline_index]) # new temp object to detect local x-axis and y-axis of first handle # Temp Bevel Object for temp curve temp_bevel_curve = bpy.data.curves.new('__temp_bevel', 'CURVE') temp_spline = temp_bevel_curve.splines.new('POLY') temp_spline.points.add(2) temp_spline.points[0].co = Vector((1.0, 0.0, 0.0, 1.0)) temp_spline.points[1].co = Vector((0.0, 1.0, 0.0, 1.0)) temp_bevel_obj = bpy.data.objects.new('__temp_bevel', temp_bevel_curve) link_object(scene, temp_bevel_obj) # Temp Curve curve_copy = curve_obj.data.copy() curve_copy.use_fill_caps = False curve_copy.bevel_object = temp_bevel_obj temp_obj = bpy.data.objects.new('__temp', curve_copy) link_object(scene, temp_obj) temp_obj.location = curve_obj.location temp_obj.rotation_mode = curve_obj.rotation_mode temp_obj.rotation_quaternion = curve_obj.rotation_quaternion temp_obj.rotation_euler = curve_obj.rotation_euler # Convert temp curve to mesh bpy.ops.object.select_all(action='DESELECT') # deselect all first set_active_object(temp_obj) set_object_select(temp_obj, True) bpy.ops.object.convert(target='MESH') offset = 0 micro_offset = 0 #cyclic check for i, spline in enumerate(curve.splines): if i > spline_index: break #ps = get_spline_points(spline) if i > 0: ps_count = len(get_spline_points(curve.splines[i - 1])) offset += ps_count - 1 if spline.use_cyclic_u: offset += 1 elif i > 0: micro_offset += 1 #offset += spline_index * curve.resolution_u #print(offset) # get x-axis and y-axis of the first handle handle_x = temp_obj.data.vertices[curve.resolution_u * (index + offset) * 3 + micro_offset * 3].co handle_y = temp_obj.data.vertices[curve.resolution_u * (index + offset) * 3 + 1 + micro_offset * 3].co target_x = handle_x - points[index].co.xyz target_y = handle_y - points[index].co.xyz target_x.normalize() target_y.normalize() # delete temp objects set_object_select(temp_bevel_obj, True) bpy.ops.object.delete() # Match bevel x-axis to handle x-axis bevel_x = Vector((1.0, 0.0, 0.0)) target_x = mul(curve_mat.to_3x3(), target_x) rot_1 = bevel_x.rotation_difference(target_x) # Match bevel y-axis to handle y-axis bevel_y = mul(rot_1.to_matrix(), Vector((0.0, 1.0, 0.0))) target_y = mul(curve_mat.to_3x3(), target_y) rot_2 = bevel_y.rotation_difference(target_y) # Select curve object again set_active_object(curve_obj) set_object_select(curve_obj, True) return mul(rot_2, rot_1)
def paintVerts(self, context, start_point, end_point, start_color, end_color, circular_gradient=False, use_hue_blend=False): region = context.region rv3d = context.region_data obj = context.active_object mesh = obj.data # Create a new bmesh to work with bm = bmesh.new() bm.from_mesh(mesh) bm.verts.ensure_lookup_table() # List of structures containing 3d vertex and project 2d position of vertex vertex_data = None # Will contain vert, and vert coordinates in 2d view space if mesh.use_paint_mask_vertex: # Face masking not currently supported vertex_data = [(v, view3d_utils.location_3d_to_region_2d( region, rv3d, obj.matrix_world @ v.co)) for v in bm.verts if v.select] else: vertex_data = [(v, view3d_utils.location_3d_to_region_2d( region, rv3d, obj.matrix_world @ v.co)) for v in bm.verts] # Vertex transformation math down_vector = Vector((0, -1, 0)) direction_vector = Vector( (end_point.x - start_point.x, end_point.y - start_point.y, 0)).normalized() rotation = direction_vector.rotation_difference(down_vector) translation_matrix = Matrix.Translation( Vector((-start_point.x, -start_point.y, 0))) inverse_translation_matrix = translation_matrix.inverted() rotation_matrix = rotation.to_matrix().to_4x4() combinedMat = inverse_translation_matrix @ rotation_matrix @ translation_matrix transStart = combinedMat @ start_point.to_4d( ) # Transform drawn line : rotate it to align to horizontal line transEnd = combinedMat @ end_point.to_4d() minY = transStart.y maxY = transEnd.y heightTrans = maxY - minY # Get the height of transformed vector transVector = transEnd - transStart transLen = transVector.length # Calculate hue, saturation and value shift for blending if use_hue_blend: start_color = Color(start_color[:3]) end_color = Color(end_color[:3]) c1_hue = start_color.h c2_hue = end_color.h hue_separation = c2_hue - c1_hue if hue_separation > 0.5: hue_separation = hue_separation - 1 elif hue_separation < -0.5: hue_separation = hue_separation + 1 c1_sat = start_color.s sat_separation = end_color.s - c1_sat c1_val = start_color.v val_separation = end_color.v - c1_val color_layer = bm.loops.layers.color.active for data in vertex_data: vertex = data[0] vertCo4d = Vector((data[1].x, data[1].y, 0)) transVec = combinedMat @ vertCo4d t = 0 if circular_gradient: curVector = transVec.to_4d() - transStart curLen = curVector.length t = abs(max(min(curLen / transLen, 1), 0)) else: t = abs(max(min((transVec.y - minY) / heightTrans, 1), 0)) color = Color((1, 0, 0)) if use_hue_blend: # Hue wraps, and fmod doesn't work with negative values color.h = fmod(1.0 + c1_hue + hue_separation * t, 1.0) color.s = c1_sat + sat_separation * t color.v = c1_val + val_separation * t else: color.r = start_color[0] + (end_color[0] - start_color[0]) * t color.g = start_color[1] + (end_color[1] - start_color[1]) * t color.b = start_color[2] + (end_color[2] - start_color[2]) * t if mesh.use_paint_mask: # Masking by face face_loops = [ loop for loop in vertex.link_loops if loop.face.select ] # Get only loops that belong to selected faces else: # Masking by verts or no masking at all face_loops = [loop for loop in vertex.link_loops ] # Get remaining vert loops for loop in face_loops: new_color = loop[color_layer] new_color[:3] = color loop[color_layer] = new_color bm.to_mesh(mesh) bm.free() bpy.ops.object.mode_set(mode='VERTEX_PAINT')
def main2(): global all_scale_def,xoffset_def,yoffset_def,zrot_def obj = bpy.context.active_object mesh = obj.data is_editmode = (obj.mode == 'EDIT') # if in EDIT Mode switch to OBJECT if is_editmode: bpy.ops.object.mode_set(mode='OBJECT', toggle=False) # if no UVtex - create it if not mesh.uv_textures: uvtex = bpy.ops.mesh.uv_texture_add() uvtex = mesh.uv_textures.active uvtex.active_render = True img = None aspect = 1.0 mat = obj.active_material try: if mat: img = mat.active_texture aspect = img.image.size[0]/img.image.size[1] for f in mesh.faces: if not is_editmode or f.select: uvtex.data[f.index].image = img.image else: img = None except: pass # # Main action # if all_scale_def: sc = 1.0/all_scale_def else: sc = 1.0 # Calculate Average Normal v = Vector((0,0,0)) cnt = 0 for f in mesh.faces: if f.select: cnt += 1 v = v + f.normal zv = Vector((0,0,1)) q = v.rotation_difference(zv) sx = 1 * sc sy = 1 * sc sz = 1 * sc ofx = xoffset_def ofy = yoffset_def rz = zrot_def / 180 * pi for i, uv in enumerate(uvtex.data): if mesh.faces[i].select: uvs = uv.uv1, uv.uv2, uv.uv3, uv.uv4 for j, v_idx in enumerate(mesh.faces[i].vertices): n = mesh.faces[i].normal co = q * mesh.vertices[v_idx].co x = co.x * sx y = co.y * sy z = co.z * sz uvs[j][0] = x * cos(rz) - y * sin(rz) + xoffset_def uvs[j][1] = aspect*(- x * sin(rz) - y * cos(rz)) + yoffset_def # Back to EDIT Mode if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False)
class VIEW3D_OT_MeshPaint(Operator): bl_idname = "viev3d.mesh_paint" bl_label = "Mesh Paint" @classmethod def poll(cls, context): return (context.mode == "OBJECT") def invoke(self, context, event): if context.area.type == "VIEW_3D": # the arguments we pass the the callback args = (self, context) # Add the region OpenGL drawing callback # draw in view space with "POST_VIEW" and "PRE_VIEW" self._handle_3d = bpy.types.SpaceView3D.draw_handler_add( draw_callback_3d, args, "WINDOW", "POST_VIEW") self._handle_2d = bpy.types.SpaceView3D.draw_handler_add( draw_callback_2d, args, "WINDOW", "POST_PIXEL") self.transform_mode = "MOVE" self.mouse_path = [Vector((0, 0, 0)), Vector((0, 0, 1))] self.normal = Vector((0, 0, 1)) self.rot_dir_arrow = Vector((1, 0, 0)) self.scale_model = 1.0 self.rotate_angle = 0 self.rotate_angle_old = 0 self.model_2d_point = None self.LMB_PRESS = False # self.draw_mouse_path = [] # 2d path screen space self.prev_location = None # self.start_distance_scale = 0 # self.current_distance_scale = 0 self.current_model = add_model(context, self.mouse_path[0], self.normal, self.scale_model) context.window_manager.modal_handler_add(self) return {"RUNNING_MODAL"} else: self.report({"WARNING"}, "View3D not found, cannot run operator") return {"CANCELLED"} def get_origin_and_direction(self, event, context): region = context.region region_3d = context.space_data.region_3d mouse_coord = (event.mouse_region_x, event.mouse_region_y) origin = region_2d_to_origin_3d(region, region_3d, mouse_coord) direction = region_2d_to_vector_3d(region, region_3d, mouse_coord) return origin, direction def get_2d_point_from_3d(self, event, context): region = context.region region_3d = context.space_data.region_3d result = location_3d_to_region_2d(region, region_3d, self.current_model.location) return result def calculate_angle(self, event, context): self.model_2d_point = self.get_2d_point_from_3d(event, context) self.mouse_coord = Vector((event.mouse_region_x, event.mouse_region_y)) dir = self.mouse_coord - self.model_2d_point dir.normalize() self.mouse_coord = self.model_2d_point + dir * 100 self.rotate_angle = math.degrees( math.atan2(self.mouse_coord.y - self.model_2d_point.y, self.mouse_coord.x - self.model_2d_point.x)) if self.rotate_angle < 0: self.rotate_angle += 360 def change_scale_current_model(self, context, event): loc, rot, scale = self.current_model.matrix_world.decompose() loc = Matrix.Translation(self.mouse_path[0]) rot = rot.to_matrix().to_4x4() scale = Matrix.Scale(self.scale_model, 4) mat_w = loc @ rot @ scale self.current_model.matrix_world = mat_w def draw_asset(self, context, event): if self.LMB_PRESS: nexus_model_SCN = context.scene.nexus_model_manager # self.draw_mouse_path.append((event.mouse_region_x, event.mouse_region_y)) # 2d path screen space distance = 0 distance_vector = Vector( (self.prev_location.x - self.current_model.location.x, self.prev_location.y - self.current_model.location.y, self.prev_location.z - self.current_model.location.z)) distance = distance_vector.length # for point in self.draw_mouse_path: # if old_point != None: # distance += math.hypot(old_point[0] - point[0], old_point[1] - point[1]) # # else: # # distance += math.hypot(point[0], point[1]) # old_point = point if distance >= nexus_model_SCN.distance_between_asset: # self.draw_mouse_path = [] # self.draw_mouse_path.append((event.mouse_region_x, event.mouse_region_y)) self.prev_location = self.current_model.location distance = 0 random_scale_and_rotation(self.current_model, self.normal, nexus_model_SCN, self) self.current_model = add_model(context, self.mouse_path[0], self.normal, self.scale_model) def modal(self, context, event): context.area.tag_redraw() nexus_model_SCN = context.scene.nexus_model_manager mod = None if event.shift: mod = "SHIFT" elif event.ctrl: mod = "CTRL" # if event.alt: # mod.append("Alt") # if event.ctrl: # mod.append("Ctrl") tip_text = "LMB - Add Model | G - Move, R - Rotate, MOUSEWHEEL +ctrl 0.1, +shift 0.01 - Scale | N - Align by normal | RMB / ESC - Cancel" context.area.header_text_set(tip_text) if event.type == "MOUSEMOVE": if self.transform_mode == "MOVE": # new origin and normal origin, direction = self.get_origin_and_direction( event, context) bHit = None pos_hit = None normal_hit = None face_index_hit = None obj_hit = None matrix_world = None # hide mesh self.current_model.hide_set(True) canvas = nexus_model_SCN.canvas_object if canvas == None: # trace bHit, pos_hit, normal_hit, face_index_hit, obj_hit, matrix_world = context.scene.ray_cast( view_layer=context.view_layer, origin=origin, direction=direction) else: # trace bHit, pos_hit, normal_hit, face_index_hit = canvas.ray_cast( origin=origin, direction=direction) # show mesh self.current_model.hide_set(False) if bHit: self.normal = normal_hit.normalized() self.mouse_path[0] = pos_hit self.mouse_path[1] = pos_hit + (self.normal * 2.0) loc, rot, scale = self.current_model.matrix_world.decompose( ) loc = Matrix.Translation(self.mouse_path[0]) rot_add = Euler( Vector((0, 0, math.radians(self.rotate_angle)))) rot_add = rot_add.to_matrix().to_4x4() scale = Matrix.Scale(self.scale_model, 4) # apply rotation by normal if checked "align_by_normal" if nexus_model_SCN.align_by_normal: # rot = self.normal.to_track_quat("Z","Y").to_euler() rot = self.normal.rotation_difference(Vector( (0, 0, 1))) rot.invert() rot = rot.to_euler().to_matrix().to_4x4() else: rot = Euler((0, 0, 0)).to_matrix().to_4x4() rot = rot @ rot_add mat_w = loc @ rot @ scale self.current_model.matrix_world = mat_w # draw assets self.draw_asset(context, event) elif self.transform_mode == "ROTATE": self.calculate_angle(event, context) delta_angle = self.rotate_angle - self.rotate_angle_old self.current_model.rotation_euler.rotate_axis( "Z", math.radians(delta_angle)) self.rotate_angle_old = self.rotate_angle # elif self.transform_mode == "SCALE": # self.model_2d_point = self.get_2d_point_from_3d(event, context) # x = self.model_2d_point.x - event.mouse_region_x # y = self.model_2d_point.y - event.mouse_region_y # self.current_distance_scale = math.hypot(x, y) # delta_scale = self.current_distance_scale - self.start_distance_scale # self.scale_model = self.scale_model + delta_scale * 0.1 # self.current_model.scale = Vector((self.scale_model, self.scale_model, self.scale_model)) if event.type == "WHEELUPMOUSE": if mod == "CTRL": self.scale_model += 0.1 elif mod == "SHIFT": self.scale_model += 0.01 self.change_scale_current_model(context, event) elif event.type == "WHEELDOWNMOUSE": if mod == "CTRL": self.scale_model -= 0.1 elif mod == "SHIFT": self.scale_model -= 0.01 self.change_scale_current_model(context, event) if event.value == "PRESS": if event.type == "LEFTMOUSE": self.transform_mode = "MOVE" self.LMB_PRESS = True # self.draw_mouse_path.append((event.mouse_region_x, event.mouse_region_y)) # 2d path screen space random_scale_and_rotation(self.current_model, self.normal, nexus_model_SCN, self) self.prev_location = self.current_model.location # 3d path world path self.current_model = add_model(context, self.mouse_path[0], self.normal, self.scale_model) return {"RUNNING_MODAL"} elif event.type == "R": self.transform_mode = "ROTATE" return {"RUNNING_MODAL"} elif event.type == "G": self.transform_mode = "MOVE" return {"RUNNING_MODAL"} # elif event.type == "S": # self.transform_mode = "SCALE" # self.model_2d_point = self.get_2d_point_from_3d(event, context) # x = self.model_2d_point.x - event.mouse_region_x # y = self.model_2d_point.y - event.mouse_region_y # self.start_distance_scale = math.hypot(x, y) # return {"RUNNING_MODAL"} elif event.type == "N": nexus_model_SCN.align_by_normal = not nexus_model_SCN.align_by_normal return {"RUNNING_MODAL"} elif event.type in {"RIGHTMOUSE", "ESC"}: bpy.ops.object.select_all(action="DESELECT") self.current_model.select_set(True) bpy.ops.object.delete() bpy.types.SpaceView3D.draw_handler_remove( self._handle_3d, "WINDOW") bpy.types.SpaceView3D.draw_handler_remove( self._handle_2d, "WINDOW") context.area.header_text_set( text=None) # return header text to default return {"CANCELLED"} if event.value == "RELEASE": if event.type == "LEFTMOUSE": self.LMB_PRESS = False # self.draw_mouse_path = [] # 2d path screen space return {"RUNNING_MODAL"}
def process(self): verts_socket, poly_socket = self.inputs norm_socket, norm_abs_socket, origins_socket, centers_socket = self.outputs if not any([s.is_linked for s in self.outputs]): return if not (verts_socket.is_linked and poly_socket.is_linked): return pols_ = poly_socket.sv_get() vers_tupls = verts_socket.sv_get() vers_vects = Vector_generate(vers_tupls) # make mesh temp утилитарно - удалить в конце mat_collect = [] normals_out = [] origins = [] norm_abs_out = [] for verst, versv, pols in zip(vers_tupls, vers_vects, pols_): # medians в векторах medians = [] normals = [] centrs = [] norm_abs = [] for p in pols: # medians # it calcs middle point of opposite edges, # than finds length vector between this two points v0 = versv[p[0]] v1 = versv[p[1]] v2 = versv[p[2]] lp=len(p) if lp >= 4: l = ((lp-2)//2) + 2 v3 = versv[p[l]] poi_2 = (v2+v3)/2 # normals norm = geometry.normal(v0, v1, v2, v3) normals.append(norm) else: poi_2 = v2 # normals norm = geometry.normal(v0, v1, v2) normals.append(norm) poi_1 = (v0+v1)/2 vm = poi_2 - poi_1 medians.append(vm) # centrs x,y,z = zip(*[verst[poi] for poi in p]) x,y,z = sum(x)/len(x), sum(y)/len(y), sum(z)/len(z) current_center = Vector((x,y,z)) centrs.append(current_center) # normal absolute !!! # это совершенно нормально!!! ;-) norm_abs.append(current_center+norm) if self.Separate: norm_abs_out.append(norm_abs) origins.append(centrs) normals_out.append(normals) else: norm_abs_out.extend(norm_abs) origins.extend(centrs) normals_out.extend(normals) mat_collect_ = [] for cen, med, nor in zip(centrs, medians, normals): loc = Matrix.Translation(cen) # need better solution for Z,Y vectors + may be X vector correction vecz = Vector((0, 1e-6, 1)) q_rot0 = vecz.rotation_difference(nor).to_matrix().to_4x4() q_rot2 = nor.rotation_difference(vecz).to_matrix().to_4x4() if med[1]>med[0]: vecy = Vector((1e-6, 1, 0)) * q_rot2 else: vecy = Vector((1, 1e-6, 0)) * q_rot2 q_rot1 = vecy.rotation_difference(med).to_matrix().to_4x4() # loc is matrix * rot vector * rot vector M = loc*q_rot1*q_rot0 lM = [ j[:] for j in M ] mat_collect_.append(lM) mat_collect.extend(mat_collect_) if not self.Separate: norm_abs_out = [norm_abs_out] origins = [origins] normals_out = [normals_out] centers_socket.sv_set(mat_collect) norm_abs_socket.sv_set(Vector_degenerate(norm_abs_out)) origins_socket.sv_set(Vector_degenerate(origins)) norm_socket.sv_set(Vector_degenerate(normals_out))
def best_planar_map(): global all_scale_def,xoffset_def,yoffset_def,zrot_def, tex_aspect obj = bpy.context.active_object mesh = obj.data is_editmode = (obj.mode == 'EDIT') # if in EDIT Mode switch to OBJECT if is_editmode: bpy.ops.object.mode_set(mode='OBJECT', toggle=False) # if no UVtex - create it if not mesh.uv_textures: uvtex = bpy.ops.mesh.uv_texture_add() uvtex = mesh.uv_textures.active #uvtex.active_render = True img = None aspect = 1.0 mat = obj.active_material try: if mat: img = mat.active_texture aspect = img.image.size[0]/img.image.size[1] except: pass aspect = aspect * tex_aspect # # Main action # if all_scale_def: sc = 1.0/all_scale_def else: sc = 1.0 # Calculate Average Normal v = Vector((0,0,0)) cnt = 0 for f in mesh.polygons: if f.select: cnt += 1 v = v + f.normal zv = Vector((0,0,1)) q = v.rotation_difference(zv) sx = 1 * sc sy = 1 * sc sz = 1 * sc ofx = xoffset_def ofy = yoffset_def rz = zrot_def / 180 * pi cosrz = cos(rz) sinrz = sin(rz) #uvs = mesh.uv_loop_layers[mesh.uv_loop_layers.active_index].data uvs = mesh.uv_layers.active.data for i, pol in enumerate(mesh.polygons): if not is_editmode or mesh.polygons[i].select: for j, loop in enumerate(mesh.polygons[i].loop_indices): v_idx = mesh.loops[loop].vertex_index n = pol.normal co = q * mesh.vertices[v_idx].co x = co.x * sx y = co.y * sy z = co.z * sz uvs[loop].uv[0] = x * cosrz - y * sinrz + xoffset_def uvs[loop].uv[1] = aspect*(- x * sinrz - y * cosrz) + yoffset_def # Back to EDIT Mode if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False)
def extract_primitives(glTF, blender_mesh, library, blender_object, blender_vertex_groups, modifiers, export_settings): """ Extract primitives from a mesh. Polygons are triangulated and sorted by material. Vertices in multiple faces get split up as necessary. """ print_console('INFO', 'Extracting primitive: ' + blender_mesh.name) # # First, decide what attributes to gather (eg. how many COLOR_n, etc.) # Also calculate normals/tangents now if necessary. # use_normals = export_settings[gltf2_blender_export_keys.NORMALS] if use_normals: blender_mesh.calc_normals_split() use_tangents = False if use_normals and export_settings[gltf2_blender_export_keys.TANGENTS]: if blender_mesh.uv_layers.active and len(blender_mesh.uv_layers) > 0: try: blender_mesh.calc_tangents() use_tangents = True except Exception: print_console( 'WARNING', 'Could not calculate tangents. Please try to triangulate the mesh first.' ) tex_coord_max = 0 if export_settings[gltf2_blender_export_keys.TEX_COORDS]: if blender_mesh.uv_layers.active: tex_coord_max = len(blender_mesh.uv_layers) color_max = 0 if export_settings[gltf2_blender_export_keys.COLORS]: color_max = len(blender_mesh.vertex_colors) bone_max = 0 # number of JOINTS_n sets needed (1 set = 4 influences) armature = None if blender_vertex_groups and export_settings[ gltf2_blender_export_keys.SKINS]: if modifiers is not None: modifiers_dict = {m.type: m for m in modifiers} if "ARMATURE" in modifiers_dict: modifier = modifiers_dict["ARMATURE"] armature = modifier.object # Skin must be ignored if the object is parented to a bone of the armature # (This creates an infinite recursive error) # So ignoring skin in that case is_child_of_arma = (armature and blender_object and blender_object.parent_type == "BONE" and blender_object.parent.name == armature.name) if is_child_of_arma: armature = None if armature: skin = gltf2_blender_gather_skins.gather_skin( armature, export_settings) if not skin: armature = None else: joint_name_to_index = { joint.name: index for index, joint in enumerate(skin.joints) } group_to_joint = [ joint_name_to_index.get(g.name) for g in blender_vertex_groups ] # Find out max number of bone influences for blender_polygon in blender_mesh.polygons: for loop_index in blender_polygon.loop_indices: vertex_index = blender_mesh.loops[ loop_index].vertex_index groups_count = len( blender_mesh.vertices[vertex_index].groups) bones_count = (groups_count + 3) // 4 bone_max = max(bone_max, bones_count) use_morph_normals = use_normals and export_settings[ gltf2_blender_export_keys.MORPH_NORMAL] use_morph_tangents = use_morph_normals and use_tangents and export_settings[ gltf2_blender_export_keys.MORPH_TANGENT] shape_keys = [] if blender_mesh.shape_keys and export_settings[ gltf2_blender_export_keys.MORPH]: for blender_shape_key in blender_mesh.shape_keys.key_blocks: if blender_shape_key == blender_shape_key.relative_key or blender_shape_key.mute: continue split_normals = None if use_morph_normals: split_normals = blender_shape_key.normals_split_get() shape_keys.append(ShapeKey( blender_shape_key, split_normals, )) use_materials = export_settings[gltf2_blender_export_keys.MATERIALS] # # Gather the verts and indices for each primitive. # prims = {} blender_mesh.calc_loop_triangles() for loop_tri in blender_mesh.loop_triangles: blender_polygon = blender_mesh.polygons[loop_tri.polygon_index] material_idx = -1 if use_materials: material_idx = blender_polygon.material_index prim = prims.get(material_idx) if not prim: prim = Prim() prims[material_idx] = prim for loop_index in loop_tri.loops: vertex_index = blender_mesh.loops[loop_index].vertex_index vertex = blender_mesh.vertices[vertex_index] # vert will be a tuple of all the vertex attributes. # Used as cache key in prim.verts. vert = (vertex_index, ) v = vertex.co vert += ((v[0], v[1], v[2]), ) if use_normals: n = blender_mesh.loops[loop_index].normal vert += ((n[0], n[1], n[2]), ) if use_tangents: t = blender_mesh.loops[loop_index].tangent b = blender_mesh.loops[loop_index].bitangent vert += ((t[0], t[1], t[2]), ) vert += ((b[0], b[1], b[2]), ) # TODO: store just bitangent_sign in vert, not whole bitangent? for tex_coord_index in range(0, tex_coord_max): uv = blender_mesh.uv_layers[tex_coord_index].data[ loop_index].uv uv = (uv.x, 1.0 - uv.y) vert += (uv, ) for color_index in range(0, color_max): color = blender_mesh.vertex_colors[color_index].data[ loop_index].color col = ( color_srgb_to_scene_linear(color[0]), color_srgb_to_scene_linear(color[1]), color_srgb_to_scene_linear(color[2]), color[3], ) vert += (col, ) if bone_max: bones = [] if vertex.groups: for group_element in vertex.groups: weight = group_element.weight if weight <= 0.0: continue try: joint = group_to_joint[group_element.group] except Exception: continue if joint is None: continue bones.append((joint, weight)) bones.sort(key=lambda x: x[1], reverse=True) bones = tuple(bones) vert += (bones, ) for shape_key in shape_keys: v_morph = shape_key.shape_key.data[vertex_index].co v_morph = v_morph - v # store delta vert += ((v_morph[0], v_morph[1], v_morph[2]), ) if use_morph_normals: normals = shape_key.split_normals n_morph = Vector(normals[loop_index * 3:loop_index * 3 + 3]) n_morph = n_morph - n # store delta vert += ((n_morph[0], n_morph[1], n_morph[2]), ) vert_idx = prim.verts.setdefault(vert, len(prim.verts)) prim.indices.append(vert_idx) # # Put the verts into attribute arrays. # result_primitives = [] for material_idx, prim in prims.items(): if not prim.indices: continue vs = [] ns = [] ts = [] uvs = [[] for _ in range(tex_coord_max)] cols = [[] for _ in range(color_max)] joints = [[] for _ in range(bone_max)] weights = [[] for _ in range(bone_max)] vs_morph = [[] for _ in shape_keys] ns_morph = [[] for _ in shape_keys] ts_morph = [[] for _ in shape_keys] for vert in prim.verts.keys(): i = 0 i += 1 # skip over Blender mesh index v = vert[i] i += 1 v = convert_swizzle_location(v, armature, blender_object, export_settings) vs.extend(v) if use_normals: n = vert[i] i += 1 n = convert_swizzle_normal(n, armature, blender_object, export_settings) ns.extend(n) if use_tangents: t = vert[i] i += 1 t = convert_swizzle_tangent(t, armature, blender_object, export_settings) ts.extend(t) b = vert[i] i += 1 b = convert_swizzle_tangent(b, armature, blender_object, export_settings) b_sign = -1.0 if (Vector(n).cross(Vector(t))).dot( Vector(b)) < 0.0 else 1.0 ts.append(b_sign) for tex_coord_index in range(0, tex_coord_max): uv = vert[i] i += 1 uvs[tex_coord_index].extend(uv) for color_index in range(0, color_max): col = vert[i] i += 1 cols[color_index].extend(col) if bone_max: bones = vert[i] i += 1 for j in range(0, 4 * bone_max): if j < len(bones): joint, weight = bones[j] else: joint, weight = 0, 0.0 joints[j // 4].append(joint) weights[j // 4].append(weight) for shape_key_index in range(0, len(shape_keys)): v_morph = vert[i] i += 1 v_morph = convert_swizzle_location(v_morph, armature, blender_object, export_settings) vs_morph[shape_key_index].extend(v_morph) if use_morph_normals: n_morph = vert[i] i += 1 n_morph = convert_swizzle_normal(n_morph, armature, blender_object, export_settings) ns_morph[shape_key_index].extend(n_morph) if use_morph_tangents: rotation = n_morph.rotation_difference(n) t_morph = Vector(t) t_morph.rotate(rotation) ts_morph[shape_key_index].extend(t_morph) attributes = {} attributes['POSITION'] = vs if ns: attributes['NORMAL'] = ns if ts: attributes['TANGENT'] = ts for i, uv in enumerate(uvs): attributes['TEXCOORD_%d' % i] = uv for i, col in enumerate(cols): attributes['COLOR_%d' % i] = col for i, js in enumerate(joints): attributes['JOINTS_%d' % i] = js for i, ws in enumerate(weights): attributes['WEIGHTS_%d' % i] = ws for i, vm in enumerate(vs_morph): attributes['MORPH_POSITION_%d' % i] = vm for i, nm in enumerate(ns_morph): attributes['MORPH_NORMAL_%d' % i] = nm for i, tm in enumerate(ts_morph): attributes['MORPH_TANGENT_%d' % i] = tm result_primitives.append({ 'attributes': attributes, 'indices': prim.indices, 'material': material_idx, }) print_console('INFO', 'Primitives created: %d' % len(result_primitives)) return result_primitives
def best_planar_map(): global all_scale_def, xoffset_def, yoffset_def, zrot_def, tex_aspect obj = bpy.context.active_object mesh = obj.data is_editmode = (obj.mode == 'EDIT') # if in EDIT Mode switch to OBJECT if is_editmode: bpy.ops.object.mode_set(mode='OBJECT', toggle=False) # if no UVtex - create it if not mesh.uv_layers: uvtex = bpy.ops.mesh.uv_texture_add() uvtex = mesh.uv_layers.active #uvtex.active_render = True img = None aspect = 1.0 mat = obj.active_material try: if mat: img = mat.active_texture aspect = img.image.size[0] / img.image.size[1] except: pass aspect = aspect * tex_aspect # # Main action # if all_scale_def: sc = 1.0 / all_scale_def else: sc = 1.0 # Calculate Average Normal v = Vector((0, 0, 0)) cnt = 0 for f in mesh.polygons: if f.select: cnt += 1 v = v + f.normal zv = Vector((0, 0, 1)) q = v.rotation_difference(zv) sx = 1 * sc sy = 1 * sc sz = 1 * sc ofx = xoffset_def ofy = yoffset_def rz = zrot_def / 180 * pi cosrz = cos(rz) sinrz = sin(rz) #uvs = mesh.uv_loop_layers[mesh.uv_loop_layers.active_index].data uvs = mesh.uv_layers.active.data for i, pol in enumerate(mesh.polygons): if not is_editmode or mesh.polygons[i].select: for j, loop in enumerate(mesh.polygons[i].loop_indices): v_idx = mesh.loops[loop].vertex_index n = pol.normal co = q @ (mesh.vertices[v_idx].co) x = co.x * sx y = co.y * sy z = co.z * sz uvs[loop].uv[0] = x * cosrz - y * sinrz + xoffset_def uvs[loop].uv[1] = aspect * (-x * sinrz - y * cosrz) + yoffset_def # Back to EDIT Mode if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False)
def process(self): verts_socket, poly_socket = self.inputs norm_socket, norm_abs_socket, origins_socket, centers_socket = self.outputs if not any([s.is_linked for s in self.outputs]): return if not (verts_socket.is_linked and poly_socket.is_linked): return pols_ = poly_socket.sv_get() vers_tupls = verts_socket.sv_get() vers_vects = Vector_generate(vers_tupls) # make mesh temp утилитарно - удалить в конце mat_collect = [] normals_out = [] origins = [] norm_abs_out = [] for verst, versv, pols in zip(vers_tupls, vers_vects, pols_): # medians в векторах medians = [] normals = [] centrs = [] norm_abs = [] for p in pols: # medians # it calcs middle point of opposite edges, # than finds length vector between this two points v0 = versv[p[0]] v1 = versv[p[1]] v2 = versv[p[2]] lp = len(p) if lp >= 4: l = ((lp - 2) // 2) + 2 v3 = versv[p[l]] poi_2 = (v2 + v3) / 2 # normals norm = geometry.normal(v0, v1, v2, v3) normals.append(norm) else: poi_2 = v2 # normals norm = geometry.normal(v0, v1, v2) normals.append(norm) poi_1 = (v0 + v1) / 2 vm = poi_2 - poi_1 medians.append(vm) # centrs x, y, z = zip(*[verst[poi] for poi in p]) x, y, z = sum(x) / len(x), sum(y) / len(y), sum(z) / len(z) current_center = Vector((x, y, z)) centrs.append(current_center) # normal absolute !!! # это совершенно нормально!!! ;-) norm_abs.append(current_center + norm) if self.Separate: norm_abs_out.append(norm_abs) origins.append(centrs) normals_out.append(normals) else: norm_abs_out.extend(norm_abs) origins.extend(centrs) normals_out.extend(normals) mat_collect_ = [] for cen, med, nor in zip(centrs, medians, normals): loc = Matrix.Translation(cen) # need better solution for Z,Y vectors + may be X vector correction vecz = Vector((0, 1e-6, 1)) q_rot0 = vecz.rotation_difference(nor).to_matrix().to_4x4() q_rot2 = nor.rotation_difference(vecz).to_matrix().to_4x4() if med[1] > med[0]: vecy = Vector((1e-6, 1, 0)) * q_rot2 else: vecy = Vector((1, 1e-6, 0)) * q_rot2 q_rot1 = vecy.rotation_difference(med).to_matrix().to_4x4() # loc is matrix * rot vector * rot vector M = loc * q_rot1 * q_rot0 lM = [j[:] for j in M] mat_collect_.append(lM) mat_collect.extend(mat_collect_) if not self.Separate: norm_abs_out = [norm_abs_out] origins = [origins] normals_out = [normals_out] centers_socket.sv_set(mat_collect) norm_abs_socket.sv_set(Vector_degenerate(norm_abs_out)) origins_socket.sv_set(Vector_degenerate(origins)) norm_socket.sv_set(Vector_degenerate(normals_out))
#file = csv.reader(open('Coordenadas.csv', newline=''), delimiter=',') #for row in file: # x = row[0] # y = row[1] # z = row[2] # bpy.ops.mesh.primitive_uv_cilinder_add(location = (float(x),float(y),float(z))) #Laptop #Add path file. fp = "Coordenadas.csv" with open(fp) as csvfile: rdr = csv.reader(csvfile) for i, row in enumerate(rdr): x = row[0] y = row[1] z = row[2] #bpy.ops.mesh.primitive_uv_sphere_add(location = (float(x),float(y),float(z))) myStartLoc = Vector((float(x), float(y), float(z))) myRotQuaternion = upVector.rotation_difference(myStartLoc) myRotEulerAngles = myRotQuaternion.to_euler() myRotEulerAnglesVec = ((myRotEulerAngles.x, myRotEulerAngles.y, myRotEulerAngles.z)) bpy.ops.mesh.primitive_cylinder_add(vertices=8, radius=7.5, depth=75, end_fill_type='NGON', location=myStartLoc, rotation=myRotEulerAnglesVec)
def get_point_rotation(scene, curve_obj, index=0, spline_index=0): # Get curve attributes curve_mat = curve_obj.matrix_world curve = curve_obj.data points = get_spline_points(curve.splines[spline_index]) # new temp object to detect local x-axis and y-axis of first handle # Temp Bevel Object for temp curve temp_bevel_curve = bpy.data.curves.new('__temp_bevel', 'CURVE') temp_spline = temp_bevel_curve.splines.new('POLY') temp_spline.points.add(2) temp_spline.points[0].co = Vector((1.0, 0.0, 0.0, 1.0)) temp_spline.points[1].co = Vector((0.0, 1.0, 0.0, 1.0)) temp_bevel_obj = bpy.data.objects.new('__temp_bevel', temp_bevel_curve) scene.objects.link(temp_bevel_obj) # Temp Curve curve_copy = curve_obj.data.copy() curve_copy.use_fill_caps = False curve_copy.bevel_object = temp_bevel_obj temp_obj = bpy.data.objects.new('__temp', curve_copy) scene.objects.link(temp_obj) temp_obj.location = curve_obj.location temp_obj.rotation_mode = curve_obj.rotation_mode temp_obj.rotation_quaternion = curve_obj.rotation_quaternion temp_obj.rotation_euler = curve_obj.rotation_euler # Convert temp curve to mesh bpy.ops.object.select_all(action='DESELECT') # deselect all first scene.objects.active = temp_obj temp_obj.select = True bpy.ops.object.convert(target='MESH') offset = 0 micro_offset = 0 #cyclic check for i, spline in enumerate(curve.splines): if i > spline_index: break #ps = get_spline_points(spline) if i > 0: ps_count = len(get_spline_points(curve.splines[i-1])) offset += ps_count-1 if spline.use_cyclic_u: offset += 1 elif i > 0: micro_offset += 1 #offset += spline_index * curve.resolution_u #print(offset) # get x-axis and y-axis of the first handle handle_x = temp_obj.data.vertices[curve.resolution_u * (index + offset) * 3 + micro_offset * 3].co handle_y = temp_obj.data.vertices[curve.resolution_u * (index + offset) * 3 + 1 + micro_offset * 3].co target_x = handle_x - points[index].co.xyz target_y = handle_y - points[index].co.xyz target_x.normalize() target_y.normalize() # delete temp objects temp_bevel_obj.select = True bpy.ops.object.delete() # Match bevel x-axis to handle x-axis bevel_x = Vector((1.0, 0.0, 0.0)) target_x = curve_mat.to_3x3() * target_x rot_1 = bevel_x.rotation_difference(target_x) # Match bevel y-axis to handle y-axis bevel_y = rot_1.to_matrix() * Vector((0.0, 1.0, 0.0)) target_y = curve_mat.to_3x3() * target_y rot_2 = bevel_y.rotation_difference(target_y) # Select curve object again scene.objects.active = curve_obj curve_obj.select = True return rot_2 * rot_1
def process(self): if self.outputs['Centers'].is_linked or self.outputs['Normals'].is_linked or \ self.outputs['Origins'].is_linked or self.outputs['Norm_abs'].is_linked: if 'Polygons' in self.inputs and 'Vertices' in self.inputs \ and self.inputs['Polygons'].is_linked and self.inputs['Vertices'].is_linked: pols_ = SvGetSocketAnyType(self, self.inputs['Polygons']) vers_tupls = SvGetSocketAnyType(self, self.inputs['Vertices']) vers_vects = Vector_generate(vers_tupls) # make mesh temp утилитарно - удалить в конце mat_collect = [] normals_out = [] origins = [] norm_abs_out = [] for verst, versv, pols in zip(vers_tupls, vers_vects, pols_): # medians в векторах medians = [] normals = [] centrs = [] norm_abs = [] for p in pols: # medians # it calcs middle point of opposite edges, # than finds length vector between this two points v0 = versv[p[0]] v1 = versv[p[1]] v2 = versv[p[2]] lp=len(p) if lp >= 4: l = ((lp-2)//2) + 2 v3 = versv[p[l]] poi_2 = (v2+v3)/2 # normals norm = geometry.normal(v0, v1, v2, v3) normals.append(norm) else: poi_2 = v2 # normals norm = geometry.normal(v0, v1, v2) normals.append(norm) poi_1 = (v0+v1)/2 vm = poi_2 - poi_1 medians.append(vm) # centrs x,y,z = zip(*[verst[poi] for poi in p]) x,y,z = sum(x)/len(x), sum(y)/len(y), sum(z)/len(z) current_center = Vector((x,y,z)) centrs.append(current_center) # normal absolute !!! # это совершенно нормально!!! ;-) norm_abs.append(current_center+norm) norm_abs_out.append(norm_abs) origins.append(centrs) normals_out.extend(normals) mat_collect_ = [] for cen, med, nor in zip(centrs, medians, normals): loc = Matrix.Translation(cen) # need better solution for Z,Y vectors + may be X vector correction vecz = Vector((0, 1e-6, 1)) q_rot0 = vecz.rotation_difference(nor).to_matrix().to_4x4() q_rot2 = nor.rotation_difference(vecz).to_matrix().to_4x4() vecy = Vector((1e-6, 1, 0)) * q_rot2 q_rot1 = vecy.rotation_difference(med).to_matrix().to_4x4() # loc is matrix * rot vector * rot vector M = loc*q_rot1*q_rot0 lM = [ j[:] for j in M ] mat_collect_.append(lM) mat_collect.extend(mat_collect_) SvSetSocketAnyType(self, 'Centers', mat_collect) SvSetSocketAnyType(self, 'Norm_abs', Vector_degenerate(norm_abs_out)) SvSetSocketAnyType(self, 'Origins', Vector_degenerate(origins)) SvSetSocketAnyType(self, 'Normals', Vector_degenerate([normals_out]))