def register(cls): cls.min_max_time_steps_per_frame = NewMinMaxIntProperty( name_min="Min Substeps", description_min="Minimum number of substeps per frame calculation", min_min=1, max_min=100, default_min=1, name_max="Max Substeps", description_max="Maximum number of substeps per frame calculation", min_max=1, max_max=100, default_max=8, ) cls.enable_adaptive_obstacle_time_stepping = BoolProperty( name="Enable Adaptive Time Stepping for Obstacles", description="Include obstacle velocities when calculating number" " of frame substeps. Enabling may improve the accuracy of" " fluid-solid interaction for fast moving obstacles.", default=False, ) cls.particle_jitter_factor = FloatProperty( name="Particle Jitter", description="Amount of random jitter that is added to newly spawned" " fluid particles. Higher values may improve simulation accuracy," " but may cause 'bumpy' artifacts in the initial mesh shape.", min=0.0, max=1.0, default=1.0, precision=2, subtype='FACTOR', ) cls.PICFLIP_ratio = FloatProperty( name="PIC/FLIP Ratio", description="Ratio of PIC velocity to FLIP velocity update mixture." " PIC velocity method is not very accurate, but stable. FLIP" " velocity method is very accurate, but less stable. Using a" " value of 0.0 results in a completely FLIP simulator, while" " using a value of 1.0 results in a completely PIC simulator.", min=0.0, max=1.0, default=0.05, precision=2, subtype='FACTOR', ) cls.CFL_condition_number = IntProperty( name="Safety Factor (CFL Number)", description="Maximum number of grid cells a particle can travel" " in a single substep. A larger number may speed up simulation" " baking by reducing the number of required substeps at the" " cost of accuracy.", min=1, max=50, default=5, ) cls.enable_extreme_velocity_removal = BoolProperty( name="Remove particles with extreme velocities", description="Attempt to remove extreme particle velocities that" " cause the simulator to exceed the maximum number of allowed" " frame substeps. Enabling this option may prevent simulation" " blow-up in extreme cases. Disable this option if fast moving" " fluid is disappearing from the simulation domain.", default=True, ) cls.enable_gpu_features = BoolProperty( name="Enable GPU Features", description="Enable simulator to accelerate some computations" " with your GPU device. TIP: Compare simulation performance" " with this setting on/off to test what is faster on your" " hardware setup. Note: you may only notice a difference on" " higher resolution simulations.", default=True) cls.num_threads_auto_detect = IntProperty( name="Threads", description= "Number of threads to use simultaneously while simulating", min=1, max=1024, default=1, ) cls.num_threads_fixed = IntProperty( name="Threads", description= "Number of threads to use simultaneously while simulating", min=1, max=1024, default=1, ) cls.threading_mode = EnumProperty( name="Threading Mode", description="Determing the amount of simulation threads used", items=types.threading_modes, default='THREADING_MODE_AUTO_DETECT', options={'HIDDEN'}, ) cls.enable_asynchronous_meshing = BoolProperty( name="Enable Async Meshing", description="Run mesh generation process in a separate thread while" " the simulation is running. May increase simulation performance" " but will use more RAM if enabled.", default=True, ) cls.precompute_static_obstacles = BoolProperty( name="Precompute Static Obstacles", description="Precompute data for static obstacles. If enabled," " the simulator will avoid recomputing data for non-animated" " obstacles. Increases simulation performance but will use" " more RAM if enabled.", default=True, ) cls.reserve_temporary_grids = BoolProperty( name="Reserve Temporary Grid Memory", description="Reserve space in memory for temporary grids. Increases" " simulation performance for scenes with animated or keyframed" " obstacles but will use more RAM if enabled.", default=True, ) cls.experimental_optimization_features = BoolProperty( name="Enable Experimental Optimization Features", description="Enable features that may boost performance. Compare" " simulation performance with this setting on/off to test" " what is faster on your hardware setup. Note: you may only" " notice a difference on higher resolution simulations.", default=True, )
class SvBevelNode(bpy.types.Node, SverchCustomTreeNode): """ Triggers: Bevel, Round, Smooth Tooltip: Bevel vertices, edges and faces. Create rounded corners. """ bl_idname = 'SvBevelNode' bl_label = 'Bevel' bl_icon = 'MOD_BEVEL' @throttled def mode_change(self, context): self.inputs[5].name = 'BevelEdges' if not self.vertexOnly else 'VerticesMask' if 'Spread' in self.inputs: self.inputs['Spread'].hide_safe = self.miter_inner == 'SHARP' and self.miter_outer == 'SHARP' offset_: FloatProperty( name='Amount', description='Amount to offset beveled edge', default=0.0, min=0.0, update=updateNode) offset_modes = [ ("OFFSET", "Offset", "Amount is offset of new edges from original", 1), ("WIDTH", "Width", "Amount is width of new face", 2), ("DEPTH", "Depth", "Amount is perpendicular distance from original edge to bevel face", 3), ("PERCENT", "Percent", "Amount is percent of adjacent edge length", 4) ] offsetType: EnumProperty( name='Amount Type', description="What distance Amount measures", items=offset_modes, default='OFFSET', update=updateNode) segments_: IntProperty( name="Segments", description="Number of segments in bevel", default=1, min=1, update=updateNode) profile_: FloatProperty( name="Profile", description="Profile shape; 0.5 - round", default=0.5, min=0.0, max=1.0, update=updateNode) vertexOnly: BoolProperty( name="Vertex mode", description="Only bevel edges, not edges", default=False, update=mode_change) clamp_overlap : BoolProperty( name = "Clamp Overlap", description = "do not allow beveled edges/vertices to overlap each other", default = False, update = updateNode) loop_slide : BoolProperty( name = "Loop Slide", description = "prefer to slide along edges to having even widths", default = True, update = updateNode) miter_types = [ ('SHARP', "Sharp", "Sharp", 0), ('PATCH', "Patch", "Patch", 1), ('ARC', "Arc", "Arc", 2) ] miter_outer : EnumProperty( name = "Outer", description = "Outer mitter type", items = miter_types, default = 'SHARP', update = mode_change) miter_inner : EnumProperty( name = "Inner", description = "Inner mitter type", items = miter_types, default = 'SHARP', update = mode_change) spread : FloatProperty( name = "Spread", description = "Amount to offset beveled edge", default = 0.0, min = 0.0, update = updateNode) def sv_init(self, context): si, so = self.inputs.new, self.outputs.new si('SvVerticesSocket', "Vertices") si('SvStringsSocket', 'Edges') si('SvStringsSocket', 'Polygons') si('SvStringsSocket', 'FaceData') si('SvStringsSocket', 'BevelFaceData') si('SvStringsSocket', 'BevelEdges') si('SvStringsSocket', "Offset").prop_name = "offset_" si('SvStringsSocket', "Segments").prop_name = "segments_" si('SvStringsSocket', "Profile").prop_name = "profile_" si('SvStringsSocket', "Spread").prop_name = "spread" so('SvVerticesSocket', 'Vertices') so('SvStringsSocket', 'Edges') so('SvStringsSocket', 'Polygons') so('SvStringsSocket', 'FaceData') so('SvStringsSocket', 'NewPolys') self.mode_change(context) def draw_buttons(self, context, layout): layout.prop(self, "vertexOnly") layout.prop(self, "clamp_overlap") layout.label(text="Amount type:") layout.prop(self, "offsetType", expand=True) def draw_buttons_ext(self, context, layout): self.draw_buttons(context, layout) layout.prop(self, "loop_slide") layout.label(text="Miter type:") layout.prop(self, 'miter_inner') layout.prop(self, 'miter_outer') def get_socket_data(self): vertices = self.inputs['Vertices'].sv_get(default=[[]]) edges = self.inputs['Edges'].sv_get(default=[[]]) faces = self.inputs['Polygons'].sv_get(default=[[]]) if 'FaceData' in self.inputs: face_data = self.inputs['FaceData'].sv_get(default=[[]]) else: face_data = [[]] if 'BevelFaceData' in self.inputs: bevel_face_data = self.inputs['BevelFaceData'].sv_get(default=[[]]) else: bevel_face_data = [[]] if self.vertexOnly: mask = self.inputs['VerticesMask'].sv_get(default=[[]]) else: mask = self.inputs['BevelEdges'].sv_get(default=[[]]) offsets = self.inputs['Offset'].sv_get()[0] segments = self.inputs['Segments'].sv_get()[0] profiles = self.inputs['Profile'].sv_get()[0] if 'Spread' in self.inputs: spreads = self.inputs['Spread'].sv_get()[0] else: spreads = [0.0] return vertices, edges, faces, face_data, mask, offsets, segments, profiles, bevel_face_data, spreads def create_geom(self, bm, mask): if not self.vertexOnly: b_edges = get_bevel_edges(bm, mask) geom = list(bm.verts) + list(b_edges) + list(bm.faces) else: b_verts = get_bevel_verts(bm, mask) geom = b_verts + list(bm.edges) + list(bm.faces) return geom 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: fullList(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: 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 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) 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 register(): bpy.utils.register_class(SampleGeneratorPanel) # bpy.types.Scene.sg_label_mode = EnumProperty( # items = [('sgSegment', 'Segmented','Segment'), ('sgBBox', 'Bounding Box','Bounding Box')], # name = "Label Mode", # description = "Controls which kind of labels are generated." ) # bpy.types.Scene.sg_render_mode = EnumProperty( # items = [('sgBackground', 'Background','Background'), ('sgCropped', 'Cropped','Cropped')], # name = "Render Mode", # description = "The rendering Mode.") bpy.types.Scene.sg_objectGroup = PointerProperty( type=bpy.types.Group, name="Object Group", description="An Object group with all objects that are to be rendered." ) bpy.types.Scene.sg_backgroundPath = StringProperty( subtype="FILE_PATH", name="Background Path", description="Path to background images.") bpy.types.Scene.sg_nSamples = IntProperty( name="Number Samples", min=0, max=999999999, description="Number of generated Samples.") bpy.types.Scene.sg_cam = PointerProperty( name="Camera", type=bpy.types.Object, description="The scenes camera Object. (needed for perspective changes)" ) bpy.types.Scene.sg_sun = PointerProperty( name="Sun", type=bpy.types.Object, description= "The scenes Lightsource. (needed for light rotation and intensity adjustments)" ) bpy.types.Scene.sg_ground = PointerProperty( name="Ground", type=bpy.types.Object, description= "The scenes Ground Object. (will be set to shadow catcher and disabled for shadowless rendering)" ) bpy.types.Scene.sg_cam_target = PointerProperty( name="Camera Target", type=bpy.types.Object, description="The camera Target. (Camera is always pointed at this)") bpy.types.Scene.sg_cam_dist = FloatProperty( name="Camera distance", default=2.2, subtype='DISTANCE', unit='LENGTH', description="Cameras distance to Objects.") bpy.types.Scene.sg_img_size = IntVectorProperty( name="Image Size", size=2, default=(300, 300), description= "Size of the rendered image (In Background rendering this is set to size of background image)." ) bpy.utils.register_class(GenerateSamplesOperator) bpy.types.INFO_MT_render.append(menu_func)
class SFR_Settings(PropertyGroup): #### SETTINGS OPTIMIZER #### detection_method: EnumProperty( name="Optimization Method", items=( ('MANUAL', 'Manual', 'Manual Scene Optimizer'), ('AUTOMATIC', 'Automatic', 'Automatic Scene Optimizer'), ), default='AUTOMATIC', description= "Optimization method, manual for basic setups, automatic for more precise settings", options=set(), # Not animatable! ) threshold: FloatProperty( name="Threshold", default=0.1, max=1, min=0.01, description= "Threshold on which the next benchmark method should set in", options=set(), # Not animatable! ) resolution: IntProperty( name="Benchmark Res", default=5, max=20, min=1, description= "Resolution the benchmark should run, higher = more precision but slower", options=set(), # Not animatable! ) frame_skipped: IntProperty( name="Frame Offset", default=10, max=20, min=1, description="Frames between automatic benchmarks", options=set(), # Not animatable! ) inputdir: StringProperty( name="Benchmark Folder", default="C:/temp/", description="Benchmarking Frames will be saved here", subtype='DIR_PATH', maxlen=1024, options=set(), # Not animatable! ) use_diffuse: BoolProperty(name="Diffuse", default=True, description="Benchmark diffuse") use_glossy: BoolProperty(name="Glossy", default=True, description="Benchmark glossy") use_transparent: BoolProperty(name="Transparency", default=True, description="Benchmark transparency") use_transmission: BoolProperty(name="Transmission", default=True, description="Benchmark transmission") use_volume: BoolProperty(name="Volume", default=True, description="Benchmark volume") use_indirect: BoolProperty(name="Indirect Brightness", default=True, description="Benchmark indirect brightness") use_caustics: BoolProperty(name="Caustics", default=False, description="Benchmark caustic blur") #### TEXTURE OPTIMIZER #### diffuse_resize: IntProperty( name="Diffuse / Albedo", default=0, max=7, min=0, description= "the factor by which the diffuse or albedo textures will be scaled down, 0 = unaffected \nrecommended: 0", options=set(), # Not animatable! ) ao_resize: IntProperty( name="Ambient Occlusion", default=2, max=7, min=0, description= "the factor by which the ambient occlusion textures will be scaled down, 0 = unaffected \nrecommended: 2", options=set(), # Not animatable! ) specular_resize: IntProperty( name="Specular / Metallic", default=2, max=7, min=0, description= "the factor by which the specular or metallic textures will be scaled down, 0 = unaffected \nrecommended: 2", options=set(), # Not animatable! ) roughness_resize: IntProperty( name="Roughness / Glossiness", default=2, max=7, min=0, description= "the factor by which the roughness or glossiness textures will be scaled down, 0 = unaffected \nrecommended: 2", options=set(), # Not animatable! ) normal_resize: IntProperty( name="Normal / Bump", default=1, max=7, min=0, description= "the factor by which the normal or bump textures will be scaled down, 0 = unaffected \nrecommended: 1", options=set(), # Not animatable! ) opacity_resize: IntProperty( name="Opacity / Transparency", default=1, max=7, min=0, description= "the factor by which the opacity or transparency textures will be scaled down, 0 = unaffected \nrecommended: 1", options=set(), # Not animatable! ) translucency_resize: IntProperty( name="Translucency", default=1, max=7, min=0, description= "the factor by which the translucency textures will be scaled down, 0 = unaffected \nrecommended: 1", options=set(), # Not animatable! ) create_backup: BoolProperty( name="Create Backup", default=True, description= 'Creates a backup of all the image files in the folder "textures backup"\nwe heavily recommend to keep this enabled' )
class SHIPGENERATOR_OT_hull(Operator): bl_label = "Shipgenerator hull" bl_idname = "shipgenerator.hull" bl_description = "Create a hull surface" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_options = {'REGISTER', 'UNDO'} width: IntProperty(name="Hull Width", default=4, min=0, max=15, description="Used as a width property") seed: IntProperty( name="Generational Seed", default=1, min=-99999999, max=99999999, description="Used for randomizing the seed of generation") def invoke(self, context, event): return context.window_manager.invoke_props_dialog(self) def create_surface(self, context, p_name: str, p_location: [float, float, float], p_collection=None, p_parent: Object = None): bpy.ops.surface.primitive_nurbs_surface_surface_add() new_surface = context.object new_surface.name = p_name new_surface.location = p_location new_surface.parent = p_parent new_surface.data.splines[0].use_endpoint_u = True new_surface.data.splines[0].use_endpoint_v = True new_surface.data.splines[0].use_smooth = False self.set_random_positions(new_surface, 0, 0, 0) if p_collection is not None: context.collection.objects.unlink(new_surface) p_collection.objects.link(new_surface) return new_surface def get_point_y_z(self, p_surface, p_z_row: int, p_y_column: int, p_width: int): index = p_y_column * p_width + p_z_row return p_surface.data.splines[0].points[index] def get_point_index(p_surface, p_index: int): return p_surface.data.splines[0].points[p_index] def set_random_positions(self, p_surface: bpy.types.SurfaceCurve, p_min_x: int, p_max_x: int, p_seed: int, p_y_offset=2, p_z_offset=2): y_start = 0 row_x = [p_min_x, p_min_x, p_min_x, p_min_x] if p_min_x != p_max_x: logging.info("Will Randomize X position") random.seed(p_seed) row_x = [ 0, random.randrange(p_min_x, p_max_x), random.randrange(p_min_x, p_max_x), random.randrange(p_min_x, p_max_x) ] row_index = 0 for point in p_surface.data.splines[0].points: position = point.co position[0] = row_x[row_index] position[1] = y_start position[2] = p_z_offset * row_index if row_index < 3: row_index += 1 else: row_index = 0 y_start += p_y_offset def set_column_points_to_position(self, p_surface, p_y: int, p_width: int, p_position: []): for z_index in range(0, p_width): point = self.get_point_y_z(p_surface, z_index, p_y, p_width) point.co = p_position[z_index] def get_column_points_positions(self, p_surface, p_y: int, p_width: int): points_position = [] for row_index in range(0, p_width): point = self.get_point_y_z(p_surface, row_index, p_y, p_width) points_position.append(point.co) return points_position def execute(self, context): hull_collection = bpy.data.collections.new('Hull') context.scene.collection.children.link(hull_collection) surface = self.create_surface(context, "Hull_Main_Stern", [0.0, 0.0, 0.0], hull_collection) self.set_random_positions(surface, 3, 6, self.seed, 3, 2) surface_two = self.create_surface(context, "Hull_Main_Bow", [0.0, 9.0, 0.0], hull_collection, surface) for column_index in range(0, 4): surface_positions = self.get_column_points_positions( surface, column_index, 4) self.set_column_points_to_position(surface_two, column_index, 4, surface_positions) surface_bow = self.create_surface(context, "Hull_Bow", [0, 18, 0], hull_collection, surface) self.set_random_positions(surface_bow, 3, 6, self.seed, random.randrange(2, 7), 2) surface_positions = self.get_column_points_positions(surface, 0, 4) self.set_column_points_to_position(surface_bow, 0, 4, surface_positions) self.set_column_points_to_position(surface_bow, 3, 4, [(0, 16, 1, 1), (0, 17, 3, 1), (0, 18, 4, 1), (0, 18, 6, 1)]) return {'FINISHED'}
class GenerateCollisionMesh(RDOperator): """ :ref:`operator` for creating a collision mesh using the builtin subdivide and shrinkwrap operators. **Preconditions:** **Postconditions:** """ bl_idname = config.OPERATOR_PREFIX + "generatecollisionmesh" bl_label = "Generate Collision Mesh for selected" shrinkWrapOffset = FloatProperty(name="Shrinkwrap Offset", default=0.001, unit='LENGTH', min=0, max=0.5) subdivisionLevels = IntProperty(name="Subdivision Levels", default=2) @classmethod def run(cls, shrinkWrapOffset, subdivisionLevels): return super().run(**cls.pass_keywords()) @RDOperator.OperatorLogger def execute(self, context): from . import segments, model target_name = [ i.name for i in bpy.context.selected_objects if i.type == 'MESH' ][0] self.logger.debug("Creating Collision mesh for: %s", target_name) armature = context.active_object.name bpy.ops.object.select_all(action='DESELECT') bpy.context.scene.objects.active = bpy.data.objects[target_name] d = bpy.data.objects[target_name].dimensions bpy.ops.mesh.primitive_cube_add( location=bpy.data.objects[target_name].location, rotation=bpy.data.objects[target_name].rotation_euler) bpy.context.object.dimensions = d * 1000000 bpy.ops.object.transform_apply(scale=True) mod = bpy.context.object.modifiers.new(name='subsurf', type='SUBSURF') mod.subdivision_type = 'SIMPLE' mod.levels = self.subdivisionLevels bpy.ops.object.modifier_apply(modifier='subsurf') mod = bpy.context.object.modifiers.new(name='shrink_wrap', type='SHRINKWRAP') mod.wrap_method = "NEAREST_SURFACEPOINT" mod.offset = self.shrinkWrapOffset * 1000 self.logger.debug("%f, %f", mod.offset, self.shrinkWrapOffset) mod.target = bpy.data.objects[target_name] bpy.ops.object.modifier_apply(modifier='shrink_wrap') if not bpy.context.object.name.startswith("COL_"): bpy.context.object.name = 'COL_' + target_name[4:] name = bpy.context.object.name context.active_object.RobotEditor.tag = 'COLLISION' self.logger.debug("Created mesh: %s", bpy.context.active_object.name) if 'RD_COLLISON_OBJECT_MATERIAL' in bpy.data.materials: bpy.ops.object.material_slot_add() context.active_object.data.materials[0] = bpy.data.materials[ 'RD_COLLISON_OBJECT_MATERIAL'] self.logger.debug("Assigned material to : %s", bpy.context.active_object.name) else: self.logger.debug("Could not find material for collision mesh") bpy.ops.object.select_all(action='DESELECT') model.SelectModel.run(model_name=armature) segments.SelectSegment.run( segment_name=bpy.data.objects[target_name].parent_bone) bpy.data.objects[name].select = True bpy.ops.object.parent_set(type='BONE', keep_transform=True) bpy.ops.object.select_all(action='DESELECT') model.SelectModel.run(model_name=armature) return {'FINISHED'} def invoke(self, context, event): return context.window_manager.invoke_props_dialog(self)
class QuickExplode(ObjectModeOperator, Operator): """Make selected objects explode""" bl_idname = "object.quick_explode" bl_label = "Quick Explode" bl_options = {'REGISTER', 'UNDO'} style: EnumProperty( name="Explode Style", items=( ('EXPLODE', "Explode", ""), ('BLEND', "Blend", ""), ), default='EXPLODE', ) amount: IntProperty( name="Number of Pieces", min=2, max=10000, soft_min=2, soft_max=10000, default=100, ) frame_duration: IntProperty( name="Duration", min=1, max=300000, soft_min=1, soft_max=10000, default=50, ) frame_start: IntProperty( name="Start Frame", min=1, max=300000, soft_min=1, soft_max=10000, default=1, ) frame_end: IntProperty( name="End Frame", min=1, max=300000, soft_min=1, soft_max=10000, default=10, ) velocity: FloatProperty( name="Outwards Velocity", min=0, max=300000, soft_min=0, soft_max=10, default=1, ) fade: BoolProperty( name="Fade", description="Fade the pieces over time", default=True, ) def execute(self, context): fake_context = context.copy() obj_act = context.active_object if obj_act is None or obj_act.type != 'MESH': self.report({'ERROR'}, "Active object is not a mesh") return {'CANCELLED'} mesh_objects = [ obj for obj in context.selected_objects if obj.type == 'MESH' and obj != obj_act ] mesh_objects.insert(0, obj_act) if self.style == 'BLEND' and len(mesh_objects) != 2: self.report({'ERROR'}, "Select two mesh objects") self.style = 'EXPLODE' return {'CANCELLED'} elif not mesh_objects: self.report({'ERROR'}, "Select at least one mesh object") return {'CANCELLED'} for obj in mesh_objects: if obj.particle_systems: self.report({'ERROR'}, "Object %r already has a " "particle system" % obj.name) return {'CANCELLED'} if self.style == 'BLEND': from_obj = mesh_objects[1] to_obj = mesh_objects[0] for obj in mesh_objects: fake_context["object"] = obj bpy.ops.object.particle_system_add(fake_context) settings = obj.particle_systems[-1].settings settings.count = self.amount # first set frame end, to prevent frame start clamping settings.frame_end = self.frame_end - self.frame_duration settings.frame_start = self.frame_start settings.lifetime = self.frame_duration settings.normal_factor = self.velocity settings.render_type = 'NONE' explode = obj.modifiers.new(name='Explode', type='EXPLODE') explode.use_edge_cut = True if self.fade: explode.show_dead = False uv = obj.data.uv_layers.new(name="Explode fade") explode.particle_uv = uv.name mat = object_ensure_material(obj, "Explode Fade") mat.blend_method = 'BLEND' mat.shadow_method = 'HASHED' if not mat.use_nodes: mat.use_nodes = True nodes = mat.node_tree.nodes for node in nodes: if node.type == 'OUTPUT_MATERIAL': node_out_mat = node break node_surface = node_out_mat.inputs['Surface'].links[ 0].from_node node_x = node_surface.location[0] node_y = node_surface.location[1] - 400 offset_x = 200 node_mix = nodes.new('ShaderNodeMixShader') node_mix.location = (node_x - offset_x, node_y) mat.node_tree.links.new(node_surface.outputs[0], node_mix.inputs[1]) mat.node_tree.links.new(node_mix.outputs["Shader"], node_out_mat.inputs['Surface']) offset_x += 200 node_trans = nodes.new('ShaderNodeBsdfTransparent') node_trans.location = (node_x - offset_x, node_y) mat.node_tree.links.new(node_trans.outputs["BSDF"], node_mix.inputs[2]) offset_x += 200 node_ramp = nodes.new('ShaderNodeValToRGB') node_ramp.location = (node_x - offset_x, node_y) offset_x += 200 mat.node_tree.links.new(node_ramp.outputs["Alpha"], node_mix.inputs["Fac"]) color_ramp = node_ramp.color_ramp color_ramp.elements[0].color[3] = 0.0 color_ramp.elements[1].color[3] = 1.0 if self.style == 'BLEND': color_ramp.elements[0].position = 0.333 color_ramp.elements[1].position = 0.666 if obj == to_obj: # reverse ramp alpha color_ramp.elements[0].color[3] = 1.0 color_ramp.elements[1].color[3] = 0.0 node_sep = nodes.new('ShaderNodeSeparateXYZ') node_sep.location = (node_x - offset_x, node_y) offset_x += 200 mat.node_tree.links.new(node_sep.outputs["X"], node_ramp.inputs["Fac"]) node_uv = nodes.new('ShaderNodeUVMap') node_uv.location = (node_x - offset_x, node_y) node_uv.uv_map = uv.name mat.node_tree.links.new(node_uv.outputs["UV"], node_sep.inputs["Vector"]) if self.style == 'BLEND': settings.physics_type = 'KEYED' settings.use_emit_random = False settings.rotation_mode = 'NOR' psys = obj.particle_systems[-1] fake_context["particle_system"] = obj.particle_systems[-1] bpy.ops.particle.new_target(fake_context) bpy.ops.particle.new_target(fake_context) if obj == from_obj: psys.targets[1].object = to_obj else: psys.targets[0].object = from_obj settings.normal_factor = -self.velocity explode.show_unborn = False explode.show_dead = True else: settings.factor_random = self.velocity settings.angular_velocity_factor = self.velocity / 10.0 return {'FINISHED'} def invoke(self, context, _event): self.frame_start = context.scene.frame_current self.frame_end = self.frame_start + self.frame_duration return self.execute(context)
class LodGenerate(Operator): """Generate levels of detail using the decimate modifier""" bl_idname = "object.lod_generate" bl_label = "Generate Levels of Detail" bl_options = {'REGISTER', 'UNDO'} count = IntProperty( name="Count", default=3, ) target = FloatProperty( name="Target Size", min=0.0, max=1.0, default=0.1, ) package = BoolProperty( name="Package into Group", default=False, ) @classmethod def poll(cls, context): return (context.active_object is not None) def execute(self, context): scene = context.scene ob = scene.objects.active lod_name = ob.name lod_suffix = "lod" lod_prefix = "" if lod_name.lower().endswith("lod0"): lod_suffix = lod_name[-3:-1] lod_name = lod_name[:-3] elif lod_name.lower().startswith("lod0"): lod_suffix = "" lod_prefix = lod_name[:3] lod_name = lod_name[4:] group_name = lod_name.strip(' ._') if self.package: try: bpy.ops.object.group_link(group=group_name) except TypeError: bpy.ops.group.create(name=group_name) step = (1.0 - self.target) / (self.count - 1) for i in range(1, self.count): scene.objects.active = ob bpy.ops.object.duplicate() lod = context.selected_objects[0] scene.objects.active = ob bpy.ops.object.lod_add() scene.objects.active = lod if lod_prefix: lod.name = lod_prefix + str(i) + lod_name else: lod.name = lod_name + lod_suffix + str(i) lod.location.y = ob.location.y + 3.0 * i if i == 1: modifier = lod.modifiers.new("lod_decimate", 'DECIMATE') else: modifier = lod.modifiers[-1] modifier.ratio = 1.0 - step * i ob.lod_levels[i].object = lod if self.package: bpy.ops.object.group_link(group=group_name) lod.parent = ob if self.package: for level in ob.lod_levels[1:]: level.object.hide = level.object.hide_render = True lod.select = False ob.select = True scene.objects.active = ob return {'FINISHED'}
class SubdivisionSet(Operator): """Sets a Subdivision Surface Level (1-5)""" bl_idname = "object.subdivision_set" bl_label = "Subdivision Set" bl_options = {'REGISTER', 'UNDO'} level: IntProperty( name="Level", min=-100, max=100, soft_min=-6, soft_max=6, default=1, ) relative: BoolProperty( name="Relative", description=("Apply the subsurf level as an offset " "relative to the current level"), default=False, ) @classmethod def poll(cls, context): obs = context.selected_editable_objects return (obs is not None) def execute(self, context): level = self.level relative = self.relative if relative and level == 0: return {'CANCELLED'} # nothing to do if not relative and level < 0: self.level = level = 0 def set_object_subd(obj): for mod in obj.modifiers: if mod.type == 'MULTIRES': if not relative: if level > mod.total_levels: sub = level - mod.total_levels for _ in range(sub): bpy.ops.object.multires_subdivide( modifier="Multires") if obj.mode == 'SCULPT': if mod.sculpt_levels != level: mod.sculpt_levels = level elif obj.mode == 'OBJECT': if mod.levels != level: mod.levels = level return else: if obj.mode == 'SCULPT': if mod.sculpt_levels + level <= mod.total_levels: mod.sculpt_levels += level elif obj.mode == 'OBJECT': if mod.levels + level <= mod.total_levels: mod.levels += level return elif mod.type == 'SUBSURF': if relative: mod.levels += level else: if mod.levels != level: mod.levels = level return # add a new modifier try: if obj.mode == 'SCULPT': mod = obj.modifiers.new("Multires", 'MULTIRES') if level > 0: for _ in range(level): bpy.ops.object.multires_subdivide( modifier="Multires") else: mod = obj.modifiers.new("Subdivision", 'SUBSURF') mod.levels = level except: self.report({'WARNING'}, "Modifiers cannot be added to object: " + obj.name) for obj in context.selected_editable_objects: set_object_subd(obj) return {'FINISHED'}
class ImportGLTF2(Operator, ImportHelper): """Load a glTF 2.0 file""" bl_idname = 'import_scene.gltf' bl_label = 'Import glTF 2.0' filter_glob: StringProperty(default="*.glb;*.gltf", options={'HIDDEN'}) files: CollectionProperty( name="File Path", type=bpy.types.OperatorFileListElement, ) loglevel: IntProperty(name='Log Level', description="Log Level") import_pack_images: BoolProperty( name='Pack images', description='Pack all images into .blend file', default=True) import_shading: EnumProperty( name="Shading", items=(("NORMALS", "Use Normal Data", ""), ("FLAT", "Flat Shading", ""), ("SMOOTH", "Smooth Shading", "")), description="How normals are computed during import", default="NORMALS") def draw(self, context): layout = self.layout layout.prop(self, 'import_pack_images') layout.prop(self, 'import_shading') def execute(self, context): return self.import_gltf2(context) def import_gltf2(self, context): import os self.set_debug_log() import_settings = self.as_keywords() if self.files: # Multiple file import ret = {'CANCELLED'} dirname = os.path.dirname(self.filepath) for file in self.files: path = os.path.join(dirname, file.name) if self.unit_import(path, import_settings) == {'FINISHED'}: ret = {'FINISHED'} return ret else: # Single file import return self.unit_import(self.filepath, import_settings) def unit_import(self, filename, import_settings): import time from .io.imp.gltf2_io_gltf import glTFImporter from .blender.imp.gltf2_blender_gltf import BlenderGlTF self.gltf_importer = glTFImporter(filename, import_settings) success, txt = self.gltf_importer.read() if not success: self.report({'ERROR'}, txt) return {'CANCELLED'} success, txt = self.gltf_importer.checks() if not success: self.report({'ERROR'}, txt) return {'CANCELLED'} self.gltf_importer.log.critical( "Data are loaded, start creating Blender stuff") start_time = time.time() BlenderGlTF.create(self.gltf_importer) elapsed_s = "{:.2f}s".format(time.time() - start_time) self.gltf_importer.log.critical("glTF import finished in " + elapsed_s) self.gltf_importer.log.removeHandler(self.gltf_importer.log_handler) return {'FINISHED'} def set_debug_log(self): import logging if bpy.app.debug_value == 0: self.loglevel = logging.CRITICAL elif bpy.app.debug_value == 1: self.loglevel = logging.ERROR elif bpy.app.debug_value == 2: self.loglevel = logging.WARNING elif bpy.app.debug_value == 3: self.loglevel = logging.INFO else: self.loglevel = logging.NOTSET
class UVEditorSettings(PropertyGroup): initialized: BoolProperty(default=False) show_stretch: BoolProperty( name="Display Stretch", description= "Display faces colored according to the difference in shape between UVs and their 3D coordinates (blue for low distortion, red for high distortion)", default=False) display_stretch_type: EnumProperty( name="Display Stretch Type", description="Type of stretch to draw", items={('ANGLE', "Angle", "Angle distortion between UV and 3D angles", 0), ('AREA', "Area", "Area distortion between UV and 3D faces", 1)}, default='ANGLE') uv_opacity: FloatProperty(name="UV Opacity", description="Opacity of UV overlays", default=1.0, min=0.0, max=1.0) edge_display_type: EnumProperty( name="Display style for UV edges", description="Type of stretch to draw", items={('OUTLINE', "Outline", "Display white edges with black outline", 0), ('DASH', "Dash", "Display dashed black-white edges", 1), ('BLACK', "Black", "Display black edges", 2), ('WHITE', "White", "Display white edges", 3)}, default='OUTLINE') show_modified_edges: BoolProperty( name="Modified Edges", description="Display edges after modifiers are applied", default=False) show_faces: BoolProperty(name="Faces", description="Display faces over the image", default=True) show_metadata: BoolProperty( name="Show Metadata", description="Display metadata properties of the image", default=True) tile_grid_shape: IntVectorProperty( name="UDIM Grid Shape", description="How many tiles will be shown in the background", size=2, default=(0, 0), min=0, max=100) use_custom_grid: BoolProperty( name="Custom Grid", description="Use a grid with a user-defined number of steps", default=True) custom_grid_subdivisions: IntProperty( name="Dynamic Grid Size", description="Number of Grid units in UV space that make one UV Unit", default=10, min=1, max=100) show_region_toolbar: BoolProperty(name="Show Toolbar", description="", default=False) show_region_ui: BoolProperty(name="Show Sidebar", description="", default=False) show_region_tool_header: BoolProperty(name="Show Tool Settings", description="", default=False) show_region_hud: BoolProperty(name="Show Adjust Last Operation", description="", default=False) pixel_snap_mode: EnumProperty( name="Snap to Pixels", description="", items={('DISABLED', "Disabled", "Don't snap to pixels", 0), ('CORNER', "Corner", "Snap to pixel corners", 1), ('CENTER', "Center", "Snap to pixel centers", 2)}, default='DISABLED') lock_bounds: BoolProperty( name="Constrain to Image Bounds", description="Constraint to stay within the image bounds while editing", default=False) use_live_unwrap: BoolProperty( name="Live Unwrap", description= "Continuously unwrap the selected island while transforming pinned vertices", default=False) def set(self, area): space = area.spaces[0] uv_editor = space.uv_editor uv_editor.show_stretch = self.show_stretch uv_editor.display_stretch_type = self.display_stretch_type uv_editor.uv_opacity = self.uv_opacity uv_editor.edge_display_type = self.edge_display_type uv_editor.show_modified_edges = self.show_modified_edges uv_editor.show_faces = self.show_faces uv_editor.show_metadata = self.show_metadata uv_editor.tile_grid_shape = self.tile_grid_shape uv_editor.use_custom_grid = self.use_custom_grid uv_editor.custom_grid_subdivisions = self.custom_grid_subdivisions space.show_region_toolbar = self.show_region_toolbar space.show_region_ui = self.show_region_ui space.show_region_tool_header = self.show_region_tool_header space.show_region_hud = self.show_region_hud uv_editor.pixel_snap_mode = self.pixel_snap_mode uv_editor.lock_bounds = self.lock_bounds uv_editor.use_live_unwrap = self.use_live_unwrap def save_from_area(self, area): space = area.spaces[0] uv_editor = space.uv_editor self.show_stretch = uv_editor.show_stretch self.display_stretch_type = uv_editor.display_stretch_type self.uv_opacity = uv_editor.uv_opacity self.edge_display_type = uv_editor.edge_display_type self.show_modified_edges = uv_editor.show_modified_edges self.show_faces = uv_editor.show_faces self.show_metadata = uv_editor.show_metadata self.tile_grid_shape = uv_editor.tile_grid_shape self.use_custom_grid = uv_editor.use_custom_grid self.custom_grid_subdivisions = uv_editor.custom_grid_subdivisions self.show_region_toolbar = space.show_region_toolbar self.show_region_ui = space.show_region_ui self.show_region_tool_header = space.show_region_tool_header self.show_region_hud = space.show_region_hud self.pixel_snap_mode = uv_editor.pixel_snap_mode self.lock_bounds = uv_editor.lock_bounds self.use_live_unwrap = uv_editor.use_live_unwrap def save_from_property(self, property): self.show_stretch = property.show_stretch self.display_stretch_type = property.display_stretch_type self.uv_opacity = property.uv_opacity self.edge_display_type = property.edge_display_type self.show_modified_edges = property.show_modified_edges self.show_faces = property.show_faces self.show_metadata = property.show_metadata self.tile_grid_shape = property.tile_grid_shape self.use_custom_grid = property.use_custom_grid self.custom_grid_subdivisions = property.custom_grid_subdivisions self.show_region_toolbar = property.show_region_toolbar self.show_region_ui = property.show_region_ui self.show_region_tool_header = property.show_region_tool_header self.show_region_hud = property.show_region_hud self.pixel_snap_mode = property.pixel_snap_mode self.lock_bounds = property.lock_bounds self.use_live_unwrap = property.use_live_unwrap
class ExportGLTF2_Base: # TODO: refactor to avoid boilerplate def __init__(self): from io_scene_gltf2.io.exp import gltf2_io_draco_compression_extension self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists( ) bl_options = {'UNDO', 'PRESET'} export_format: EnumProperty( name='Format', items= (('GLB', 'glTF Binary (.glb)', 'Exports a single file, with all data packed in binary form. ' 'Most efficient and portable, but more difficult to edit later'), ('GLTF_EMBEDDED', 'glTF Embedded (.gltf)', 'Exports a single file, with all data packed in JSON. ' 'Less efficient than binary, but easier to edit later'), ('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)', 'Exports multiple files, with separate JSON, binary and texture data. ' 'Easiest to edit later')), description=( 'Output format and embedding options. Binary is most efficient, ' 'but JSON (embedded or separate) may be easier to edit later'), default='GLB') ui_tab: EnumProperty( items=(('GENERAL', "General", "General settings"), ('MESHES', "Meshes", "Mesh settings"), ('OBJECTS', "Objects", "Object settings"), ('ANIMATION', "Animation", "Animation settings")), name="ui_tab", description="Export setting categories", ) export_copyright: StringProperty( name='Copyright', description='Legal rights and conditions for the model', default='') export_image_format: EnumProperty( name='Images', items= (('NAME', 'Automatic', 'Determine the image format from the blender image name'), ('JPEG', 'JPEG Format (.jpg)', 'Encode and save textures as .jpg files. Be aware of a possible loss in quality' ), ('PNG', 'PNG Format (.png)', 'Encode and save textures as .png files')), description= ('Output format for images. PNG is lossless and generally preferred, but JPEG might be preferable for web ' 'applications due to the smaller file size'), default='NAME') export_texcoords: BoolProperty( name='UVs', description='Export UVs (texture coordinates) with meshes', default=True) export_normals: BoolProperty( name='Normals', description='Export vertex normals with meshes', default=True) export_draco_mesh_compression_enable: BoolProperty( name='Draco mesh compression', description='Compress mesh using Draco', default=False) export_draco_mesh_compression_level: IntProperty( name='Compression level', description= 'Compression level (0 = most speed, 6 = most compression, higher values currently not supported)', default=6, min=0, max=6) export_draco_position_quantization: IntProperty( name='Position quantization bits', description= 'Quantization bits for position values (0 = no quantization)', default=14, min=0, max=30) export_draco_normal_quantization: IntProperty( name='Normal quantization bits', description='Quantization bits for normal values (0 = no quantization)', default=10, min=0, max=30) export_draco_texcoord_quantization: IntProperty( name='Texcoord quantization bits', description= 'Quantization bits for texture coordinate values (0 = no quantization)', default=12, min=0, max=30) export_tangents: BoolProperty( name='Tangents', description='Export vertex tangents with meshes', default=False) export_materials: BoolProperty(name='Materials', description='Export materials', default=True) export_colors: BoolProperty(name='Vertex Colors', description='Export vertex colors with meshes', default=True) export_cameras: BoolProperty(name='Cameras', description='Export cameras', default=False) export_selected: BoolProperty(name='Selected Objects', description='Export selected objects only', default=False) export_extras: BoolProperty( name='Custom Properties', description='Export custom properties as glTF extras', default=False) export_yup: BoolProperty(name='+Y Up', description='Export using glTF convention, +Y up', default=True) export_apply: BoolProperty( name='Apply Modifiers', description='Apply modifiers (excluding Armatures) to mesh objects -' 'WARNING: prevents exporting shape keys', default=False) export_animations: BoolProperty( name='Animations', description='Exports active actions and NLA tracks as glTF animations', default=True) export_frame_range: BoolProperty( name='Limit to Playback Range', description='Clips animations to selected playback range', default=True) export_frame_step: IntProperty( name='Sampling Rate', description='How often to evaluate animated values (in frames)', default=1, min=1, max=120) export_force_sampling: BoolProperty( name='Always Sample Animations', description='Apply sampling to all animations', default=True) export_nla_strips: BoolProperty(name='NLA Strips', description='Export NLA Strip animations', default=True) export_def_bones: BoolProperty( name='Export Deformation bones only', description= 'Export Deformation bones only (and needed bones for hierarchy)', default=False) export_current_frame: BoolProperty( name='Use Current Frame', description='Export the scene in the current animation frame', default=False) export_skins: BoolProperty(name='Skinning', description='Export skinning (armature) data', default=True) export_all_influences: BoolProperty( name='Include All Bone Influences', description= 'Allow >4 joint vertex influences. Models may appear incorrectly in many viewers', default=False) export_morph: BoolProperty(name='Shape Keys', description='Export shape keys (morph targets)', default=True) export_morph_normal: BoolProperty( name='Shape Key Normals', description='Export vertex normals with shape keys (morph targets)', default=True) export_morph_tangent: BoolProperty( name='Shape Key Tangents', description='Export vertex tangents with shape keys (morph targets)', default=False) export_lights: BoolProperty( name='Punctual Lights', description='Export directional, point, and spot lights. ' 'Uses "KHR_lights_punctual" glTF extension', default=False) export_displacement: BoolProperty( name='Displacement Textures (EXPERIMENTAL)', description='EXPERIMENTAL: Export displacement textures. ' 'Uses incomplete "KHR_materials_displacement" glTF extension', default=False) will_save_settings: BoolProperty( name='Remember Export Settings', description='Store glTF export settings in the Blender project', default=False) # Custom scene property for saving settings scene_key = "glTF2ExportSettings" # def invoke(self, context, event): settings = context.scene.get(self.scene_key) self.will_save_settings = False if settings: try: for (k, v) in settings.items(): setattr(self, k, v) self.will_save_settings = True except (AttributeError, TypeError): self.report({ "ERROR" }, "Loading export settings failed. Removed corrupted settings" ) del context.scene[self.scene_key] return ExportHelper.invoke(self, context, event) def save_settings(self, context): # find all export_ props all_props = self.properties export_props = { x: getattr(self, x) for x in dir(all_props) if x.startswith("export_") and all_props.get(x) is not None } context.scene[self.scene_key] = export_props def execute(self, context): import os import datetime from .blender.exp import gltf2_blender_export if self.will_save_settings: self.save_settings(context) if self.export_format == 'GLB': self.filename_ext = '.glb' else: self.filename_ext = '.gltf' # All custom export settings are stored in this container. export_settings = {} export_settings['timestamp'] = datetime.datetime.now() export_settings['gltf_filepath'] = bpy.path.ensure_ext( self.filepath, self.filename_ext) export_settings['gltf_filedirectory'] = os.path.dirname( export_settings['gltf_filepath']) + '/' export_settings['gltf_format'] = self.export_format export_settings['gltf_image_format'] = self.export_image_format export_settings['gltf_copyright'] = self.export_copyright export_settings['gltf_texcoords'] = self.export_texcoords export_settings['gltf_normals'] = self.export_normals export_settings[ 'gltf_tangents'] = self.export_tangents and self.export_normals if self.is_draco_available: export_settings[ 'gltf_draco_mesh_compression'] = self.export_draco_mesh_compression_enable export_settings[ 'gltf_draco_mesh_compression_level'] = self.export_draco_mesh_compression_level export_settings[ 'gltf_draco_position_quantization'] = self.export_draco_position_quantization export_settings[ 'gltf_draco_normal_quantization'] = self.export_draco_normal_quantization export_settings[ 'gltf_draco_texcoord_quantization'] = self.export_draco_texcoord_quantization else: export_settings['gltf_draco_mesh_compression'] = False export_settings['gltf_materials'] = self.export_materials export_settings['gltf_colors'] = self.export_colors export_settings['gltf_cameras'] = self.export_cameras export_settings['gltf_selected'] = self.export_selected export_settings['gltf_layers'] = True # self.export_layers export_settings['gltf_extras'] = self.export_extras export_settings['gltf_yup'] = self.export_yup export_settings['gltf_apply'] = self.export_apply export_settings['gltf_current_frame'] = self.export_current_frame export_settings['gltf_animations'] = self.export_animations if self.export_animations: export_settings['gltf_frame_range'] = self.export_frame_range export_settings['gltf_force_sampling'] = self.export_force_sampling if self.export_force_sampling: export_settings['gltf_def_bones'] = self.export_def_bones else: export_settings['gltf_def_bones'] = False export_settings['gltf_nla_strips'] = self.export_nla_strips else: export_settings['gltf_frame_range'] = False export_settings['gltf_move_keyframes'] = False export_settings['gltf_force_sampling'] = False export_settings['gltf_def_bones'] = False export_settings['gltf_skins'] = self.export_skins if self.export_skins: export_settings[ 'gltf_all_vertex_influences'] = self.export_all_influences else: export_settings['gltf_all_vertex_influences'] = False export_settings['gltf_frame_step'] = self.export_frame_step export_settings['gltf_morph'] = self.export_morph if self.export_morph: export_settings['gltf_morph_normal'] = self.export_morph_normal else: export_settings['gltf_morph_normal'] = False if self.export_morph and self.export_morph_normal: export_settings['gltf_morph_tangent'] = self.export_morph_tangent else: export_settings['gltf_morph_tangent'] = False export_settings['gltf_lights'] = self.export_lights export_settings['gltf_displacement'] = self.export_displacement export_settings['gltf_binary'] = bytearray() export_settings['gltf_binaryfilename'] = os.path.splitext( os.path.basename( bpy.path.ensure_ext(self.filepath, self.filename_ext)))[0] + '.bin' return gltf2_blender_export.save(context, export_settings) def draw(self, context): pass
class AddTwistedTorus(bpy.types.Operator): bl_idname = "mesh.primitive_twisted_torus_add" bl_label = "Add Twisted Torus" bl_description = "Construct a twisted torus mesh" bl_options = {'REGISTER', 'UNDO', 'PRESET'} major_radius = FloatProperty(name="Major Radius", description="Radius from the origin to the" " center of the cross section", min=0.01, max=100.0, default=1.0) minor_radius = FloatProperty( name="Minor Radius", description="Radius of the torus' cross section", min=0.01, max=100.0, default=0.25) major_segments = IntProperty( name="Major Segments", description="Number of segments for the main ring of the torus", min=3, max=256, default=48) minor_segments = IntProperty( name="Minor Segments", description="Number of segments for the minor ring of the torus", min=3, max=256, default=12) twists = IntProperty(name="Twists", description="Number of twists of the torus", min=0, max=256, default=1) use_abso = BoolProperty( name="Use Int/Ext Controls", description="Use the Int/Ext controls for torus dimensions", default=False) abso_major_rad = FloatProperty( name="Exterior Radius", description="Total Exterior Radius of the torus", min=0.01, max=100.0, default=1.0) abso_minor_rad = FloatProperty( name="Inside Radius", description="Total Interior Radius of the torus", min=0.01, max=100.0, default=0.5) def execute(self, context): if self.use_abso is True: extra_helper = (self.abso_major_rad - self.abso_minor_rad) * 0.5 self.major_radius = self.abso_minor_rad + extra_helper self.minor_radius = extra_helper verts, faces = add_twisted_torus(self.major_radius, self.minor_radius, self.major_segments, self.minor_segments, self.twists) # Create the mesh object from this geometry data. obj = create_mesh_object(context, verts, [], faces, "TwistedTorus") return {'FINISHED'}
class CAP_FormatData_Alembic(PropertyGroup): instance_id: IntProperty(default=-1) # scene start_frame: IntProperty( name = "Start Frame", description = "The start frame of the export. Leave at the default value (1) to take the start frame of the current scene.", default = 1, ) end_frame: IntProperty( name = "End Frame", description = "The end frame of the export. Leave at the default value (250) to take the start frame of the current scene.", default = 250, ) transform_samples: IntProperty( name = "Transform Samples", description = "The number of times per-frame transformations are sampled.", default = 1, min = 1, max = 128, ) geometry_samples: IntProperty( name = "Geometry Samples", description = "The number of times per-frame object data is sampled.", default = 1, min = 1, max = 128, ) shutter_open: FloatProperty( name = "Shutter Open", description = "The time at which the shutter is open.", default = 0.0, step = 0.1, min = -1, max = 1, ) shutter_close: FloatProperty( name = "Shutter Close", description = "The time at which the shutter is closed.", default = 1.0, step = 0.1, min = -1, max = 1, ) flatten_hierarchy: BoolProperty( name = "Flatten Hierarchy", description = "Do not preserve object parent/child relationships on export.", default = False ) global_scale: FloatProperty( name = "Global Scale", description = "The value to which all objects will be scaled with respect to the world's origin point.", default = 1.0, soft_min = 0.1, soft_max = 10, step = 0.1, min = 0.0001, max = 1000, ) # object export_uvs: BoolProperty( name = "Export UVs", description = "Include mesh UVs with the export.", default = True ) pack_uvs: BoolProperty( name = "Pack UV Islands", description = "Export UVs with packed islands.", default = True ) export_normals: BoolProperty( name = "Export Normals", description = "Include mesh normals with the export.", default = True ) export_colors: BoolProperty( name = "Export Vertex Colors", description = "Include vertex colors with the export.", default = False ) export_face_sets: BoolProperty( name = "Export Face Sets", description = "Export per-face shading group assignments.", default = False ) use_subdiv_schema: BoolProperty( name = "Use Subdivision Schema", description = "Export meshes using Alembic’s subdivision schema.", default = False ) apply_subdiv: BoolProperty( name = "Apply Subsurface Divisions", description = "Export subdivision surfaces as meshes.", default = False ) export_curves_as_mesh: BoolProperty( name = "Export Curves as Meshes", description = "Export curves and NURBS surfaces as meshes.", default = False ) compression_type: EnumProperty( name='Compression Type', description='???', items=( ('OGAWA', 'OGAWA', '???'), ('HDF5', 'HDF5', '???'), ), ) # particles export_hair: BoolProperty( name = "Export Hair", description = "Exports hair particle systems as animated curves.", default = False ) export_particles: BoolProperty( name = "Export Particles", description = "Exports non-hair particle systems.", default = False ) def export(self, context, export_preset, filePath): """ Calls the Alembic export operator module to export the currently selected objects. """ bpy.ops.wm.alembic_export( # core filepath = filePath + ".abc", check_existing = False, as_background_job = False, selected = True, renderable_only = False, visible_layers_only = False, # scene start = self.start_frame, end = self.end_frame, xsamples = self.transform_samples, gsamples = self.geometry_samples, sh_open = self.shutter_open, sh_close = self.shutter_close, flatten = self.flatten_hierarchy, global_scale = self.global_scale, # object uvs = self.export_uvs, packuv = self.pack_uvs, normals = self.export_normals, vcolors = self.export_colors, face_sets = self.export_face_sets, subdiv_schema = self.use_subdiv_schema, apply_subdiv = self.apply_subdiv, curves_as_mesh = self.export_curves_as_mesh, compression_type = self.compression_type, # trianglulate = False, # part of the API, but Capsule does this elsewhere. # quad_method = ??? # see above, although I should provide options like this API does. # ngon_method = ??? # ^ # particles export_hair = self.export_hair, export_particles = self.export_particles, ) def draw_addon_preferences(self, layout, exportData, exp): """ Draws the panel that represents all the options that the export format has. """ filepresets_box = layout.column(align=True) filepresets_box.separator() export_tabs = filepresets_box.row(align=True) # tab bar and tab bar padding export_tabs.separator() export_tabs.prop(exp, "alembic_menu_options", expand=True) export_tabs.separator() # separation space between tab bar and contents export_separator = filepresets_box.column(align=True) export_separator.separator() export_separator.separator() if exp.alembic_menu_options == 'Scene': export_main = filepresets_box.row(align=True) export_main.separator() export_1 = export_main.column(align=True) export_1.separator() export_1.prop(exportData, "start_frame") export_1.prop(exportData, "end_frame") export_1.prop(exportData, "shutter_open") export_1.prop(exportData, "shutter_close") export_main.separator() export_main.separator() export_main.separator() export_2 = export_main.column(align=True) export_2.separator() export_2.prop(exportData, "flatten_hierarchy") export_2.separator() export_2.prop(exportData, "transform_samples") export_2.prop(exportData, "geometry_samples") export_2.prop(exportData, "global_scale") export_2.separator() export_main.separator() if exp.alembic_menu_options == 'Object': export_main = filepresets_box.row(align=True) export_main.separator() export_1 = export_main.column(align=True) export_1.separator() export_1.prop(exportData, "use_subdiv_schema") export_1.prop(exportData, "apply_subdiv") export_1.prop(exportData, "export_curves_as_mesh") export_1.separator() export_1.prop(exportData, "compression_type") export_1.separator() export_main.separator() export_main.separator() export_main.separator() export_2 = export_main.column(align=True) export_2.separator() export_2.prop(exportData, "export_uvs") export_2.prop(exportData, "pack_uvs") export_2.prop(exportData, "export_normals") export_2.prop(exportData, "export_colors") export_2.prop(exportData, "export_face_sets") export_2.separator() export_main.separator() elif exp.alembic_menu_options == 'Particles': export_main = filepresets_box.row(align=True) export_main.separator() export_1 = export_main.column(align=True) export_1.prop(exportData, "export_hair") export_1.prop(exportData, "export_particles") export_1.separator() export_main.separator() export_main.separator() export_main.separator() export_2 = export_main.row(align=True) export_2.separator() export_main.separator()
class SvListInputNode(bpy.types.Node, SverchCustomTreeNode): ''' Creta a float or int List ''' bl_idname = 'SvListInputNode' bl_label = 'List Input' bl_icon = 'OUTLINER_OB_EMPTY' defaults = [0 for i in range(32)] int_ = IntProperty(name='int_', description='integer number', default=1, min=1, max=32, update=updateNode) v_int = IntProperty(name='int_', description='integer number', default=1, min=1, max=10, update=updateNode) int_list = IntVectorProperty(name='int_list', description="Integer list", default=defaults, size=32, update=updateNode) float_list = FloatVectorProperty(name='float_list', description="Float list", default=defaults, size=32, update=updateNode) vector_list = FloatVectorProperty(name='vector_list', description="Vector list", default=defaults, size=32, update=updateNode) def changeMode(self, context): if self.mode == 'vector': if 'Vector List' not in self.outputs: self.outputs.remove(self.outputs[0]) self.outputs.new('VerticesSocket', 'Vector List', 'Vector List') return else: if 'List' not in self.outputs: self.outputs.remove(self.outputs[0]) self.outputs.new('StringsSocket', 'List', 'List') return modes = [("int_list", "Int", "Integer", "", 1), ("float_list", "Float", "Float", "", 2), ("vector", "Vector", "Vector", "", 3)] mode = EnumProperty(items=modes, default='int_list', update=changeMode) def init(self, context): self.outputs.new('StringsSocket', "List", "List") def draw_buttons(self, context, layout): if self.mode == 'vector': layout.prop(self, "v_int", text="List Length") else: layout.prop(self, "int_", text="List Length") layout.prop(self, "mode", expand=True) if self.mode == 'vector': col = layout.column(align=False) for i in range(self.v_int): row = col.row(align=True) for j in range(3): row.prop(self, 'vector_list', index=i * 3 + j, text='XYZ'[j]) else: col = layout.column(align=True) for i in range(self.int_): col.prop(self, self.mode, index=i, text=str(i)) def update(self): if any((n in self.outputs for n in ['List', 'Vector List'])) and self.outputs[0].links: if self.mode == 'int_list': SvSetSocketAnyType(self, "List", [list(self.int_list[:self.int_])]) elif self.mode == 'float_list': SvSetSocketAnyType(self, "List", [list(self.float_list[:self.int_])]) elif self.mode == 'vector': c = self.v_int * 3 v_l = list(self.vector_list) out = list(zip(v_l[0:c:3], v_l[1:c:3], v_l[2:c:3])) SvSetSocketAnyType(self, "Vector List", [out]) def update_socket(self, context): self.update()
class ResourcePsetProperties(PropertyGroup): active_pset_id: IntProperty(name="Active Pset ID") active_pset_name: StringProperty(name="Pset Name") properties: CollectionProperty(name="Properties", type=Attribute) pset_name: EnumProperty(items=getResourcePsetNames, name="Pset Name") qto_name: EnumProperty(items=getResourceQtoNames, name="Qto Name")
class FloorplanProperty(bpy.types.PropertyGroup): fp_types = [ ("RECTANGULAR", "Rectangular", "", 0), ("CIRCULAR", "Circular", "", 1), ("COMPOSITE", "Composite", "", 2), ("H-SHAPED", "H-Shaped", "", 3), ("RANDOM", "Random", "", 4), ] type: EnumProperty(items=fp_types, default="RECTANGULAR", description="Type of floorplan") seed: IntProperty( name="Seed", min=0, max=10000, default=1, description="Seed for random generation", ) width: FloatProperty( name="Width", min=0.01, max=100.0, default=4, unit="LENGTH", description="Base Width of floorplan", ) length: FloatProperty( name="Length", min=0.01, max=100.0, default=4, unit="LENGTH", description="Base Length of floorplan", ) random_extension_amount: BoolProperty( name="Random Extension Amount", default=True, description="Randomize the amount of extensions") extension_amount: IntProperty( name="Extension Amount", min=1, max=4, default=1, description="Amount of extensions to generate", ) radius: FloatProperty(name="Radius", min=0.1, max=100.0, default=1.0, unit="LENGTH", description="Radius of circle") segments: IntProperty( name="Segments", min=3, max=100, default=32, description="Number of segments in the circle", ) def get_segment_width(self, propname): return self.get(propname, 1.0) def set_segment_width(self, value, propname): """ Clamp the segment width to less than default_width + base width ONLY for H-Shaped floorplan """ default_width = 1.0 maximum_width = default_width + self.width # -- calculate offsets of adjacent segments adjacent_prop = { "tw1": "tw2", "tw2": "tw1", "tw3": "tw4", "tw4": "tw3", }.get(propname) maximum_width += (default_width - self.get(adjacent_prop, 1.0)) if self.type == "H-SHAPED": self[propname] = clamp(value, 0.0, maximum_width) else: self[propname] = value tw1: FloatProperty( name="Tail Width 1", min=0.0, max=100.0, unit="LENGTH", description="Width of floorplan segment", get=lambda self: self.get_segment_width("tw1"), set=lambda self, value: self.set_segment_width(value, "tw1"), ) tl1: FloatProperty( name="Tail Length 1", min=0.0, max=100.0, default=1, unit="LENGTH", description="Length of floorplan segment", ) tw2: FloatProperty( name="Tail Width 2", min=0.0, max=100.0, unit="LENGTH", description="Width of floorplan segment", get=lambda self: self.get_segment_width("tw2"), set=lambda self, value: self.set_segment_width(value, "tw2"), ) tl2: FloatProperty( name="Tail Length 2", min=0.0, max=100.0, default=1, unit="LENGTH", description="Length of floorplan segment", ) tw3: FloatProperty( name="Tail Width 3", min=0.0, max=100.0, unit="LENGTH", description="Width of floorplan segment", get=lambda self: self.get_segment_width("tw3"), set=lambda self, value: self.set_segment_width(value, "tw3"), ) tl3: FloatProperty( name="Tail Length 3", min=0.0, max=100.0, default=1, unit="LENGTH", description="Length of floorplan segment", ) tw4: FloatProperty( name="Tail Width 4", min=0.0, max=100.0, unit="LENGTH", description="Width of floorplan segment", get=lambda self: self.get_segment_width("tw4"), set=lambda self, value: self.set_segment_width(value, "tw4"), ) tl4: FloatProperty( name="Tail Length 4", min=0.0, max=100.0, default=1, unit="LENGTH", description="Length of floorplan segment", ) cap_tris: BoolProperty( name="Cap Triangles", default=False, description="Set the fill type to triangles", ) def draw(self, context, layout): row = layout.row() row.prop(self, "type", text="") box = layout.box() if self.type == "RECTANGULAR": col = box.column(align=True) col.prop(self, "width") col.prop(self, "length") elif self.type == "RANDOM": col = box.column(align=True) col.prop(self, "seed") col.prop(self, "width") col.prop(self, "length") col.prop(self, "random_extension_amount") if not self.random_extension_amount: col.prop(self, "extension_amount") elif self.type == "CIRCULAR": col = box.column(align=True) col.prop(self, "radius") col.prop(self, "segments") row = box.row() row.prop(self, "cap_tris", toggle=True) elif self.type == "COMPOSITE": row = box.row(align=True) row.prop(self, "width") row.prop(self, "length") col = box.column(align=True) col.prop(self, "tl1", text="Fan Length 1") col.prop(self, "tl2", text="Fan Length 2") col.prop(self, "tl3", text="Fan Length 3") col.prop(self, "tl4", text="Fan Length 4") elif self.type == "H-SHAPED": row = box.row(align=True) row.prop(self, "width") row.prop(self, "length") row = box.row(align=True) col = row.column(align=True) col.prop(self, "tw1") col.prop(self, "tw2") col.prop(self, "tw3") col.prop(self, "tw4") col = row.column(align=True) col.prop(self, "tl1") col.prop(self, "tl2") col.prop(self, "tl3") col.prop(self, "tl4")
class WorkSchedulePsetProperties(PropertyGroup): active_pset_id: IntProperty(name="Active Pset ID") active_pset_name: StringProperty(name="Pset Name") properties: CollectionProperty(name="Properties", type=Attribute) pset_name: EnumProperty(items=getWorkSchedulePsetNames, name="Pset Name")
class Voronoi2DNode(bpy.types.Node, SverchCustomTreeNode): """ Triggers: Voronoi vr Tooltip: Generate 2D Voronoi diagram for a set of vertices. """ bl_idname = 'Voronoi2DNode' bl_label = 'Voronoi 2D' bl_icon = 'OUTLINER_OB_EMPTY' sv_icon = 'SV_VORONOI' clip: FloatProperty(name='clip', description='Clipping Distance', default=1.0, min=0, update=updateNode) bound_modes = [('BOX', 'Bounding Box', "Bounding Box", 0), ('CIRCLE', 'Bounding Circle', "Bounding Circle", 1)] bound_mode: EnumProperty(name='Bounds Mode', description="Bounding mode", items=bound_modes, default='BOX', update=updateNode) draw_bounds: BoolProperty(name="Draw Bounds", description="Draw bounding edges", default=True, update=updateNode) draw_hangs: BoolProperty( name="Draw Tails", description="Draw lines that end outside of clipping area", default=True, update=updateNode) def update_sockets(self, context): if 'Faces' in self.outputs: self.outputs['Faces'].hide_safe = not self.make_faces if 'MaxSides' in self.inputs: self.inputs['MaxSides'].hide_safe = not self.make_faces updateNode(self, context) make_faces: BoolProperty( name="Make faces", description="Use `fill holes` function to make Voronoi polygons", default=False, update=update_sockets) ordered_faces: BoolProperty( name="Ordered faces", description= "Make sure that faces are generated in the same order as corresponding input vertices", default=False, update=updateNode) max_sides: IntProperty(name='Sides', description='Maximum number of polygon sides', default=10, min=3, update=updateNode) def sv_init(self, context): self.inputs.new('SvVerticesSocket', "Vertices") self.inputs.new('SvStringsSocket', 'MaxSides').prop_name = 'max_sides' self.outputs.new('SvVerticesSocket', "Vertices") self.outputs.new('SvStringsSocket', "Edges") self.outputs.new('SvStringsSocket', "Faces") self.update_sockets(context) def draw_buttons(self, context, layout): layout.label(text="Bounds mode:") layout.prop(self, "bound_mode", text='') layout.prop(self, "draw_bounds") if not self.draw_bounds: layout.prop(self, "draw_hangs") layout.prop(self, "clip", text="Clipping") layout.prop(self, "make_faces") def draw_buttons_ext(self, context, layout): self.draw_buttons(context, layout) if self.make_faces: layout.prop(self, 'ordered_faces') def process(self): if not self.inputs['Vertices'].is_linked: return if not self.outputs['Vertices'].is_linked: return points_in = self.inputs['Vertices'].sv_get() if 'MaxSides' in self.inputs: max_sides_in = self.inputs['MaxSides'].sv_get() else: max_sides_in = [[10]] pts_out = [] edges_out = [] faces_out = [] for sites, max_sides in zip_long_repeat(points_in, max_sides_in): if isinstance(max_sides, (list, tuple)): max_sides = max_sides[0] new_vertices, edges, new_faces = voronoi_bounded( sites, bound_mode=self.bound_mode, clip=self.clip, draw_bounds=self.draw_bounds, draw_hangs=self.draw_hangs, make_faces=self.make_faces, ordered_faces=self.ordered_faces, max_sides=max_sides) pts_out.append(new_vertices) edges_out.append(edges) faces_out.append(new_faces) #edges_out.append(finite_edges) # outputs self.outputs['Vertices'].sv_set(pts_out) self.outputs['Edges'].sv_set(edges_out) if 'Faces' in self.outputs and self.make_faces: self.outputs['Faces'].sv_set(faces_out)
class NLA_OT_bake(Operator): """Bake all selected objects location/scale/rotation animation to an action""" bl_idname = "nla.bake" bl_label = "Bake Action" bl_options = {'REGISTER', 'UNDO'} frame_start: IntProperty( name="Start Frame", description="Start frame for baking", min=0, max=300000, default=1, ) frame_end: IntProperty( name="End Frame", description="End frame for baking", min=1, max=300000, default=250, ) step: IntProperty( name="Frame Step", description="Frame Step", min=1, max=120, default=1, ) only_selected: BoolProperty( name="Only Selected Bones", description="Only key selected bones (Pose baking only)", default=True, ) visual_keying: BoolProperty( name="Visual Keying", description="Keyframe from the final transformations (with constraints applied)", default=False, ) clear_constraints: BoolProperty( name="Clear Constraints", description="Remove all constraints from keyed object/bones, and do 'visual' keying", default=False, ) clear_parents: BoolProperty( name="Clear Parents", description="Bake animation onto the object then clear parents (objects only)", default=False, ) use_current_action: BoolProperty( name="Overwrite Current Action", description="Bake animation into current action, instead of creating a new one " "(useful for baking only part of bones in an armature)", default=False, ) clean_curves: BoolProperty( name="Clean Curves", description="After baking curves, remove redundant keys", default=False, ) bake_types: EnumProperty( name="Bake Data", description="Which data's transformations to bake", options={'ENUM_FLAG'}, items=( ('POSE', "Pose", "Bake bones transformations"), ('OBJECT', "Object", "Bake object transformations"), ), default={'POSE'}, ) def execute(self, context): from bpy_extras import anim_utils do_pose = 'POSE' in self.bake_types do_object = 'OBJECT' in self.bake_types objects = context.selected_editable_objects if do_pose and not do_object: objects = [obj for obj in objects if obj.pose is not None] object_action_pairs = ( [(obj, getattr(obj.animation_data, "action", None)) for obj in objects] if self.use_current_action else [(obj, None) for obj in objects] ) actions = anim_utils.bake_action_objects( object_action_pairs, frames=range(self.frame_start, self.frame_end + 1, self.step), only_selected=self.only_selected, do_pose=do_pose, do_object=do_object, do_visual_keying=self.visual_keying, do_constraint_clear=self.clear_constraints, do_parents_clear=self.clear_parents, do_clean=self.clean_curves, ) if not any(actions): self.report({'INFO'}, "Nothing to bake") return {'CANCELLED'} return {'FINISHED'} def invoke(self, context, _event): scene = context.scene self.frame_start = scene.frame_start self.frame_end = scene.frame_end self.bake_types = {'POSE'} if context.mode == 'POSE' else {'OBJECT'} wm = context.window_manager return wm.invoke_props_dialog(self)
class QuickFur(ObjectModeOperator, Operator): """Add fur setup to the selected objects""" bl_idname = "object.quick_fur" bl_label = "Quick Fur" bl_options = {'REGISTER', 'UNDO'} density: EnumProperty( name="Fur Density", items=(('LIGHT', "Light", ""), ('MEDIUM', "Medium", ""), ('HEAVY', "Heavy", "")), default='MEDIUM', ) view_percentage: IntProperty( name="View %", min=1, max=100, soft_min=1, soft_max=100, default=10, ) length: FloatProperty( name="Length", min=0.001, max=100, soft_min=0.01, soft_max=10, default=0.1, ) def execute(self, context): fake_context = context.copy() mesh_objects = [ obj for obj in context.selected_objects if obj.type == 'MESH' ] if not mesh_objects: self.report({'ERROR'}, "Select at least one mesh object") return {'CANCELLED'} mat = bpy.data.materials.new("Fur Material") for obj in mesh_objects: fake_context["object"] = obj bpy.ops.object.particle_system_add(fake_context) psys = obj.particle_systems[-1] psys.settings.type = 'HAIR' if self.density == 'LIGHT': psys.settings.count = 100 elif self.density == 'MEDIUM': psys.settings.count = 1000 elif self.density == 'HEAVY': psys.settings.count = 10000 psys.settings.child_nbr = self.view_percentage psys.settings.hair_length = self.length psys.settings.use_strand_primitive = True psys.settings.use_hair_bspline = True psys.settings.child_type = 'INTERPOLATED' psys.settings.tip_radius = 0.25 obj.data.materials.append(mat) psys.settings.material = len(obj.data.materials) return {'FINISHED'}
class SvListItemNode(bpy.types.Node, SverchCustomTreeNode): ''' Triggers: List Item Out Tooltip: Get elements from list at desired indexes ''' bl_idname = 'SvListItemNode' bl_label = 'List Item' bl_icon = 'OUTLINER_OB_EMPTY' sv_icon = 'SV_LIST_ITEM' level: IntProperty(name='level_to_count', default=2, min=1, update=updateNode) index: IntProperty(name='Index', default=0, update=updateNode) typ: StringProperty(name='typ', default='') newsock: BoolProperty(name='newsock', default=False) def draw_buttons(self, context, layout): '''draw buttons on the node''' layout.prop(self, "level", text="level") def sv_init(self, context): '''create sockets''' self.inputs.new('SvStringsSocket', "Data") self.inputs.new('SvStringsSocket', "Index").prop_name = 'index' self.outputs.new('SvStringsSocket', "Item") self.outputs.new('SvStringsSocket', "Other") def migrate_from(self, old_node): self.index = old_node.item def sv_update(self): """adapt socket type to input type""" if self.inputs['Data'].is_linked: inputsocketname = 'Data' outputsocketname = ['Item', 'Other'] changable_sockets(self, inputsocketname, outputsocketname) def process(self): data = self.inputs['Data'].sv_get(default=[], deepcopy=False) indexes = self.inputs['Index'].sv_get(deepcopy=False) if self.level - 1: out = self.get_(data, self.level - 1, indexes, self.get_items) else: out = self.get_items(data, indexes[0]) self.outputs[0].sv_set(out) if self.level - 1: out = self.get_(data, self.level - 1, indexes, self.get_other) else: out = self.get_other(data, indexes[0]) self.outputs[1].sv_set(out) def get_items(self, data, indexes): '''extract the indexes from the list''' if type(data) in [list, tuple]: return [ data[index] for index in indexes if -len(data) <= index < len(data) ] if type(data) == str: return ''.join([ data[index] for index in indexes if -len(data) <= index < len(data) ]) elif type(data) == np.ndarray: return data[indexes] else: return None def get_other(self, data, indexes): '''remove the indexes from the list''' if type(data) == np.ndarray: mask = np.ones(len(data), bool) mask[indexes] = False return data[mask] is_tuple = False if type(data) == tuple: data = list(data) is_tuple = True if type(data) == list: out_data = data.copy() m_indexes = indexes.copy() for idx, index in enumerate(indexes): if index < 0: m_indexes[idx] = len(out_data) - abs(index) for i in sorted(set(m_indexes), reverse=True): if -1 < i < len(out_data): del out_data[i] if is_tuple: return tuple(out_data) else: return out_data if type(data) == str: return ''.join( [d for idx, d in enumerate(data) if idx not in indexes]) else: return None def get_(self, data, level, indexes, func): # get is build-in method of Node class """iterative function to get down to the requested level""" if level == 1: obj_num = max(len(data), len(indexes)) index_iter = repeat_last(indexes) data_iter = repeat_last(data) return [ self.get_(next(data_iter), level - 1, next(index_iter), func) for _ in range(obj_num) ] elif level: return [self.get_(obj, level - 1, indexes, func) for obj in data] else: return func(data, indexes)
class AddGem(Operator): bl_idname = "mesh.primitive_gem_add" bl_label = "Add Gem" bl_description = "Construct an offset faceted gem mesh" bl_options = {'REGISTER', 'UNDO', 'PRESET'} Gem : BoolProperty(name = "Gem", default = True, description = "Gem") #### change properties name : StringProperty(name = "Name", description = "Name") change : BoolProperty(name = "Change", default = False, description = "change Gem") segments: IntProperty( name="Segments", description="Longitudial segmentation", min=3, max=265, default=8 ) pavilion_radius: FloatProperty( name="Radius", description="Radius of the gem", min=0.01, max=9999.0, default=1.0 ) crown_radius: FloatProperty( name="Table Radius", description="Radius of the table(top)", min=0.01, max=9999.0, default=0.6 ) crown_height: FloatProperty( name="Table height", description="Height of the top half", min=0.01, max=9999.0, default=0.35 ) pavilion_height: FloatProperty( name="Pavilion height", description="Height of bottom half", min=0.01, max=9999.0, default=0.8 ) def draw(self, context): layout = self.layout box = layout.box() box.prop(self, "segments") box.prop(self, "pavilion_radius") box.prop(self, "crown_radius") box.prop(self, "crown_height") box.prop(self, "pavilion_height") def execute(self, context): if bpy.context.mode == "OBJECT": if context.selected_objects != [] and context.active_object and \ ('Gem' in context.active_object.data.keys()) and (self.change == True): obj = context.active_object oldmesh = obj.data oldmeshname = obj.data.name verts, faces = add_gem( self.pavilion_radius, self.crown_radius, self.segments, self.pavilion_height, self.crown_height) mesh = bpy.data.meshes.new("TMP") mesh.from_pydata(verts, [], faces) mesh.update() obj.data = mesh for material in oldmesh.materials: obj.data.materials.append(material) bpy.data.meshes.remove(oldmesh) obj.data.name = oldmeshname else: verts, faces = add_gem( self.pavilion_radius, self.crown_radius, self.segments, self.pavilion_height, self.crown_height) obj = create_mesh_object(context, verts, [], faces, "Gem") obj.data["Gem"] = True obj.data["change"] = False for prm in GemParameters(): obj.data[prm] = getattr(self, prm) if bpy.context.mode == "EDIT_MESH": active_object = context.active_object name_active_object = active_object.name bpy.ops.object.mode_set(mode='OBJECT') verts, faces = add_gem( self.pavilion_radius, self.crown_radius, self.segments, self.pavilion_height, self.crown_height) obj = create_mesh_object(context, verts, [], faces, "TMP") obj.select_set(True) active_object.select_set(True) bpy.ops.object.join() context.active_object.name = name_active_object bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'}
class ImageNode(bpy.types.Node, SverchCustomTreeNode): ''' Image ''' bl_idname = 'ImageNode' bl_label = 'Image' bl_icon = 'FILE_IMAGE' name_image = StringProperty(name='image_name', description='image name', default='', update=updateNode) R = FloatProperty(name='R', description='R', default=0.30, min=0, max=1, options={'ANIMATABLE'}, update=updateNode) G = FloatProperty(name='G', description='G', default=0.59, min=0, max=1, options={'ANIMATABLE'}, update=updateNode) B = FloatProperty(name='B', description='B', default=0.11, min=0, max=1, options={'ANIMATABLE'}, update=updateNode) Xvecs = IntProperty(name='Xvecs', description='Xvecs', default=10, min=2, max=100, options={'ANIMATABLE'}, update=updateNode) Yvecs = IntProperty(name='Yvecs', description='Yvecs', default=10, min=2, max=100, options={'ANIMATABLE'}, update=updateNode) Xstep = FloatProperty(name='Xstep', description='Xstep', default=1.0, min=0.01, max=100, options={'ANIMATABLE'}, update=updateNode) Ystep = FloatProperty(name='Ystep', description='Ystep', default=1.0, min=0.01, max=100, options={'ANIMATABLE'}, update=updateNode) def sv_init(self, context): self.inputs.new('StringsSocket', "vecs X", "vecs X").prop_name = 'Xvecs' self.inputs.new('StringsSocket', "vecs Y", "vecs Y").prop_name = 'Yvecs' self.inputs.new('StringsSocket', "Step X", "Step X").prop_name = 'Xstep' self.inputs.new('StringsSocket', "Step Y", "Step Y").prop_name = 'Ystep' self.outputs.new('VerticesSocket', "vecs", "vecs") self.outputs.new('StringsSocket', "edgs", "edgs") self.outputs.new('StringsSocket', "pols", "pols") def draw_buttons(self, context, layout): layout.prop_search(self, "name_image", bpy.data, 'images', text="image") row = layout.row(align=True) row.scale_x = 10.0 row.prop(self, "R", text="R") row.prop(self, "G", text="G") row.prop(self, "B", text="B") def process(self): # inputs if 'vecs X' in self.inputs and self.inputs['vecs X'].is_linked: IntegerX = min( int(SvGetSocketAnyType(self, self.inputs['vecs X'])[0][0]), 100) else: IntegerX = int(self.Xvecs) if 'vecs Y' in self.inputs and self.inputs['vecs Y'].is_linked: IntegerY = min( int(SvGetSocketAnyType(self, self.inputs['vecs Y'])[0][0]), 100) else: IntegerY = int(self.Yvecs) if 'Step X' in self.inputs and self.inputs['Step X'].is_linked: StepX = SvGetSocketAnyType(self, self.inputs['Step X'])[0] fullList(StepX, IntegerX) else: StepX = [self.Xstep] fullList(StepX, IntegerX) if 'Step Y' in self.inputs and self.inputs['Step Y'].is_linked: StepY = SvGetSocketAnyType(self, self.inputs['Step Y'])[0] fullList(StepY, IntegerY) else: StepY = [self.Ystep] fullList(StepY, IntegerY) # outputs if 'vecs' in self.outputs and self.outputs['vecs'].is_linked: out = self.make_vertices(IntegerX - 1, IntegerY - 1, StepX, StepY, self.name_image) SvSetSocketAnyType(self, 'vecs', [out]) else: SvSetSocketAnyType(self, 'vecs', [[[]]]) if 'edgs' in self.outputs and self.outputs['edgs'].is_linked: listEdg = [] for i in range(IntegerY): for j in range(IntegerX - 1): listEdg.append((IntegerX * i + j, IntegerX * i + j + 1)) for i in range(IntegerX): for j in range(IntegerY - 1): listEdg.append( (IntegerX * j + i, IntegerX * j + i + IntegerX)) edg = list(listEdg) SvSetSocketAnyType(self, 'edgs', [edg]) else: SvSetSocketAnyType(self, 'edgs', [[[]]]) if 'pols' in self.outputs and self.outputs['pols'].is_linked: listPlg = [] for i in range(IntegerX - 1): for j in range(IntegerY - 1): listPlg.append((IntegerX * j + i, IntegerX * j + i + 1, IntegerX * j + i + IntegerX + 1, IntegerX * j + i + IntegerX)) plg = list(listPlg) SvSetSocketAnyType(self, 'pols', [plg]) else: SvSetSocketAnyType(self, 'pols', [[[]]]) def make_vertices(self, delitelx, delitely, stepx, stepy, image_name): lenx = bpy.data.images[image_name].size[0] leny = bpy.data.images[image_name].size[1] if delitelx > lenx: delitelx = lenx if delitely > leny: delitely = leny R, G, B = self.R, self.G, self.B xcoef = lenx // delitelx ycoef = leny // delitely # copy images data, pixels is created on every access with [i], extreme speedup. # http://blender.stackexchange.com/questions/3673/why-is-accessing-image-data-so-slow imag = bpy.data.images[image_name].pixels[:] vertices = [] addition = 0 for y in range(delitely + 1): addition = int(ycoef * y * 4 * lenx) for x in range(delitelx + 1): # каждый пиксель кодируется RGBA, и записан строкой, без разделения на строки и столбцы. middle = (imag[addition] * R + imag[addition + 1] * G + imag[addition + 2] * B) * imag[addition + 3] vertex = [x * stepx[x], y * stepy[y], middle] vertices.append(vertex) addition += int(xcoef * 4) return vertices
class FractureCell(Operator): bl_idname = "object.add_fracture_cell_objects" bl_label = "Cell fracture selected mesh objects" bl_options = {'PRESET'} # ------------------------------------------------------------------------- # Source Options source: EnumProperty( name="Source", items=( ('VERT_OWN', "Own Verts", "Use own vertices"), ('VERT_CHILD', "Child Verts", "Use child object vertices"), ('PARTICLE_OWN', "Own Particles", ("All particle systems of the " "source object")), ('PARTICLE_CHILD', "Child Particles", ("All particle systems of the " "child objects")), ('PENCIL', "Grease Pencil", "This object's grease pencil"), ), options={'ENUM_FLAG'}, default={'PARTICLE_OWN'}, ) source_limit: IntProperty( name="Source Limit", description="Limit the number of input points, 0 for unlimited", min=0, max=5000, default=100, ) source_noise: FloatProperty( name="Noise", description="Randomize point distribution", min=0.0, max=1.0, default=0.0, ) cell_scale: FloatVectorProperty( name="Scale", description="Scale Cell Shape", size=3, min=0.0, max=1.0, default=(1.0, 1.0, 1.0), ) # ------------------------------------------------------------------------- # Recursion recursion: IntProperty( name="Recursion", description="Break shards recursively", min=0, max=5000, default=0, ) recursion_source_limit: IntProperty( name="Source Limit", description= "Limit the number of input points, 0 for unlimited (applies to recursion only)", min=0, max=5000, default=8, ) recursion_clamp: IntProperty( name="Clamp Recursion", description= "Finish recursion when this number of objects is reached (prevents recursing for extended periods of time), zero disables", min=0, max=10000, default=250, ) recursion_chance: FloatProperty( name="Random Factor", description="Likelihood of recursion", min=0.0, max=1.0, default=0.25, ) recursion_chance_select: EnumProperty( name="Recurse Over", items=( ('RANDOM', "Random", ""), ('SIZE_MIN', "Small", "Recursively subdivide smaller objects"), ('SIZE_MAX', "Big", "Recursively subdivide bigger objects"), ('CURSOR_MIN', "Cursor Close", "Recursively subdivide objects closer to the cursor"), ('CURSOR_MAX', "Cursor Far", "Recursively subdivide objects farther from the cursor"), ), default='SIZE_MIN', ) # ------------------------------------------------------------------------- # Mesh Data Options use_smooth_faces: BoolProperty( name="Smooth Faces", default=False, ) use_sharp_edges: BoolProperty( name="Sharp Edges", description="Set sharp edges when disabled", default=True, ) use_sharp_edges_apply: BoolProperty( name="Apply Split Edge", description="Split sharp hard edges", default=True, ) use_data_match: BoolProperty( name="Match Data", description="Match original mesh materials and data layers", default=True, ) use_island_split: BoolProperty( name="Split Islands", description="Split disconnected meshes", default=True, ) margin: FloatProperty( name="Margin", description="Gaps for the fracture (gives more stable physics)", min=0.0, max=1.0, default=0.001, ) material_index: IntProperty( name="Material", description="Material index for interior faces", default=0, ) use_interior_vgroup: BoolProperty( name="Interior VGroup", description="Create a vertex group for interior verts", default=False, ) # ------------------------------------------------------------------------- # Physics Options mass_mode: EnumProperty( name="Mass Mode", items=( ('VOLUME', "Volume", "Objects get part of specified mass based on their volume"), ('UNIFORM', "Uniform", "All objects get the specified mass"), ), default='VOLUME', ) mass: FloatProperty( name="Mass", description="Mass to give created objects", min=0.001, max=1000.0, default=1.0, ) # ------------------------------------------------------------------------- # Object Options use_recenter: BoolProperty( name="Recenter", description="Recalculate the center points after splitting", default=True, ) use_remove_original: BoolProperty( name="Remove Original", description="Removes the parents used to create the shatter", default=True, ) # ------------------------------------------------------------------------- # Scene Options # # .. different from object options in that this controls how the objects # are setup in the scene. use_layer_index: IntProperty( name="Layer Index", description="Layer to add the objects into or 0 for existing", default=0, min=0, max=20, ) use_layer_next: BoolProperty( name="Next Layer", description="At the object into the next layer (layer index overrides)", default=True, ) group_name: StringProperty( name="Group", description="Create objects int a group " "(use existing or create new)", ) # ------------------------------------------------------------------------- # Debug use_debug_points: BoolProperty( name="Debug Points", description="Create mesh data showing the points used for fracture", default=False, ) use_debug_redraw: BoolProperty( name="Show Progress Realtime", description="Redraw as fracture is done", default=True, ) use_debug_bool: BoolProperty( name="Debug Boolean", description="Skip applying the boolean modifier", default=False, ) def execute(self, context): keywords = self.as_keywords() # ignore=("blah",) main(context, **keywords) return {'FINISHED'} def invoke(self, context, event): print(self.recursion_chance_select) wm = context.window_manager return wm.invoke_props_dialog(self, width=600) def draw(self, context): layout = self.layout box = layout.box() col = box.column() col.label(text="Point Source") rowsub = col.row() rowsub.prop(self, "source") rowsub = col.row() rowsub.prop(self, "source_limit") rowsub.prop(self, "source_noise") rowsub = col.row() rowsub.prop(self, "cell_scale") box = layout.box() col = box.column() col.label(text="Recursive Shatter") rowsub = col.row(align=True) rowsub.prop(self, "recursion") rowsub.prop(self, "recursion_source_limit") rowsub.prop(self, "recursion_clamp") rowsub = col.row() rowsub.prop(self, "recursion_chance") rowsub.prop(self, "recursion_chance_select", expand=True) box = layout.box() col = box.column() col.label(text="Mesh Data") rowsub = col.row() rowsub.prop(self, "use_smooth_faces") rowsub.prop(self, "use_sharp_edges") rowsub.prop(self, "use_sharp_edges_apply") rowsub.prop(self, "use_data_match") rowsub = col.row() # on same row for even layout but infact are not all that related rowsub.prop(self, "material_index") rowsub.prop(self, "use_interior_vgroup") # could be own section, control how we subdiv rowsub.prop(self, "margin") rowsub.prop(self, "use_island_split") box = layout.box() col = box.column() col.label(text="Physics") rowsub = col.row(align=True) rowsub.prop(self, "mass_mode") rowsub.prop(self, "mass") box = layout.box() col = box.column() col.label(text="Object") rowsub = col.row(align=True) rowsub.prop(self, "use_recenter") box = layout.box() col = box.column() col.label(text="Scene") rowsub = col.row(align=True) rowsub.prop(self, "use_layer_index") rowsub.prop(self, "use_layer_next") rowsub.prop(self, "group_name") box = layout.box() col = box.column() col.label(text="Debug") rowsub = col.row(align=True) rowsub.prop(self, "use_debug_redraw") rowsub.prop(self, "use_debug_points") rowsub.prop(self, "use_debug_bool")
def register(): Scene.armature = EnumProperty( name='Armature', description='Select the armature which will be used by Cats', items=Common.get_armature_list, update=Common.update_material_list ) Scene.full_body = BoolProperty( name='Apply Full Body Tracking Fix', description="Applies a general fix for Full Body Tracking.\n\n" 'Can potentially reduce the knee bending of every avatar in VRChat.\n' 'You can safely ignore the "Spine length zero" warning in Unity', default=False ) Scene.combine_mats = BoolProperty( name='Combine Same Materials', description="Combines similar materials into one, reducing draw calls.\n\n" 'Your avatar should visibly look the same after this operation.\n' 'This is a very important step for optimizing your avatar.\n' 'If you have problems with this, uncheck this option and tell us!\n', default=True ) Scene.remove_zero_weight = BoolProperty( name='Remove Zero Weight Bones', description="Cleans up the bones hierarchy, deleting all bones that don't directly affect any vertices.\n" 'Uncheck this if bones you want to keep got deleted', default=True ) Scene.keep_end_bones = BoolProperty( name='Keep End Bones', description="Saves end bones from deletion." '\n\nThis can improve skirt movement for dynamic bones, but increases the bone count.' '\nThis can also fix issues with crumbled finger bones in Unity.' '\nMake sure to always uncheck "Add Leaf Bones" when exporting or use the CATS export button', default=False ) Scene.join_meshes = BoolProperty( name='Join Meshes', description='Joins all meshes of this model together.' '\nIt also:' '\n - Applies all transformations' '\n - Repairs broken armature modifiers' '\n - Applies all decimation and mirror modifiers' '\n - Merges UV maps correctly' '\n' '\nINFO: You should always join your meshes', default=True ) Scene.connect_bones = BoolProperty( name='Connect Bones', description="This connects all bones to their child bone if they have exactly one child bone.\n" "This will not change how the bones function in any way, it just improves the aesthetic of the armature", default=True ) Scene.use_google_only = BoolProperty( name='Use Old Translations (not recommended)', description="Ignores the internal dictionary and only uses the Google Translator for shape key translations." "\n" '\nThis will result in slower translation speed and worse translations, but the translations will be like in CATS version 0.9.0 and older.' "\nOnly use this if you have animations which rely on the old translations and you don't want to convert them to the new ones", default=False ) Scene.show_more_options = BoolProperty( name='Show More Options', description="Shows more model options", default=False ) Scene.merge_mode = EnumProperty( name="Merge Mode", description="Mode", items=[ ("ARMATURE", "Merge Armatures", "Here you can merge two armatures together."), ("MESH", "Attach Mesh", "Here you can attach a mesh to an armature.") ] ) Scene.merge_armature_into = EnumProperty( name='Base Armature', description='Select the armature into which the other armature will be merged\n', items=Common.get_armature_list ) Scene.merge_armature = EnumProperty( name='Merge Armature', description='Select the armature which will be merged into the selected armature above\n', items=Common.get_armature_merge_list ) Scene.attach_to_bone = EnumProperty( name='Attach to Bone', description='Select the bone to which the armature will be attached to\n', items=Common.get_bones_merge ) Scene.attach_mesh = EnumProperty( name='Attach Mesh', description='Select the mesh which will be attached to the selected bone in the selected armature\n', items=Common.get_top_meshes ) Scene.merge_same_bones = BoolProperty( name='Merge All Bones', description='Merges all bones together that have the same name instead of only the base bones (Hips, Spine, etc).' '\nYou will have to make sure that all the bones you want to merge have the same name.' '\n' "\nIf this is checked, you won't need to fix the model with CATS beforehand but it is still advised to do so." "\nIf this is unchecked, CATS will only merge the base bones (Hips, Spine, etc)." "\n" "\nThis can have unintended side effects, so check your model afterwards!" "\n", default=False ) Scene.apply_transforms = BoolProperty( name='Apply Transforms', description='Check this if both armatures and meshes are already at their correct positions.' '\nThis will cause them to stay exactly like they are when merging', default=False ) # Decimation Scene.decimation_mode = EnumProperty( name="Decimation Mode", description="Decimation Mode", items=[ ("SAFE", "Safe", 'Decent results - no shape key loss\n' '\n' "This will only decimate meshes with no shape keys.\n" "The results are decent and you won't lose any shape keys.\n" 'Eye Tracking and Lip Syncing will be fully preserved.'), ("HALF", "Half", 'Good results - minimal shape key loss\n' "\n" "This will only decimate meshes with less than 4 shape keys as those are often not used.\n" 'The results are better but you will lose the shape keys in some meshes.\n' 'Eye Tracking and Lip Syncing should still work.'), ("FULL", "Full", 'Best results - full shape key loss\n' '\n' "This will decimate your whole model deleting all shape keys in the process.\n" 'This will give the best results but you will lose the ability to add blinking and Lip Syncing.\n' 'Eye Tracking will still work if you disable Eye Blinking.'), ("CUSTOM", "Custom", 'Custom results - custom shape key loss\n' '\n' "This will let you choose which meshes and shape keys should not be decimated.\n") ], default='HALF' ) Scene.selection_mode = EnumProperty( name="Selection Mode", description="Selection Mode", items=[ ("SHAPES", "Shape Keys", 'Select all the shape keys you want to preserve here.'), ("MESHES", "Meshes", "Select all the meshes you don't want to decimate here.") ] ) Scene.add_shape_key = EnumProperty( name='Shape', description='The shape key you want to keep', items=Common.get_shapekeys_decimation ) Scene.add_mesh = EnumProperty( name='Mesh', description='The mesh you want to leave untouched by the decimation', items=Common.get_meshes_decimation ) Scene.decimate_fingers = BoolProperty( name="Save Fingers", description="Check this if you don't want to decimate your fingers!\n" "Results will be worse but there will be no issues with finger movement.\n" "This is probably only useful if you have a VR headset.\n" "\n" "This operation requires the finger bones to be named specifically:\n" "Thumb(0-2)_(L/R)\n" "IndexFinger(1-3)_(L/R)\n" "MiddleFinger(1-3)_(L/R)\n" "RingFinger(1-3)_(L/R)\n" "LittleFinger(1-3)_(L/R)" ) Scene.decimate_hands = BoolProperty( name="Save Hands", description="Check this if you don't want to decimate your full hands!\n" "Results will be worse but there will be no issues with hand movement.\n" "This is probably only useful if you have a VR headset.\n" "\n" "This operation requires the finger and hand bones to be named specifically:\n" "Left/Right wrist\n" "Thumb(0-2)_(L/R)\n" "IndexFinger(1-3)_(L/R)\n" "MiddleFinger(1-3)_(L/R)\n" "RingFinger(1-3)_(L/R)\n" "LittleFinger(1-3)_(L/R)" ) Scene.max_tris = IntProperty( name='Tris', description="The target amount of tris after decimation", default=70000, min=1, max=200000 ) # Eye Tracking Scene.eye_mode = EnumProperty( name="Eye Mode", description="Mode", items=[ ("CREATION", "Creation", "Here you can create eye tracking."), ("TESTING", "Testing", "Here you can test how eye tracking will look ingame.") ], update=Eyetracking.stop_testing ) Scene.mesh_name_eye = EnumProperty( name='Mesh', description='The mesh with the eyes vertex groups', items=Common.get_meshes ) Scene.head = EnumProperty( name='Head', description='The head bone containing the eye bones', items=Common.get_bones_head ) Scene.eye_left = EnumProperty( name='Left Eye', description='The models left eye bone', items=Common.get_bones_eye_l ) Scene.eye_right = EnumProperty( name='Right Eye', description='The models right eye bone', items=Common.get_bones_eye_r ) Scene.wink_left = EnumProperty( name='Blink Left', description='The shape key containing a blink with the left eye', items=Common.get_shapekeys_eye_blink_l ) Scene.wink_right = EnumProperty( name='Blink Right', description='The shape key containing a blink with the right eye', items=Common.get_shapekeys_eye_blink_r ) Scene.lowerlid_left = EnumProperty( name='Lowerlid Left', description='The shape key containing a slightly raised left lower lid.\n' 'Can be set to "Basis" to disable lower lid movement', items=Common.get_shapekeys_eye_low_l ) Scene.lowerlid_right = EnumProperty( name='Lowerlid Right', description='The shape key containing a slightly raised right lower lid.\n' 'Can be set to "Basis" to disable lower lid movement', items=Common.get_shapekeys_eye_low_r ) Scene.disable_eye_movement = BoolProperty( name='Disable Eye Movement', description='IMPORTANT: Do your decimation first if you check this!\n' '\n' 'Disables eye movement. Useful if you only want blinking.\n' 'This creates eye bones with no movement bound to them.\n' 'You still have to assign "LeftEye" and "RightEye" to the eyes in Unity', subtype='DISTANCE' ) Scene.disable_eye_blinking = BoolProperty( name='Disable Eye Blinking', description='Disables eye blinking. Useful if you only want eye movement.\n' 'This will create the necessary shape keys but leaves them empty', subtype='NONE' ) Scene.eye_distance = FloatProperty( name='Eye Movement Range', description='Higher = more eye movement\n' 'Lower = less eye movement\n' 'Warning: Too little or too much range can glitch the eyes.\n' 'Test your results in the "Eye Testing"-Tab!\n', default=0.8, min=0.0, max=2.0, step=1.0, precision=2, subtype='FACTOR' ) Scene.eye_rotation_x = IntProperty( name='Up - Down', description='Rotate the eye bones on the vertical axis', default=0, min=-19, max=25, step=1, subtype='FACTOR', update=Eyetracking.set_rotation ) Scene.eye_rotation_y = IntProperty( name='Left - Right', description='Rotate the eye bones on the horizontal axis.' '\nThis is from your own point of view', default=0, min=-19, max=19, step=1, subtype='FACTOR', update=Eyetracking.set_rotation ) Scene.iris_height = IntProperty( name='Iris Height', description='Moves the iris away from the eye ball', default=0, min=0, max=100, step=1, subtype='FACTOR' ) Scene.eye_blink_shape = FloatProperty( name='Blink Strength', description='Test the blinking of the eye', default=1.0, min=0.0, max=1.0, step=1.0, precision=2, subtype='FACTOR' ) Scene.eye_lowerlid_shape = FloatProperty( name='Lowerlid Strength', description='Test the lowerlid blinking of the eye', default=1.0, min=0.0, max=1.0, step=1.0, precision=2, subtype='FACTOR' ) # Visemes Scene.mesh_name_viseme = EnumProperty( name='Mesh', description='The mesh with the mouth shape keys', items=Common.get_meshes ) Scene.mouth_a = EnumProperty( name='Viseme AA', description='Shape key containing mouth movement that looks like someone is saying "aa".\nDo not put empty shape keys like "Basis" in here', items=Common.get_shapekeys_mouth_ah, ) Scene.mouth_o = EnumProperty( name='Viseme OH', description='Shape key containing mouth movement that looks like someone is saying "oh".\nDo not put empty shape keys like "Basis" in here', items=Common.get_shapekeys_mouth_oh, ) Scene.mouth_ch = EnumProperty( name='Viseme CH', description='Shape key containing mouth movement that looks like someone is saying "ch". Opened lips and clenched teeth.\nDo not put empty shape keys like "Basis" in here', items=Common.get_shapekeys_mouth_ch, ) Scene.shape_intensity = FloatProperty( name='Shape Key Mix Intensity', description='Controls the strength in the creation of the shape keys. Lower for less mouth movement strength', default=1.0, min=0.0, max=10.0, step=0.1, precision=2, subtype='FACTOR' ) # Bone Parenting Scene.root_bone = EnumProperty( name='To Parent', description='List of bones that look like they could be parented together to a root bone', items=Rootbone.get_parent_root_bones, ) # Optimize Scene.optimize_mode = EnumProperty( name="Optimize Mode", description="Mode", items=[ ("ATLAS", "Atlas", "Allows you to make a texture atlas."), ("MATERIAL", "Material", "Some various options on material manipulation."), ("BONEMERGING", "Bone Merging", "Allows child bones to be merged into their parents."), ] ) # Atlas # Material.add_to_atlas = BoolProperty( # description='Add this material to the atlas', # default=False # ) # Scene.material_list_index = IntProperty( # default=0 # ) # Scene.material_list = CollectionProperty( # type=Atlas.MaterialsGroup # ) # Scene.clear_materials = BoolProperty( # description='Clear materials checkbox', # default=True # ) # Bone Merging Scene.merge_ratio = FloatProperty( name='Merge Ratio', description='Higher = more bones will be merged\n' 'Lower = less bones will be merged\n', default=50, min=1, max=100, step=1, precision=0, subtype='PERCENTAGE' ) Scene.merge_mesh = EnumProperty( name='Mesh', description='The mesh with the bones vertex groups', items=Common.get_meshes ) Scene.merge_bone = EnumProperty( name='To Merge', description='List of bones that look like they could be merged together to reduce overall bones', items=Rootbone.get_parent_root_bones, ) # Settings Scene.embed_textures = BoolProperty( name='Embed Textures on Export', description='Enable this to embed the texture files into the FBX file upon export.' '\nUnity will automatically extract these textures and put them into a separate folder.' '\nThis might not work for everyone and it increases the file size of the exported FBX file', default=False, update=Settings.update_settings ) Scene.use_custom_mmd_tools = BoolProperty( name='Use Custom mmd_tools', description='Enable this to use your own version of mmd_tools. This will disable the internal cats mmd_tools', default=False, update=Settings.update_settings ) Scene.debug_translations = BoolProperty( name='Debug Google Translations', description='Tests the Google Translations and prints the Google response in case of error', default=False )
class BlenderkitDownloadOperator(bpy.types.Operator): """Download and link asset to scene. Only link if asset already available locally.""" bl_idname = "scene.blenderkit_download" bl_label = "BlenderKit Asset Download" bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} asset_type: EnumProperty( name="Type", items=asset_types, description="Type of download", default="MODEL", ) asset_index: IntProperty(name="Asset Index", description='asset index in search results', default=-1) target_object: StringProperty( name="Target Object", description="Material or object target for replacement", default="") material_target_slot: IntProperty( name="Asset Index", description='asset index in search results', default=0) model_location: FloatVectorProperty(name='Asset Location', default=(0, 0, 0)) model_rotation: FloatVectorProperty(name='Asset Rotation', default=(0, 0, 0)) replace: BoolProperty(name='Replace', description='replace selection with the asset', default=False) cast_parent: StringProperty(name="Particles Target Object", description="", default="") # @classmethod # def poll(cls, context): # return bpy.context.window_manager.BlenderKitModelThumbnails is not '' def execute(self, context): s = bpy.context.scene sr = s['search results'] asset_data = sr[self.asset_index].to_dict( ) # TODO CHECK ALL OCCURRENCES OF PASSING BLENDER ID PROPS TO THREADS! au = s.get('assets used') if au == None: s['assets used'] = {} if asset_data['asset_base_id'] in s.get('assets used'): asset_data = s['assets used'][ asset_data['asset_base_id']].to_dict() atype = asset_data['asset_type'] if bpy.context.mode != 'OBJECT' and ( atype == 'model' or atype == 'material' ) and bpy.context.view_layer.objects.active is not None: bpy.ops.object.mode_set(mode='OBJECT') if self.replace: # cleanup first, assign later. obs = utils.get_selected_models() for ob in obs: kwargs = { 'cast_parent': self.cast_parent, 'target_object': ob.name, 'material_target_slot': ob.active_material_index, 'model_location': tuple(ob.matrix_world.translation), 'model_rotation': tuple(ob.matrix_world.to_euler()), 'replace': False, 'parent': ob.parent } utils.delete_hierarchy(ob) start_download(asset_data, **kwargs) else: kwargs = { 'cast_parent': self.cast_parent, 'target_object': self.target_object, 'material_target_slot': self.material_target_slot, 'model_location': tuple(self.model_location), 'model_rotation': tuple(self.model_rotation), 'replace': False } start_download(asset_data, **kwargs) return {'FINISHED'}
class OUT_DebugNode(buildingNode, BuildingTree): '''Building Output''' bl_idname = 'OUT_DebugNode' bl_label = 'Debug' bl_icon = 'NODETREE' bl_width_min = 200 ##\brief An empty function to silence some custom property updates. #\detail The superclass method cannot be used, Properties can't find it. def updateEmpty(self, context): return lastmode = StringProperty(default="", update=updateEmpty) value = StringProperty(default="", update=updateEmpty) stringX = StringProperty(default="", update=updateEmpty) stringY = StringProperty(default="", update=updateEmpty) stringZ = StringProperty(default="", update=updateEmpty) ob_name = StringProperty(default="", update=updateEmpty) mesh_name = StringProperty(default="", update=updateEmpty) v_count = IntProperty(update=updateEmpty) e_count = IntProperty(update=updateEmpty) f_count = IntProperty(update=updateEmpty) ob_pos_X = StringProperty(default="", update=updateEmpty) ob_pos_Y = StringProperty(default="", update=updateEmpty) ob_pos_Z = StringProperty(default="", update=updateEmpty) color = FloatVectorProperty(size=3, update=updateEmpty) ##\brief Checks whether the node needs to be updated. def updateNode(self, context): if not self.lastmode == self.mode_list: self.lastmode = self.mode_list self.updateInputs(self.mode_list) modes = [("Value", "Value", ""), ("Vec3", "Vec3", ""), ("Mesh", "Mesh", ""), ("Selection", "Selection", ""), ("Color", "Color", "")] mode_list = EnumProperty(name="Debug Mode", items=modes, update=updateNode) ##\brief Empty method, to avoid exceptions in the update process. def triggerData(self, context): return ##\brief Custom flooding method, returns the node's pointer. def floodObsolete(self, context): return [self.as_pointer()] ##\brief Re-calculates the node's data. def recalculate(self): if len(self.inputs) > 0: if len(self.inputs[0].links) != 0: if self.mode_list == "Value": floats = self.inputs[0].returnData() string = "" for f in floats: string = string + str(f)[:8] + ", " string = string[:len(string) - 2] self.value = string if len(self.inputs) > 1: if len(self.inputs[1].links) != 0: if self.mode_list == "Vec3": array = self.inputs[1].returnData()[0] self.stringX = str(array[0]) self.stringY = str(array[1]) self.stringZ = str(array[2]) if len(self.inputs) > 2: if len(self.inputs[2].links) != 0: if self.mode_list == "Mesh": obs = self.inputs[2].returnData()[0] self.ob_name = obs[0].name self.mesh_name = obs[0].data.name if len(self.inputs) > 3: if len(self.inputs[3].links) != 0: if self.mode_list == "Selection": sel = self.inputs[3].returnData()[0] self.v_count = len(sel[0]) self.e_count = len(sel[1]) self.f_count = len(sel[2]) if len(self.inputs) > 4: if len(self.inputs[4].links) != 0: if self.mode_list == "Color": self.color = self.inputs[4].returnData()[0] else: self.ob_name = "" self.stringX = "" self.stringY = "" self.stringZ = "" self.value = "" self.v_count = "" self.e_count = "" self.f_count = "" ##\brief Initializes the node. def init(self, context): self.inputs.new("socket_FLOAT", "Value") self.inputs.new("socket_VEC3_F", "Vec3") self.inputs.new("socket_MESH", "Mesh") self.inputs.new("socket_SELECTION", "Selection") self.inputs.new("socket_COL", "Color") self.use_custom_color = True self.color = (1, 1, 1) self.updateNode(context) ##\brief GUI. def draw_buttons(self, context, layout): #Needed for the update operator - this node gives the operator a self-reference so that the operator can backtrack to its caller and call this node's "recalculate()" method layout.context_pointer_set("CALLER", self) layout.separator() row1 = layout.row(align=True) row1.prop(self, "mode_list", "") layout.separator() if self.mode_list == "Value": layout.label(text=self.value) elif self.mode_list == "Vec3": row = layout.row(align=True) col1 = row.column(align=True) col2 = row.column(align=True) rowC11 = col1.row(align=True) rowC12 = col1.row(align=True) rowC13 = col1.row(align=True) rowC21 = col2.row(align=True) rowC22 = col2.row(align=True) rowC23 = col2.row(align=True) rowC11.label(text="X:") rowC12.label(text="Y:") rowC13.label(text="Z:") rowC21.label(text=self.stringX) rowC22.label(text=self.stringY) rowC23.label(text=self.stringZ) elif self.mode_list == "Mesh": rowNO = layout.row(align=False) rowNO.label(text=self.ob_name, icon='OBJECT_DATA') rowNM = layout.row(align=False) rowNM.label(text=self.mesh_name, icon='MESH_DATA') elif self.mode_list == "Color": row1 = layout.row() if len(self.inputs[4].links) > 0: row1.label(text="RGB: " + str(round(self.color[0], 2)) + ", " + str(round(self.color[1], 2)) + ", " + str(round(self.color[2], 2))) else: row1.label(text="RGB: NO INPUT") else: rowVC = layout.row(align=True) rowEC = layout.row(align=True) rowFC = layout.row(align=True) VCcol1 = rowVC.column(align=True) VCcol2 = rowVC.column(align=True) ECcol1 = rowEC.column(align=True) ECcol2 = rowEC.column(align=True) FCcol1 = rowFC.column(align=True) FCcol2 = rowFC.column(align=True) VCcol1.label("Vertices:") ECcol1.label("Edges:") FCcol1.label("Faces:") VCcol2.label(str(self.v_count)) ECcol2.label(str(self.e_count)) FCcol2.label(str(self.f_count)) layout.operator("output.update", text="Update", emboss=True) layout.separator() ##\brief Makes inputs and outputs visible, based on the node's current settings. def updateInputs(self, context): #hide all inputs for input in self.inputs: input.enabled = False #add new inputs, based on the selected mode if self.mode_list == "Value": self.inputs[0].enabled = True elif self.mode_list == "Vec3": self.inputs[1].enabled = True elif self.mode_list == "Mesh": self.inputs[2].enabled = True elif self.mode_list == "Selection": self.inputs[3].enabled = True elif self.mode_list == "Color": self.inputs[4].enabled = True else: return ()
class SvOBJInsolationNode(bpy.types.Node, SverchCustomTreeNode): ''' Insolation by RayCast Object ''' bl_idname = 'SvOBJInsolationNode' bl_label = 'Object ID Insolation' bl_icon = 'OUTLINER_OB_EMPTY' mode: BoolProperty(name='input mode', default=False, update=updateNode) #mode2 = BoolProperty(name='output mode', default=False, update=updateNode) sort_critical: IntProperty(name='sort_critical', default=12, min=1, max=24, update=updateNode) separate: BoolProperty(name='separate the', default=False, update=updateNode) def sv_init(self, context): si, so = self.inputs.new, self.outputs.new #si('StringsSocket', 'Date') si('SvObjectSocket', 'Predator') si('SvObjectSocket', 'Victim') si('VerticesSocket', 'SunRays').use_prop = True #so('SvColorSocket', "Color") so('VerticesSocket', "Centers") #so('VerticesSocket', "HitP") so('StringsSocket', "Hours") # self.inputs[2].prop[2] = -1 # z down # <--- mayybe? def draw_buttons_ext(self, context, layout): row = layout.row(align=True) row.prop(self, "mode", text="In Mode") row.prop(self, "sort_critical", text="Limit") #row.prop(self, "mode2", text="Out Mode") def process(self): o, r, e = self.inputs #dd,o,r,e = self.inputs N, H = self.outputs #S,H,P,N = self.outputs outfin, OutLoc_, obj, rec, sm1, sc = [], [], o.sv_get(), r.sv_get( )[0], self.mode, self.sort_critical #lenor = len(s.sv_get()[0]) lendir = len(e.sv_get()[0]) leno = len(obj) #st, en = match_cross([s.sv_get()[0], e.sv_get()[0]]) # 1,1,1,2,2,2 + 4,5,6,4,5,6 st = [] for i in rec.data.polygons: st.append(i.center[:]) #(np.array(st_).sum(axis=1)/len(i.vertices)).tolist()) #(np.array([[rec.data.vertices[k].co[:] for k in i.vertices]/len(i.vertices) for i in rec.data.polygons]).sum(axis=1)).tolist() if N.is_linked: N.sv_set([st]) lenor = len(st) st, en = match_cross([st, e.sv_get()[0]]) # 1,1,1,2,2,2 + 4,5,6,4,5,6 for OB in obj: if OB.type == 'FONT': NOB = FakeObj(OB) else: NOB = OB if sm1: obm = NOB.matrix_local.inverted() outfin.append([ NOB.ray_cast(obm @ Vector(i), obm @ Vector(i2)) for i, i2 in zip(st, en) ]) else: outfin.append([NOB.ray_cast(i, i2) for i, i2 in zip(st, en)]) if OB.type == 'FONT': del NOB self.debug(outfin) OutS_ = np.array([[i[0] for i in i2] for i2 in outfin]).reshape([leno, lenor, lendir]) def colset(rec, OutS_): OutS_ = 1 - OutS_.sum(axis=2) / lendir OutS = np.array([[[i, i, i] for i in k] for k in OutS_.tolist() ]).reshape([leno, lenor, 3]).tolist() if not 'SvInsol' in rec.data.vertex_colors: rec.data.vertex_colors.new(name='SvInsol') colors = rec.data.vertex_colors['SvInsol'].data for i, pol in enumerate(rec.data.polygons): self.debug(pol.loop_indices, OutS[0][i]) for co in pol.loop_indices: colors[co].color = OutS[0][i] colset(rec, OutS_) def matset(rec): # add new material with nodes ms = rec.material_slots if not 'svmat' in bpy.data.materials: manew = bpy.data.materials.new('svmat') manew.use_nodes = True if not len(ms): # append if no slots rec.data.materials.append(manew) if not ms[-1].material: # assign if no material in slot ms[-1].material = manew trem = ms[-1].material.node_tree matnodes = trem.nodes if not 'Attribute' in matnodes: att = matnodes.new('ShaderNodeAttribute') else: att = matnodes['Attribute'] if not 'Diffuse BSDF' in matnodes: dif = matnodes.new('ShaderNodeBsdfDiffuse') else: dif = matnodes['Diffuse BSDF'] att.attribute_name = 'SvInsol' trem.links.new(dif.inputs[0], att.outputs[0]) matset(rec) if H.is_linked: OutH = [] for k in OutS_.sum(axis=2).tolist(): OutH_ = [] for i in k: li = lendir - i if li < sc + 1: OutH_.append([str(li)]) else: OutH_.append(['']) OutH.append(OutH_) #OutH = [[[str(lendir-i)] for i in k] for k in OutS_.sum(axis=2).tolist()] H.sv_set(OutH) '''if S.is_linked: OutS = np.array([[[i,i,0,1.0] for i in k] for k in OutS_.tolist()]).reshape([leno,lenor,4]).tolist() #OutS = 1-OutS_.sum(axis=2)/lendir #OutS = np.array([[[[i,i,0,1.0] for t in range(4)] for i in k] for k in OutS_.tolist()]).reshape([leno,lenor*4,4]).tolist() #.reshape([leno,lenor*4,4]).tolist() #OutS = [round(1-sum([OutS_[0][k*u] for u in range(lendir)])/lendir, 1) for k in range(lenor)] S.sv_set(OutS)''' ''' # colors works wrong if sm2: if P.is_linked: for i,i2 in zip(obj,outfin): omw = i.matrix_world OutLoc_.append([(omw*i[1])[:] for i in i2]) OutLoc_ = np.array(OutLoc_).reshape([leno,lenor,lendir,3]) OutLoc = OutLoc_[0,:,0] #OutLoc = [[OutLoc_[0][k*u] for u in range(lendir)] for k in range(lenor)] P.sv_set([OutLoc.tolist()]) else: if P.is_linked: OutLoc_ = np.array([[i[1][:] for i in i2] for i2 in outfin]).reshape([leno,lenor,lendir,3]) #OutLoc_ = [[i[1][:] for i in i2] for i2 in outfin] OutLoc = OutLoc_[0,:,0] #OutLoc = [[OutLoc_[0][k*u] for u in range(lendir)] for k in range(lenor)] P.sv_set([OutLoc.tolist()]) ''' ''' # N solved upper easily
class LightMapPack(Operator): '''Follow UVs from active quads along continuous face loops''' bl_idname = "uv.lightmap_pack" bl_label = "Lightmap Pack" bl_options = {'REGISTER', 'UNDO'} PREF_CONTEXT = bpy.props.EnumProperty( name="Selection", items=(("SEL_FACES", "Selected Faces", "Space all UVs evently"), ("ALL_FACES", "All Faces", "Average space UVs edge length of each loop"), ("ALL_OBJECTS", "Selected Mesh Object", "Average space UVs edge length of each loop") ), ) # Image & UVs... PREF_PACK_IN_ONE = BoolProperty( name="Share Tex Space", description=("Objects Share texture space, map all objects " "into 1 uvmap"), default=True, ) PREF_NEW_UVLAYER = BoolProperty( name="New UV Layer", description="Create a new UV layer for every mesh packed", default=False, ) PREF_APPLY_IMAGE = BoolProperty( name="New Image", description=("Assign new images for every mesh (only one if " "shared tex space enabled)"), default=False, ) PREF_IMG_PX_SIZE = IntProperty( name="Image Size", description="Width and Height for the new image", min=64, max=5000, default=512, ) # UV Packing... PREF_BOX_DIV = IntProperty( name="Pack Quality", description="Pre Packing before the complex boxpack", min=1, max=48, default=12, ) PREF_MARGIN_DIV = FloatProperty( name="Margin", description="Size of the margin as a division of the UV", min=0.001, max=1.0, default=0.1, ) def execute(self, context): kwargs = self.as_keywords() PREF_CONTEXT = kwargs.pop("PREF_CONTEXT") if PREF_CONTEXT == 'SEL_FACES': kwargs["PREF_ACT_ONLY"] = True kwargs["PREF_SEL_ONLY"] = True elif PREF_CONTEXT == 'ALL_FACES': kwargs["PREF_ACT_ONLY"] = True kwargs["PREF_SEL_ONLY"] = False elif PREF_CONTEXT == 'ALL_OBJECTS': kwargs["PREF_ACT_ONLY"] = False kwargs["PREF_SEL_ONLY"] = False else: raise Exception("invalid context") kwargs["PREF_MARGIN_DIV"] = int(1.0 / (kwargs["PREF_MARGIN_DIV"] / 100.0)) return unwrap(self, context, **kwargs) def invoke(self, context, event): wm = context.window_manager return wm.invoke_props_dialog(self)