Esempio n. 1
0
class SvTorusNode(bpy.types.Node, SverchCustomTreeNode):
    ''' Torus '''
    bl_idname = 'SvTorusNode'
    bl_label = 'Torus'
    bl_icon = 'MESH_TORUS'

    def update_mode(self, context):
        # switch radii input sockets (R,r) <=> (eR,iR)
        if self.mode == 'EXT_INT':
            self.inputs['R'].prop_name = "torus_eR"
            self.inputs['r'].prop_name = "torus_iR"
        else:
            self.inputs['R'].prop_name = "torus_R"
            self.inputs['r'].prop_name = "torus_r"

        updateNode(self, context)

    # keep the equivalent radii pair in sync (eR,iR) => (R,r)
    def external_internal_radii_changed(self, context):
        if self.mode == "EXT_INT":
            self.torus_R = (self.torus_eR + self.torus_iR) * 0.5
            self.torus_r = (self.torus_eR - self.torus_iR) * 0.5
            updateNode(self, context)

    # keep the equivalent radii pair in sync (R,r) => (eR,iR)
    def major_minor_radii_changed(self, context):
        if self.mode == "MAJOR_MINOR":
            self.torus_eR = self.torus_R + self.torus_r
            self.torus_iR = self.torus_R - self.torus_r
            updateNode(self, context)

    # TORUS DIMENSIONS options
    mode = EnumProperty(
        name="Torus Dimensions",
        items=(("MAJOR_MINOR", "Major/Minor",
                "Use the Major/Minor radii for torus dimensions."),
               ("EXT_INT", "Exterior/Interior",
                "Use the Exterior/Interior radii for torus dimensions.")),
        update=update_mode)

    torus_R = FloatProperty(
        name="Major Radius",
        min=0.00,
        max=100.0,
        default=1.0,
        subtype='DISTANCE',
        unit='LENGTH',
        description=
        "Radius from the torus origin to the center of the cross section",
        update=major_minor_radii_changed)

    torus_r = FloatProperty(name="Minor Radius",
                            min=0.00,
                            max=100.0,
                            default=.25,
                            subtype='DISTANCE',
                            unit='LENGTH',
                            description="Radius of the torus' cross section",
                            update=major_minor_radii_changed)

    torus_iR = FloatProperty(
        name="Interior Radius",
        min=0.00,
        max=100.0,
        default=.75,
        subtype='DISTANCE',
        unit='LENGTH',
        description=
        "Interior radius of the torus (closest to the torus center)",
        update=external_internal_radii_changed)

    torus_eR = FloatProperty(
        name="Exterior Radius",
        min=0.00,
        max=100.0,
        default=1.25,
        subtype='DISTANCE',
        unit='LENGTH',
        description=
        "Exterior radius of the torus (farthest from the torus center)",
        update=external_internal_radii_changed)

    # TORUS RESOLUTION options
    torus_n1 = IntProperty(
        name="Revolution Sections",
        default=32,
        min=3,
        soft_min=3,
        description="Number of sections around the torus center",
        update=updateNode)

    torus_n2 = IntProperty(
        name="Spin Sections",
        default=16,
        min=3,
        soft_min=3,
        description="Number of sections around the torus tube",
        update=updateNode)

    # TORUS Phase Options
    torus_rP = FloatProperty(
        name="Revolution Phase",
        default=0.0,
        description="Phase the revolution sections by this radian amount",
        update=updateNode)

    torus_sP = FloatProperty(
        name="Spin Phase",
        default=0.0,
        description="Phase the spin sections by this radian amount",
        update=updateNode)

    torus_sT = IntProperty(
        name="Spin Twist",
        default=0,
        description="Twist the spin sections by this number of increments",
        update=updateNode)

    # OTHER options
    Separate = BoolProperty(name='Separate',
                            description='Separate UV coords',
                            default=False,
                            update=updateNode)

    def sv_init(self, context):
        self.inputs.new('StringsSocket', "R").prop_name = 'torus_R'
        self.inputs.new('StringsSocket', "r").prop_name = 'torus_r'
        self.inputs.new('StringsSocket', "n1").prop_name = 'torus_n1'
        self.inputs.new('StringsSocket', "n2").prop_name = 'torus_n2'
        self.inputs.new('StringsSocket', "rP").prop_name = 'torus_rP'
        self.inputs.new('StringsSocket', "sP").prop_name = 'torus_sP'
        self.inputs.new('StringsSocket', "sT").prop_name = 'torus_sT'

        self.outputs.new('VerticesSocket', "Vertices")
        self.outputs.new('StringsSocket', "Edges")
        self.outputs.new('StringsSocket', "Polygons")
        self.outputs.new('VerticesSocket', "Normals")

    def draw_buttons(self, context, layout):
        layout.prop(self, "Separate", text="Separate")
        layout.prop(self, 'mode', expand=True)

    def process(self):
        # return if no outputs are connected
        if not any(s.is_linked for s in self.outputs):
            return

        # input values lists (single or multi value)
        input_RR = self.inputs["R"].sv_get()[
            0]  # list of MAJOR or EXTERIOR radii
        input_rr = self.inputs["r"].sv_get()[
            0]  # list of MINOR or INTERIOR radii
        input_n1 = self.inputs["n1"].sv_get()[
            0]  # list of number of MAJOR sections
        input_n2 = self.inputs["n2"].sv_get()[
            0]  # list of number of MINOR sections
        input_rP = self.inputs["rP"].sv_get()[0]  # list of REVOLUTION phases
        input_sP = self.inputs["sP"].sv_get()[0]  # list of SPIN phases
        input_sT = self.inputs["sT"].sv_get()[0]  # list of SPIN twists

        # bound check the list values
        input_RR = list(map(lambda x: max(0, x), input_RR))
        input_rr = list(map(lambda x: max(0, x), input_rr))
        input_n1 = list(map(lambda x: max(3, int(x)), input_n1))
        input_n2 = list(map(lambda x: max(3, int(x)), input_n2))

        # convert input radii values to MAJOR/MINOR, based on selected mode
        if self.mode == 'EXT_INT':
            # convert radii from EXTERIOR/INTERIOR to MAJOR/MINOR
            # (extend radii lists to a matching length before conversion)
            input_RR, input_rr = match_long_repeat([input_RR, input_rr])
            input_R = list(map(lambda x, y: (x + y) * 0.5, input_RR, input_rr))
            input_r = list(map(lambda x, y: (x - y) * 0.5, input_RR, input_rr))
        else:  # values already given as MAJOR/MINOR radii
            input_R = input_RR
            input_r = input_rr

        parameters = match_long_repeat([
            input_R, input_r, input_n1, input_n2, input_rP, input_sP, input_sT
        ])

        if self.outputs['Vertices'].is_linked or self.outputs[
                'Normals'].is_linked:
            vertList = []
            normList = []
            for R, r, n1, n2, rP, sP, sT in zip(*parameters):
                verts, norms = torus_verts(R, r, n1, n2, rP, sP, sT,
                                           self.Separate)
                vertList.append(verts)
                normList.append(norms)
            self.outputs['Vertices'].sv_set(vertList)
            self.outputs['Normals'].sv_set(normList)

        if self.outputs['Edges'].is_linked:
            edgeList = []
            for R, r, n1, n2, rP, sP, sT in zip(*parameters):
                edges = torus_edges(n1, n2, sT)
                edgeList.append(edges)
            self.outputs['Edges'].sv_set(edgeList)

        if self.outputs['Polygons'].is_linked:
            polyList = []
            for R, r, n1, n2, rP, sP, sT in zip(*parameters):
                polys = torus_polygons(n1, n2, sT)
                polyList.append(polys)
            self.outputs['Polygons'].sv_set(polyList)
Esempio n. 2
0
class Solids(bpy.types.Operator):
    """Add one of the (regular) solids (mesh)"""
    bl_idname = "mesh.primitive_solid_add"
    bl_label = "(Regular) solids"
    bl_description = "Add one of the Platonic, Archimedean or Catalan solids"
    bl_options = {'REGISTER', 'UNDO', 'PRESET'}

    source = EnumProperty(items=(("4", "Tetrahedron",
                                  ""), ("6", "Hexahedron",
                                        ""), ("8", "Octahedron",
                                              ""), ("12", "Dodecahedron", ""),
                                 ("20", "Icosahedron", "")),
                          name="Source",
                          description="Starting point of your solid")
    size = FloatProperty(
        name="Size",
        description="Radius of the sphere through the vertices",
        min=0.01,
        soft_min=0.01,
        max=100,
        soft_max=100,
        default=1.0)
    vTrunc = FloatProperty(name="Vertex Truncation",
                           description="Ammount of vertex truncation",
                           min=0.0,
                           soft_min=0.0,
                           max=2.0,
                           soft_max=2.0,
                           default=0.0,
                           precision=3,
                           step=0.5)
    eTrunc = FloatProperty(name="Edge Truncation",
                           description="Ammount of edge truncation",
                           min=0.0,
                           soft_min=0.0,
                           max=1.0,
                           soft_max=1.0,
                           default=0.0,
                           precision=3,
                           step=0.2)
    snub = EnumProperty(items=(("None", "No Snub", ""),
                               ("Left", "Left Snub", ""), ("Right",
                                                           "Right Snub", "")),
                        name="Snub",
                        description="Create the snub version")
    dual = BoolProperty(name="Dual",
                        description="Create the dual of the current solid",
                        default=False)
    keepSize = BoolProperty(
        name="Keep Size",
        description="Keep the whole solid at a constant size",
        default=False)
    preset = EnumProperty(
        items=(("0", "Custom", ""), ("t4", "Truncated Tetrahedron", ""),
               ("r4", "Cuboctahedron", ""), ("t6", "Truncated Cube", ""),
               ("t8", "Truncated Octahedron",
                ""), ("b6", "Rhombicuboctahedron",
                      ""), ("c6", "Truncated Cuboctahedron", ""),
               ("s6", "Snub Cube", ""), ("r12", "Icosidodecahedron", ""),
               ("t12", "Truncated Dodecahedron",
                ""), ("t20", "Truncated Icosahedron",
                      ""), ("b12", "Rhombicosidodecahedron",
                            ""), ("c12", "Truncated Icosidodecahedron",
                                  ""), ("s12", "Snub Dodecahedron", ""),
               ("dt4", "Triakis Tetrahedron",
                ""), ("dr4", "Rhombic Dodecahedron",
                      ""), ("dt6", "Triakis Octahedron",
                            ""), ("dt8", "Tetrakis Hexahedron", ""),
               ("db6", "Deltoidal Icositetrahedron",
                ""), ("dc6", "Disdyakis Dodecahedron",
                      ""), ("ds6", "Pentagonal Icositetrahedron",
                            ""), ("dr12", "Rhombic Triacontahedron",
                                  ""), ("dt12", "Triakis Icosahedron", ""),
               ("dt20", "Pentakis Dodecahedron",
                ""), ("db12", "Deltoidal Hexecontahedron",
                      ""), ("dc12", "Disdyakis Triacontahedron",
                            ""), ("ds12", "Pentagonal Hexecontahedron", "")),
        name="Presets",
        description="Parameters for some hard names")

    # actual preset values
    p = {
        "t4": ["4", 2 / 3, 0, 0, "None"],
        "r4": ["4", 1, 1, 0, "None"],
        "t6": ["6", 2 / 3, 0, 0, "None"],
        "t8": ["8", 2 / 3, 0, 0, "None"],
        "b6": ["6", 1.0938, 1, 0, "None"],
        "c6": ["6", 1.0572, 0.585786, 0, "None"],
        "s6": ["6", 1.0875, 0.704, 0, "Left"],
        "r12": ["12", 1, 0, 0, "None"],
        "t12": ["12", 2 / 3, 0, 0, "None"],
        "t20": ["20", 2 / 3, 0, 0, "None"],
        "b12": ["12", 1.1338, 1, 0, "None"],
        "c12": ["20", 0.921, 0.553, 0, "None"],
        "s12": ["12", 1.1235, 0.68, 0, "Left"],
        "dt4": ["4", 2 / 3, 0, 1, "None"],
        "dr4": ["4", 1, 1, 1, "None"],
        "dt6": ["6", 2 / 3, 0, 1, "None"],
        "dt8": ["8", 2 / 3, 0, 1, "None"],
        "db6": ["6", 1.0938, 1, 1, "None"],
        "dc6": ["6", 1.0572, 0.585786, 1, "None"],
        "ds6": ["6", 1.0875, 0.704, 1, "Left"],
        "dr12": ["12", 1, 0, 1, "None"],
        "dt12": ["12", 2 / 3, 0, 1, "None"],
        "dt20": ["20", 2 / 3, 0, 1, "None"],
        "db12": ["12", 1.1338, 1, 1, "None"],
        "dc12": ["20", 0.921, 0.553, 1, "None"],
        "ds12": ["12", 1.1235, 0.68, 1, "Left"]
    }

    #previous preset, for User-friendly reasons
    previousSetting = ""

    def execute(self, context):
        # turn off undo for better performance (3-5x faster), also makes sure
        #  that mesh ops are undoable and entire script acts as one operator
        bpy.context.user_preferences.edit.use_global_undo = False

        # piece of code to make presets remain until parameters are changed
        if self.preset != "0":
            #if preset, set preset
            if self.previousSetting != self.preset:
                using = self.p[self.preset]
                self.source = using[0]
                self.vTrunc = using[1]
                self.eTrunc = using[2]
                self.dual = using[3]
                self.snub = using[4]
            else:
                using = self.p[self.preset]
                result0 = self.source == using[0]
                result1 = abs(self.vTrunc - using[1]) < 0.004
                result2 = abs(self.eTrunc - using[2]) < 0.0015
                result4 = using[4] == self.snub or (
                    (using[4] == "Left") and self.snub in ["Left", "Right"])
                if (result0 and result1 and result2 and result4):
                    if self.p[self.previousSetting][3] != self.dual:
                        if self.preset[0] == "d":
                            self.preset = self.preset[1:]
                        else:
                            self.preset = "d" + self.preset
                else:
                    self.preset = "0"

        self.previousSetting = self.preset

        # generate mesh
        verts, faces = createSolid(self.source, self.vTrunc, self.eTrunc,
                                   self.dual, self.snub)

        # turn n-gons in quads and tri's
        faces = createPolys(faces)

        # resize to normal size, or if keepSize, make sure all verts are of length 'size'
        if self.keepSize:
            rad = self.size / verts[-1 if self.dual else 0].length
        else:
            rad = self.size
        verts = [i * rad for i in verts]

        # generate object
        # Create new mesh
        mesh = bpy.data.meshes.new("Solid")

        # Make a mesh from a list of verts/edges/faces.
        mesh.from_pydata(verts, [], faces)

        # Update mesh geometry after adding stuff.
        mesh.update()

        object_data_add(context, mesh, operator=None)
        # object generation done

        # turn undo back on
        bpy.context.user_preferences.edit.use_global_undo = True

        return {'FINISHED'}
Esempio n. 3
0
class SvIcosphereNode(bpy.types.Node, SverchCustomTreeNode):
    "IcoSphere primitive"

    bl_idname = 'SvIcosphereNode'
    bl_label = 'IcoSphere'
    bl_icon = 'MESH_ICOSPHERE'

    replacement_nodes = [('SphereNode', None, dict(Faces='Polygons'))]

    def set_subdivisions(self, value):
        # print(value, self.subdivisions_max)
        if value > self.subdivisions_max:
            self['subdivisions'] = self.subdivisions_max
        else:
            self['subdivisions'] = value
        return None

    def get_subdivisions(self):
        return self['subdivisions']

    subdivisions = IntProperty(
        name = "Subdivisions", description = "How many times to recursively subdivide the sphere",
        default=2, min=0,
        set = set_subdivisions, get = get_subdivisions,
        update=updateNode)

    subdivisions_max = IntProperty(
        name = "Max. Subdivisions", description = "Maximum number of subdivisions available",
        default = 5, min=2,
        update=updateNode)
    
    radius = FloatProperty(
        name = "Radius",
        default=1.0, min=0.0,
        update=updateNode)

    def sv_init(self, context):
        self['subdivisions'] = 2
        
        self.inputs.new('StringsSocket', 'Subdivisions').prop_name = 'subdivisions'
        self.inputs.new('StringsSocket', 'Radius').prop_name = 'radius'

        self.outputs.new('VerticesSocket', "Vertices")
        self.outputs.new('StringsSocket',  "Edges")
        self.outputs.new('StringsSocket',  "Faces")

    def draw_buttons_ext(self, context, layout):
        layout.prop(self, "subdivisions_max")

    def process(self):
        # return if no outputs are connected
        if not any(s.is_linked for s in self.outputs):
            return

        subdivisions_s = self.inputs['Subdivisions'].sv_get()[0]
        radius_s = self.inputs['Radius'].sv_get()[0]

        out_verts = []
        out_edges = []
        out_faces = []

        objects = match_long_repeat([subdivisions_s, radius_s])

        for subdivisions, radius in zip(*objects):
            if subdivisions == 0:
                # In this case we just return the icosahedron
                verts, edges, faces = icosahedron(radius)
                out_verts.append(verts)
                out_edges.append(edges)
                out_faces.append(faces)
                continue

            if subdivisions > self.subdivisions_max:
                subdivisions = self.subdivisions_max
            
            bm = bmesh.new()
            bmesh.ops.create_icosphere(bm,
                    subdivisions = subdivisions,
                    diameter = radius)
            verts, edges, faces = pydata_from_bmesh(bm)
            bm.free()

            out_verts.append(verts)
            out_edges.append(edges)
            out_faces.append(faces)

        self.outputs['Vertices'].sv_set(out_verts)
        self.outputs['Edges'].sv_set(out_edges)
        self.outputs['Faces'].sv_set(out_faces)
Esempio n. 4
0
class SvRevolutionSurfaceNode(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: Revolution Surface
    Tooltip: Generate a surface of revolution (similar to Spin / Lathe modifier)
    """
    bl_idname = 'SvExRevolutionSurfaceNode'
    bl_label = 'Revolution Surface'
    bl_icon = 'MOD_SCREW'

    v_min : FloatProperty(
        name = "Angle From",
        description = "Minimal value of V surface parameter",
        default = 0.0,
        update = updateNode)

    v_max : FloatProperty(
        name = "Angle To",
        description = "Minimal value of V surface parameter",
        default = 2*pi,
        update = updateNode)

    origins = [
        ('GLOBAL', "Global origin", "Global origin", 0),
        ('POINT', "Revolution axis", "Rotation axis", 1)
    ]

    origin : EnumProperty(
            name = "Origin",
            items = origins,
            default = 'GLOBAL', # default for pre-existing nodes
            update = updateNode)

    def sv_init(self, context):
        self.inputs.new('SvCurveSocket', "Profile")
        p = self.inputs.new('SvVerticesSocket', "Point")
        p.use_prop = True
        p.default_property = (0.0, 0.0, 0.0)
        p = self.inputs.new('SvVerticesSocket', "Direction")
        p.use_prop = True
        p.default_property = (0.0, 0.0, 1.0)
        self.inputs.new('SvStringsSocket', 'AngleFrom').prop_name = 'v_min'
        self.inputs.new('SvStringsSocket', 'AngleTo').prop_name = 'v_max'
        self.outputs.new('SvSurfaceSocket', "Surface")
        # default for newly created nodes
        self.origin = 'POINT'

    def draw_buttons(self, context, layout):
        layout.prop(self, "origin")

    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        point_s = self.inputs['Point'].sv_get()
        direction_s = self.inputs['Direction'].sv_get()
        curve_s = self.inputs['Profile'].sv_get()
        v_min_s = self.inputs['AngleFrom'].sv_get()
        v_max_s = self.inputs['AngleTo'].sv_get()

        if isinstance(curve_s[0], SvCurve):
            curve_s = [curve_s]
        point_s = ensure_nesting_level(point_s, 3)
        direction_s = ensure_nesting_level(direction_s, 3)
        v_min_s = ensure_nesting_level(v_min_s, 2)
        v_max_s = ensure_nesting_level(v_max_s, 2)

        surface_out = []
        for curves, points, directions, v_mins, v_maxs in zip_long_repeat(curve_s, point_s, direction_s, v_min_s, v_max_s):
            for curve, point, direction, v_min, v_max in zip_long_repeat(curves, points, directions, v_mins, v_maxs):
                origin = self.origin == 'GLOBAL'
                surface = SvRevolutionSurface.build(curve,
                                np.array(point), np.array(direction),
                                v_min, v_max,
                                global_origin=origin)
                surface_out.append(surface)

        self.outputs['Surface'].sv_set(surface_out)
Esempio n. 5
0
class TracerProperties(PropertyGroup):
    """Options for tools"""
    curve_spline = EnumProperty(
        name="Spline",
        items=(("POLY", "Poly", "Use Poly spline type"),
               ("NURBS", "Nurbs", "Use Nurbs spline type"),
               ("BEZIER", "Bezier", "Use Bezier spline type")),
        description="Choose which type of spline to use when curve is created",
        default="BEZIER")
    curve_handle = EnumProperty(
        name="Handle",
        items=(("ALIGNED", "Aligned", "Use Aligned Handle Type"),
               ("AUTOMATIC", "Automatic", "Use Auto Handle Type"),
               ("FREE_ALIGN", "Free Align", "Use Free Handle Type"),
               ("VECTOR", "Vector", "Use Vector Handle Type")),
        description="Choose which type of handle to use when curve is created",
        default="VECTOR")
    curve_resolution = IntProperty(name="Bevel Resolution",
                                   min=1,
                                   max=32,
                                   default=4,
                                   description="Adjust the Bevel resolution")
    curve_depth = FloatProperty(name="Bevel Depth",
                                min=0.0,
                                max=100.0,
                                default=0.1,
                                description="Adjust the Bevel depth")
    curve_u = IntProperty(name="Resolution U",
                          min=0,
                          max=64,
                          default=12,
                          description="Adjust the Surface resolution")
    curve_join = BoolProperty(
        name="Join Curves",
        default=False,
        description="Join all the curves after they have been created")
    curve_smooth = BoolProperty(name="Smooth",
                                default=True,
                                description="Render curve smooth")
    # Option to Duplicate Mesh
    object_duplicate = BoolProperty(
        name="Apply to Copy",
        default=False,
        description="Apply curve to a copy of object")
    # Distort Mesh options
    distort_modscale = IntProperty(
        name="Modulation Scale",
        min=0,
        max=50,
        default=2,
        description=
        "Add a scale to modulate the curve at random points, set to 0 to disable"
    )
    distort_noise = FloatProperty(
        name="Mesh Noise",
        min=0.0,
        max=50.0,
        default=0.00,
        description="Adjust noise added to mesh before adding curve")
    # Particle Options
    particle_step = IntProperty(
        name="Step Size",
        min=1,
        max=50,
        default=5,
        description="Sample one every this number of frames")
    particle_auto = BoolProperty(
        name="Auto Frame Range",
        default=True,
        description="Calculate Frame Range from particles life")
    particle_f_start = IntProperty(name='Start Frame',
                                   min=1,
                                   max=5000,
                                   default=1,
                                   description='Start frame')
    particle_f_end = IntProperty(name="End Frame",
                                 min=1,
                                 max=5000,
                                 default=250,
                                 description="End frame")
    # F-Curve Modifier Properties
    fcnoise_rot = BoolProperty(name="Rotation",
                               default=False,
                               description="Affect Rotation")
    fcnoise_loc = BoolProperty(name="Location",
                               default=True,
                               description="Affect Location")
    fcnoise_scale = BoolProperty(name="Scale",
                                 default=False,
                                 description="Affect Scale")
    fcnoise_amp = IntProperty(name="Amp",
                              min=1,
                              max=500,
                              default=5,
                              description="Adjust the amplitude")
    fcnoise_timescale = FloatProperty(name="Time Scale",
                                      min=1,
                                      max=500,
                                      default=50,
                                      description="Adjust the time scale")
    fcnoise_key = BoolProperty(
        name="Add Keyframe",
        default=True,
        description=
        "Keyframe is needed for tool, this adds a LocRotScale keyframe")
    show_curve_settings = BoolProperty(
        name="Curve Settings",
        default=False,
        description="Change the curve settings for the created curve")
    material_settings = BoolProperty(
        name="Material Settings",
        default=False,
        description="Change the material settings for the created curve")
    particle_settings = BoolProperty(
        name="Particle Settings",
        default=False,
        description="Show the settings for the created curve")
    animation_settings = BoolProperty(
        name="Animation Settings",
        default=False,
        description="Show the settings for the Animations")
    distort_curve = BoolProperty(
        name="Add Distortion",
        default=False,
        description="Set options to distort the final curve")
    connect_noise = BoolProperty(
        name="F-Curve Noise",
        default=False,
        description="Adds F-Curve Noise Modifier to selected objects")
    settings_objectTrace = BoolProperty(
        name="Object Trace Settings",
        default=False,
        description="Trace selected mesh object with a curve")
    settings_objectsConnect = BoolProperty(
        name="Objects Connect Settings",
        default=False,
        description="Connect objects with a curve controlled by hooks")
    settings_objectTrace = BoolProperty(
        name="Object Trace Settings",
        default=False,
        description="Trace selected mesh object with a curve")
    respect_order = BoolProperty(
        name="Order",
        default=False,
        description="Remember order objects were selected")
    settings_particleTrace = BoolProperty(
        name="Particle Trace Settings",
        default=False,
        description="Trace particle path with a  curve")
    settings_particleConnect = BoolProperty(
        name="Particle Connect Settings",
        default=False,
        description=
        "Connect particles with a curves and animated over particle lifetime")
    settings_growCurve = BoolProperty(
        name="Grow Curve Settings",
        default=False,
        description="Animate curve bevel over time by keyframing points radius"
    )
    settings_fcurve = BoolProperty(name="F-Curve Settings",
                                   default=False,
                                   description="F-Curve Settings")
    settings_toggle = BoolProperty(name="Settings",
                                   default=False,
                                   description="Toggle Settings")
    # Animation Options
    anim_auto = BoolProperty(name="Auto Frame Range",
                             default=True,
                             description="Automatically calculate Frame Range")
    anim_f_start = IntProperty(name="Start",
                               min=1,
                               max=2500,
                               default=1,
                               description="Start frame / Hidden object")
    anim_length = IntProperty(name="Duration",
                              min=1,
                              soft_max=1000,
                              max=2500,
                              default=100,
                              description="Animation Length")
    anim_f_fade = IntProperty(
        name="Fade After",
        min=0,
        soft_max=250,
        max=2500,
        default=10,
        description="Fade after this frames / Zero means no fade")
    anim_delay = IntProperty(name="Grow",
                             min=0,
                             max=50,
                             default=5,
                             description="Frames it takes a point to grow")
    anim_tails = BoolProperty(
        name='Tails on endpoints',
        default=True,
        description='Set radius to zero for open splines endpoints')
    anim_keepr = BoolProperty(
        name="Keep Radius",
        default=True,
        description="Try to keep radius data from original curve")
    animate = BoolProperty(name="Animate Result",
                           default=False,
                           description="Animate the final curve objects")
    # Convert to Curve options
    convert_conti = BoolProperty(
        name="Continuous",
        default=True,
        description="Create a continuous curve using verts from mesh")
    convert_everyedge = BoolProperty(
        name="Every Edge",
        default=False,
        description="Create a curve from all verts in a mesh")
    convert_edgetype = EnumProperty(
        name="Edge Type for Curves",
        items=(("CONTI", "Continuous",
                "Create a continuous curve using verts from mesh"),
               ("EDGEALL", "All Edges",
                "Create a curve from every edge in a mesh")),
        description="Choose which type of spline to use when curve is created",
        default="CONTI")
    convert_joinbefore = BoolProperty(
        name="Join objects before convert",
        default=False,
        description=
        "Join all selected mesh to one object before converting to mesh")
    # Mesh Follow Options
    fol_edge_select = BoolProperty(name="Edge",
                                   default=False,
                                   description="Grow from edges")
    fol_vert_select = BoolProperty(name="Vertex",
                                   default=False,
                                   description="Grow from verts")
    fol_face_select = BoolProperty(name="Face",
                                   default=True,
                                   description="Grow from faces")
    fol_mesh_type = EnumProperty(
        name="Mesh type",
        default="VERTS",
        description="Mesh feature to draw cruves from",
        items=(("VERTS", "Verts", "Draw from Verts"),
               ("EDGES", "Edges", "Draw from Edges"), ("FACES", "Faces",
                                                       "Draw from Faces"),
               ("OBJECT", "Object", "Draw from Object origin")))
    fol_start_frame = IntProperty(name="Start Frame",
                                  min=1,
                                  max=2500,
                                  default=1,
                                  description="Start frame for range to trace")
    fol_end_frame = IntProperty(name="End Frame",
                                min=1,
                                max=2500,
                                default=250,
                                description="End frame for range to trace")
    fol_perc_verts = FloatProperty(
        name="Reduce selection by",
        min=0.001,
        max=1.000,
        default=0.5,
        description="percentage of total verts to trace")
    fol_sel_option = EnumProperty(name="Selection type",
                                  description="Choose which objects to follow",
                                  default="RANDOM",
                                  items=(("RANDOM", "Random",
                                          "Follow Random items"),
                                         ("CUSTOM", "Custom Select",
                                          "Follow selected items"),
                                         ("ALL", "All", "Follow all items")))
    trace_mat_color = FloatVectorProperty(name="Material Color",
                                          description="Choose material color",
                                          min=0,
                                          max=1,
                                          default=(0.0, 0.3, 0.6),
                                          subtype="COLOR")
    trace_mat_random = BoolProperty(
        name="Random Color",
        default=False,
        description='Make the material colors random')
    # Material custom Properties properties
    mat_simple_adv_toggle = EnumProperty(
        name="Material Options",
        items=(("SIMPLE", "Simple", "Show Simple Material Options"),
               ("ADVANCED", "Advanced", "Show Advanced Material Options")),
        description="Choose which Material Options to show",
        default="SIMPLE")
    mat_run_color_blender = BoolProperty(
        name="Run Color Blender",
        default=False,
        description="Generate colors from a color scheme")
    mmColors = EnumProperty(
        items=(("RANDOM", "Random", "Use random colors"),
               ("CUSTOM", "Custom", "Use custom colors"),
               ("BW", "Black/White", "Use Black and White"),
               ("BRIGHT", "Bright Colors",
                "Use Bright colors"), ("EARTH", "Earth", "Use Earth colors"),
               ("GREENBLUE", "Green to Blue", "Use Green to Blue colors")),
        description="Choose which type of colors the materials uses",
        default="BRIGHT",
        name="Define a color palette")
    # Custom property for how many keyframes to skip
    mmSkip = IntProperty(name="frames",
                         min=1,
                         max=500,
                         default=20,
                         description="Number of frames between each keyframes")
    # Custom property to enable/disable random order for the
    mmBoolRandom = BoolProperty(
        name="Random Order",
        default=False,
        description="Randomize the order of the colors")
    # Custom Color properties
    mmColor1 = FloatVectorProperty(min=0,
                                   max=1,
                                   default=(0.8, 0.8, 0.8),
                                   description="Custom Color 1",
                                   subtype="COLOR")
    mmColor2 = FloatVectorProperty(min=0,
                                   max=1,
                                   default=(0.8, 0.8, 0.3),
                                   description="Custom Color 2",
                                   subtype="COLOR")
    mmColor3 = FloatVectorProperty(min=0,
                                   max=1,
                                   default=(0.8, 0.5, 0.6),
                                   description="Custom Color 3",
                                   subtype="COLOR")
    mmColor4 = FloatVectorProperty(min=0,
                                   max=1,
                                   default=(0.2, 0.8, 0.289),
                                   description="Custom Color 4",
                                   subtype="COLOR")
    mmColor5 = FloatVectorProperty(min=0,
                                   max=1,
                                   default=(1.0, 0.348, 0.8),
                                   description="Custom Color 5",
                                   subtype="COLOR")
    mmColor6 = FloatVectorProperty(min=0,
                                   max=1,
                                   default=(0.4, 0.67, 0.8),
                                   description="Custom Color 6",
                                   subtype="COLOR")
    mmColor7 = FloatVectorProperty(min=0,
                                   max=1,
                                   default=(0.66, 0.88, 0.8),
                                   description="Custom Color 7",
                                   subtype="COLOR")
    mmColor8 = FloatVectorProperty(min=0,
                                   max=1,
                                   default=(0.8, 0.38, 0.22),
                                   description="Custom Color 8",
                                   subtype="COLOR")
    # BW Color properties
    bwColor1 = FloatVectorProperty(min=0,
                                   max=1,
                                   default=(0.0, 0.0, 0.0),
                                   description="Black/White Color 1",
                                   subtype="COLOR")
    bwColor2 = FloatVectorProperty(min=0,
                                   max=1,
                                   default=(1.0, 1.0, 1.0),
                                   description="Black/White Color 2",
                                   subtype="COLOR")
    # Bright Color properties
    brightColor1 = FloatVectorProperty(min=0,
                                       max=1,
                                       default=(1.0, 0.0, 0.75),
                                       description="Bright Color 1",
                                       subtype="COLOR")
    brightColor2 = FloatVectorProperty(min=0,
                                       max=1,
                                       default=(0.0, 1.0, 1.0),
                                       description="Bright Color 2",
                                       subtype="COLOR")
    brightColor3 = FloatVectorProperty(min=0,
                                       max=1,
                                       default=(0.0, 1.0, 0.0),
                                       description="Bright Color 3",
                                       subtype="COLOR")
    brightColor4 = FloatVectorProperty(min=0,
                                       max=1,
                                       default=(1.0, 1.0, 0.0),
                                       description="Bright Color 4",
                                       subtype="COLOR")
    # Earth Color Properties
    earthColor1 = FloatVectorProperty(min=0,
                                      max=1,
                                      default=(0.068, 0.019, 0.014),
                                      description="Earth Color 1",
                                      subtype="COLOR")
    earthColor2 = FloatVectorProperty(min=0,
                                      max=1,
                                      default=(0.089, 0.060, 0.047),
                                      description="Earth Color 2",
                                      subtype="COLOR")
    earthColor3 = FloatVectorProperty(min=0,
                                      max=1,
                                      default=(0.188, 0.168, 0.066),
                                      description="Earth Color 3",
                                      subtype="COLOR")
    earthColor4 = FloatVectorProperty(min=0,
                                      max=1,
                                      default=(0.445, 0.296, 0.065),
                                      description="Earth Color 4",
                                      subtype="COLOR")
    earthColor5 = FloatVectorProperty(min=0,
                                      max=1,
                                      default=(0.745, 0.332, 0.065),
                                      description="Earth Color 5",
                                      subtype="COLOR")
    # Green to Blue Color properties
    greenblueColor1 = FloatVectorProperty(min=0,
                                          max=1,
                                          default=(0.296, 0.445, 0.074),
                                          description="Green/Blue Color 1",
                                          subtype="COLOR")
    greenblueColor2 = FloatVectorProperty(min=0,
                                          max=1,
                                          default=(0.651, 1.0, 0.223),
                                          description="Green/Blue Color 2",
                                          subtype="COLOR")
    greenblueColor3 = FloatVectorProperty(min=0,
                                          max=1,
                                          default=(0.037, 0.047, 0.084),
                                          description="Green/Blue Color 3",
                                          subtype="COLOR")

    # Toolbar show/hide booleans for tool options
    btrace_menu_items = [
        ('tool_help', "Help", "Pick one of the options below", "INFO", 0),
        ('tool_objectTrace', "Object Trace",
         "Trace selected mesh object with a curve", "FORCE_MAGNETIC", 1),
        ('tool_objectsConnect', "Objects Connect",
         "Connect objects with a curve controlled by hooks",
         "OUTLINER_OB_EMPTY", 2),
        ('tool_meshFollow', "Mesh Follow",
         "Follow selection items on animated mesh object", "DRIVER", 3),
        ('tool_handwrite', "Handwriting",
         "Create and Animate curve using the grease pencil", "BRUSH_DATA", 4),
        ('tool_particleTrace', "Particle Trace",
         "Trace particle path with a  curve", "PARTICLES", 5),
        ('tool_particleConnect', "Particle Connect",
         "Connect particles with a curves and animated over particle lifetime",
         "MOD_PARTICLES", 6),
        ('tool_growCurve', "Grow Curve",
         "Animate curve bevel over time by keyframing points radius",
         "META_BALL", 7),
        ('tool_fcurve', "F-Curve Noise",
         "Add F-Curve noise to selected objects", "RNDCURVE", 8),
        ('tool_colorblender', "Color Blender",
         "Pick the color of the created curves", "COLOR", 9),
    ]
    btrace_toolmenu = EnumProperty(name="Tools",
                                   items=btrace_menu_items,
                                   description="",
                                   default='tool_help')
Esempio n. 6
0
class BAS_OT_mask_extractor_quick(Operator):
    """Extracts the masked area to create a new mesh"""
    bl_idname = "bas.mask_extractor_quick"
    bl_label = "Quick Mask Extractor"
    bl_options = {'REGISTER', 'UNDO'}

    offset : FloatProperty(min = -10.0, max = 10.0, default = 0.1, name="Offset")
    thickness : FloatProperty(min = 0.0, max = 10.0, default = 0.5, name="Thickness")
    smoothPasses : IntProperty(min = 0, max = 30, default = 12, name="Smooth Passes")  
    mode : EnumProperty(name="Extract Mode",
                     items = (("SOLID","Solid",""),
                              ("SINGLE","One Sided",""),
                              ("FLAT","Flat","")),
                     default = "SOLID", description="Mode in how to apply the mesh extraction"
    )
    superSmooth : BoolProperty(default = False, name="Super Smooth")
    editNewMesh : BoolProperty(default = True, name="Edit New Mesh", description="Edit new mesh when extracting it from mask")
    keepMask : BoolProperty(default = False, name="Keep Mask", description="Keep Original Mask")
    postEdition : BoolProperty(default = False, name="Post-Edition", description="Be able to edit some values after extracting, the apply changes.")
    fails : IntProperty (default=0, name="Number of User Fails xD")
    smooth_borders : BoolProperty(default = True, name="Smooth Borders")

    @classmethod
    def poll(cls, context):
        return context.active_object is not None and context.active_object.mode == 'SCULPT'
    
    def draw(self, context): 
        layout = self.layout
        layout.prop(self, "mode", text="Mode")
        layout.prop(self, "thickness", text="Thickness")
        layout.prop(self, "smoothPasses", text="Smooth Passes")
        layout.prop(self, "editNewMesh", text="Edit New Mesh")
        layout.prop(self, "keepMask", text="Keep Mask")
        layout.prop(self, "postEdition", text="Post-Edition")
    
    def execute(self, context):
        props = context.window_manager.bas_extractor
        activeObj = context.active_object # Referencia al objeto activo
        try:
            if activeObj.modifiers["Multires"]:
                ShowMessageBox("The extractor is not compatible with Multires Modifier", "Can't extract mask", 'ERROR')
                return {'FINISHED'}
        except:
            pass
        bpy.ops.paint.mask_flood_fill(mode='INVERT') # INVERTIMOS LA MÁSCARA
        bpy.ops.paint.hide_show(action='HIDE', area='MASKED') # ESCONDEMOS LA PARTE NO ENMASCARADA (LA AHORA ENMASCARADA)
        bpy.ops.object.mode_set(mode='EDIT') # Cambiamos a edit
        bpy.ops.mesh.select_all(action='SELECT') # SELECCIONAR TODOS LOS VERTICES VISIBLES (YA ESTAN POR DEFECTO, CASI TODOS, SINO: CAMBIAR TIPO SELECCION A VERT/EDGE)
        # Duplicado de la malla
        bpy.ops.mesh.duplicate_move(MESH_OT_duplicate={"mode":1}, TRANSFORM_OT_translate={"value":(0, 0, 0), "orient_type":'GLOBAL', "orient_matrix":((0, 0, 0), (0, 0, 0), (0, 0, 0)), "orient_matrix_type":'GLOBAL', "constraint_axis":(False, False, False), "mirror":False, "use_proportional_edit":False, "proportional_edit_falloff":'SMOOTH', "proportional_size":1, "use_proportional_connected":False, "use_proportional_projected":False, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "gpencil_strokes":False, "cursor_transform":False, "texture_space":False, "remove_on_cancel":False, "release_confirm":False, "use_accurate":False})
        try:
            bpy.ops.mesh.separate(type='SELECTED') # Separamos la malla duplicada
        except:
            if self.fails < 2:
                ShowMessageBox("Where is the mask? Please, create a mask before calling this!", "Can't do this!", 'ERROR')
            elif self.fails < 5:
                ShowMessageBox("As I tell you.... YOU CAN'T EXTRACT A MESH FROM A MASK IF YOU DON'T HAVE A MASK!!!!", "Can't do this!", 'ERROR')
            elif self.fails < 10:
                ShowMessageBox("I wonder why natural selection has not acted yet. OK. Create a mask or...", "Can't do this!", 'ERROR')
            elif self.fails == 10:
                ShowMessageBox("...I will format your computer you bad boy/girl!", "Who dare me!", 'ERROR')
            else:
                ShowMessageBox("Where is the mask? Please, create a mask before calling this!", "Can't do this!", 'ERROR')
            self.fails += 1
            bpy.ops.object.mode_set(mode='OBJECT')
            bpy.ops.object.select_all(action='DESELECT')
            activeObj.select_set(state=True)
            context.view_layer.objects.active = activeObj # context.selected_objects[0]
            bpy.ops.object.mode_set(mode='SCULPT') # volvemos a Sculpt
            bpy.ops.paint.hide_show(action='SHOW', area='ALL') # mostrar todo
            bpy.ops.paint.mask_flood_fill(mode='VALUE', value=0) # borrar mascara si no se quiere mantener
            return {'FINISHED'}
        if self.fails > 9:
            ShowMessageBox("You got it!", "ALELUYA!", 'FUND')
        self.fails = 0
        bpy.ops.object.mode_set(mode='OBJECT') # Cambiamos a Object
        n = len(context.selected_objects)
        context.view_layer.objects.active = context.selected_objects[0] if n == 1 else context.selected_objects[1] if n > 1 else activeObj # Seleccionamos la malla extraida

        props.is_created = True

        # TRUCO PARA BORRAR GEOMETRIA SUELTA, BORDES ETC
        bpy.ops.object.mode_set(mode='EDIT') # trick
        bpy.ops.mesh.select_mode(type='VERT', action='TOGGLE')
        bpy.ops.mesh.select_all(action='SELECT')
        bpy.ops.mesh.delete_loose() # borrar vertices sueltos para cada malla
        bpy.ops.object.mode_set(mode='OBJECT') # Cambiamos a Object

        extractedMesh = context.active_object # Guardamos referencia a la malla extraida
        props.extracted = extractedMesh
        bpy.ops.object.select_all(action='DESELECT') # deseleccionar todo # QUITANDO ESTA LINEA PUEDES VER EL OUTLINE DE LA MALLA EXTRAIDA MIENTARS ESCULPES EN LA MALLA BASE, UTIL EN ALGUNOS CASOS
        # Solid mode, doble cara
        if self.mode == 'SOLID':
            bpy.ops.object.mode_set(mode='OBJECT')
            obj = context.active_object
            if self.smoothPasses > 0: # aplicar smooth inicial solo si los pases son mayores a 0
                smooth = obj.modifiers.new(name="Smooth", type='SMOOTH')
                smooth.iterations = self.smoothPasses
                if not self.postEdition:
                    bpy.ops.object.modifier_apply(modifier="Smooth")
            solidi = obj.modifiers.new(name="Solid", type='SOLIDIFY')
            solidi.thickness = self.thickness
            solidi.offset = 1 # add later
            solidi.thickness_clamp = 0
            solidi.use_rim = True
            solidi.use_rim_only = False
            if not self.postEdition:
                bpy.ops.object.modifier_apply(modifier="Solid")
            if self.superSmooth: # post-smooth para suavizarlo mucho más
                co_smooth = obj.modifiers.new(name="Co_Smooth", type='CORRECTIVE_SMOOTH')
                co_smooth.iterations = 30
                co_smooth.smooth_type = 'LENGTH_WEIGHTED'
                co_smooth.use_only_smooth = True
                if not self.postEdition:
                    bpy.ops.object.modifier_apply(modifier="Co_Smooth")
        # Modo Single, sólo una cara
        elif self.mode == 'SINGLE':
            bpy.ops.object.mode_set(mode='OBJECT')
            obj = context.active_object
            if self.smoothPasses > 0 and self.superSmooth==False:
                smooth = obj.modifiers.new(name="Smooth", type='SMOOTH')
                smooth.iterations = self.smoothPasses
                if not self.postEdition:
                    bpy.ops.object.modifier_apply(modifier="Smooth")
            solidi = obj.modifiers.new(name="Solid", type='SOLIDIFY')
            solidi.thickness = self.thickness
            solidi.offset = 1 # add later
            solidi.thickness_clamp = 0
            solidi.use_rim = True
            solidi.use_rim_only = True # only one sided
            if not self.postEdition:
                bpy.ops.object.modifier_apply(modifier="Solid")
            if self.superSmooth: # post-smooth para suavizarlo mucho más
                # Seleccion de borde entre malla extraida y malla original
                bpy.ops.object.mode_set(mode='EDIT')
                bpy.ops.mesh.select_all(action='DESELECT')
                bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT', action='TOGGLE')    
                bpy.ops.mesh.select_non_manifold()
                # Invertir
                bpy.ops.mesh.select_all(action='INVERT')
                # Añadir al vertex group 
                bpy.ops.object.vertex_group_add()
                bpy.ops.object.vertex_group_assign()
                # Aplica smooth
                bpy.ops.object.mode_set(mode='OBJECT')
                smooth = obj.modifiers.new(name="Co_Smooth", type='SMOOTH')
                smooth.factor = 1.5
                smooth.iterations = 30 # valor máximo
                smooth.vertex_group = context.object.vertex_groups.active.name # usa vertex group
                if not self.postEdition:
                    bpy.ops.object.modifier_apply(modifier="Co_Smooth")
                if self.smooth_borders:
                    smooth = obj.modifiers.new(name="Lap_Smooth", type='LAPLACIANSMOOTH')
                    smooth.invert_vertex_group = True
                    smooth.vertex_group = context.object.vertex_groups.active.name
                    smooth.use_normalized = False
                    smooth.use_volume_preserve = False
                    smooth.iterations = 100
                    if not self.postEdition:
                        bpy.ops.object.modifier_apply(modifier="Lap_Smooth")
        
        # Flat mode. Sólo un plano
        elif self.mode == 'FLAT':
            pass
        # Dependiendo si queremos editar la nueva malla o no
        if self.editNewMesh: # Si vamos a la malla a editar, primero tenemos que pasar por la malla de origen para mostrarla al completo
            context.view_layer.objects.active = activeObj # objeto origen como activo
            bpy.ops.object.mode_set(mode='SCULPT') # Cambiamos a Sculpt
            bpy.ops.paint.hide_show(action='SHOW', area='ALL') # mostrar todo
            if self.keepMask == False:
                bpy.ops.paint.mask_flood_fill(mode='VALUE', value=0) # borrar mascara si no se quiere mantener
            else:
                bpy.ops.paint.mask_flood_fill(mode='INVERT') # invertir máscara para dejarla tal cual estaba en un inicio
            bpy.ops.object.mode_set(mode='OBJECT') # volver a object mode
            context.view_layer.objects.active = extractedMesh # malla extraida marcada como activa
            bpy.ops.object.mode_set(mode='SCULPT') # Cambiamos a Sculpt de nuevo
            bpy.ops.paint.mask_flood_fill(mode='VALUE', value=0) # quitar mascara de la malla extraida
        else:
            context.view_layer.objects.active = activeObj # context.selected_objects[0]
            bpy.ops.object.mode_set(mode='SCULPT') # volvemos a Sculpt
            bpy.ops.paint.hide_show(action='SHOW', area='ALL') # mostrar todo
            if self.keepMask == False:
                bpy.ops.paint.mask_flood_fill(mode='VALUE', value=0) # borrar mascara si no se quiere mantener
            else:
                bpy.ops.paint.mask_flood_fill(mode='INVERT') # invertir máscara para dejarla tal cual estaba en un inicio

        if not props.post_edition:
            props.is_created = False
        if props.mode == 'FLAT':
            props.is_created = False

        return {'FINISHED'}
Esempio n. 7
0
class OBJECT_OT_gem_normalize(Operator):
    bl_label = "Normalize Gem"
    bl_description = ("Separate loose, center origin and fix orientation."
                      "\nNOTE: gem ID can be added with Edit Gem tool")
    bl_idname = "object.jewelcraft_gem_normalize"
    bl_options = {"REGISTER", "UNDO"}

    axis_size: FloatProperty(default=1.0, options={"HIDDEN"})
    axis_width: FloatProperty(default=7.0, options={"HIDDEN"})
    axis_in_front: BoolProperty(default=True, options={"HIDDEN"})
    y_align: BoolProperty(options={"HIDDEN"})
    snap_to_edge: BoolProperty(options={"HIDDEN"})

    @classmethod
    def poll(cls, context):
        return context.mode == "OBJECT"

    def modal(self, context, event):
        if event.type in {"ESC", "RET", "SPACE"}:
            bpy.types.SpaceView3D.draw_handler_remove(self.handler, "WINDOW")
            bpy.types.SpaceView3D.draw_handler_remove(self.handler_text,
                                                      "WINDOW")
            context.workspace.status_text_set(None)
            context.region.tag_redraw()

            if event.type == "ESC":
                return {"CANCELLED"}

            return self.execute(context)

        elif event.type in {"LEFT_ARROW", "RIGHT_ARROW"
                            } and event.value == "PRESS":

            if event.ctrl:
                if event.type == "LEFT_ARROW":
                    if self.y_var > 1:
                        self.y_var -= 1
                        self.modal_pass(context)
                else:
                    self.y_var += 1
                    self.modal_pass(context)

            else:
                if event.type == "LEFT_ARROW":
                    if self.rot_var > 1:
                        self.rot_var -= 1
                        self.modal_pass(context)
                else:
                    self.rot_var += 1
                    self.modal_pass(context)

        elif event.type in {"DOWN_ARROW", "UP_ARROW"
                            } and event.value == "PRESS":
            if event.type == "DOWN_ARROW":
                if self.xy_loc > 0:
                    self.xy_loc -= 1
                    self.modal_pass(context)
            else:
                if self.xy_loc < 2:
                    self.xy_loc += 1
                    self.modal_pass(context)

        elif event.type == "Y" and event.value == "PRESS":
            self.y_align = not self.y_align
            self.modal_pass(context)

        elif event.type == "E" and event.value == "PRESS":
            self.snap_to_edge = not self.snap_to_edge
            self.modal_pass(context)

        elif event.type == "X" and event.value == "PRESS":
            self.axis_in_front = not self.axis_in_front
            context.region.tag_redraw()

        elif event.type in {"LEFT_BRACKET", "RIGHT_BRACKET"
                            } and event.value == "PRESS":
            if event.type == "LEFT_BRACKET":
                if self.axis_width > 0.5:
                    self.axis_width -= 0.1
            else:
                self.axis_width += 0.1

            context.region.tag_redraw()

        elif event.type in {"MINUS", "EQUAL"} and event.value == "PRESS":
            if event.type == "MINUS":
                if self.axis_size > 0.1:
                    self.axis_size -= 0.1
            else:
                self.axis_size += 0.1

            context.region.tag_redraw()

        elif (event.type in {
                "MIDDLEMOUSE",
                "WHEELUPMOUSE",
                "WHEELDOWNMOUSE",
                "NUMPAD_1",
                "NUMPAD_2",
                "NUMPAD_3",
                "NUMPAD_4",
                "NUMPAD_5",
                "NUMPAD_6",
                "NUMPAD_7",
                "NUMPAD_8",
                "NUMPAD_9",
                "NUMPAD_MINUS",
                "NUMPAD_PLUS",
        }):
            return {"PASS_THROUGH"}

        return {"RUNNING_MODAL"}

    def execute(self, context):
        import collections
        import operator
        import itertools

        rotvar = self.rot_var - 1
        yvar = self.y_var - 1
        app = self.mats.append

        bpy.ops.mesh.separate(type="LOOSE")
        bpy.ops.object.origin_set(type="ORIGIN_GEOMETRY", center="MEDIAN")

        for ob in context.selected_objects:
            normal_groups = collections.defaultdict(float)

            for poly in ob.data.polygons:
                normal_groups[poly.normal.copy().freeze()] += poly.area

            normals = sorted(normal_groups.items(),
                             key=operator.itemgetter(1),
                             reverse=True)

            try:
                normal = normals[rotvar][0]
            except IndexError:
                normal = normals[0][0]

            mat = normal.to_track_quat("Z", "Y").to_matrix().to_4x4()
            ob.matrix_world @= mat
            ob.data.transform(mat.inverted())

            # Adjust origin
            # ------------------------------

            verts = sorted(ob.data.vertices,
                           key=operator.attrgetter("co.xy.length"),
                           reverse=True)[:8]

            # Z height

            co_z_low = min(verts, key=operator.attrgetter("co.z")).co.z

            if co_z_low != 0.0:
                mat = Matrix.Translation((0.0, 0.0, co_z_low))
                ob.matrix_world @= mat
                ob.data.transform(mat.inverted())

            # Y align

            if self.y_align:

                if self.snap_to_edge:
                    cos = [(
                        (v1.co.xy + v2.co.xy) / 2,
                        (v1.co.xy - v2.co.xy).length,
                    ) for v1, v2 in itertools.combinations(verts, 2)]
                    cos.sort(key=operator.itemgetter(1))

                    try:
                        vec = cos[yvar][0]
                    except IndexError:
                        vec = cos[0][0]

                else:
                    try:
                        vec = verts[yvar].co.xy
                    except IndexError:
                        vec = verts[0].co.xy

                vec.negate()
                vec.resize_3d()

                mat = vec.to_track_quat("Y", "Z").to_matrix().to_4x4()
                ob.matrix_world @= mat
                ob.data.transform(mat.inverted())

            # XY center

            if self.xy_loc != 0:

                if self.xy_loc == 1:
                    context.view_layer.update()

                    xy_min = min((x[0], x[1]) for x in ob.bound_box)
                    xy_max = max((x[0], x[1]) for x in ob.bound_box)

                    x_loc = (xy_min[0] + xy_max[0]) / 2
                    y_loc = (xy_min[1] + xy_max[1]) / 2

                    co_xy = (x_loc, y_loc)

                elif self.xy_loc == 2:
                    co_xy = min(ob.data.vertices,
                                key=operator.attrgetter("co.z")).co.xy

                if co_xy[0] != 0.0 or co_xy[1] != 0.0:
                    mat = Matrix.Translation((*co_xy, 0.0))
                    ob.matrix_world @= mat
                    ob.data.transform(mat.inverted())

            # Display axis

            app(ob.matrix_world.copy())

        return {"FINISHED"}

    def modal_pass(self, context):
        self.mats.clear()
        bpy.ops.object.duplicate()

        self.execute(context)

        # Cleanup

        for ob in context.selected_objects:
            bpy.data.meshes.remove(ob.data)

        # Restore selection

        for ob_name in self.ob_names:
            bpy.data.objects[ob_name].select_set(True)

        context.view_layer.objects.active = bpy.data.objects[ob_name]

    def invoke(self, context, event):
        self.ob_names = []
        unique_meshes = set()

        for ob in context.selected_objects:
            if ob.type != "MESH" or ob.data in unique_meshes:
                ob.select_set(False)
                continue
            self.ob_names.append(ob.name)
            unique_meshes.add(ob.data)

        if not self.ob_names:
            self.report({"ERROR"}, "At least one mesh object must be selected")
            return {"CANCELLED"}

        self.mats = []
        self.rot_var = 1
        self.y_var = 1
        self.xy_loc = 0
        self.xy_loc_enum = (_("Median"), _("Bounds"), _("Culet"))
        self.prefs = context.preferences.addons[var.ADDON_ID].preferences

        self.modal_pass(context)

        # Onscreen

        self.padding_x, self.padding_y = view3d_lib.padding_init(context)

        view3d_lib.options_init(
            self,
            (
                (_("In Front"), "(X)", "axis_in_front", view3d_lib.TYPE_BOOL),
                (_("Size"), "(-/=)", "axis_size", view3d_lib.TYPE_NUM),
                (_("Width"), "([/])", "axis_width", view3d_lib.TYPE_NUM),
                ("", "", None, None),
                (_("Orientation"), "(←/→)", "rot_var", view3d_lib.TYPE_NUM),
                (_("Center"), "(↓/↑)", "xy_loc", view3d_lib.TYPE_ENUM),
                ("", "", None, None),
                (_("Align Y"), "(Y)", "y_align", view3d_lib.TYPE_BOOL),
                ("", "", "y_align", view3d_lib.TYPE_DEP_ON),
                (_("Snap to Edges"), "(E)", "snap_to_edge",
                 view3d_lib.TYPE_BOOL),
                (_("Direction"), "(Ctrl ←/→)", "y_var", view3d_lib.TYPE_NUM),
            ),
        )

        # Draw handlers

        self.handler = bpy.types.SpaceView3D.draw_handler_add(
            view3d_lib.draw_axis,
            (self, context),
            "WINDOW",
            "POST_VIEW",
        )
        self.handler_text = bpy.types.SpaceView3D.draw_handler_add(
            view3d_lib.options_display,
            (self, context, self.padding_x, self.padding_y),
            "WINDOW",
            "POST_PIXEL",
        )

        context.window_manager.modal_handler_add(self)
        context.workspace.status_text_set("ESC: Cancel, ↵/␣: Confirm")

        return {"RUNNING_MODAL"}
Esempio n. 8
0
class Preferences(AddonPreferences):
    """Preferences class: Preferences for this add-on"""

    bl_idname = "uv_magic_uv"

    def update_enable_builtin_menu(self, _):
        if self['enable_builtin_menu']:
            add_builtin_menu()
        else:
            remove_builtin_menu()

    # enable to add features to built-in menu
    enable_builtin_menu = BoolProperty(
        name="Built-in Menu",
        description="Enable built-in menu",
        default=True,
        update=update_enable_builtin_menu
    )

    # for UV Sculpt
    uv_sculpt_brush_color = FloatVectorProperty(
        name="Color",
        description="Color",
        default=(1.0, 0.4, 0.4, 1.0),
        min=0.0,
        max=1.0,
        size=4,
        subtype='COLOR'
    )

    # for Overlapped UV
    uv_inspection_overlapped_color = FloatVectorProperty(
        name="Color",
        description="Color",
        default=(0.0, 0.0, 1.0, 0.3),
        min=0.0,
        max=1.0,
        size=4,
        subtype='COLOR'
    )

    # for Flipped UV
    uv_inspection_flipped_color = FloatVectorProperty(
        name="Color",
        description="Color",
        default=(1.0, 0.0, 0.0, 0.3),
        min=0.0,
        max=1.0,
        size=4,
        subtype='COLOR'
    )

    # for Texture Projection
    texture_projection_canvas_padding = FloatVectorProperty(
        name="Canvas Padding",
        description="Canvas Padding",
        size=2,
        max=50.0,
        min=0.0,
        default=(20.0, 20.0))

    # for UV Bounding Box
    uv_bounding_box_cp_size = FloatProperty(
        name="Size",
        description="Control Point Size",
        default=6.0,
        min=3.0,
        max=100.0)
    uv_bounding_box_cp_react_size = FloatProperty(
        name="React Size",
        description="Size event fired",
        default=10.0,
        min=3.0,
        max=100.0)

    # for UI
    category = EnumProperty(
        name="Category",
        description="Preferences Category",
        items=[
            ('INFO', "Information", "Information about this add-on"),
            ('CONFIG', "Configuration", "Configuration about this add-on"),
            ('UPDATE', "Update", "Update this add-on"),
        ],
        default='INFO'
    )
    info_desc_expanded = BoolProperty(
        name="Description",
        description="Description",
        default=False
    )
    info_loc_expanded = BoolProperty(
        name="Location",
        description="Location",
        default=False
    )
    conf_uv_sculpt_expanded = BoolProperty(
        name="UV Sculpt",
        description="UV Sculpt",
        default=False
    )
    conf_uv_inspection_expanded = BoolProperty(
        name="UV Inspection",
        description="UV Inspection",
        default=False
    )
    conf_texture_projection_expanded = BoolProperty(
        name="Texture Projection",
        description="Texture Projection",
        default=False
    )
    conf_uv_bounding_box_expanded = BoolProperty(
        name="UV Bounding Box",
        description="UV Bounding Box",
        default=False
    )

    # for add-on updater
    auto_check_update = BoolProperty(
        name="Auto-check for Update",
        description="If enabled, auto-check for updates using an interval",
        default=False
    )
    updater_intrval_months = IntProperty(
        name='Months',
        description="Number of months between checking for updates",
        default=0,
        min=0
    )
    updater_intrval_days = IntProperty(
        name='Days',
        description="Number of days between checking for updates",
        default=7,
        min=0
    )
    updater_intrval_hours = IntProperty(
        name='Hours',
        description="Number of hours between checking for updates",
        default=0,
        min=0,
        max=23
    )
    updater_intrval_minutes = IntProperty(
        name='Minutes',
        description="Number of minutes between checking for updates",
        default=0,
        min=0,
        max=59
    )

    def draw(self, context):
        layout = self.layout

        layout.row().prop(self, "category", expand=True)

        if self.category == 'INFO':
            layout.prop(
                self, "info_desc_expanded", text="Description",
                icon='DISCLOSURE_TRI_DOWN' if self.info_desc_expanded
                else 'DISCLOSURE_TRI_RIGHT')
            if self.info_desc_expanded:
                column = layout.column(align=True)
                column.label("Magic UV is composed of many UV editing" +
                             " features.")
                column.label("See tutorial page if you are new to this" +
                             " add-on.")
                column.label("https://github.com/nutti/Magic-UV/wiki/Tutorial")

            layout.prop(
                self, "info_loc_expanded", text="Location",
                icon='DISCLOSURE_TRI_DOWN' if self.info_loc_expanded
                else 'DISCLOSURE_TRI_RIGHT')
            if self.info_loc_expanded:
                row = layout.row(align=True)
                sp = row.split(percentage=0.5)
                sp.label("3D View > Tool shelf > Copy/Paste UV (Object mode)")
                sp = sp.split(percentage=1.0)
                col = sp.column(align=True)
                col.label("Copy/Paste UV (Among objects)")

                row = layout.row(align=True)
                sp = row.split(percentage=0.5)
                sp.label("3D View > Tool shelf > Copy/Paste UV (Edit mode)")
                sp = sp.split(percentage=1.0)
                col = sp.column(align=True)
                col.label("Copy/Paste UV (Among faces in 3D View)")
                col.label("Transfer UV")

                row = layout.row(align=True)
                sp = row.split(percentage=0.5)
                sp.label("3D View > Tool shelf > UV Manipulation (Edit mode)")
                sp = sp.split(percentage=1.0)
                col = sp.column(align=True)
                col.label("Flip/Rotate UV")
                col.label("Mirror UV")
                col.label("Move UV")
                col.label("World Scale UV")
                col.label("Preserve UV Aspect")
                col.label("Texture Lock")
                col.label("Texture Wrap")
                col.label("UV Sculpt")

                row = layout.row(align=True)
                sp = row.split(percentage=0.5)
                sp.label("3D View > Tool shelf > UV Manipulation (Edit mode)")
                sp = sp.split(percentage=1.0)
                col = sp.column(align=True)
                col.label("Unwrap Constraint")
                col.label("Texture Projection")
                col.label("UVW")

                row = layout.row(align=True)
                sp = row.split(percentage=0.5)
                sp.label("UV/Image Editor > Tool shelf > Copy/Paste UV")
                sp = sp.split(percentage=1.0)
                col = sp.column(align=True)
                col.label("Copy/Paste UV (Among faces in UV/Image Editor)")

                row = layout.row(align=True)
                sp = row.split(percentage=0.5)
                sp.label("UV/Image Editor > Tool shelf > UV Manipulation")
                sp = sp.split(percentage=1.0)
                col = sp.column(align=True)
                col.label("Align UV")
                col.label("Smooth UV")
                col.label("Select UV")
                col.label("Pack UV (Extension)")

                row = layout.row(align=True)
                sp = row.split(percentage=0.5)
                sp.label("UV/Image Editor > Tool shelf > Editor Enhancement")
                sp = sp.split(percentage=1.0)
                col = sp.column(align=True)
                col.label("Align UV Cursor")
                col.label("UV Cursor Location")
                col.label("UV Bounding Box")
                col.label("UV Inspection")

        elif self.category == 'CONFIG':
            layout.prop(self, "enable_builtin_menu", text="Built-in Menu")

            layout.separator()

            layout.prop(
                self, "conf_uv_sculpt_expanded", text="UV Sculpt",
                icon='DISCLOSURE_TRI_DOWN' if self.conf_uv_sculpt_expanded
                else 'DISCLOSURE_TRI_RIGHT')
            if self.conf_uv_sculpt_expanded:
                sp = layout.split(percentage=0.05)
                col = sp.column()  # spacer
                sp = sp.split(percentage=0.3)
                col = sp.column()
                col.label("Brush Color:")
                col.prop(self, "uv_sculpt_brush_color", text="")
                layout.separator()

            layout.prop(
                self, "conf_uv_inspection_expanded", text="UV Inspection",
                icon='DISCLOSURE_TRI_DOWN' if self.conf_uv_inspection_expanded
                else 'DISCLOSURE_TRI_RIGHT')
            if self.conf_uv_inspection_expanded:
                sp = layout.split(percentage=0.05)
                col = sp.column()  # spacer
                sp = sp.split(percentage=0.3)
                col = sp.column()
                col.label("Overlapped UV Color:")
                col.prop(self, "uv_inspection_overlapped_color", text="")
                sp = sp.split(percentage=0.45)
                col = sp.column()
                col.label("Flipped UV Color:")
                col.prop(self, "uv_inspection_flipped_color", text="")
                layout.separator()

            layout.prop(
                self, "conf_texture_projection_expanded",
                text="Texture Projection",
                icon='DISCLOSURE_TRI_DOWN'
                if self.conf_texture_projection_expanded
                else 'DISCLOSURE_TRI_RIGHT')
            if self.conf_texture_projection_expanded:
                sp = layout.split(percentage=0.05)
                col = sp.column()       # spacer
                sp = sp.split(percentage=0.3)
                col = sp.column()
                col.prop(self, "texture_projection_canvas_padding")
                layout.separator()

            layout.prop(
                self, "conf_uv_bounding_box_expanded", text="UV Bounding Box",
                icon='DISCLOSURE_TRI_DOWN'
                if self.conf_uv_bounding_box_expanded
                else 'DISCLOSURE_TRI_RIGHT')
            if self.conf_uv_bounding_box_expanded:
                sp = layout.split(percentage=0.05)
                col = sp.column()       # spacer
                sp = sp.split(percentage=0.3)
                col = sp.column()
                col.label("Control Point:")
                col.prop(self, "uv_bounding_box_cp_size")
                col.prop(self, "uv_bounding_box_cp_react_size")
                layout.separator()

        elif self.category == 'UPDATE':
            addon_updater_ops.update_settings_ui(self, context)
class Curveaceous_galore(Operator):
    """Add many types of curves"""
    bl_idname = "mesh.curveaceous_galore"
    bl_label = "2D Profiles"
    bl_options = {'REGISTER', 'UNDO', 'PRESET'}

    # align_matrix for the invoke
    align_matrix = None

    # general properties
    ProfileTypes = [('Profile', 'Profile', 'Profile'),
                    ('Arrow', 'Arrow', 'Arrow'),
                    ('Rectangle', 'Rectangle', 'Rectangle'),
                    ('Flower', 'Flower', 'Flower'), ('Star', 'Star', 'Star'),
                    ('Arc', 'Arc', 'Arc'),
                    ('Cogwheel', 'Cogwheel', 'Cogwheel'),
                    ('Nsided', 'Nsided', 'Nsided'),
                    ('Splat', 'Splat', 'Splat'),
                    ('Cycloid', 'Cycloid', 'Cycloid'),
                    ('Helix', 'Helix (3D)', 'Helix'),
                    ('Noise', 'Noise (3D)', 'Noise')]
    ProfileType = EnumProperty(name="Type",
                               description="Form of Curve to create",
                               items=ProfileTypes)
    SplineTypes = [('POLY', 'Poly', 'POLY'), ('NURBS', 'Nurbs', 'NURBS'),
                   ('BEZIER', 'Bezier', 'BEZIER')]
    outputType = EnumProperty(name="Output splines",
                              description="Type of splines to output",
                              items=SplineTypes)

    # Curve Options
    shapeItems = [('2D', '2D', '2D'), ('3D', '3D', '3D')]
    shape = EnumProperty(name="2D / 3D",
                         items=shapeItems,
                         description="2D or 3D Curve")
    use_cyclic_u = BoolProperty(name="Cyclic",
                                default=True,
                                description="make curve closed")
    endp_u = BoolProperty(name="use_endpoint_u",
                          default=True,
                          description="stretch to endpoints")
    order_u = IntProperty(name="order_u",
                          default=4,
                          min=2,
                          soft_min=2,
                          max=6,
                          soft_max=6,
                          description="Order of nurbs spline")
    bezHandles = [('VECTOR', 'Vector', 'VECTOR'),
                  ('AUTOMATIC', 'Auto', 'AUTOMATIC')]
    handleType = EnumProperty(name="Handle type",
                              default='AUTOMATIC',
                              description="bezier handles type",
                              items=bezHandles)

    # ProfileCurve properties
    ProfileCurveType = IntProperty(name="Type",
                                   min=1,
                                   soft_min=1,
                                   max=5,
                                   soft_max=5,
                                   default=1,
                                   description="Type of ProfileCurve")
    ProfileCurvevar1 = FloatProperty(name="var_1",
                                     default=0.25,
                                     description="var1 of ProfileCurve")
    ProfileCurvevar2 = FloatProperty(name="var_2",
                                     default=0.25,
                                     description="var2 of ProfileCurve")

    # Arrow, Rectangle, MiscCurve properties
    MiscCurveType = IntProperty(name="Type",
                                min=0,
                                soft_min=0,
                                max=3,
                                soft_max=3,
                                default=0,
                                description="Type of Curve")
    MiscCurvevar1 = FloatProperty(name="var_1",
                                  default=1.0,
                                  description="var1 of Curve")
    MiscCurvevar2 = FloatProperty(name="var_2",
                                  default=0.5,
                                  description="var2 of Curve")
    MiscCurvevar3 = FloatProperty(name="var_3",
                                  default=0.1,
                                  min=0,
                                  soft_min=0,
                                  description="var3 of Curve")

    # Common properties
    innerRadius = FloatProperty(name="Inner radius",
                                default=0.5,
                                min=0,
                                soft_min=0,
                                description="Inner radius")
    middleRadius = FloatProperty(name="Middle radius",
                                 default=0.95,
                                 min=0,
                                 soft_min=0,
                                 description="Middle radius")
    outerRadius = FloatProperty(name="Outer radius",
                                default=1.0,
                                min=0,
                                soft_min=0,
                                description="Outer radius")

    # Flower properties
    petals = IntProperty(name="Petals",
                         default=8,
                         min=2,
                         soft_min=2,
                         description="Number of petals")
    petalWidth = FloatProperty(name="Petal width",
                               default=2.0,
                               min=0.01,
                               soft_min=0.01,
                               description="Petal width")

    # Star properties
    starPoints = IntProperty(name="Star points",
                             default=8,
                             min=2,
                             soft_min=2,
                             description="Number of star points")
    starTwist = FloatProperty(name="Twist", default=0.0, description="Twist")

    # Arc properties
    arcSides = IntProperty(name="Arc sides",
                           default=6,
                           min=1,
                           soft_min=1,
                           description="Sides of arc")
    startAngle = FloatProperty(name="Start angle",
                               default=0.0,
                               description="Start angle")
    endAngle = FloatProperty(name="End angle",
                             default=90.0,
                             description="End angle")
    arcType = IntProperty(name="Arc type",
                          default=3,
                          min=1,
                          soft_min=1,
                          max=3,
                          soft_max=3,
                          description="Sides of arc")

    # Cogwheel properties
    teeth = IntProperty(name="Teeth",
                        default=8,
                        min=2,
                        soft_min=2,
                        description="number of teeth")
    bevel = FloatProperty(name="Bevel",
                          default=0.5,
                          min=0,
                          soft_min=0,
                          max=1,
                          soft_max=1,
                          description="Bevel")

    # Nsided property
    Nsides = IntProperty(name="Sides",
                         default=8,
                         min=3,
                         soft_min=3,
                         description="Number of sides")

    # Splat properties
    splatSides = IntProperty(name="Splat sides",
                             default=24,
                             min=3,
                             soft_min=3,
                             description="Splat sides")
    splatScale = FloatProperty(name="Splat scale",
                               default=1.0,
                               min=0.0001,
                               soft_min=0.0001,
                               description="Splat scale")
    seed = IntProperty(name="Seed",
                       default=0,
                       min=0,
                       soft_min=0,
                       description="Seed")
    basis = IntProperty(name="Basis",
                        default=0,
                        min=0,
                        soft_min=0,
                        max=14,
                        soft_max=14,
                        description="Basis")

    # Helix properties
    helixPoints = IntProperty(name="resolution",
                              default=100,
                              min=3,
                              soft_min=3,
                              description="resolution")
    helixHeight = FloatProperty(name="Height",
                                default=2.0,
                                min=0,
                                soft_min=0,
                                description="Helix height")
    helixStart = FloatProperty(name="Start angle",
                               default=0.0,
                               description="Helix start angle")
    helixEnd = FloatProperty(name="Endangle",
                             default=360.0,
                             description="Helix end angle")
    helixWidth = FloatProperty(name="Width",
                               default=1.0,
                               description="Helix width")
    helix_a = FloatProperty(name="var_1",
                            default=0.0,
                            description="Helix var1")
    helix_b = FloatProperty(name="var_2",
                            default=0.0,
                            description="Helix var2")

    # Cycloid properties
    cycloPoints = IntProperty(name="Resolution",
                              default=100,
                              min=3,
                              soft_min=3,
                              description="Resolution")
    cycloType = IntProperty(
        name="Type",
        default=1,
        min=0,
        soft_min=0,
        max=2,
        soft_max=2,
        description=
        "Type: Cycloid , Hypocycloid / Hypotrochoid , Epicycloid / Epitrochoid"
    )
    cyclo_a = FloatProperty(name="R",
                            default=4.0,
                            min=0.01,
                            soft_min=0.01,
                            description="Cycloid: R radius a")
    cyclo_b = FloatProperty(name="r",
                            default=1.0,
                            min=0.01,
                            soft_min=0.01,
                            description="Cycloid: r radius b")
    cyclo_d = FloatProperty(name="d",
                            default=1.0,
                            description="Cycloid: d distance")

    # Noise properties
    noiseType = IntProperty(
        name="Type",
        default=0,
        min=0,
        soft_min=0,
        max=2,
        soft_max=2,
        description="Noise curve type: Linear, Circular or Knot")
    noisePoints = IntProperty(name="Resolution",
                              default=100,
                              min=3,
                              soft_min=3,
                              description="Resolution")
    noiseLength = FloatProperty(name="Length",
                                default=2.0,
                                min=0.01,
                                soft_min=0.01,
                                description="Curve Length")
    noiseSize = FloatProperty(name="Noise size",
                              default=0.25,
                              min=0.0001,
                              soft_min=0.0001,
                              description="Noise size")
    noiseScaleX = FloatProperty(name="Noise x",
                                default=0.5,
                                min=0.0001,
                                soft_min=0.0001,
                                description="Noise x")
    noiseScaleY = FloatProperty(name="Noise y",
                                default=0.5,
                                min=0.0001,
                                soft_min=0.0001,
                                description="Noise y")
    noiseScaleZ = FloatProperty(name="Noise z",
                                default=0.5,
                                min=0.0001,
                                soft_min=0.0001,
                                description="Noise z")
    noiseTaper = FloatProperty(name="Noise taper",
                               default=0.0,
                               min=0.0001,
                               soft_min=0.0001,
                               max=1.0,
                               soft_max=1.0,
                               description="Noise taper")
    noiseOctaves = IntProperty(name="Octaves",
                               default=2,
                               min=1,
                               soft_min=1,
                               max=16,
                               soft_max=16,
                               description="Basis")
    noiseBasis = IntProperty(name="Basis",
                             default=0,
                             min=0,
                             soft_min=0,
                             max=9,
                             soft_max=9,
                             description="Basis")
    noiseSeed = IntProperty(name="Seed",
                            default=1,
                            min=0,
                            soft_min=0,
                            description="Random Seed")

    ##### DRAW #####
    def draw(self, context):
        layout = self.layout

        # general options
        col = layout.column()
        col.prop(self, 'ProfileType')
        col.label(text=self.ProfileType + " Options:")

        # options per ProfileType
        box = layout.box()
        if self.ProfileType == 'Profile':
            box.prop(self, 'ProfileCurveType')
            box.prop(self, 'ProfileCurvevar1')
            box.prop(self, 'ProfileCurvevar2')

        elif self.ProfileType == 'Arrow':
            box.prop(self, 'MiscCurveType')
            box.prop(self, 'MiscCurvevar1', text='Height')
            box.prop(self, 'MiscCurvevar2', text='Width')

        elif self.ProfileType == 'Rectangle':
            box.prop(self, 'MiscCurveType')
            box.prop(self, 'MiscCurvevar1', text='Width')
            box.prop(self, 'MiscCurvevar2', text='Height')
            if self.MiscCurveType == 2:
                box.prop(self, 'MiscCurvevar3', text='Corners')

        elif self.ProfileType == 'Flower':
            box.prop(self, 'petals')
            box.prop(self, 'petalWidth')
            box.prop(self, 'innerRadius')
            box.prop(self, 'outerRadius')

        elif self.ProfileType == 'Star':
            box.prop(self, 'starPoints')
            box.prop(self, 'starTwist')
            box.prop(self, 'innerRadius')
            box.prop(self, 'outerRadius')

        elif self.ProfileType == 'Arc':
            box.prop(self, 'arcSides')
            box.prop(self, 'arcType')
            box.prop(self, 'startAngle')
            box.prop(self, 'endAngle')
            box.prop(self, 'innerRadius')
            box.prop(self, 'outerRadius')

        elif self.ProfileType == 'Cogwheel':
            box.prop(self, 'teeth')
            box.prop(self, 'bevel')
            box.prop(self, 'innerRadius')
            box.prop(self, 'middleRadius')
            box.prop(self, 'outerRadius')

        elif self.ProfileType == 'Nsided':
            box.prop(self, 'Nsides')
            box.prop(self, 'outerRadius')

        elif self.ProfileType == 'Splat':
            box.prop(self, 'splatSides')
            box.prop(self, 'outerRadius')
            box.prop(self, 'splatScale')
            box.prop(self, 'seed')
            box.prop(self, 'basis')

        elif self.ProfileType == 'Cycloid':
            box.prop(self, 'cycloPoints')
            box.prop(self, 'cycloType')
            box.prop(self, 'cyclo_a')
            box.prop(self, 'cyclo_b')
            if self.cycloType != 0:
                box.prop(self, 'cyclo_d')

        elif self.ProfileType == 'Helix':
            box.prop(self, 'helixPoints')
            box.prop(self, 'helixHeight')
            box.prop(self, 'helixWidth')
            box.prop(self, 'helixStart')
            box.prop(self, 'helixEnd')
            box.prop(self, 'helix_a')
            box.prop(self, 'helix_b')

        elif self.ProfileType == 'Noise':
            box.prop(self, 'noiseType')
            box.prop(self, 'noisePoints')
            box.prop(self, 'noiseLength')
            if self.noiseType in [0, 1]:
                box.prop(self, 'noiseSize')
                box.prop(self, 'noiseScaleX')
                box.prop(self, 'noiseScaleY')
            box.prop(self, 'noiseScaleZ')
            if self.noiseType == 0:
                box.prop(self, 'noiseTaper')
            box.prop(self, 'noiseOctaves')
            box.prop(self, 'noiseBasis')
            box.prop(self, 'noiseSeed')

        col = layout.column()
        col.label(text="Output Curve Type:")
        col.row().prop(self, 'outputType', expand=True)

        # output options
        if self.outputType == 'NURBS':
            col.prop(self, 'order_u')
        elif self.outputType == 'BEZIER':
            col.row().prop(self, 'handleType', expand=True)

    ##### POLL #####
    @classmethod
    def poll(cls, context):
        return context.scene is not None

    ##### EXECUTE #####
    def execute(self, context):
        # turn off undo
        undo = context.user_preferences.edit.use_global_undo
        context.user_preferences.edit.use_global_undo = False

        # deal with 2D - 3D curve differences
        if self.ProfileType in ['Helix', 'Cycloid', 'Noise']:
            self.shape = '3D'
        else:
            self.shape = '2D'

        if self.ProfileType in ['Helix', 'Noise', 'Cycloid']:
            self.use_cyclic_u = False
            if self.ProfileType in ['Cycloid']:
                if self.cycloType == 0:
                    self.use_cyclic_u = False
                else:
                    self.use_cyclic_u = True
        else:
            if self.ProfileType == 'Arc' and self.arcType == 1:
                self.use_cyclic_u = False
            else:
                self.use_cyclic_u = True

        # main function
        main(context, self, self.align_matrix or Matrix())

        # restore pre operator undo state
        context.user_preferences.edit.use_global_undo = undo

        return {'FINISHED'}

    ##### INVOKE #####
    def invoke(self, context, event):
        # store creation_matrix
        self.align_matrix = align_matrix(context)
        self.execute(context)

        return {'FINISHED'}
Esempio n. 10
0
class SvViewer2D(bpy.types.Node, SverchCustomTreeNode):
    '''Curved interpolation'''
    bl_idname = 'SvViewer2D'
    bl_label = 'Viewer 2D'
    bl_icon = 'HIDE_OFF'
    sv_icon = 'SV_EASING'

    modes = [
        ('Number', 'Number', 'Visualize number list', '', 1),
        ('Path', 'Path', 'Visualize vertices sequence', '', 2),
        ('Curve', 'Curve', 'Visualize curve', '', 3),
        ('Mesh', 'Mesh', 'Visualize mesh data', '', 4),

    ]
    plane = [
        ('XY', 'XY', 'Project on XY plane', '', 1),
        ('XZ', 'XZ', 'Project on XZ plane', '', 2),
        ('YZ', 'YZ', 'Project on YZ plane', '', 3),


    ]

    def update_mode(self, context):
        self.update_sockets()
        updateNode(self, context)

    def update_sockets(self):
        self.inputs['Polygon Color'].hide_safe = self.mode != 'Mesh'
        self.inputs['Number'].hide_safe = not self.mode == 'Number'
        self.inputs['Curve'].hide_safe = not self.mode == 'Curve'
        self.inputs['Vecs'].hide_safe = self.mode in ['Number', 'Curve']
        self.inputs['Edges'].hide_safe = self.mode in ['Number', 'Path', 'Curve']
        self.inputs['Polygons'].hide_safe = self.mode in ['Number', 'Path', 'Curve']

    mode: EnumProperty(
        name='Mode',
        items=modes,
        default='Path',
        description="Display Mode",
        update=update_mode)

    working_plane: EnumProperty(
        name='Proyection Plane',
        items=plane,
        default='XY',
        description="2D plane where geometry will be projected",
        update=update_mode)

    activate: BoolProperty(
        name='Show', description='Activate drawing',
        default=True, update=updateNode
    )
    cyclic: BoolProperty(
        name='Cycle', description='Join first and last vertices',
        default=True, update=updateNode
    )

    draw_scale: FloatProperty(
        min=0.0, default=10.0, name='Scale',
        description='Drawing Scale', update=updateNode
    )
    drawing_size: IntVectorProperty(
        update=updateNode, name='Size', default=(150, 150),
        size=2
        )
    draw_verts: BoolProperty(
        default=False, name='See Verts',
        description='Drawing Verts', update=updateNode
    )
    point_size: IntProperty(
        min=1, default=4, name='Verts Size',
        description='Point Size', update=updateNode
    )
    edge_width: IntProperty(
        min=1, default=1, name='Edge Width',
        description='Edge Width', update=updateNode
    )

    curve_samples: IntProperty(
        min=2, default=25, name='Samples',
        description='Curve Resolution', update=updateNode
    )
    vector_color: FloatVectorProperty(
        update=updateNode, name='Vertices Color', default=(.9, .9, .95, 1.0),
        size=4, min=0.0, max=1.0, subtype='COLOR'
        )
    vector_toggle: BoolProperty(
        update=updateNode, name='Display Vertices', default=True
        )
    vector_random_colors: BoolProperty(
        update=updateNode, name='Random Vertices Color', default=False
        )
    random_seed: IntProperty(
        min=1, default=1, name='Random Seed',
        description='Seed of random colors', update=updateNode
    )
    color_per_point: BoolProperty(
        update=updateNode, name='Color per point', default=False,
        description='Toggle between color per point or per object'
        )
    color_per_edge: BoolProperty(
        update=updateNode, name='Color per edge', default=False,
        description='Toggle between color per edge or per object'
        )
    color_per_polygon: BoolProperty(
        update=updateNode, name='Color per polygon', default=False,
        description='Toggle between color per polygon or per object'
        )
    polygon_use_vertex_color: BoolProperty(
        update=update_mode, name='Polys Vertex Color', default=False,
        description='Colorize polygons using vertices color'
        )
    edges_use_vertex_color: BoolProperty(
        update=update_mode, name='Edges Vertex Color', default=False,
        description='Colorize edges using vertices color'
        )

    edge_color: FloatVectorProperty(
        update=updateNode, name='Edges Color', default=(.9, .9, .35, 1.0),
        size=4, min=0.0, max=1.0, subtype='COLOR'
        )
    edge_toggle: BoolProperty(
        update=updateNode, name='Display Edges', default=True
        )
    polygon_color: FloatVectorProperty(
        update=updateNode, name='Ploygons Color', default=(.2, .7, 1.0, 1.0),
        size=4, min=0.0, max=1.0, subtype='COLOR'
        )
    polygon_toggle: BoolProperty(
        update=updateNode, name='Display Polygons', default=True
        )
    background_color: FloatVectorProperty(
        update=updateNode, name='', default=(.01, .01, .01, 1.0),
        size=4, min=0.0, max=1.0, subtype='COLOR'
        )
    draw_background: BoolProperty(
        update=updateNode, name='Display Background', default=True
        )

    location_theta: FloatProperty(name="location theta")

    def draw_buttons(self, context, layout):
        r0 = layout.row()
        r0.prop(self, "activate", text="", icon="HIDE_" + ("OFF" if self.activate else "ON"))
        r0.prop(self, "mode")
        c0 = layout.column(align=True)
        row = c0.row(align=True)
        row.prop(self, "draw_background", text='', icon='WORLD')
        if self.draw_background:
            row.prop(self, "background_color")


        if self.mode == 'Number':
            row = c0.row(align=True)
            for j in range(2):
                row.prop(self, 'drawing_size', index=j, text='XY'[j])
            row = c0.row(align=True)
            row.prop(self, "point_size")
            row.prop(self, "edge_width")

        else:
            row = c0.row(align=True)
            row.prop(self, "working_plane", expand=True)
            c0.prop(self, "draw_scale")
            row = c0.row(align=True)
            row.prop(self, "point_size")
            row.prop(self, "edge_width")

            if self.mode in ["Path", "Curve"]:
                layout.prop(self, "cyclic")
            if self.mode == "Curve":
                layout.prop(self, "curve_samples")

    def sv_init(self, context):
        self.inputs.new('SvStringsSocket', "Number")
        self.inputs.new('SvVerticesSocket', "Vecs")
        self.inputs.new('SvStringsSocket', "Edges")
        self.inputs.new('SvStringsSocket', "Polygons")
        self.inputs.new('SvCurveSocket', "Curve")
        vc0 = self.inputs.new('SvColorSocket', "Vector Color")
        vc0.prop_name = 'vector_color'
        vc0.custom_draw = 'draw_color_socket'
        vc = self.inputs.new('SvColorSocket', "Edge Color")
        vc.prop_name = 'edge_color'
        vc.custom_draw = 'draw_color_socket'
        vc2 = self.inputs.new('SvColorSocket', "Polygon Color")
        vc2.prop_name = 'polygon_color'
        vc2.custom_draw = 'draw_color_socket'
        self.id_data.update_gl_scale_info()
        self.update_sockets()

    def draw_color_socket(self, socket, context, layout):
        socket_info = socket_dict[socket.prop_name]
        layout.prop(self, socket_info[0], text="", icon=socket_info[1])
        layout.prop(self, socket_info[2], text="", icon='COLOR')
        display_color = not socket.is_linked
        draw_name = True
        if len(socket_info) < 5:
            layout.prop(self, socket_info[3], text="", icon='VPAINT_HLT')

        else:
            layout.prop(self, socket_info[3], text="", icon='MOD_NOISE')
            if socket_info[3] in self and self[socket_info[3]]:
                layout.prop(self, socket_info[4], text="Seed")
                draw_name = False

        if socket_info[3] in self:
            display_color = display_color and  not self[socket_info[3]]


        if display_color:
            layout.prop(self, socket.prop_name, text="")
        else:
            if draw_name:
                layout.label(text=socket.name+ '. ' + SvGetSocketInfo(socket))

    def get_drawing_attributes(self):
        """ obtain the dpi adjusted xy and scale factors, cache location_theta """
        scale, multiplier = get_params({
            'render_scale': 1.0, 'render_location_xy_multiplier': 1.0}, direct=True)
        self.location_theta = multiplier
        return scale

    def get_offset(self):
        return [int(j) for j in (Vector(self.absolute_location) + Vector((self.width + 20, 0)))[:]]
    def create_config(self):
        config = lambda: None
        scale = self.get_drawing_attributes()
        margin = 10* scale
        config.mode = self.mode
        config.loc = (0, 0 - margin)
        config.sys_scale = scale
        config.scale = scale * self.draw_scale
        config.cyclic = self.cyclic
        config.background_color = self.background_color
        config.draw_background = self.draw_background
        config.plane = self.working_plane
        config.draw_verts = self.vector_toggle
        config.draw_edges = self.edge_toggle
        config.draw_polys = self.polygon_toggle and self.inputs['Polygons'].is_linked
        config.point_size = self.point_size
        config.edge_width = self.edge_width
        config.color_per_point = self.color_per_point
        config.color_per_edge = self.color_per_edge
        config.color_per_polygon = self.color_per_polygon
        config.polygon_use_vertex_color = self.polygon_use_vertex_color
        config.edges_use_vertex_color = self.edges_use_vertex_color
        config.random_colors = self.vector_random_colors

        return config

    def process(self):
        n_id = node_id(self)
        nvBGL.callback_disable(n_id)
        inputs = self.inputs
        # end early
        if not self.activate:
            return

        if self.mode == 'Number':
            if not inputs['Number'].is_linked:
                return
            numbers = inputs['Number'].sv_get(default=[[]])
        elif self.mode == 'Curve':
            if not inputs['Curve'].is_linked:
                return
            curves = inputs['Curve'].sv_get(default=[[]])
        else:
            if not inputs['Vecs'].is_linked:
                return
            vecs = inputs['Vecs'].sv_get(default=[[]])

        edges = inputs['Edges'].sv_get(default=[[]])
        polygons = inputs['Polygons'].sv_get(default=[[]])
        vector_color = inputs['Vector Color'].sv_get(default=[[self.vector_color]])
        edge_color = inputs['Edge Color'].sv_get(default=[[self.edge_color]])
        poly_color = inputs['Polygon Color'].sv_get(default=[[self.polygon_color]])
        seed_set(self.random_seed)
        config = self.create_config()

        config.vector_color = vector_color
        config.edge_color = edge_color
        config.poly_color = poly_color
        config.edges = edges


        if self.mode == 'Number':
            config.size = self.drawing_size
            geom = generate_number_geom(config, numbers)
        elif self.mode == 'Path':
            geom = generate_graph_geom(config, vecs)
        elif self.mode == 'Curve':
            paths = []
            for curve in curves:
                t_min, t_max = curve.get_u_bounds()
                ts = np_linspace(t_min, t_max, num=self.curve_samples, dtype=np_float64)
                paths.append(curve.evaluate_array(ts).tolist())

            geom = generate_graph_geom(config, paths)

        else:
            config.polygons = polygons
            if not inputs['Edges'].is_linked and self.edge_toggle:
                config.edges = polygons_to_edges_np(polygons, unique_edges=True)

            geom = generate_mesh_geom(config, vecs)


        draw_data = {
            'mode': 'custom_function',
            'tree_name': self.id_data.name[:],
            'node_name': self.name[:],
            'loc': get_drawing_location,
            'custom_function': view_2d_geom,
            'args': (geom, config)
        }
        nvBGL.callback_enable(n_id, draw_data)

    def sv_free(self):
        nvBGL.callback_disable(node_id(self))
Esempio n. 11
0
def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

    # Define properties
    Scene.measureit_default_color = FloatVectorProperty(
        name="Default color",
        description="Default Color",
        default=(0.173, 0.545, 1.0, 1.0),
        min=0.1,
        max=1,
        subtype='COLOR',
        size=4)
    Scene.measureit_font_size = IntProperty(name="Text Size",
                                            description="Default text size",
                                            default=14, min=10, max=150)
    Scene.measureit_hint_space = FloatProperty(name='Separation', min=0, max=100, default=0.1,
                                               precision=3,
                                               description="Default distance to display measure")
    Scene.measureit_gl_ghost = BoolProperty(name="All",
                                            description="Display measures for all objects,"
                                                        " not only selected",
                                            default=True)
    Scene.measureit_gl_txt = StringProperty(name="Text", maxlen=256,
                                            description="Short description (use | for line break)")

    Scene.measureit_gl_precision = IntProperty(name='Precision', min=0, max=5, default=2,
                                               description="Number of decimal precision")
    Scene.measureit_gl_show_d = BoolProperty(name="ShowDist",
                                             description="Display distances",
                                             default=True)
    Scene.measureit_gl_show_n = BoolProperty(name="ShowName",
                                             description="Display texts",
                                             default=False)
    Scene.measureit_scale = BoolProperty(name="Scale",
                                         description="Use scale factor",
                                         default=False)
    Scene.measureit_scale_factor = FloatProperty(name='Factor', min=0.001, max=9999999,
                                                 default=1.0,
                                                 precision=3,
                                                 description="Scale factor 1:x")
    Scene.measureit_scale_color = FloatVectorProperty(name="Scale color",
                                                      description="Scale Color",
                                                      default=(1, 1, 0, 1.0),
                                                      min=0.1,
                                                      max=1,
                                                      subtype='COLOR',
                                                      size=4)
    Scene.measureit_scale_font = IntProperty(name="Font",
                                             description="Text size",
                                             default=14, min=10, max=150)
    Scene.measureit_scale_pos_x = IntProperty(name="X Position",
                                              description="Margin on the X axis",
                                              default=5,
                                              min=0,
                                              max=100)
    Scene.measureit_scale_pos_y = IntProperty(name="Y Position",
                                              description="Margin on the Y axis",
                                              default=5,
                                              min=0,
                                              max=100)
    Scene.measureit_gl_scaletxt = StringProperty(name="ScaleText", maxlen=48,
                                                 description="Scale title",
                                                 default="Scale:")
    Scene.measureit_scale_precision = IntProperty(name='Precision', min=0, max=5, default=0,
                                                  description="Number of decimal precision")
    Scene.measureit_ovr = BoolProperty(name="Override",
                                       description="Override colors and fonts",
                                       default=False)
    Scene.measureit_ovr_font = IntProperty(name="Font",
                                           description="Override text size",
                                           default=14, min=10, max=150)
    Scene.measureit_ovr_color = FloatVectorProperty(name="Override color",
                                                    description="Override Color",
                                                    default=(1, 0, 0, 1.0),
                                                    min=0.1,
                                                    max=1,
                                                    subtype='COLOR',
                                                    size=4)
    Scene.measureit_ovr_width = IntProperty(name='Override width', min=1, max=10, default=1,
                                            description='override line width')

    Scene.measureit_ovr_font_rotation = IntProperty(name='Rotate', min=0, max=360, default=0,
                                                    description="Text rotation in degrees")
    Scene.measureit_ovr_font_align = EnumProperty(items=(('L', "Left Align", "Use current render"),
                                                         ('C', "Center Align", ""),
                                                         ('R', "Right Align", "")),
                                                  name="Align Font",
                                                  description="Set Font Alignment")
    Scene.measureit_units = EnumProperty(items=(('1', "Automatic", "Use scene units"),
                                                ('2', "Meters", ""),
                                                ('3', "Centimeters", ""),
                                                ('4', "Millimeters", ""),
                                                ('5', "Feet", ""),
                                                ('6', "Inches", "")),
                                         name="Units",
                                         default="2",
                                         description="Units")
    Scene.measureit_hide_units = BoolProperty(name="hide_units",
                                              description="Do not display unit of measurement on viewport",
                                              default=False)
    Scene.measureit_render = BoolProperty(name="Render",
                                          description="Save an image with measures over"
                                                      " render image",
                                          default=False)
    Scene.measureit_render_type = EnumProperty(items=(('1', "Frame", "Render current frame"),
                                                      ('2', "Animation", "")),
                                               name="Render type",
                                               description="Type of render image")
    Scene.measureit_sum = EnumProperty(items=(('99', "-", "Select a group for sum"),
                                              ('0', "A", ""),
                                              ('1', "B", ""),
                                              ('2', "C", ""),
                                              ('3', "D", ""),
                                              ('4', "E", ""),
                                              ('5', "F", ""),
                                              ('6', "G", ""),
                                              ('7', "H", ""),
                                              ('8', "I", ""),
                                              ('9', "J", ""),
                                              ('10', "K", ""),
                                              ('11', "L", ""),
                                              ('12', "M", ""),
                                              ('13', "N", ""),
                                              ('14', "O", ""),
                                              ('15', "P", ""),
                                              ('16', "Q", ""),
                                              ('17', "R", ""),
                                              ('18', "S", ""),
                                              ('19', "T", ""),
                                              ('20', "U", ""),
                                              ('21', "V", ""),
                                              ('22', "W", ""),
                                              ('23', "X", ""),
                                              ('24', "Y", ""),
                                              ('25', "Z", "")),
                                       name="Sum in Group",
                                       description="Add segment length in selected group")

    Scene.measureit_rf = BoolProperty(name="render_frame",
                                      description="Add a frame in render output",
                                      default=False)
    Scene.measureit_rf_color = FloatVectorProperty(name="Fcolor",
                                                   description="Frame Color",
                                                   default=(0.9, 0.9, 0.9, 1.0),
                                                   min=0.1,
                                                   max=1,
                                                   subtype='COLOR',
                                                   size=4)
    Scene.measureit_rf_border = IntProperty(name='fborder ', min=1, max=1000, default=10,
                                            description='Frame space from border')
    Scene.measureit_rf_line = IntProperty(name='fline', min=1, max=10, default=1,
                                          description='Line width for border')

    Scene.measureit_glarrow_a = EnumProperty(items=(('99', "--", "No arrow"),
                                                    ('1', "Line",
                                                     "The point of the arrow are lines"),
                                                    ('2', "Triangle",
                                                     "The point of the arrow is triangle"),
                                                    ('3', "TShape",
                                                     "The point of the arrow is a T")),
                                             name="A end",
                                             description="Add arrows to point A")
    Scene.measureit_glarrow_b = EnumProperty(items=(('99', "--", "No arrow"),
                                                    ('1', "Line",
                                                     "The point of the arrow are lines"),
                                                    ('2', "Triangle",
                                                     "The point of the arrow is triangle"),
                                                    ('3', "TShape",
                                                     "The point of the arrow is a T")),
                                             name="B end",
                                             description="Add arrows to point B")
    Scene.measureit_glarrow_s = IntProperty(name="Size",
                                            description="Arrow size",
                                            default=15, min=6, max=500)

    Scene.measureit_debug = BoolProperty(name="Debug",
                                         description="Display information for debugging"
                                                     " (expand/collapse for enabling or disabling)"
                                                     " this information is only renderered for "
                                                     "selected objects",
                                         default=False)
    Scene.measureit_debug_select = BoolProperty(name="Selected",
                                                description="Display information "
                                                            "only for selected items",
                                                default=False)
    Scene.measureit_debug_vertices = BoolProperty(name="Vertices",
                                                  description="Display vertex index number",
                                                  default=True)
    Scene.measureit_debug_objects = BoolProperty(name="Objects",
                                                 description="Display object scene index number",
                                                 default=False)
    Scene.measureit_debug_vert_loc = BoolProperty(name="Location",
                                                  description="Display vertex location",
                                                  default=False)
    Scene.measureit_debug_object_loc = BoolProperty(name="Location",
                                                    description="Display object location",
                                                    default=False)
    Scene.measureit_debug_edges = BoolProperty(name="Edges",
                                               description="Display edge index number",
                                               default=False)
    Scene.measureit_debug_faces = BoolProperty(name="Faces",
                                               description="Display face index number",
                                               default=False)
    Scene.measureit_debug_normals = BoolProperty(name="Normals",
                                                 description="Display face normal "
                                                             "vector and creation order",
                                                 default=False)
    Scene.measureit_debug_normal_details = BoolProperty(name="Details",
                                                        description="Display face normal details",
                                                        default=True)
    Scene.measureit_debug_font = IntProperty(name="Font",
                                             description="Debug text size",
                                             default=14, min=10, max=150)
    Scene.measureit_debug_vert_color = FloatVectorProperty(name="Debug color",
                                                           description="Debug Color",
                                                           default=(1, 0, 0, 1.0),
                                                           min=0.1,
                                                           max=1,
                                                           subtype='COLOR',
                                                           size=4)
    Scene.measureit_debug_face_color = FloatVectorProperty(name="Debug face color",
                                                           description="Debug face Color",
                                                           default=(0, 1, 0, 1.0),
                                                           min=0.1,
                                                           max=1,
                                                           subtype='COLOR',
                                                           size=4)
    Scene.measureit_debug_norm_color = FloatVectorProperty(name="Debug vector color",
                                                           description="Debug vector Color",
                                                           default=(1.0, 1.0, 0.1, 1.0),
                                                           min=0.1,
                                                           max=1,
                                                           subtype='COLOR',
                                                           size=4)
    Scene.measureit_debug_edge_color = FloatVectorProperty(name="Debug vector color",
                                                           description="Debug vector Color",
                                                           default=(0.1, 1.0, 1.0, 1.0),
                                                           min=0.1,
                                                           max=1,
                                                           subtype='COLOR',
                                                           size=4)
    Scene.measureit_debug_obj_color = FloatVectorProperty(name="Debug vector color",
                                                          description="Debug vector Color",
                                                          default=(1.0, 1.0, 1.0, 1.0),
                                                          min=0.1,
                                                          max=1,
                                                          subtype='COLOR',
                                                          size=4)
    Scene.measureit_debug_normal_size = FloatProperty(name='Len', min=0.001, max=9,
                                                      default=0.5,
                                                      precision=2,
                                                      description="Normal arrow size")
    Scene.measureit_debug_width = IntProperty(name='Debug width', min=1, max=10, default=2,
                                              description='Vector line thickness')
    Scene.measureit_debug_precision = IntProperty(name='Precision', min=0, max=5, default=1,
                                                  description="Number of decimal precision")
    Scene.measureit_debug_vert_loc_toggle = EnumProperty(items=(('1', "Local",
                                                                 "Uses local coordinates"),
                                                                ('2', "Global",
                                                                 "Uses global coordinates")),
                                                         name="Coordinates",
                                                         description="Choose coordinate system")
    Scene.measureit_font_rotation = IntProperty(name='Rotate', min=0, max=360, default=0,
                                                description="Default text rotation in degrees")
    Scene.measureit_font_align = EnumProperty(items=(('L', "Left Align", "Use current render"),
                                                     ('C', "Center Align", ""),
                                                     ('R', "Right Align", "")),
                                              name="Align Font",
                                              description="Set Font Alignment")

    # OpenGL flag
    wm = WindowManager
    # register internal property
    wm.measureit_run_opengl = BoolProperty(default=False)
Esempio n. 12
0
class WSphereData(bpy.types.PropertyGroup):
    radius = FloatProperty(name="Radius",
                           description="Radius of the Sphere",
                           default=1.0,
                           min=0.0,
                           soft_min=0.0001,
                           step=1,
                           unit='LENGTH',
                           set=setRadius,
                           get=getRadius)

    segments = IntProperty(name="Segments",
                           description="Segments on diametr",
                           default=24,
                           min=3,
                           soft_min=3,
                           step=1,
                           subtype='NONE',
                           set=setSegments,
                           get=getSegments)

    rings = IntProperty(name="Rings",
                        description="Rings",
                        default=12,
                        min=2,
                        soft_min=2,
                        step=1,
                        subtype='NONE',
                        set=setRing,
                        get=getRing)

    divisions = IntProperty(name="Division",
                            description="Divisions of the base mesh",
                            default=2,
                            min=0,
                            soft_min=0,
                            step=1,
                            subtype='NONE',
                            set=setDivisions,
                            get=getDivisions)

    Topos = [('UV', "UV", "", 1), ('TETRA', "Tetrahedron", "", 2),
             ('CUBE', "Cube", "", 3), ('OCTA', "Octahedron", "", 4),
             ('ICOSA', "Icosahedron", "", 5)]

    base = EnumProperty(items=Topos,
                        name="Topology",
                        description="Type of sphere topology",
                        default='CUBE',
                        set=setBase,
                        get=getBase)

    smoothed = BoolProperty(name="Smooth",
                            description="Smooth shading",
                            default=True,
                            set=setSmoothed,
                            get=getSmoothed)

    tris = BoolProperty(name="Tris",
                        description="Triangulate divisions",
                        default=False,
                        set=setTris,
                        get=getTris)
Esempio n. 13
0
class Make_WSphere(bpy.types.Operator):
    """Create primitive WSphere"""
    bl_idname = "mesh.make_wsphere"
    bl_label = "WSphere"
    bl_options = {'UNDO', 'REGISTER'}

    radius = FloatProperty(name="Radius",
                           description="Radius of the Sphere",
                           default=1.0,
                           min=0.0,
                           soft_min=0.0001,
                           step=1,
                           unit='LENGTH')

    segments = IntProperty(name="Segments",
                           description="Segments on diametr",
                           default=24,
                           min=3,
                           soft_min=3,
                           step=1,
                           subtype='NONE')

    rings = IntProperty(name="Rings",
                        description="Rings",
                        default=12,
                        min=2,
                        soft_min=2,
                        step=1,
                        subtype='NONE')

    divisions = IntProperty(name="Division",
                            description="Divisions of the base mesh",
                            default=2,
                            min=0,
                            soft_min=0,
                            step=1,
                            subtype='NONE')

    Topos = [('UV', "UV", "", 1), ('TETRA', "Tetrahedron", "", 2),
             ('CUBE', "Cube", "", 3), ('OCTA', "Octahedron", "", 4),
             ('ICOSA', "Icosahedron", "", 5)]

    base = EnumProperty(items=Topos,
                        name="Topology",
                        description="Type of sphere topology",
                        default='CUBE')

    smoothed = BoolProperty(name="Smooth",
                            description="Smooth shading",
                            default=True)

    tris = BoolProperty(name="Tris",
                        description="Triangulate divisions",
                        default=False)

    def execute(self, context):
        """
        WSphere_defaults = {
        "radius": 1.0,
        "segments": 24,
        "rings": 12,
        "base": 3,
        "divisions": 2,
        "tris": False,
        "smoothed": True
        """

        WSphere_defaults["radius"] = self.radius
        WSphere_defaults["segments"] = self.segments
        WSphere_defaults["rings"] = self.rings
        WSphere_defaults["base"] = self.base
        WSphere_defaults["divisions"] = self.divisions
        WSphere_defaults["tris"] = self.tris
        WSphere_defaults["smoothed"] = self.smoothed

        #verts, edges, faces = primitive_polySphere(**WSphere_defaults)

        if self.base == "UV":
            verts, edges, faces = primitive_UVSphere(
                radius=WSphere_defaults["radius"],
                segments=WSphere_defaults["segments"],
                rings=WSphere_defaults["rings"])
        else:
            verts, edges, faces = primitive_polySphere(
                base=WSphere_defaults["base"],
                radius=WSphere_defaults["radius"],
                divisions=WSphere_defaults["divisions"],
                tris=WSphere_defaults["tris"])

        create_mesh_object(context, verts, edges, faces, "WSphere")

        context.object.data.WSphere["animArgs"] = WSphere_defaults

        context.object.data.WType = 'WSPHERE'
        bpy.ops.object.shade_smooth()
        return {'FINISHED'}
Esempio n. 14
0
class SvVDExperimental(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: exp vd mk3
    Tooltip: drawing, with experimental features

    not a very exciting node.
    """

    bl_idname = 'SvVDExperimental'
    bl_label = 'Viewer Draw Mk3'
    bl_icon = 'GREASEPENCIL'
    sv_icon = 'SV_DRAW_VIEWER'

    node_dict = {}

    def populate_node_with_custom_shader_from_text(self):
        if self.custom_shader_location in bpy.data.texts:
            try:
                vertex_shader, fragment_shader, draw_fragment = get_shader_data(
                    named_shader=self.custom_shader_location)

                self.custom_vertex_shader = vertex_shader
                self.custom_fragment_shader = fragment_shader
                self.node_dict[hash(self)] = {'draw_fragment': draw_fragment}

            except Exception as err:
                print(err)
                print(traceback.format_exc())

                # reset custom shader
                self.custom_vertex_shader = ''
                self.custom_fragment_shader = ''
                self.node_dict[hash(self)] = {}

    def wrapped_update(self, context=None):
        self.populate_node_with_custom_shader_from_text()
        if context:
            self.process_node(context)

    n_id: StringProperty(default='')
    activate: BoolProperty(name='Show',
                           description='Activate',
                           default=True,
                           update=updateNode)

    vert_color: FloatVectorProperty(subtype='COLOR',
                                    min=0,
                                    max=1,
                                    default=(0.8, 0.8, 0.8, 1.0),
                                    name='vert color',
                                    size=4,
                                    update=updateNode)

    edge_color: FloatVectorProperty(subtype='COLOR',
                                    min=0,
                                    max=1,
                                    default=(0.5, 1.0, 0.5, 1.0),
                                    name='edge color',
                                    size=4,
                                    update=updateNode)

    face_color: FloatVectorProperty(subtype='COLOR',
                                    min=0,
                                    max=1,
                                    default=(0.14, 0.54, 0.81, 1.0),
                                    name='face color',
                                    size=4,
                                    update=updateNode)

    vector_light: FloatVectorProperty(name='vector light',
                                      subtype='DIRECTION',
                                      min=0,
                                      max=1,
                                      size=3,
                                      default=(0.2, 0.6, 0.4),
                                      update=updateNode)

    extended_matrix: BoolProperty(
        default=False,
        description='Allows mesh.transform(matrix) operation, quite fast!')

    handle_concave_quads: BoolProperty(
        name='Handle Concave Quads',
        default=False,
        update=updateNode,
        description=
        'tessellate quads using geometry.tessellate_polygon, expect some speed impact'
    )

    # glGet with argument GL_POINT_SIZE_RANGE
    point_size: FloatProperty(description="glPointSize( GLfloat size)",
                              update=updateNode,
                              default=4.0,
                              min=1.0,
                              max=15.0)
    line_width: IntProperty(description="glLineWidth( GLfloat width)",
                            update=updateNode,
                            default=1,
                            min=1,
                            max=5)

    display_verts: BoolProperty(default=True,
                                update=updateNode,
                                name="display verts")
    display_edges: BoolProperty(default=True,
                                update=updateNode,
                                name="display edges")
    display_faces: BoolProperty(default=True,
                                update=updateNode,
                                name="display faces")
    draw_gl_wireframe: BoolProperty(default=False,
                                    update=updateNode,
                                    name="draw gl wireframe")
    draw_gl_polygonoffset: BoolProperty(default=True,
                                        update=updateNode,
                                        name="draw gl polygon offset")

    custom_vertex_shader: StringProperty(default=default_vertex_shader,
                                         name='vertex shader')
    custom_fragment_shader: StringProperty(default=default_fragment_shader,
                                           name='fragment shader')
    custom_shader_location: StringProperty(update=wrapped_update,
                                           name='custom shader location')

    selected_draw_mode: EnumProperty(
        items=enum_item_5(
            ["flat", "facet", "smooth", "fragment"],
            ['SNAP_VOLUME', 'ALIASED', 'ANTIALIASED', 'SCRIPTPLUGINS']),
        description="pick how the node will draw faces",
        default="flat",
        update=updateNode)

    # dashed line props
    use_dashed: BoolProperty(name='use dashes', update=updateNode)
    u_dash_size: FloatProperty(default=0.12,
                               min=0.0001,
                               name="dash size",
                               update=updateNode)
    u_gap_size: FloatProperty(default=0.19,
                              min=0.0001,
                              name="gap size",
                              update=updateNode)
    u_resolution: FloatVectorProperty(default=(25.0, 18.0),
                                      size=2,
                                      min=0.01,
                                      name="resolution",
                                      update=updateNode)

    def configureAttrSocket(self, context):
        self.inputs['attrs'].hide_safe = not self.node_ui_show_attrs_socket

    node_ui_show_attrs_socket: BoolProperty(default=False,
                                            name='show attrs socket',
                                            update=configureAttrSocket)

    def sv_init(self, context):
        inew = self.inputs.new
        inew('SvVerticesSocket', 'verts')
        inew('SvStringsSocket', 'edges')
        inew('SvStringsSocket', 'faces')
        inew('SvMatrixSocket', 'matrix')

        attr_socket = inew('SvStringsSocket', 'attrs')
        attr_socket.hide = True
        attr_socket.quick_link_to_node = "SvVDAttrsNode"

        self.node_dict[hash(self)] = {}

    def draw_buttons(self, context, layout):
        r0 = layout.row()
        r0.prop(self,
                "activate",
                text="",
                icon="HIDE_" + ("OFF" if self.activate else "ON"))
        r0.separator()
        r0.prop(self, "selected_draw_mode", expand=True, text='')

        b1 = layout.column()
        if b1:
            inside_box = b1.row(align=True)
            button_column = inside_box.column(align=True)
            button_column.prop(self,
                               "display_verts",
                               text='',
                               icon="UV_VERTEXSEL")
            button_column.prop(self,
                               "display_edges",
                               text='',
                               icon="UV_EDGESEL")
            button_column.prop(self,
                               "display_faces",
                               text='',
                               icon="UV_FACESEL")

            colors_column = inside_box.column(align=True)
            colors_column.prop(self, "vert_color", text='')
            colors_column.prop(self, "edge_color", text='')
            if not self.selected_draw_mode == 'fragment':
                colors_column.prop(self, "face_color", text='')
            else:
                colors_column.prop(self,
                                   "custom_shader_location",
                                   icon='TEXT',
                                   text='')

        row = layout.row(align=True)
        self.wrapper_tracked_ui_draw_op(row,
                                        "node.sverchok_mesh_baker_mk3",
                                        icon='OUTLINER_OB_MESH',
                                        text="B A K E")
        row.separator()
        self.wrapper_tracked_ui_draw_op(row,
                                        "node.view3d_align_from",
                                        icon='CURSOR',
                                        text='')

    def draw_buttons_ext(self, context, layout):
        self.draw_buttons(context, layout)
        self.draw_additional_props(context, layout)
        layout.prop(self, "use_dashed")
        if self.use_dashed:
            layout.prop(self, "u_dash_size")
            layout.prop(self, "u_gap_size")
            layout.row().prop(self, "u_resolution")

    def bake(self):
        with self.sv_throttle_tree_update():
            bpy.ops.node.sverchok_mesh_baker_mk3(idname=self.name,
                                                 idtree=self.id_data.name)

    def rclick_menu(self, context, layout):
        self.draw_additional_props(context, layout)

    def draw_additional_props(self, context, layout):
        layout.prop(self, 'vector_light', text='')
        layout.prop(self, 'point_size', text='Point Size')
        layout.prop(self, 'line_width', text='Edge Width')
        layout.separator()
        layout.prop(self, 'handle_concave_quads', toggle=True)
        layout.prop(self, 'draw_gl_wireframe', toggle=True)
        layout.prop(self, 'draw_gl_polygonoffset', toggle=True)
        layout.prop(self, 'node_ui_show_attrs_socket', toggle=True)
        layout.separator()

    def add_gl_stuff_to_config(self, config):
        config.dashed_shader = gpu.types.GPUShader(dashed_vertex_shader,
                                                   dashed_fragment_shader)

    def fill_config(self):

        config = lambda: None
        config.vector_light = self.vector_light[:]
        config.vcol = self.vert_color[:]
        config.line4f = self.edge_color[:]
        config.face4f = self.face_color[:]
        config.display_verts = self.display_verts
        config.display_edges = self.display_edges
        config.display_faces = self.display_faces
        config.shade = self.selected_draw_mode
        config.draw_gl_wireframe = self.draw_gl_wireframe
        config.draw_gl_polygonoffset = self.draw_gl_polygonoffset
        config.point_size = self.point_size
        config.line_width = self.line_width
        config.extended_matrix = self.extended_matrix
        config.draw_dashed = self.use_dashed
        config.u_dash_size = self.u_dash_size
        config.u_gap_size = self.u_gap_size
        config.u_resolution = self.u_resolution[:]

        return config

    def get_data(self):
        verts_socket, edges_socket, faces_socket, matrix_socket = self.inputs[:
                                                                              4]
        edge_indices = [[]]
        face_indices = [[]]

        propv = verts_socket.sv_get(deepcopy=False, default=[[]])
        coords = propv

        if edges_socket.is_linked:
            prope = edges_socket.sv_get(deepcopy=False, default=[[]])
            edge_indices = prope

        if faces_socket.is_linked:
            propf = faces_socket.sv_get(deepcopy=False, default=[[]])
            face_indices = propf

        if matrix_socket.is_linked:
            m = matrix_socket.sv_get(deepcopy=False, default=[Matrix()])
            verts, matrix = match_long_repeat([propv, m])
            coords = [
                multiply_vectors_deep(mx, v) for mx, v in zip(matrix, verts)
            ]
        else:
            matrix = [Matrix()]
            verts = coords
        return match_long_repeat(
            [coords, edge_indices, face_indices, verts, matrix])

    def faces_diplay(self, geom, config):

        if self.selected_draw_mode == 'facet' and self.display_faces:
            facet_verts, facet_verts_vcols = generate_facet_data(
                geom.verts, geom.faces, config.face4f, config.vector_light)
            geom.facet_verts = facet_verts
            geom.facet_verts_vcols = facet_verts_vcols
        elif self.selected_draw_mode == 'smooth' and self.display_faces:
            geom.smooth_vcols = generate_smooth_data(geom.verts, geom.faces,
                                                     config.face4f,
                                                     config.vector_light)
        elif self.selected_draw_mode == 'fragment' and self.display_faces:

            config.draw_fragment_function = None

            # double reload, for testing.
            ND = self.node_dict.get(hash(self))
            if not ND:
                if self.custom_shader_location in bpy.data.texts:
                    self.populate_node_with_custom_shader_from_text()
                    ND = self.node_dict.get(hash(self))

            if ND and ND.get('draw_fragment'):
                config.draw_fragment_function = ND.get('draw_fragment')
                config.shader = gpu.types.GPUShader(
                    self.custom_vertex_shader, self.custom_fragment_shader)
            else:
                config.shader = gpu.types.GPUShader(default_vertex_shader,
                                                    default_fragment_shader)

            config.batch = batch_for_shader(config.shader,
                                            'TRIS', {"position": geom.verts},
                                            indices=geom.faces)

    def handle_attr_socket(self):
        """
        this socket expects input dictionary wrapped. once.

            [  {attr: attr_vale, attr2: attr2_value } ]

        """

        if self.node_ui_show_attrs_socket and not self.inputs[
                'attrs'].hide and self.inputs['attrs'].is_linked:
            socket_acquired_attrs = self.inputs['attrs'].sv_get(
                default=[{
                    'activate': False
                }])

            if socket_acquired_attrs:
                try:
                    with hard_freeze(self) as node:
                        for k, new_value in socket_acquired_attrs[0].items():
                            print(f"setattr(node, {k}, {new_value})")
                            setattr(node, k, new_value)
                except Exception as err:
                    print('error inside socket_acquired_attrs: ', err)
                    self.id_data.unfreeze(
                        hard=True)  # ensure this thing is unfrozen

    def format_draw_data(self, func=None, args=None):
        return {
            'tree_name': self.id_data.name[:],
            'custom_function': func,
            'args': args
        }

    def process(self):

        self.handle_attr_socket()

        if not (self.id_data.sv_show and self.activate):
            callback_disable(node_id(self))
            return

        n_id = node_id(self)
        callback_disable(n_id)

        if not any(
            [self.display_verts, self.display_edges, self.display_faces]):
            return

        verts_socket, edges_socket, faces_socket, matrix_socket = self.inputs[:
                                                                              4]

        if verts_socket.is_linked:

            display_faces = self.display_faces and faces_socket.is_linked
            display_edges = self.display_edges and (edges_socket.is_linked
                                                    or faces_socket.is_linked)

            config = self.fill_config()
            data = self.get_data()
            if len(data[0]) > 1:
                coords, edge_indices, face_indices = mesh_join(
                    data[0], data[1], data[2])
                if not coords:
                    return
            elif len(data[0][0]) > 0:
                coords, edge_indices, face_indices = [
                    d[0].tolist() if type(d[0]) == ndarray else d[0]
                    for d in data[:3]
                ]
            else:
                return
            geom = lambda: None
            geom.verts = coords

            if self.display_verts and not any([display_edges, display_faces]):
                gl_instructions = self.format_draw_data(func=draw_verts,
                                                        args=(geom, config))
                callback_enable(n_id, gl_instructions)
                return

            if edges_socket.is_linked and not faces_socket.is_linked:
                if self.use_dashed:
                    self.add_gl_stuff_to_config(config)

                geom.edges = edge_indices
                gl_instructions = self.format_draw_data(func=draw_edges,
                                                        args=(geom, config))
                callback_enable(n_id, gl_instructions)
                return

            if faces_socket.is_linked:

                #  expecting mixed bag of tris/quads/ngons
                if self.display_faces:
                    geom.faces = ensure_triangles(coords, face_indices,
                                                  self.handle_concave_quads)

                if self.display_edges:
                    if self.use_dashed:
                        self.add_gl_stuff_to_config(config)

                    # we don't want to draw the inner edges of triangulated faces; use original face_indices.
                    # pass edges from socket if we can, else we manually compute them from faces
                    geom.edges = edge_indices if edges_socket.is_linked else edges_from_faces(
                        face_indices)

                if self.display_faces:
                    self.faces_diplay(geom, config)

                gl_instructions = self.format_draw_data(func=draw_complex,
                                                        args=(geom, config))
                callback_enable(n_id, gl_instructions)
                return

            return

        elif matrix_socket.is_linked:
            matrices = matrix_socket.sv_get(deepcopy=False, default=[Matrix()])
            gl_instructions = self.format_draw_data(func=draw_matrix,
                                                    args=(matrices, ))
            callback_enable(n_id, gl_instructions)

    def sv_copy(self, node):
        self.n_id = ''

    @property
    def fully_enabled(self):
        return "attrs" in self.inputs

    def sv_update(self):
        if not self.fully_enabled:
            return

        try:
            socket_one_has_upstream_links = self.inputs[0].other
            socket_two_has_upstream_links = self.inputs[1].other

            if not socket_one_has_upstream_links:
                callback_disable(node_id(self))
        except:
            self.debug(f'vd draw update holdout {self.n_id}')

    def sv_free(self):
        callback_disable(node_id(self))

    def show_viewport(self, is_show: bool):
        """It should be called by node tree to show/hide objects"""
        if not self.activate:
            # just ignore request
            pass
        else:
            if is_show:
                self.process()
            else:
                callback_disable(node_id(self))
Esempio n. 15
0
class LuxCoreConfig(PropertyGroup):
    """
    Main config storage class.
    Access (in ui or export) with scene.luxcore.config
    """

    # These settings are mostly not directly transferrable to LuxCore properties
    # They need some if/else decisions and aggregation, e.g. to build the engine name from parts
    engines = [
        ("PATH", "Path", "Unidirectional path tracer; " + SIMPLE_DESC, 0),
        ("BIDIR", "Bidir", "Bidirectional path tracer; " + COMPLEX_DESC, 1),
    ]
    engine: EnumProperty(name="Engine", items=engines, default="PATH")

    # Only available when tiled rendering is off
    samplers = [
        ("SOBOL", "Sobol", SIMPLE_DESC, 0),
        ("METROPOLIS", "Metropolis", COMPLEX_DESC, 1),
        ("RANDOM", "Random",
         "Recommended only if the BCD denoiser is used (use Sobol otherwise)",
         2),
    ]
    sampler: EnumProperty(name="Sampler", items=samplers, default="SOBOL")

    # SOBOL properties
    sobol_adaptive_strength: FloatProperty(
        name="Adaptive Strength",
        default=0.9,
        min=0,
        max=0.95,
        description=SOBOL_ADAPTIVE_STRENGTH_DESC)

    # Noise estimation (used by adaptive samplers like SOBOL and RANDOM)
    noise_estimation: PointerProperty(type=LuxCoreConfigNoiseEstimation)

    # METROPOLIS properties
    # sampler.metropolis.largesteprate
    metropolis_largesteprate: FloatProperty(name="Large Mutation Probability",
                                            default=40,
                                            min=0,
                                            max=100,
                                            precision=0,
                                            subtype="PERCENTAGE",
                                            description=LARGE_STEP_RATE_DESC)
    # sampler.metropolis.maxconsecutivereject
    metropolis_maxconsecutivereject: IntProperty(
        name="Max Consecutive Rejects",
        default=512,
        min=0,
        description=MAX_CONSECUTIVE_REJECT_DESC)
    # sampler.metropolis.imagemutationrate
    metropolis_imagemutationrate: FloatProperty(
        name="Image Mutation Rate",
        default=10,
        min=0,
        max=100,
        precision=0,
        subtype="PERCENTAGE",
        description=IMAGE_MUTATION_RATE_DESC)

    # Only available when engine is PATH (not BIDIR)
    devices = [
        ("CPU", "CPU",
         "Use the arithmetic logic units in your central processing unit", 0),
        ("OCL", "OpenCL", "Use the good ol' pixel cruncher", 1),
    ]
    device: EnumProperty(name="Device", items=devices, default="CPU")
    # A trick so we can show the user that bidir can only be used on the CPU (see UI code)
    bidir_device: EnumProperty(name="Device",
                               items=devices,
                               default="CPU",
                               description="Bidir only available on CPU")

    use_tiles: BoolProperty(name="Tiled",
                            default=False,
                            description=TILED_DESCRIPTION)

    # Special properties of the various engines
    path: PointerProperty(type=LuxCoreConfigPath)
    tile: PointerProperty(type=LuxCoreConfigTile)
    # BIDIR properties
    # light.maxdepth
    # TODO description
    bidir_light_maxdepth: IntProperty(name="Light Depth",
                                      default=10,
                                      min=1,
                                      soft_max=16)
    # path.maxdepth
    # TODO description
    bidir_path_maxdepth: IntProperty(name="Eye Depth",
                                     default=10,
                                     min=1,
                                     soft_max=16)

    # Pixel filter
    filters = [
        ("BLACKMANHARRIS", "Blackman-Harris",
         "Default, usually the best option", 0),
        ("MITCHELL_SS", "Mitchell",
         "Sharp, but can produce black ringing artifacts around bright pixels",
         1), ("GAUSSIAN", "Gaussian", "Blurry", 2),
        ("NONE", "None",
         "Disable pixel filtering. Fastest setting when rendering on GPU", 3)
    ]
    filter: EnumProperty(name="Filter",
                         items=filters,
                         default="BLACKMANHARRIS",
                         description=FILTER_DESC)
    filter_width: FloatProperty(name="Filter Width",
                                default=1.5,
                                min=0.5,
                                soft_max=3,
                                description=FILTER_WIDTH_DESC,
                                subtype="PIXEL")
    gaussian_alpha: FloatProperty(
        name="Gaussian Filter Alpha",
        default=2,
        min=0.1,
        max=10,
        description=
        "Gaussian rate of falloff. Lower values give blurrier images")

    # Light strategy
    light_strategy_items = [
        ("LOG_POWER", "Log Power", LOG_POWER_DESC, 0),
        ("POWER", "Power", POWER_DESC, 1),
        ("UNIFORM", "Uniform", UNIFORM_DESC, 2),
    ]
    light_strategy: EnumProperty(
        name="Light Strategy",
        items=light_strategy_items,
        default="LOG_POWER",
        description="Decides how the lights in the scene are sampled")

    # Special properties of the direct light sampling cache
    dls_cache: PointerProperty(type=LuxCoreConfigDLSCache)
    # Special properties of the photon GI cache
    photongi: PointerProperty(type=LuxCoreConfigPhotonGI)
    # Special properties of the env. light cache (aka automatic portals)
    envlight_cache: PointerProperty(type=LuxCoreConfigEnvLightCache)

    # FILESAVER options
    use_filesaver: BoolProperty(name="Only write LuxCore scene", default=False)
    filesaver_format_items = [
        ("TXT", "Text", "Save as .scn and .cfg text files", 0),
        ("BIN", "Binary", "Save as .bcf binary file", 1),
    ]
    filesaver_format: EnumProperty(name="",
                                   items=filesaver_format_items,
                                   default="TXT")
    filesaver_path: StringProperty(
        name="",
        subtype="DIR_PATH",
        description="Output path where the scene is saved")

    # Seed
    seed: IntProperty(name="Seed", default=1, min=1, description=SEED_DESC)
    use_animated_seed: BoolProperty(name="Animated Seed",
                                    default=False,
                                    description=ANIM_SEED_DESC)

    # Min. epsilon settings (drawn in ui/units.py)
    show_min_epsilon: BoolProperty(
        name="Advanced LuxCore Settings",
        default=False,
        description="Show/Hide advanced LuxCore features. "
        "Only change them if you know what you are doing")
    min_epsilon: FloatProperty(
        name="Min. Epsilon",
        default=1e-5,
        soft_min=1e-6,
        soft_max=1e-1,
        precision=5,
        description=
        "User higher values when artifacts due to floating point precision "
        "issues appear in the rendered image")
    max_epsilon: FloatProperty(
        name="Max. Epsilon",
        default=1e-1,
        soft_min=1e-3,
        soft_max=1e+2,
        precision=5,
        description="Might need adjustment along with the min epsilon to avoid "
        "artifacts due to floating point precision issues")

    film_opencl_enable: BoolProperty(
        name="Use OpenCL",
        default=True,
        description=
        "Use OpenCL to accelerate tonemapping and other imagepipeline "
        "operations (applies to viewport and final render). "
        "Disabling this option will save a bit of RAM, especially if "
        "the render resolution is large. "
        "This option is ignored in Non-OpenCL builds")

    def film_opencl_device_items_callback(self, context):
        devices = context.scene.luxcore.opencl.devices
        items = [("none", "None", "", 0)]
        items += [(str(i), device.name, "", i + 1)
                  for i, device in enumerate(devices)
                  if device.type == "OPENCL_GPU"]
        # There is a known bug with using a callback,
        # Python must keep a reference to the strings
        # returned or Blender will misbehave or even crash.
        global film_opencl_device_items
        film_opencl_device_items = items
        return items

    film_opencl_device: EnumProperty(
        name="Device",
        items=film_opencl_device_items_callback,
        description="Which device to use to compute the imagepipeline")
Esempio n. 16
0
class SvLampOutNode(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: Lamp
    Tooltip: Generate Lamp objects
    """

    bl_idname = "SvLampOutNode"
    bl_label = "Lamp"
    bl_icon = "OUTLINER_OB_LAMP"

    activate = BoolProperty(name = "Activate",
        default=True,
        description='When enabled this will process incoming data',
        update=updateNode)

    lamp_name = StringProperty(
        default='Lamp_Alpha',
        update=updateNode,
        description="sets which base name the object will use")

    lamp_types = [
            ("POINT", "Point", "Omnidirectional point light source", "LAMP_POINT", 0),
            ("SUN", "Sun", "Constant direction parallel light source", "LAMP_SUN", 1),
            ("SPOT", "Spot", "Direcitonal cone light source", "LAMP_SPOT", 2),
            ("HEMI", "Hemi", "180 degrees constant light source (not supported in Cycles)", "LAMP_HEMI", 3),
            ("AREA", "Area", "Directional area light source", "LAMP_AREA", 4)
        ]
    
    def update_type(self, context):
        is_spot = (self.type == 'SPOT')
        self.inputs['Spot Size'].hide_safe = not is_spot
        self.inputs['Spot Blend'].hide_safe = not is_spot
        updateNode(self, context)

    type = EnumProperty(name = "Type",
            description = "Light source type",
            items = lamp_types,
            default = "POINT",
            update = update_type)

    area_types = [
            ("RECTANGLE", "Rectangle", "Rectangular area", 0),
            ("SQUARE", "Square", "Square area", 1)
        ]

    def update_area_type(self, context):
        square = (self.type != 'AREA' or self.area_type == 'SQUARE')
        self.inputs['Size'].hide_safe = not square
        self.inputs['Size X'].hide_safe = square
        self.inputs['Size Y'].hide_safe = square
        updateNode(self, context)

    area_type = EnumProperty(name = "Area type",
            description = "Area shape type",
            default = "RECTANGLE",
            items = area_types,
            update = update_area_type)

    size = FloatProperty(name = "Size",
            description = "Light source size",
            default = 0.1,
            update=updateNode)

    size_x = FloatProperty(name = "Size X",
            description = "Light source size",
            default = 0.1,
            update=updateNode)
    size_y = FloatProperty(name = "Size Y",
            description = "Light source size",
            default = 0.1,
            update=updateNode)

    spot_size = FloatProperty(name = "Spot Size",
            description = "Angle of the spotlight beam (degrees)",
            default = 45.0, min = 0.0, max = 180.0,
            update=updateNode)

    spot_blend = FloatProperty(name = "Spot Blend",
            description = "The softness of the spotlight edge",
            default = 0.15, min=0.0, max=1.0,
            update=updateNode)

    strength = FloatProperty(name = "Strength",
            description = "Lamp power",
            default = 100.0, min=0.0, max=1000000,
            update=updateNode)

    show_cone = BoolProperty(name = "Show cone",
            description = "Draw transparent cone in the 3D View",
            default = False,
            update=updateNode)

    max_bounces = IntProperty(name = "Max Bounces",
            description = "Maximum number of bounces the lamp will contribute to the render",
            min = 1, max = 1000000, default = 1024,
            update=updateNode)

    cast_shadow = BoolProperty(name = "Cast shadow",
            description = "Lamp casts shadows",
            default = True,
            update=updateNode)

    multiple_imporance = BoolProperty(name = "Multiple importance",
            description = "Use multiple importance sampling for the lamp",
            default = True,
            update=updateNode)

    use_nodes = BoolProperty(name = "Use Nodes",
            description = "Use node tree instead of directly specified color",
            default = True,
            update=updateNode)

    light_color = FloatVectorProperty(name = "Color",
        description = "Light color",
        update=updateNode, default=(1.0, 1.0, 1.0, 1.0),
        size=4, min=0.0, max=1.0, subtype='COLOR'
    )

    emission_node_name = StringProperty(name = "Emission Node",
            description = "Name of Emission node in the lamp shader, that contains Sthrength and Color inputs",
            default = "Emission",
            update=updateNode)

    def sv_init(self, context):
        self.inputs.new('MatrixSocket', 'Origin')
        self.inputs.new('StringsSocket', 'Size').prop_name = 'size'

        i = self.inputs.new('StringsSocket', 'Size X')
        i.prop_name = 'size_x'
        i.hide_safe = True

        i = self.inputs.new('StringsSocket', 'Size Y')
        i.prop_name = 'size_y'
        i.hide_safe = True

        i = self.inputs.new('StringsSocket', 'Spot Size')
        i.prop_name = 'spot_size'
        i.hide_safe = True

        i = self.inputs.new('StringsSocket', 'Spot Blend')
        i.prop_name = 'spot_blend'
        i.hide_safe = True

        i = self.inputs.new('StringsSocket', 'Strength')
        i.prop_name = 'strength'

        color_socket = self.inputs.new('SvColorSocket', "Color")
        color_socket.prop_name = 'light_color'

        self.outputs.new('SvObjectSocket', 'Objects')

    def draw_buttons(self, context, layout):
        view_icon = 'OUTLINER_OB_LAMP' if self.activate else 'ERROR'
        layout.prop(self, "activate", text="UPD", toggle=True, icon=view_icon)
        layout.prop(self, 'lamp_name')
        layout.prop(self, 'type')
        if self.type == 'AREA':
            layout.prop(self, 'area_type')

    def draw_buttons_ext(self, context, layout):
        self.draw_buttons(context, layout)
        layout.prop(self, 'use_nodes')
        layout.prop(self, 'max_bounces')
        layout.prop(self, 'cast_shadow')
        layout.prop(self, 'multiple_imporance')
        if self.type == 'SPOT':
            layout.prop(self, 'show_cone')
        layout.prop(self, 'emission_node_name')

    def get_children(self):
        objects = bpy.data.objects
        objs = [obj for obj in objects if obj.type == 'LAMP']
        # critera, basename must be in object.keys and the value must be self.basemesh_name
        return [o for o in objs if o.get('basename') == self.lamp_name]

    def make_lamp(self, index, object):
        origin, size, size_x, size_y, strength, spot_size, spot_blend, color = object

        if get_data_nesting_level(color) == 2:
            color = color[0]
        if isinstance(size, (list, tuple)):
            size = size[0]
        if isinstance(size_x, (list, tuple)):
            size_x = size_x[0]
        if isinstance(size_y, (list, tuple)):
            size_y = size_y[0]
        if isinstance(strength, (list, tuple)):
            strength = strength[0]
        if isinstance(spot_size, (list, tuple)):
            spot_size = spot_size[0]
        if isinstance(spot_blend, (list, tuple)):
            spot_blend = spot_blend[0]

        scene = bpy.context.scene
        lamps_data = bpy.data.lamps
        objects = bpy.data.objects
        name = self.lamp_name + "_" + str(index)

        if name in objects:
            lamp_object = objects[name]
            if lamp_object.data.type != self.type:
                lamp_object.data.type = self.type
        else:
            lamp_data = lamps_data.new(name = name, type = self.type)
            lamp_object = objects.new(name = name, object_data = lamp_data)
            scene.objects.link(lamp_object)

        lamp_object['idx'] = index
        lamp_object['madeby'] = self.name
        lamp_object['basename'] = self.lamp_name
        
        lamp_object.matrix_local = origin

        lamp = lamp_object.data

        lamp.type = self.type
        lamp.color = color[:3]
        if self.type in ('POINT', 'SUN', 'SPOT'):
            lamp.shadow_soft_size = size
        elif self.type == 'AREA' and self.area_type == 'SQUARE':
            lamp.shape = 'SQUARE'
            lamp.size = size
        elif self.type == 'AREA' and self.area_type == 'RECTANGLE':
            lamp.shape = 'RECTANGLE'
            lamp.size = size_x
            lamp.size_y = size_y
        
        if self.type == 'SPOT':
            lamp.spot_size = radians(spot_size)
            lamp.spot_blend = spot_blend
            lamp.show_cone = self.show_cone

        if lamp.cycles:
            lamp.cycles.max_bounces = self.max_bounces
            lamp.cycles.cast_shadow = self.cast_shadow
            lamp.cycles.use_multiple_importance_sampling = self.multiple_imporance
            lamp.use_nodes = True

            if self.emission_node_name and self.emission_node_name in lamp.node_tree.nodes:
                node = lamp.node_tree.nodes[self.emission_node_name]
                node.inputs['Strength'].default_value = strength
                if len(color) != 4:
                    raise Exception("Color data must contain 4 floats (RGBA), not {}".format(len(color)))
                node.inputs['Color'].default_value = color

    def process(self):

        if not self.activate:
            return

        origins = self.inputs['Origin'].sv_get()
        sizes_sq = self.inputs['Size'].sv_get()
        sizes_x = self.inputs['Size X'].sv_get()
        sizes_y = self.inputs['Size Y'].sv_get()
        spot_sizes = self.inputs['Spot Size'].sv_get()
        spot_blends = self.inputs['Spot Blend'].sv_get()
        strengths = self.inputs['Strength'].sv_get()
        colors = self.inputs['Color'].sv_get()
        # next is not needed
        # if get_data_nesting_level(colors) == 3:
            # colors = colors[0]

        objects = match_long_repeat([origins, sizes_sq, sizes_x, sizes_y, strengths, spot_sizes, spot_blends, colors])

        for index, object in enumerate(zip(*objects)):
            self.make_lamp(index, object)

        self.remove_non_updated_objects(index)

        objs = self.get_children()
        self.outputs['Objects'].sv_set(objs)

    def remove_non_updated_objects(self, obj_index):
        objs = self.get_children()
        objs = [obj.name for obj in objs if obj['idx'] > obj_index]
        if not objs:
            return

        lamps_data = bpy.data.lamps
        objects = bpy.data.objects
        scene = bpy.context.scene

        # remove excess objects
        for object_name in objs:
            obj = objects[object_name]
            obj.hide_select = False
            scene.objects.unlink(obj)
            objects.remove(obj, do_unlink=True)

        # delete associated lamps data
        for object_name in objs:
            lamps_data.remove(lamps_data[object_name])
Esempio n. 17
0
class BAS_OT_mask_extractor(Operator):
    """Extracts the masked area to create a new mesh"""
    bl_idname = "bas.mask_extractor"
    bl_label = "Mask Extractor"
    bl_options = {'REGISTER', 'UNDO'}

    offset : FloatProperty(min = -10.0, max = 10.0, default = 0.1, name="Offset")
    thickness : FloatProperty(min = 0.0, max = 10.0, default = 0.5, name="Thickness")
    smoothPasses : IntProperty(min = 0, max = 30, default = 4, name="Smooth Passes")  
    mode : EnumProperty(name="Extract Mode",
                     items = (("SOLID","Solid",""),
                              ("SINGLE","One Sided",""),
                              ("FLAT","Flat","")),
                     default = "SOLID", description="Mode in how to apply the mesh extraction"
    )
    superSmooth : BoolProperty(default = False, name="Super Smooth")
    
    @classmethod
    def poll(cls, context):
        return context.active_object is not None and context.active_object.mode == 'SCULPT'
    
    def draw(self, context): 
        layout = self.layout
        layout.prop(self, "mode", text="Mode")
        layout.prop(self, "thickness", text="Thickness")
        #layout.prop(self, "offset", text="Offset")
        layout.prop(self, "smoothPasses", text="Smooth Passes")
    
    def execute(self, context):
        activeObj = context.active_object
        
        # This is a hackish way to support redo functionality despite sculpt mode having its own undo system.
        # The set of conditions here is not something the user can create manually from the UI.
        # Unfortunately I haven't found a way to make Undo itself work
        if  2>len(bpy.context.selected_objects)>0 and \
            context.selected_objects[0] != activeObj and \
            context.selected_objects[0].name.startswith("Extracted_"):
            rem = context.selected_objects[0]
            remname = rem.data.name
            bpy.data.scenes.get(context.scene.name).objects.unlink(rem) # checkear esto
            bpy.data.objects.remove(rem)
            # remove mesh to prevent memory being cluttered up with hundreds of high-poly objects
            bpy.data.meshes.remove(bpy.data.meshes[remname])
        
        # For multires we need to copy the object and apply the modifiers
        try:
            if activeObj.modifiers["Multires"]:
                use_multires = True
                objCopy = helper.objDuplicate(activeObj)
                context.view_layer.objects.active = objCopy
                bpy.ops.object.mode_set(mode='OBJECT')
                bpy.ops.boolean.mod_apply()
        except:
            use_multires = False
            pass
            
        bpy.ops.object.mode_set(mode='EDIT')
        
        # Automerge will collapse the mesh so we need it off.
        if context.scene.tool_settings.use_mesh_automerge:
            automerge = True
            bpy.data.scenes[context.scene.name].tool_settings.use_mesh_automerge = False
        else:
            automerge = False

        # Until python can read sculpt mask data properly we need to rely on the hiding trick
        #bpy.ops.mesh.select_all(action='SELECT')
        #bpy.ops.mesh.normals_make_consistent()
        bpy.ops.mesh.select_all(action='DESELECT')
        bpy.ops.object.mode_set(mode='SCULPT')
        bpy.ops.paint.hide_show(action='HIDE', area='MASKED')
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.select_mode(type="FACE")
        bpy.ops.mesh.reveal()
        bpy.ops.mesh.duplicate_move(MESH_OT_duplicate=None, TRANSFORM_OT_translate=None)
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.select_all(action = 'DESELECT')
        bpy.ops.object.mode_set(mode='EDIT')

        #print(context.active_object)
        #print(context.view_layer.objects.active)

        # For multires we already have a copy, so lets use that instead of separate.
        if use_multires == True:
            bpy.ops.mesh.select_all(action='INVERT')
            bpy.ops.mesh.delete(type='FACE')
            context.view_layer.objects.active = objCopy
        else:
            try:
                bpy.ops.mesh.separate(type="SELECTED")
                context.view_layer.objects.active = context.selected_objects[0] #bpy.context.window.scene.objects[0] #context.selected_objects[0]
            except:
                bpy.ops.object.mode_set(mode='SCULPT')
                bpy.ops.paint.hide_show(action='SHOW', area='ALL')
                return {'FINISHED'}
        bpy.ops.object.mode_set(mode='OBJECT')
        
        # Rename the object for disambiguation
        context.view_layer.objects.active.name = "Extracted_" + context.view_layer.objects.active.name
        #bpy.ops.object.mode_set(mode='EDIT')
        #print(context.active_object)
        #print(context.view_layer.objects.active)
        
        # Solid mode should create a two-sided mesh
        if self.mode == 'SOLID':
            '''
            if self.superSmooth:
                # Seleccion de borde entre malla extraida y malla original
                bpy.ops.object.mode_set(mode='EDIT')
                bpy.ops.mesh.select_all(action='DESELECT')
                bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE', action='TOGGLE')
                bpy.ops.mesh.select_non_manifold()
                # Aumentar seleccion en 1
                bpy.ops.mesh.select_more()
                # Invertir
                bpy.ops.mesh.select_all(action='INVERT')
                # Añadir al vertex group 
                bpy.ops.object.vertex_group_add()
                bpy.ops.object.vertex_group_assign()
                # Guardar referencia para más tarde
                ob = context.object
                group = ob.vertex_groups.active
            '''
            bpy.ops.object.mode_set(mode='OBJECT')
            obj = context.active_object
            if self.smoothPasses > 0: # aplicar smooth inicial solo si los pases son mayores a 0
                smooth = obj.modifiers.new(name="Smooth", type='SMOOTH')
                smooth.iterations = self.smoothPasses
                bpy.ops.object.modifier_apply(modifier="Smooth")
            solidi = obj.modifiers.new(name="Solid", type='SOLIDIFY')
            solidi.thickness = self.thickness
            solidi.offset = 1 # add later
            solidi.thickness_clamp = 0
            solidi.use_rim = True
            solidi.use_rim_only = False
            bpy.ops.object.modifier_apply(modifier="Solid")
            if self.superSmooth: # post-smooth para suavizarlo mucho más
                #bpy.ops.object.vertex_group_select()
                #smooth = obj.modifiers.new(name="Smooth", type='SMOOTH')
                #smooth.iterations = self.smoothPasses
                #smooth.vertex_group = group.name
                #bpy.ops.object.modifier_apply(modifier="Smooth")
                co_smooth = obj.modifiers.new(name="Co_Smooth", type='CORRECTIVE_SMOOTH')
                co_smooth.iterations = 30
                co_smooth.smooth_type = 'LENGTH_WEIGHTED'
                co_smooth.use_only_smooth = True
                bpy.ops.object.modifier_apply(modifier="Co_Smooth")

        elif self.mode == 'SINGLE':
            bpy.ops.object.mode_set(mode='OBJECT')
            obj = context.active_object
            if self.smoothPasses > 0 and self.superSmooth==False:
                smooth = obj.modifiers.new(name="Smooth", type='SMOOTH')
                smooth.iterations = self.smoothPasses
                bpy.ops.object.modifier_apply(modifier="Smooth")
            solidi = obj.modifiers.new(name="Solid", type='SOLIDIFY')
            solidi.thickness = self.thickness
            solidi.offset = 1 # add later
            solidi.thickness_clamp = 0
            solidi.use_rim = True
            solidi.use_rim_only = True # only one sided
            bpy.ops.object.modifier_apply(modifier="Solid")
            if self.superSmooth: # post-smooth para suavizarlo mucho más
                # Seleccion de borde entre malla extraida y malla original
                bpy.ops.object.mode_set(mode='EDIT')
                bpy.ops.mesh.select_all(action='DESELECT')
                bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT', action='TOGGLE')    
                bpy.ops.mesh.select_non_manifold()
                # Invertir
                bpy.ops.mesh.select_all(action='INVERT')
                # Añadir al vertex group 
                bpy.ops.object.vertex_group_add()
                bpy.ops.object.vertex_group_assign()
                # Aplica smooth
                bpy.ops.object.mode_set(mode='OBJECT')
                smooth = obj.modifiers.new(name="Smooth", type='SMOOTH')
                smooth.factor = 1.5
                smooth.iterations = 30 # valor máximo
                smooth.vertex_group = context.object.vertex_groups.active.name # usa vertex group
                bpy.ops.object.modifier_apply(modifier="Smooth")
                # trick scale to close up the extracted mesh to original mesh due to smooth # not necessary now

            
        elif self.mode == 'FLAT':
            pass
            ''' OLD
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.select_all(action='SELECT')
            n = 0
            while n < self.smoothPasses:
                bpy.ops.mesh.vertices_smooth()
                n+=1
            #bpy.ops.mesh.solidify(thickness=0)
            '''

            # later will add close mesh bool
            
        # clear mask on the extracted mesh
        bpy.ops.object.mode_set(mode='SCULPT')
        bpy.ops.paint.mask_flood_fill(mode='VALUE', value=0)
        
        bpy.ops.object.mode_set(mode='OBJECT')

        # make sure to recreate the odd selection situation for redo
        if use_multires:
            bpy.ops.object.select_pattern(pattern=context.active_object.name, case_sensitive=True, extend=False)

        #bpy.ops.object.select_all(action = 'DESELECT')

        #context.view_layer.objects.active = activeObj
        
        # restore automerge
        if automerge:
            bpy.data.scenes[context.scene.name].tool_settings.use_mesh_automerge = True

        # restore mode for original object
        bpy.ops.object.mode_set(mode='SCULPT')
        bpy.ops.paint.hide_show(action='SHOW', area='ALL')
        #if(usingDyntopo):
        #    bpy.ops.sculpt.dynamic_topology_toggle()
        return {'FINISHED'}
Esempio n. 18
0
class SceneSCSProps(bpy.types.PropertyGroup):
    """
    SCS Tools Scene Variables - ...Scene.scs_props...
    :return:
    """

    part_list_sorted = BoolProperty(
        name="Part List Sorted Alphabetically",
        description="Sort Part list alphabetically",
        default=False,
    )

    variant_list_sorted = BoolProperty(
        name="Variant List Sorted Alphabetically",
        description="Sort Variant list alphabetically",
        default=False,
    )
    variant_views = EnumProperty(
        name="Variant View Setting",
        description="Variant view style options",
        items=(
            ('compact', "Compact",
             "Compact view (settings just for one Variant at a time)",
             'FULLSCREEN', 0),
            ('vertical', "Vertical",
             "Vertical long view (useful for larger number of Variants)",
             'LONGDISPLAY', 1),
            ('horizontal', "Horizontal",
             "Horizontal table view (best for smaller number of Variants)",
             'SHORTDISPLAY', 2),
            ('integrated', "Integrated",
             "Integrated in Variant list (best for smaller number of Parts)",
             'LINENUMBERS_OFF', 3),
        ),
        default='horizontal',
    )

    # VISIBILITY VARIABLES
    scs_look_panel_expand = BoolProperty(
        name="Expand SCS Look Panel",
        description="Expand SCS Look panel",
        default=True,
    )
    scs_part_panel_expand = BoolProperty(
        name="Expand SCS Part Panel",
        description="Expand SCS Part panel",
        default=True,
    )
    scs_variant_panel_expand = BoolProperty(
        name="Expand SCS Variant Panel",
        description="Expand SCS Variant panel",
        default=True,
    )
    empty_object_settings_expand = BoolProperty(
        name="Expand SCS Object Settings",
        description="Expand SCS Object settings panel",
        default=True,
    )
    locator_settings_expand = BoolProperty(
        name="Expand Locator Settings",
        description="Expand locator settings panel",
        default=True,
    )
    locator_display_settings_expand = BoolProperty(
        name="Expand Locator Display Settings",
        description="Expand locator display settings panel",
        default=False,
    )
    shader_item_split_percentage = FloatProperty(
        name="UI Split Percentage",
        description=
        "This property defines percentage of UI space spliting between material item names and values.",
        min=0.000001,
        max=1.0,
        default=0.35,
    )
    shader_attributes_expand = BoolProperty(
        name="Expand SCS Material Attributes",
        description="Expand SCS material attributes panel",
        default=True,
    )
    shader_textures_expand = BoolProperty(
        name="Expand SCS Material Textures",
        description="Expand SCS material textures panel",
        default=True,
    )
    shader_presets_expand = BoolProperty(
        name="Expand Shader Presets",
        description="Expand shader presets panel",
        default=False,
    )
    global_display_settings_expand = BoolProperty(
        name="Expand Global Display Settings",
        description="Expand global display settings panel",
        default=True,
    )
    global_paths_settings_expand = BoolProperty(
        name="Expand Global Paths Settings",
        description="Expand global paths settings panel",
        default=True,
    )
    scs_root_panel_settings_expand = BoolProperty(
        name="Expand 'SCS Root Object' Settings",
        description="Expand 'SCS Root Object' settings panel",
        default=True,
    )
    global_settings_expand = BoolProperty(
        name="Expand Global Settings",
        description="Expand global settings panel",
        default=True,
    )
    scene_settings_expand = BoolProperty(
        name="Expand Scene Settings",
        description="Expand scene settings panel",
        default=True,
    )
    scs_animation_settings_expand = BoolProperty(
        name="Expand Animation Settings",
        description="Expand animation settings panel",
        default=True,
    )
    scs_animplayer_panel_expand = BoolProperty(
        name="Expand Animation Player Settings",
        description="Expand animation player panel",
        default=True,
    )
    scs_skeleton_panel_expand = BoolProperty(
        name="Expand Skeleton Settings",
        description="Expand skeleton settings panel",
        default=True,
    )
    default_export_filepath = StringProperty(
        name="Default Export Path",
        description=
        "Relative export path (relative to SCS Project Base Path) for all SCS Game Objects without custom export path "
        "(this path does not apply when exporting via menu)",
        default="",
        # subtype="FILE_PATH",
        subtype='NONE',
    )
    export_panel_expand = BoolProperty(
        name="Expand Export Panel",
        description="Expand Export panel",
        default=True,
    )
    preview_export_selection = BoolProperty(
        name="Preview selection",
        description="Preview selection which will be exported",
        default=True,
    )
    preview_export_selection_active = BoolProperty(
        name="Flag indication if selection preview is active",
        description="",
        default=False,
    )

    # VISIBILITY TOOLS SCOPE
    visibility_tools_scope = EnumProperty(
        name="Visibility Tools Scope",
        description="Selects the scope upon visibility tools are working",
        items=(
            ('Global', "Global", "Use scope of the whole scene"),
            ('SCS Root', "SCS Root", "Use the scope of current SCS Root"),
        ),
    )

    # DRAWING MODE SETTINGS
    def drawing_mode_update(self, context):
        from io_scs_tools.internals.callbacks import open_gl as _open_gl_callback

        _open_gl_callback.enable(self.drawing_mode)

    drawing_mode = EnumProperty(
        name="Custom Drawing Mode",
        description=
        "Drawing mode for custom elements (Locators and Connections)",
        items=(
            ('Normal', "Normal", "Use normal depth testing drawing"),
            ('X-ray', "X-ray", "Use X-ray drawing"),
        ),
        update=drawing_mode_update)

    # PREVIEW SETTINGS
    def show_preview_models_update(self, context):
        """
        :param context:
        :return:
        """
        scene = context.scene

        for obj in bpy.data.objects:
            if obj.type == 'EMPTY':
                if scene.scs_props.show_preview_models:
                    if not _preview_models.load(obj):
                        _preview_models.unload(obj)
                else:
                    _preview_models.unload(obj)
        return None

    show_preview_models = BoolProperty(
        name="Show Preview Models",
        description="Show preview models for locators",
        default=True,
        update=show_preview_models_update)

    # SETTINGS WHICH GET SAVED IN CONFIG FILE
    def display_locators_update(self, context):
        _config_container.update_item_in_file('GlobalDisplay.DisplayLocators',
                                              int(self.display_locators))
        return None

    def locator_size_update(self, context):
        _config_container.update_item_in_file('GlobalDisplay.LocatorSize',
                                              self.locator_size)
        return None

    def locator_empty_size_update(self, context):
        _config_container.update_item_in_file('GlobalDisplay.LocatorEmptySize',
                                              self.locator_empty_size)
        return None

    def locator_prefab_wire_color_update(self, context):
        _config_container.update_item_in_file(
            'GlobalColors.PrefabLocatorsWire',
            tuple(self.locator_prefab_wire_color))
        return None

    def locator_model_wire_color_update(self, context):
        _config_container.update_item_in_file(
            'GlobalColors.ModelLocatorsWire',
            tuple(self.locator_model_wire_color))
        return None

    def locator_coll_wire_color_update(self, context):
        _config_container.update_item_in_file(
            'GlobalColors.ColliderLocatorsWire',
            tuple(self.locator_coll_wire_color))
        return None

    def locator_coll_face_color_update(self, context):
        _config_container.update_item_in_file(
            'GlobalColors.ColliderLocatorsFace',
            tuple(self.locator_coll_face_color))
        return None

    def display_connections_update(self, context):
        _config_container.update_item_in_file(
            'GlobalDisplay.DisplayConnections', int(self.display_connections))
        return None

    def optimized_connections_drawing_update(self, context):
        _config_container.update_item_in_file(
            'GlobalDisplay.OptimizedConnsDrawing',
            int(self.optimized_connections_drawing))
        return None

    def curve_segments_update(self, context):
        _config_container.update_item_in_file('GlobalDisplay.CurveSegments',
                                              self.curve_segments)
        return None

    def np_curve_color_update(self, context):
        _config_container.update_item_in_file(
            'GlobalColors.NavigationCurveBase',
            tuple(self.np_connection_base_color))
        return None

    def mp_line_color_update(self, context):
        _config_container.update_item_in_file(
            'GlobalColors.MapLineBase', tuple(self.mp_connection_base_color))
        return None

    def tp_line_color_update(self, context):
        _config_container.update_item_in_file(
            'GlobalColors.TriggerLineBase',
            tuple(self.tp_connection_base_color))
        return None

    def display_info_update(self, context):
        _config_container.update_item_in_file('GlobalDisplay.DisplayTextInfo',
                                              self.display_info)
        return None

    def info_text_color_update(self, context):
        _config_container.update_item_in_file('GlobalColors.InfoText',
                                              tuple(self.info_text_color))
        return None

    # SCS TOOLS GLOBAL SETTINGS - DISPLAY SETTINGS
    display_locators = BoolProperty(
        name="Display Locators",
        description="Display locators in 3D views",
        default=True,
        update=display_locators_update,
    )
    locator_size = FloatProperty(
        name="Locator Size",
        description="Locator display size in 3D views",
        default=1.0,
        min=0.1,
        max=50,
        options={'HIDDEN'},
        subtype='NONE',
        unit='NONE',
        update=locator_size_update,
    )
    locator_empty_size = FloatProperty(
        name="Locator Empty Object Size",
        description="Locator Empty object display size in 3D views",
        default=0.05,
        min=0.05,
        max=0.2,
        step=0.1,
        options={'HIDDEN'},
        subtype='NONE',
        unit='NONE',
        update=locator_empty_size_update,
    )
    locator_prefab_wire_color = FloatVectorProperty(
        name="Prefab Loc Color",
        description="Color for prefab locators in 3D views",
        options={'HIDDEN'},
        subtype='COLOR',
        min=0,
        max=1,
        default=(0.5, 0.5, 0.5),
        update=locator_prefab_wire_color_update,
    )
    locator_model_wire_color = FloatVectorProperty(
        name="Model Loc Color",
        description="Color for model locators in 3D views",
        options={'HIDDEN'},
        subtype='COLOR',
        min=0,
        max=1,
        # default=(0.25, 0.25, 0.25),
        default=(0.08, 0.12, 0.25),
        update=locator_model_wire_color_update,
    )
    locator_coll_wire_color = FloatVectorProperty(
        name="Collider Loc Wire Color",
        description="Color for collider locators' wireframe in 3D views",
        options={'HIDDEN'},
        subtype='COLOR',
        min=0,
        max=1,
        default=(0.5, 0.3, 0.1),
        update=locator_coll_wire_color_update,
    )
    locator_coll_face_color = FloatVectorProperty(
        name="Collider Loc Face Color",
        description="Color for collider locators' faces in 3D views",
        options={'HIDDEN'},
        subtype='COLOR',
        min=0,
        max=1,
        default=(0.15, 0.05, 0.05),
        # default=(0.065, 0.18, 0.3),
        update=locator_coll_face_color_update,
    )
    display_connections = BoolProperty(
        name="Display Connections",
        description="Display connections in 3D views",
        default=True,
        update=display_connections_update,
    )
    curve_segments = IntProperty(
        name="Curve Segments",
        description="Curve segment number for displaying in 3D views",
        default=16,
        min=4,
        max=64,
        step=1,
        options={'HIDDEN'},
        subtype='NONE',
        update=curve_segments_update,
    )
    optimized_connections_drawing = BoolProperty(
        name="Optimized Connections Draw",
        description=
        "Draw connections only when data are updated ( switching this off might give you FPS  )",
        default=False,
        update=optimized_connections_drawing_update,
    )
    np_connection_base_color = FloatVectorProperty(
        name="Nav Curves Color",
        description="Base color for navigation curves in 3D views",
        options={'HIDDEN'},
        subtype='COLOR',
        min=0,
        max=1,
        default=(0.0, 0.1167, 0.1329),
        update=np_curve_color_update,
    )
    mp_connection_base_color = FloatVectorProperty(
        name="Map Line Color",
        description="Base color for map line connections in 3D views",
        options={'HIDDEN'},
        subtype='COLOR',
        min=0,
        max=1,
        default=(0.0, 0.2234, 0.0982),
        update=mp_line_color_update,
    )
    tp_connection_base_color = FloatVectorProperty(
        name="Trigger Line Color",
        description="Base color for trigger line connections in 3D views",
        options={'HIDDEN'},
        subtype='COLOR',
        min=0,
        max=1,
        default=(0.1706, 0.0, 0.0593),
        update=tp_line_color_update,
    )
    display_info = EnumProperty(
        name="Display Text Info",
        description="Display additional text information in 3D views",
        items=(
            ('none', "None", "No additional information displayed in 3D view"),
            ('locnames', "Locator Names",
             "Display locator names only in 3D view"),
            # ('locspeed', "Locator Nav. Points - Speed Limits", "Display navigation point locator speed limits in 3D view"),
            ('locnodes', "Locator Nav. Points - Boundary Nodes",
             "Display navigation point locator boundary node numbers in 3D view"
             ),
            ('loclanes', "Locator Nav. Points - Boundary Lanes",
             "Display navigation point locator boundary lanes in 3D view"),
            ('locinfo', "Locator Comprehensive Info",
             "Display comprehensive information for locators in 3D view"),
        ),
        default='none',
        update=display_info_update,
    )
    info_text_color = FloatVectorProperty(
        name="Info Text Color",
        description="Base color for information text in 3D views",
        options={'HIDDEN'},
        subtype='COLOR',
        min=0,
        max=1,
        default=(1.0, 1.0, 1.0),
        update=info_text_color_update,
    )
Esempio n. 19
0
class LDRImporterOps(bpy.types.Operator, ImportHelper):
    """LDR Importer Operator."""

    bl_idname = "import_scene.ldraw"
    bl_description = "Import an LDraw model (.ldr/.dat)"
    bl_label = "Import LDraw Model"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_options = {'REGISTER', 'UNDO', 'PRESET'}

    # File type filter in file browser
    filename_ext = ".ldr"

    filter_glob = StringProperty(default="*.ldr;*.dat", options={'HIDDEN'})

    # The installation path was defined, use it
    if LDrawDirs[3] != r"":
        FinalLDrawDir = LDrawDirs[3]

    # The installation path was not defined, fall back to defaults
    # On Windows, this means attempting to detect the installation
    else:

        # Run Windows installation path detection process
        if sys.platform == "win32":
            findWinLDrawDir()

        FinalLDrawDir = {
            "win32": LDrawDirs[0],
            "darwin": LDrawDirs[1]
        }.get(sys.platform, LDrawDirs[2])

    debugPrint('''The LDraw Parts Library installation path to be used is
{0}'''.format(FinalLDrawDir))

    ldrawPath = StringProperty(name="",
                               description="Path to the LDraw Parts Library",
                               default=FinalLDrawDir,
                               update=RunMe)

    # Import options

    scale = FloatProperty(name="Scale",
                          description="Use a specific scale for each brick",
                          default=1.00)

    resPrims = EnumProperty(name="Resolution of part primitives",
                            description="Resolution of part primitives",
                            items=primsOptions)

    cleanUpModel = EnumProperty(name="Model Cleanup Options",
                                description="Model Cleanup Options",
                                items=cleanupOptions)

    addGaps = BoolProperty(name="Spaces Between Bricks",
                           description="Add small spaces between each brick",
                           default=False)

    lsynthParts = BoolProperty(name="Use LSynth Parts",
                               description="Use LSynth parts during import",
                               default=False)

    def draw(self, context):
        """Display import options."""
        layout = self.layout
        box = layout.box()
        box.label("Import Options", icon='SCRIPTWIN')
        box.label("LDraw Path", icon='FILESEL')
        box.prop(self, "ldrawPath")
        box.prop(self, "scale")
        box.label("Primitives", icon='MOD_BUILD')
        box.prop(self, "resPrims", expand=True)
        box.label("Model Cleanup", icon='EDIT')
        box.prop(self, "cleanUpModel", expand=True)
        box.label("Additional Options", icon='PREFERENCES')
        box.prop(self, "addGaps")
        box.prop(self, "lsynthParts")

    def execute(self, context):
        """Set import options and run the script."""
        global LDrawDir, CleanUpOpt, GapsOpt
        LDrawDir = str(self.ldrawPath)
        WhatRes = str(self.resPrims)
        CleanUpOpt = str(self.cleanUpModel)
        GapsOpt = bool(self.addGaps)
        LSynth = bool(self.lsynthParts)

        # Clear array before adding data if it contains data already
        # Not doing so duplicates the indexes
        try:
            if paths[0]:
                del paths[:]
        except IndexError:
            pass

        # Create placeholder for index 0.
        # It will be filled with the location of the model later.
        paths.append("")

        # Always search for parts in the `models` folder
        paths.append(os.path.join(LDrawDir, "models"))

        # The unofficial folder exists, search the standard folders
        if os.path.exists(os.path.join(LDrawDir, "unofficial")):
            paths.append(os.path.join(LDrawDir, "unofficial", "parts"))

            # The user wants to use high-res unofficial primitives
            if WhatRes == "HighRes":
                paths.append(os.path.join(LDrawDir, "unofficial", "p", "48"))
            # The user wants to use low-res unofficial primitives
            elif WhatRes == "LowRes":
                paths.append(os.path.join(LDrawDir, "unofficial", "p", "8"))

            # Search in the `unofficial/p` folder
            paths.append(os.path.join(LDrawDir, "unofficial", "p"))

            # The user wants to use LSynth parts
            if LSynth:
                if os.path.exists(
                        os.path.join(LDrawDir, "unofficial", "lsynth")):
                    paths.append(os.path.join(LDrawDir, "unofficial",
                                              "lsynth"))
                    debugPrint("Use LSynth Parts selected")

        # Always search for parts in the `parts` folder
        paths.append(os.path.join(LDrawDir, "parts"))

        # The user wants to use high-res primitives
        if WhatRes == "HighRes":
            paths.append(os.path.join(LDrawDir, "p", "48"))
            debugPrint("High-res primitives substitution selected")

        # The user wants to use low-res primitives
        elif WhatRes == "LowRes":
            paths.append(os.path.join(LDrawDir, "p", "8"))
            debugPrint("Low-res primitives substitution selected")

        # The user wants to use normal-res primitives
        else:
            debugPrint("Standard-res primitives substitution selected")

        # Finally, search in the `p` folder
        paths.append(os.path.join(LDrawDir, "p"))
        """
        Blender for Windows does not like the 'update' key in ldrawPath{},
        so force it to run. We can run the process directly,
        rather than going through RunMe().
        """
        if sys.platform == "win32":
            saveInstallPath(self)

        create_model(self, context, self.scale)
        return {'FINISHED'}
Esempio n. 20
0
class LuxCoreNodeTexImagemap(bpy.types.Node, LuxCoreNodeTexture):
    bl_label = "Imagemap"
    bl_width_default = 200

    def update_image(self, context):
        self.image_user.update(self.image)
        if self.image:
            # Seems like we still need this.
            # User counting does not work reliably with Python PointerProperty.
            # Sometimes, this node is not counted as user.
            self.image.use_fake_user = True
        utils_node.force_viewport_update(self, context)

    image: PointerProperty(name="Image", type=bpy.types.Image, update=update_image)
    image_user: PointerProperty(update=utils_node.force_viewport_update, type=LuxCoreImageUser)

    channel_items = [
        ("default", "Default", "Do not convert the image cannels", 0),
        ("rgb", "RGB", "Use RGB color channels", 1),
        ("red", "Red", "Use only the red color channel", 2),
        ("green", "Green", "Use only the green color channel", 3),
        ("blue", "Blue", "Use only the blue color channel", 4),
        ("alpha", "Alpha", "Use only the alpha channel", 5),
        ("mean", "Mean (Average)", "Greyscale", 6),
        ("colored_mean", "Mean (Luminance)", "Greyscale", 7),
    ]
    channel: EnumProperty(update=utils_node.force_viewport_update, name="Channel", items=channel_items, default="default")

    wrap_items = [
        ("repeat", "Repeat", "", 0),
        ("clamp", "Clamp", "Extend the pixels of the border", 3),
        ("black", "Black", "", 1),
        ("white", "White", "", 2),
    ]
    wrap: EnumProperty(update=utils_node.force_viewport_update, name="Wrap", items=wrap_items, default="repeat")

    gamma: FloatProperty(update=utils_node.force_viewport_update, name="Gamma", default=2.2, soft_min=0, soft_max=5,
                          description="Most LDR images with sRgb colors use gamma 2.2, "
                                      "while most HDR images with linear colors use gamma 1")
    brightness: FloatProperty(update=utils_node.force_viewport_update, name="Brightness", default=1,
                               description="Brightness multiplier")

    def update_is_normal_map(self, context):
        color_output = self.outputs["Color"]
        bump_output = self.outputs["Bump"]
        alpha_output = self.outputs["Alpha"]
        was_color_enabled = color_output.enabled

        color_output.enabled = not self.is_normal_map
        alpha_output.enabled = not self.is_normal_map
        bump_output.enabled = self.is_normal_map

        utils_node.copy_links_after_socket_swap(color_output, bump_output, was_color_enabled)
        utils_node.force_viewport_update(self, context)

    is_normal_map: BoolProperty(name="Normalmap", default=False, update=update_is_normal_map,
                                 description=NORMAL_MAP_DESC)
    normal_map_scale: FloatProperty(update=utils_node.force_viewport_update, name="Height", default=1, min=0, soft_max=5,
                                     description=NORMAL_SCALE_DESC)
    normal_map_orientation_items = [
        ("opengl", "OpenGL", "Select if the image is a left-handed normal map", 0),
        ("directx", "DirectX", "Select if the image is a right-handed normal map (inverted green channel)", 1),
    ]
    normal_map_orientation: EnumProperty(update=utils_node.force_viewport_update, name="Orientation", items=normal_map_orientation_items, default="opengl")

    # This function assigns self.image to all faces of all objects using this material
    # and assigns self.image to all image editors that do not have their image pinned.
    def update_set_as_active_uvmap(self, context):
        # TODO 2.8 (Do we even still need this, or can we do something better with Eevee nodes?)
        raise NotImplementedError()
        # if not self.set_as_active_uvmap:
        #     return
        # # Reset button to "unclicked"
        # self["set_as_active_uvmap"] = False
        #
        # if not context.object:
        #     return
        # material = context.object.active_material
        #
        # for obj in context.scene.objects:
        #     for mat_index, slot in enumerate(obj.material_slots):
        #         if slot.material == material:
        #             mesh = obj.data
        #             if hasattr(mesh, "uv_textures") and mesh.uv_textures:
        #                 uv_faces = mesh.uv_textures.active.data
        #                 polygons = mesh.polygons
        #                 # Unfortunately the uv_face has no information about the material
        #                 # that is assigned to the face, so we have to get this information
        #                 # from the polygons of the mesh
        #                 for uv_face, polygon in zip(uv_faces, polygons):
        #                     if polygon.material_index == mat_index:
        #                         uv_face.image = self.image
        #
        # for space in utils_ui.get_all_spaces(context, "IMAGE_EDITOR", "IMAGE_EDITOR"):
        #     # Assign image in all image editors that do not have pinning enabled
        #     if not space.use_image_pin:
        #         space.image = self.image

    # Note: the old "use a property as a button because it is so much simpler" trick
    set_as_active_uvmap: BoolProperty(name="Show in Viewport", default=False,
                                       update=update_set_as_active_uvmap,
                                       description="Show this image map on all objects with this material")

    show_thumbnail: BoolProperty(name="", default=True, description="Show thumbnail")

    def init(self, context):
        self.add_input("LuxCoreSocketMapping2D", "2D Mapping")

        self.outputs.new("LuxCoreSocketColor", "Color")
        self.outputs.new("LuxCoreSocketFloatUnbounded", "Alpha")
        self.outputs.new("LuxCoreSocketBump", "Bump")
        self.outputs["Bump"].enabled = False

    def draw_label(self):
        if self.image:
            return self.image.name
        else:
            return self.bl_label

    def draw_buttons(self, context, layout):
        row = layout.row()
        row.prop(self, "show_thumbnail", icon=icons.IMAGE)
        # row.prop(self, "set_as_active_uvmap", toggle=True)  # TODO 2.8
        if self.show_thumbnail:
            layout.template_ID_preview(self, "image", open="image.open")
        else:
            layout.template_ID(self, "image", open="image.open")

        col = layout.column()
        col.active = self.image is not None

        col.prop(self, "is_normal_map")
        if self.image:
            col.prop(self.image, "source")

        if self.is_normal_map:
            col.prop(self, "normal_map_scale")
            col.prop(self, "normal_map_orientation")
        else:
            col.prop(self, "channel")

        col.prop(self, "wrap")

        if not self.is_normal_map:
            col.prop(self, "gamma")
            col.prop(self, "brightness")

        # Info about UV mapping (only show if default is used,
        # when no mapping node is linked)
        if not self.inputs["2D Mapping"].is_linked:
            utils_node.draw_uv_info(context, col)

        self.image_user.draw(col, context.scene)

    def sub_export(self, exporter, depsgraph, props, luxcore_name=None, output_socket=None):
        if self.image is None:
            if self.is_normal_map:
                return [0.5, 0.5, 1.0]
            else:
                return [0, 0, 0]

        try:
            filepath = ImageExporter.export(self.image, self.image_user, exporter.scene)
        except OSError as error:
            msg = 'Node "%s" in tree "%s": %s' % (self.name, self.id_data.name, error)
            LuxCoreErrorLog.add_warning(msg)
            return [1, 0, 1]

        uvscale, uvrotation, uvdelta = self.inputs["2D Mapping"].export(exporter, depsgraph, props)

        definitions = {
            "type": "imagemap",
            "file": filepath,
            "wrap": self.wrap,
            # Mapping
            "mapping.type": "uvmapping2d",
            "mapping.uvscale": uvscale,
            "mapping.rotation": uvrotation,
            "mapping.uvdelta": uvdelta,
        }

        if self.is_normal_map:
            definitions.update({
                "channel": "rgb" if self.normal_map_orientation == "opengl" else "directx2opengl_normalmap",
                "gamma": 1,
                "gain": 1,
            })
        else:
            definitions.update({
                "channel": "alpha" if output_socket == self.outputs["Alpha"] else self.channel,
                "gamma": self.gamma,
                "gain": self.brightness,
            })

        luxcore_name = self.create_props(props, definitions, luxcore_name)

        if self.is_normal_map:
            # Implicitly create a normalmap
            tex_name = luxcore_name + "_normalmap"
            helper_prefix = "scene.textures." + tex_name + "."
            helper_defs = {
                "type": "normalmap",
                "texture": luxcore_name,
                "scale": self.normal_map_scale,
            }
            props.Set(utils.create_props(helper_prefix, helper_defs))

            # The helper texture gets linked in front of this node
            return tex_name
        else:
            return luxcore_name
Esempio n. 21
0
class OBJECT_OT_gem_add(Operator):
    bl_label = "Add Gem"
    bl_description = "Add gemstone to the scene"
    bl_idname = "object.jewelcraft_gem_add"
    bl_options = {"REGISTER", "UNDO"}

    cut: EnumProperty(name="Cut",
                      items=dynamic_list.cuts,
                      update=upd_set_weight)
    stone: EnumProperty(name="Stone",
                        items=dynamic_list.stones,
                        update=upd_set_weight)
    size: FloatProperty(
        name="Size",
        default=1.0,
        min=0.0001,
        step=5,
        precision=2,
        unit="LENGTH",
        update=upd_set_weight,
    )
    weight: FloatProperty(
        name="Carats",
        description="Round diamonds only",
        default=0.004,
        min=0.0001,
        step=0.1,
        precision=3,
        update=upd_weight,
    )

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False

        layout.prop(self, "size")
        col = layout.column()
        col.enabled = self.stone == "DIAMOND" and self.cut == "ROUND"
        col.prop(self, "weight")
        layout.prop(self, "stone")
        split = layout.split(factor=0.385)
        split.row()
        split.template_icon_view(self, "cut", show_labels=True)

    def execute(self, context):
        scene = context.scene
        view_layer = context.view_layer
        space_data = context.space_data
        cut_name = var.CUTS[self.cut].name
        stone_name = var.STONES[self.stone].name
        color = var.STONES[self.stone].color or self.color

        for ob in context.selected_objects:
            ob.select_set(False)

        imported = asset.asset_import(var.GEM_ASSET_FILEPATH, ob_name=cut_name)
        ob = imported.objects[0]
        context.collection.objects.link(ob)

        if space_data.local_view:
            ob.local_view_set(space_data, True)

        ob.scale *= self.size
        ob.location = scene.cursor.location
        ob.select_set(True)
        ob["gem"] = {"cut": self.cut, "stone": self.stone}

        asset.add_material(ob, name=stone_name, color=color, is_gem=True)

        if context.mode == "EDIT_MESH":
            asset.ob_copy_to_faces(ob)
            bpy.ops.object.mode_set(mode="OBJECT")

        view_layer.objects.active = ob

        return {"FINISHED"}

    def invoke(self, context, event):
        self.color = asset.color_rnd()

        wm = context.window_manager
        return wm.invoke_props_dialog(self)
Esempio n. 22
0
class SvFrameworkNode(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: Framework / carcass / ferme
    Tooltip: Generate construction framework
    """

    bl_idname = 'SvFrameworkNode'
    bl_label = 'Framework'
    bl_icon = 'OUTLINER_OB_EMPTY'
    sv_icon = 'SV_FRAMEWORK'

    offset: FloatProperty(name="Offset",
                          description="Vertices offset along orientation axis",
                          min=0,
                          max=1.0,
                          default=0,
                          update=updateNode)

    step: FloatProperty(
        name="Step",
        description="Step between vertices along orientation axis",
        min=0,
        default=1.0,
        update=updateNode)

    n_connections: IntProperty(
        name="Conections",
        description="How many vertices to connect to each vertex",
        min=0,
        default=1,
        update=updateNode)

    max_rho: FloatProperty(name="Max Distance",
                           description="Maximum generated edge length",
                           min=0,
                           default=1,
                           update=updateNode)

    count: IntProperty(name="Count",
                       description="How many vertices to generate",
                       min=1,
                       default=10,
                       update=updateNode)

    length: FloatProperty(name="Length",
                          description="Construction height / length",
                          min=0,
                          default=10,
                          update=updateNode)

    def update_mode(self, context):
        self.inputs['Offset'].hide_safe = self.z_mode != 'AXIS'
        self.inputs['Step'].hide_safe = self.z_mode != 'AXIS'
        self.inputs[
            'Count'].hide_safe = self.z_mode != 'AXIS' or self.len_mode != 'COUNT'
        self.inputs['Curve'].hide_safe = self.z_mode == 'AXIS'
        self.inputs['Length'].hide_safe = self.len_mode != 'LENGTH'
        updateNode(self, context)

    z_modes = [("AXIS", "Axis", "Generate framework along X, Y, or Z axis", 0),
               ("CURVE", "Curve", "Generate framework along arbitrary curve",
                1)]

    z_mode: EnumProperty(name="Mode",
                         description="Third dimension generation mode",
                         default="AXIS",
                         items=z_modes,
                         update=update_mode)

    axes = [("X", "X", "X axis", 1), ("Y", "Y", "Y axis", 2),
            ("Z", "Z", "Z axis", 3)]

    orient_axis: EnumProperty(name="Orientation axis",
                              description="Framework orientation axis",
                              default="Z",
                              items=axes,
                              update=updateNode)

    len_modes = [("COUNT", "Count", "Specify vertices count", 0),
                 ("LENGTH", "Length", "Specify edges length", 1)]

    len_mode: EnumProperty(name="Length mode",
                           description="How vertices count is specified",
                           default='COUNT',
                           items=len_modes,
                           update=update_mode)

    make_basis: BoolProperty(
        name="Basis",
        description="Always make baseline vertices (without offset)",
        default=False,
        update=updateNode)

    def draw_buttons(self, context, layout):
        layout.prop(self, "z_mode", expand=True)
        if self.z_mode == 'AXIS':
            layout.prop(self, "orient_axis", expand=True)
            layout.prop(self, "len_mode", expand=True)
            layout.prop(self, "make_basis", toggle=True)

    def sv_init(self, context):
        self.inputs.new('SvVerticesSocket', 'Vertices')
        self.inputs.new('SvStringsSocket', 'Edges')
        self.inputs.new('SvVerticesSocket', 'Curve')
        self.inputs.new('SvStringsSocket', 'Offset').prop_name = 'offset'
        self.inputs.new('SvStringsSocket', 'Step').prop_name = 'step'
        self.inputs.new('SvStringsSocket',
                        'NConnections').prop_name = 'n_connections'
        self.inputs.new('SvStringsSocket', 'MaxRho').prop_name = 'max_rho'
        self.inputs.new('SvStringsSocket', 'Count').prop_name = 'count'
        self.inputs.new('SvStringsSocket', 'Length').prop_name = 'length'

        self.outputs.new('SvVerticesSocket', 'Vertices')
        self.outputs.new('SvStringsSocket', 'Edges')
        self.outputs.new('SvStringsSocket', 'Faces')

        self.update_mode(context)

    def get_orientation_vector(self):
        if self.orient_axis == 'X':
            return Vector((1, 0, 0))
        elif self.orient_axis == 'Y':
            return Vector((0, 1, 0))
        else:
            return Vector((0, 0, 1))

    def is_same(self, v1, v2):
        if self.orient_axis == 'X':
            return v1.yz == v2.yz
        elif self.orient_axis == 'Y':
            return v1.xz == v2.xz
        else:
            return v1.xy == v2.xy

    def to_2d(self, v):
        if self.orient_axis == 'X':
            return v.yz
        elif self.orient_axis == 'Y':
            return v.xz
        else:
            return v.xy

    def is_same_edge(self, v1, v2, e1, e2):
        e1 = self.to_2d(e1)
        e2 = self.to_2d(e2)
        v1 = self.to_2d(v1)
        v2 = self.to_2d(v2)
        return is_in_segment(e1, e2, v1) or is_in_segment(e1, e2, v2)

    def process(self):
        if not any(s.is_linked for s in self.outputs):
            return

        verts_in = self.inputs['Vertices'].sv_get()
        edges_in = self.inputs['Edges'].sv_get()
        offset_in = self.inputs['Offset'].sv_get()
        step_in = self.inputs['Step'].sv_get()
        n_connections_in = self.inputs['NConnections'].sv_get()
        max_rhos_in = self.inputs['MaxRho'].sv_get()
        count_in = self.inputs['Count'].sv_get()
        length_in = self.inputs['Length'].sv_get()
        if self.z_mode == 'CURVE':
            curves_in = self.inputs['Curve'].sv_get()
        else:
            curves_in = [[]]

        verts_out = []
        edges_out = []
        faces_out = []

        Z = self.get_orientation_vector()
        if self.z_mode == 'AXIS':
            z_idx = 'XYZ'.index(self.orient_axis)
        else:
            z_idx = None

        objects = match_long_repeat([
            verts_in, edges_in, offset_in, step_in, n_connections_in,
            max_rhos_in, count_in, length_in, curves_in
        ])
        for verts, edges, offsets, steps, n_connections, max_rhos, counts, lengths, curves in zip(
                *objects):
            nverts = len(verts)
            offsets = cycle_for_length(offsets, nverts)
            steps = cycle_for_length(steps, nverts)
            n_connections = cycle_for_length(n_connections, nverts)
            max_rhos = cycle_for_length(max_rhos, nverts)
            if self.len_mode == 'COUNT':
                counts = cycle_for_length(counts, nverts)
                lengths = [None for i in range(nverts)]
            else:
                counts = [None for i in range(nverts)]
                lengths = cycle_for_length(lengths, nverts)

            if curves:
                curves = cycle_for_length(curves, nverts)

            bm = bmesh.new()
            bm.verts.ensure_lookup_table()

            verts_bm = []
            for i, v in enumerate(verts):
                if self.z_mode == 'AXIS':
                    verts_line = make_verts_axis(v, Z, self.make_basis,
                                                 steps[i] * offsets[i],
                                                 steps[i], counts[i],
                                                 lengths[i])
                else:
                    verts_line = make_verts_curve(v, curves[i])
                verts_line_bm = []
                prev_bm_vert = None
                for v in verts_line:
                    bm_vert = bm.verts.new(v)
                    verts_line_bm.append(bm_vert)
                    bm.verts.ensure_lookup_table()
                    if prev_bm_vert is not None:
                        bm.edges.new((prev_bm_vert, bm_vert))
                    prev_bm_vert = bm_vert
                verts_bm.append(verts_line_bm)

            for i, j in edges:
                process_edge(bm, z_idx, verts_bm[i], verts_bm[j], steps[i],
                             steps[j], n_connections[i], n_connections[j],
                             max_rhos[i], max_rhos[j])

            verts_new, edges_new, _ = pydata_from_bmesh(bm)
            bm.free()

            verts_new, edges_new = intersect_edges_3d(verts_new, edges_new,
                                                      1e-3)
            verts_new, edges_new, _ = remove_doubles(verts_new, edges_new, [],
                                                     1e-3)

            if self.outputs['Faces'].is_linked:
                bm = bmesh_from_pydata(verts_new,
                                       edges_new, [],
                                       normal_update=True)
                if self.z_mode == 'AXIS':
                    for i, j in edges:
                        side_edges = []
                        v_i = Vector(verts[i])
                        v_j = Vector(verts[j])
                        #self.info("Check: [%s - %s]", v_i, v_j)
                        for bm_edge in bm.edges:
                            bm_v1 = bm_edge.verts[0].co
                            bm_v2 = bm_edge.verts[1].co
                            if self.is_same_edge(bm_v1, bm_v2, v_i, v_j):
                                side_edges.append(bm_edge)
                                #self.info("Yes: [%s - %s]", bm_v1, bm_v2)
                            else:
                                pass
                                #self.info("No: [%s - %s]", bm_v1, bm_v2)

                        bmesh.ops.holes_fill(bm, edges=side_edges, sides=4)
                        bm.edges.ensure_lookup_table()
                        bm.faces.ensure_lookup_table()
                else:
                    bmesh.ops.holes_fill(bm, edges=bm.edges[:], sides=4)

                verts_new, edges_new, faces_new = pydata_from_bmesh(bm)
                bm.free()
            else:
                faces_new = []

            verts_out.append(verts_new)
            edges_out.append(edges_new)
            faces_out.append(faces_new)

        self.outputs['Vertices'].sv_set(verts_out)
        self.outputs['Edges'].sv_set(edges_out)
        self.outputs['Faces'].sv_set(faces_out)
Esempio n. 23
0
class LuxCoreNodeTexBlenderVoronoi(bpy.types.Node, LuxCoreNodeTexture):
    bl_label = "Blender Voronoi"
    bl_width_default = 200

    distance_items = [
        ("actual_distance", "Actual Distance", "actual distance"),
        ("distance_squared", "Distance Squared", "distance squared"),
        ("manhattan", "Manhattan", "manhattan"),
        ("chebychev", "Chebychev", "chebychev"),
        ("minkovsky_half", "Minkowsky 1/2", "minkowsky half"),
        ("minkovsky_four", "Minkowsky 4", "minkowsky four"),
        ("minkovsky", "Minkowsky", "minkowsky"),
    ]

    dist_metric: EnumProperty(
        update=utils_node.force_viewport_update,
        name="Distance Metric",
        description=
        "Algorithm used to calculate distance of sample points to feature points",
        items=distance_items,
        default="actual_distance")
    minkowsky_exp: FloatProperty(update=utils_node.force_viewport_update,
                                 name="Exponent",
                                 default=1.0)
    noise_size: FloatProperty(update=utils_node.force_viewport_update,
                              name="Noise Size",
                              default=0.25,
                              min=MIN_NOISE_SIZE)
    w1: FloatProperty(update=utils_node.force_viewport_update,
                      name="Weight 1",
                      default=1.0,
                      min=-2,
                      max=2,
                      subtype="FACTOR")
    w2: FloatProperty(update=utils_node.force_viewport_update,
                      name="Weight 2",
                      default=0.0,
                      min=-2,
                      max=2,
                      subtype="FACTOR")
    w3: FloatProperty(update=utils_node.force_viewport_update,
                      name="Weight 3",
                      default=0.0,
                      min=-2,
                      max=2,
                      subtype="FACTOR")
    w4: FloatProperty(update=utils_node.force_viewport_update,
                      name="Weight 4",
                      default=0.0,
                      min=-2,
                      max=2,
                      subtype="FACTOR")
    bright: FloatProperty(update=utils_node.force_viewport_update,
                          name="Brightness",
                          default=1.0,
                          min=0)
    contrast: FloatProperty(update=utils_node.force_viewport_update,
                            name="Contrast",
                            default=1.0,
                            min=0)

    def init(self, context):
        self.add_input("LuxCoreSocketMapping3D", "3D Mapping")
        self.outputs.new("LuxCoreSocketColor", "Color")

    def draw_buttons(self, context, layout):
        layout.prop(self, "dist_metric")
        if self.dist_metric == "minkovsky":
            layout.prop(self, "minkowsky_exp")
        layout.prop(self, "noise_size")
        column = layout.column(align=True)
        column.prop(self, "w1")
        column.prop(self, "w2")
        column.prop(self, "w3")
        column.prop(self, "w4")

        column = layout.column(align=True)
        column.prop(self, "bright")
        column.prop(self, "contrast")

    def sub_export(self,
                   exporter,
                   depsgraph,
                   props,
                   luxcore_name=None,
                   output_socket=None):
        mapping_type, uvindex, transformation = self.inputs[
            "3D Mapping"].export(exporter, depsgraph, props)

        definitions = {
            "type": "blender_voronoi",
            "distmetric": self.dist_metric,
            "w1": self.w1,
            "w2": self.w2,
            "w3": self.w3,
            "w4": self.w4,
            "noisesize": self.noise_size,
            "bright": self.bright,
            "contrast": self.contrast,
            # Mapping
            "mapping.type": mapping_type,
            "mapping.transformation": utils.matrix_to_list(transformation),
        }
        if self.dist_metric == "minkovsky":
            definitions["exponent"] = self.minkowsky_exp

        if mapping_type == "uvmapping3d":
            definitions["mapping.uvindex"] = uvindex

        return self.create_props(props, definitions, luxcore_name)
Esempio n. 24
0
class SvMeshSelectNode(bpy.types.Node, SverchCustomTreeNode):
    '''Select vertices, edges, faces by geometric criteria'''
    bl_idname = 'SvMeshSelectNode'
    bl_label = 'Select mesh elements by location'
    bl_icon = 'UV_SYNC_SELECT'

    modes = [
        ("BySide", "By side", "Select specified side of mesh", 0),
        ("ByNormal", "By normal direction",
         "Select faces with normal in specified direction", 1),
        ("BySphere", "By center and radius",
         "Select vertices within specified distance from center", 2),
        ("ByPlane", "By plane",
         "Select vertices within specified distance from plane defined by point and normal vector",
         3),
        ("ByCylinder", "By cylinder",
         "Select vertices within specified distance from straight line defined by point and direction vector",
         4),
        ("EdgeDir", "By edge direction",
         "Select edges that are nearly parallel to specified direction", 5),
        ("Outside", "Normal pointing outside",
         "Select faces with normals pointing outside", 6),
        ("BBox", "By bounding box",
         "Select vertices within bounding box of specified points", 7)
    ]

    def update_mode(self, context):
        self.inputs['Radius'].hide_safe = (self.mode not in [
            'BySphere', 'ByPlane', 'ByCylinder', 'BBox'
        ])
        self.inputs['Center'].hide_safe = (self.mode not in [
            'BySphere', 'ByPlane', 'ByCylinder', 'Outside', 'BBox'
        ])
        self.inputs['Percent'].hide_safe = (self.mode not in [
            'BySide', 'ByNormal', 'EdgeDir', 'Outside'
        ])
        self.inputs['Direction'].hide_safe = (self.mode not in [
            'BySide', 'ByNormal', 'ByPlane', 'ByCylinder', 'EdgeDir'
        ])

        updateNode(self, context)

    mode: EnumProperty(name="Mode",
                       items=modes,
                       default='ByNormal',
                       update=update_mode)

    include_partial: BoolProperty(
        name="Include partial selection",
        description="Include partially selected edges/faces",
        default=False,
        update=updateNode)

    percent: FloatProperty(name="Percent",
                           default=1.0,
                           min=0.0,
                           max=100.0,
                           update=updateNode)

    radius: FloatProperty(name="Radius",
                          default=1.0,
                          min=0.0,
                          update=updateNode)

    def draw_buttons(self, context, layout):
        layout.prop(self, 'mode')
        if self.mode not in ['ByNormal', 'EdgeDir']:
            layout.prop(self, 'include_partial')

    def sv_init(self, context):
        self.inputs.new('VerticesSocket', "Vertices")
        self.inputs.new('StringsSocket', "Edges")
        self.inputs.new('StringsSocket', "Polygons")

        d = self.inputs.new('VerticesSocket', "Direction")
        d.use_prop = True
        d.prop = (0.0, 0.0, 1.0)

        c = self.inputs.new('VerticesSocket', "Center")
        c.use_prop = True
        c.prop = (0.0, 0.0, 0.0)

        self.inputs.new('StringsSocket', 'Percent',
                        'Percent').prop_name = 'percent'
        self.inputs.new('StringsSocket', 'Radius',
                        'Radius').prop_name = 'radius'

        self.outputs.new('StringsSocket', 'VerticesMask')
        self.outputs.new('StringsSocket', 'EdgesMask')
        self.outputs.new('StringsSocket', 'FacesMask')

        self.update_mode(context)

    def map_percent(self, values, percent):
        maxv = max(values)
        minv = min(values)
        if maxv <= minv:
            return maxv
        return maxv - percent * (maxv - minv) * 0.01

    def select_verts_by_faces(self, faces, verts):
        return [any(v in face for face in faces) for v in range(len(verts))]

    def select_edges_by_verts(self, verts_mask, edges):
        result = []
        for u, v in edges:
            if self.include_partial:
                ok = verts_mask[u] or verts_mask[v]
            else:
                ok = verts_mask[u] and verts_mask[v]
            result.append(ok)
        return result

    def select_faces_by_verts(self, verts_mask, faces):
        result = []
        for face in faces:
            if self.include_partial:
                ok = any(verts_mask[i] for i in face)
            else:
                ok = all(verts_mask[i] for i in face)
            result.append(ok)
        return result

    def by_normal(self, vertices, edges, faces):
        vertex_normals, face_normals = calc_mesh_normals(
            vertices, edges, faces)
        percent = self.inputs['Percent'].sv_get(default=[1.0])[0][0]
        direction = self.inputs['Direction'].sv_get()[0][0]
        values = [Vector(n).dot(direction) for n in face_normals]
        threshold = self.map_percent(values, percent)

        out_face_mask = [(value >= threshold) for value in values]
        out_faces = [
            face for (face, mask) in zip(faces, out_face_mask) if mask
        ]
        out_verts_mask = self.select_verts_by_faces(out_faces, vertices)
        out_edges_mask = self.select_edges_by_verts(out_verts_mask, edges)

        return out_verts_mask, out_edges_mask, out_face_mask

    def by_side(self, vertices, edges, faces):
        percent = self.inputs['Percent'].sv_get(default=[1.0])[0][0]
        direction = self.inputs['Direction'].sv_get()[0][0]
        values = [Vector(v).dot(direction) for v in vertices]
        threshold = self.map_percent(values, percent)

        out_verts_mask = [(value >= threshold) for value in values]
        out_edges_mask = self.select_edges_by_verts(out_verts_mask, edges)
        out_faces_mask = self.select_faces_by_verts(out_verts_mask, faces)

        return out_verts_mask, out_edges_mask, out_faces_mask

    def by_sphere(self, vertices, edges, faces):
        radius = self.inputs['Radius'].sv_get(default=[1.0])[0][0]
        centers = self.inputs['Center'].sv_get()[0]

        if len(centers) == 1:
            center = centers[0]
            out_verts_mask = [((Vector(v) - Vector(center)).length <= radius)
                              for v in vertices]
        else:
            # build KDTree
            tree = kdtree.KDTree(len(centers))
            for i, v in enumerate(centers):
                tree.insert(v, i)
            tree.balance()

            out_verts_mask = []
            for vertex in vertices:
                _, _, rho = tree.find(vertex)
                mask = rho <= radius
                out_verts_mask.append(mask)

        out_edges_mask = self.select_edges_by_verts(out_verts_mask, edges)
        out_faces_mask = self.select_faces_by_verts(out_verts_mask, faces)

        return out_verts_mask, out_edges_mask, out_faces_mask

    def by_plane(self, vertices, edges, faces):
        center = self.inputs['Center'].sv_get()[0][0]
        radius = self.inputs['Radius'].sv_get(default=[1.0])[0][0]
        direction = self.inputs['Direction'].sv_get()[0][0]

        d = -Vector(direction).dot(center)
        denominator = Vector(direction).length

        def rho(vertex):
            return abs(Vector(vertex).dot(direction) + d) / denominator

        out_verts_mask = [(rho(v) <= radius) for v in vertices]
        out_edges_mask = self.select_edges_by_verts(out_verts_mask, edges)
        out_faces_mask = self.select_faces_by_verts(out_verts_mask, faces)

        return out_verts_mask, out_edges_mask, out_faces_mask

    def by_cylinder(self, vertices, edges, faces):
        center = self.inputs['Center'].sv_get()[0][0]
        radius = self.inputs['Radius'].sv_get(default=[1.0])[0][0]
        direction = self.inputs['Direction'].sv_get()[0][0]

        denominator = Vector(direction).length

        def rho(vertex):
            numerator = (Vector(center) -
                         Vector(vertex)).cross(direction).length
            return numerator / denominator

        out_verts_mask = [(rho(v) <= radius) for v in vertices]
        out_edges_mask = self.select_edges_by_verts(out_verts_mask, edges)
        out_faces_mask = self.select_faces_by_verts(out_verts_mask, faces)

        return out_verts_mask, out_edges_mask, out_faces_mask

    def by_edge_dir(self, vertices, edges, faces):
        percent = self.inputs['Percent'].sv_get(default=[1.0])[0][0]
        direction = self.inputs['Direction'].sv_get()[0][0]
        dirvector = Vector(direction)
        dirlength = dirvector.length
        if dirlength <= 0:
            raise ValueError("Direction vector must have nonzero length!")

        values = []
        for i, j in edges:
            u = vertices[i]
            v = vertices[j]
            edge = Vector(u) - Vector(v)
            if edge.length > 0:
                value = abs(edge.dot(dirvector)) / (edge.length * dirlength)
            else:
                value = 0
            values.append(value)
        threshold = self.map_percent(values, percent)

        out_edges_mask = [(value >= threshold) for value in values]
        out_edges = [
            edge for (edge, mask) in zip(edges, out_edges_mask) if mask
        ]
        out_verts_mask = self.select_verts_by_faces(out_edges, vertices)
        out_faces_mask = self.select_faces_by_verts(out_verts_mask, faces)

        return out_verts_mask, out_edges_mask, out_faces_mask

    def by_outside(self, vertices, edges, faces):
        vertex_normals, face_normals = calc_mesh_normals(
            vertices, edges, faces)
        percent = self.inputs['Percent'].sv_get(default=[1.0])[0][0]
        center = self.inputs['Center'].sv_get()[0][0]
        center = Vector(center)

        def get_center(face):
            verts = [Vector(vertices[i]) for i in face]
            result = Vector((0, 0, 0))
            for v in verts:
                result += v
            return (1.0 / float(len(verts))) * result

        values = []
        for face, normal in zip(faces, face_normals):
            face_center = get_center(face)
            direction = face_center - center
            dirlength = direction.length
            if dirlength > 0:
                value = math.pi - direction.angle(normal)
            else:
                value = math.pi
            values.append(value)
        threshold = self.map_percent(values, percent)

        out_face_mask = [(value >= threshold) for value in values]
        out_faces = [
            face for (face, mask) in zip(faces, out_face_mask) if mask
        ]
        out_verts_mask = self.select_verts_by_faces(out_faces, vertices)
        out_edges_mask = self.select_edges_by_verts(out_verts_mask, edges)

        return out_verts_mask, out_edges_mask, out_face_mask

    def by_bbox(self, vertices, edges, faces):
        points = self.inputs['Center'].sv_get()[0]
        radius = self.inputs['Radius'].sv_get(default=[1.0])[0][0]

        # bounding box
        mins = tuple(min([point[i] for point in points]) for i in range(3))
        maxs = tuple(max([point[i] for point in points]) for i in range(3))

        # plus radius
        mins = tuple(mins[i] - radius for i in range(3))
        maxs = tuple(maxs[i] + radius for i in range(3))

        out_verts_mask = []
        for vertex in vertices:
            min_ok = all(mins[i] <= vertex[i] for i in range(3))
            max_ok = all(vertex[i] <= maxs[i] for i in range(3))
            out_verts_mask.append(min_ok and max_ok)

        out_edges_mask = self.select_edges_by_verts(out_verts_mask, edges)
        out_faces_mask = self.select_faces_by_verts(out_verts_mask, faces)

        return out_verts_mask, out_edges_mask, out_faces_mask

    def process(self):

        if not any(output.is_linked for output in self.outputs):
            return

        vertices_s = self.inputs['Vertices'].sv_get(default=[[]])
        edges_s = self.inputs['Edges'].sv_get(default=[[]])
        faces_s = self.inputs['Polygons'].sv_get(default=[[]])

        out_vertices = []
        out_edges = []
        out_faces = []

        meshes = match_long_repeat([vertices_s, edges_s, faces_s])
        for vertices, edges, faces in zip(*meshes):
            if self.mode == 'BySide':
                vs, es, fs = self.by_side(vertices, edges, faces)
            elif self.mode == 'ByNormal':
                vs, es, fs = self.by_normal(vertices, edges, faces)
            elif self.mode == 'BySphere':
                vs, es, fs = self.by_sphere(vertices, edges, faces)
            elif self.mode == 'ByPlane':
                vs, es, fs = self.by_plane(vertices, edges, faces)
            elif self.mode == 'ByCylinder':
                vs, es, fs = self.by_cylinder(vertices, edges, faces)
            elif self.mode == 'EdgeDir':
                vs, es, fs = self.by_edge_dir(vertices, edges, faces)
            elif self.mode == 'Outside':
                vs, es, fs = self.by_outside(vertices, edges, faces)
            elif self.mode == 'BBox':
                vs, es, fs = self.by_bbox(vertices, edges, faces)
            else:
                raise ValueError("Unknown mode: " + self.mode)

            out_vertices.append(vs)
            out_edges.append(es)
            out_faces.append(fs)

        self.outputs['VerticesMask'].sv_set(out_vertices)
        self.outputs['EdgesMask'].sv_set(out_edges)
        self.outputs['FacesMask'].sv_set(out_faces)
Esempio n. 25
0
class ExportX3D(bpy.types.Operator, ExportHelper):
    """Export selection to Extensible 3D file (.x3d)"""
    bl_idname = "export_scene.x3d"
    bl_label = 'Export X3D'
    bl_options = {'PRESET'}

    filename_ext = ".x3d"
    filter_glob: StringProperty(default="*.x3d", options={'HIDDEN'})

    use_selection: BoolProperty(
        name="Selection Only",
        description="Export selected objects only",
        default=True,  # bfa - only selected
    )
    use_mesh_modifiers: BoolProperty(
        name="Apply Modifiers",
        description="Use transformed mesh data from each object",
        default=True,
    )
    use_triangulate: BoolProperty(
        name="Triangulate",
        description="Write quads into 'IndexedTriangleSet'",
        default=False,
    )
    use_normals: BoolProperty(
        name="Normals",
        description="Write normals with geometry",
        default=False,
    )
    use_compress: BoolProperty(
        name="Compress",
        description="Compress the exported file",
        default=False,
    )
    use_hierarchy: BoolProperty(
        name="Hierarchy",
        description="Export parent child relationships",
        default=True,
    )
    name_decorations: BoolProperty(
        name="Name decorations",
        description=("Add prefixes to the names of exported nodes to "
                     "indicate their type"),
        default=True,
    )
    use_h3d: BoolProperty(
        name="H3D Extensions",
        description="Export shaders for H3D",
        default=False,
    )

    global_scale: FloatProperty(
        name="Scale",
        min=0.01,
        max=1000.0,
        default=1.0,
    )

    path_mode: path_reference_mode

    def execute(self, context):
        from . import export_x3d

        from mathutils import Matrix

        keywords = self.as_keywords(ignore=(
            "axis_forward",
            "axis_up",
            "global_scale",
            "check_existing",
            "filter_glob",
        ))
        global_matrix = axis_conversion(
            to_forward=self.axis_forward,
            to_up=self.axis_up,
        ).to_4x4() @ Matrix.Scale(self.global_scale, 4)
        keywords["global_matrix"] = global_matrix

        return export_x3d.save(context, **keywords)

    def draw(self, context):
        pass
Esempio n. 26
0
class SvRemoveDoublesNode(bpy.types.Node, SverchCustomTreeNode):
    '''Remove doubles'''
    bl_idname = 'SvRemoveDoublesNode'
    bl_label = 'Remove Doubles'
    bl_icon = 'OUTLINER_OB_EMPTY'
    sv_icon = 'SV_REMOVE_DOUBLES'

    distance: FloatProperty(name='Distance',
                            description='Remove distance',
                            default=0.001,
                            precision=3,
                            min=0,
                            update=updateNode)

    def sv_init(self, context):
        self.inputs.new('SvStringsSocket', 'Distance').prop_name = 'distance'
        self.inputs.new('SvVerticesSocket', 'Vertices')
        self.inputs.new('SvStringsSocket', 'PolyEdge')
        self.inputs.new('SvStringsSocket', 'FaceData')

        self.outputs.new('SvVerticesSocket', 'Vertices')
        self.outputs.new('SvStringsSocket', 'Edges')
        self.outputs.new('SvStringsSocket', 'Polygons')
        self.outputs.new('SvStringsSocket', 'FaceData')
        self.outputs.new('SvVerticesSocket', 'Doubles')

    def draw_buttons(self, context, layout):
        #layout.prop(self, 'distance', text="Distance")
        pass

    def process(self):
        if not any(s.is_linked for s in self.outputs):
            return

        if not self.inputs['Vertices'].is_linked:
            return

        verts = Vector_generate(self.inputs['Vertices'].sv_get())
        polys = self.inputs['PolyEdge'].sv_get(default=[[]])
        if 'FaceData' in self.inputs:
            face_data = self.inputs['FaceData'].sv_get(default=[[]])
        else:
            face_data = [[]]
        distance = self.inputs['Distance'].sv_get(default=[self.distance])[0]
        has_double_out = self.outputs['Doubles'].is_linked

        verts_out = []
        edges_out = []
        polys_out = []
        face_data_out = []
        d_out = []

        for v, p, ms, d in zip_long_repeat(verts, polys, face_data, distance):
            res = remove_doubles(v, p, d, ms, has_double_out)
            if not res:
                return
            verts_out.append(res[0])
            edges_out.append(res[1])
            polys_out.append(res[2])
            face_data_out.append(res[3])
            d_out.append(res[4])

        self.outputs['Vertices'].sv_set(verts_out)

        # restrict setting this output when there is no such input
        if self.inputs['PolyEdge'].is_linked:
            self.outputs['Edges'].sv_set(edges_out)
            self.outputs['Polygons'].sv_set(polys_out)

        if 'FaceData' in self.outputs:
            self.outputs['FaceData'].sv_set(face_data_out)
        self.outputs['Doubles'].sv_set(d_out)
Esempio n. 27
0
class CreateStash(bpy.types.Operator):
    bl_idname = "machin3.create_stash"
    bl_label = "MACHIN3: Create Stash"
    bl_options = {'REGISTER', 'UNDO'}
    bl_description = "Stash the current state of an object"

    countdown = FloatProperty(name="Countdown (s)", default=2)

    remove_sources = BoolProperty(name="Remove Sources", default=False)

    def check(self, context):
        return True

    def draw_VIEW3D(self, args):
        stashingtype = self.stashret[0]
        if stashingtype == "ACTIVE":
            meshes = [self.active.data]
            color = (1, 1, 1)

        elif stashingtype == "OTHER":
            meshes = [obj.data for obj in self.stashret[2]]
            color = (1, 1, 0)

        alpha = self.countdown / self.time

        for mesh in meshes:
            mx = self.active.matrix_world

            # offset amount depends on size of active object
            offset = sum([d for d in self.active.dimensions]) / 3 * 0.001

            edgecolor = (*color, alpha)
            edgewidth = 2

            bgl.glEnable(bgl.GL_BLEND)

            # if self.xray:
            # bgl.glDisable(bgl.GL_DEPTH_TEST)

            for edge in mesh.edges:
                v1 = mesh.vertices[edge.vertices[0]]
                v2 = mesh.vertices[edge.vertices[1]]

                # bring the coordinates into world space, and push the verts out a bit
                v1co = mx * (v1.co + v1.normal * offset)
                v2co = mx * (v2.co + v1.normal * offset)

                bgl.glLineWidth(edgewidth)
                bgl.glColor4f(*edgecolor)

                bgl.glBegin(bgl.GL_LINES)

                bgl.glVertex3f(*v1co)
                bgl.glVertex3f(*v2co)

            draw_end()

    def draw_HUD(self, args):
        draw_init(self, args)

        # title
        alpha = self.countdown / self.time

        stashingtype = self.stashret[0]

        if stashingtype == "ACTIVE":
            title = "Created %s" % self.stashret[3]
        elif stashingtype == "OTHER":
            stashnames = self.stashret[3]
            if len(stashnames) == 1:
                title = "Created %s" % self.stashret[3][0]
            else:
                title = "Created %s..%s" % (self.stashret[3][0],
                                            self.stashret[3][-1])

        HUDcolor = m3.MM_prefs().modal_hud_color
        bgl.glColor4f(*HUDcolor, alpha)

        blf.position(self.font_id, self.HUDx - 7, self.HUDy, 0)
        blf.size(self.font_id, 16, 72)
        blf.draw(self.font_id, "» " + title)

        # stashes

        offset = self.offset + 0
        self.offset = offset
        blf.size(self.font_id, 11, 72)

        if stashingtype == "ACTIVE":
            bgl.glColor4f(1, 1, 1, alpha)

            msg = "from object %s" % (self.active.name)

            blf.position(self.font_id, self.HUDx + 20, self.HUDy - 20 - offset,
                         0)
            blf.draw(self.font_id, msg)

        elif stashingtype == "OTHER":
            bgl.glColor4f(1, 1, 0, alpha)

            stashobjnames = self.stashret[1]

            for name in stashobjnames:
                msg = "from object %s" % (name)

                blf.position(self.font_id, self.HUDx + 20,
                             self.HUDy - 20 - offset, 0)
                blf.draw(self.font_id, msg)

                self.offset += 18
                offset = self.offset

            draw_prop(self,
                      "Remove Sources",
                      self.remove_sources,
                      offset=18,
                      key="press D")

        draw_end()

    def draw(self, context):
        layout = self.layout

        column = layout.column()

        column.prop(self, "remove_sources")

    def modal(self, context, event):
        context.area.tag_redraw()

        # update mouse postion for HUD
        if event.type == "MOUSEMOVE":
            self.mouse_x = event.mouse_region_x
            self.mouse_y = event.mouse_region_y

        if event.type == "D" and event.value == "PRESS":
            # don't do anything
            if event.shift or event.alt or event.ctrl or not self.sources:
                return {'PASS_THROUGH'}

            # hide/unhide sources to pretend they are removed already, when they only actually get removed once the counter ran out
            else:
                self.remove_sources = not self.remove_sources

                for obj in self.sources:
                    obj.hide = self.remove_sources

                return {'RUNNING_MODAL'}

        # FINISH when countdown is 0

        if self.countdown < 0:
            # print("Countdown of %d seconds finished" % (self.time))

            # remove time handler
            context.window_manager.event_timer_remove(self.TIMER)

            # remove draw handlers
            bpy.types.SpaceView3D.draw_handler_remove(self.HUD, 'WINDOW')
            bpy.types.SpaceView3D.draw_handler_remove(self.VIEW3D, 'WINDOW')

            # remove sources
            if self.remove_sources:
                for obj in self.sources:
                    bpy.data.objects.remove(obj, do_unlink=True)

            return {'FINISHED'}

        # COUNT DOWN

        if event.type == 'TIMER':
            self.countdown -= 0.1

        return {'PASS_THROUGH'}

    def invoke(self, context, event):
        self.active = m3.get_active()

        # create the stash
        self.stashret = self.main(context, self.active)

        # get source objects
        if self.stashret[0] == "OTHER":
            sourcenames = self.stashret[1]

            self.sources = [bpy.data.objects.get(name) for name in sourcenames]

            # hide them based on the remove_sources prop
            for obj in self.sources:
                obj.hide = self.remove_sources
        else:
            self.sources = []

        self.time = self.countdown

        # # mouse positions
        self.mouse_x = self.init_mouse_x = self.fixed_mouse_x = event.mouse_region_x
        self.mouse_y = self.init_mouse_y = self.fixed_mouse_y = event.mouse_region_y

        # draw handler
        args = (self, context)
        self.HUD = bpy.types.SpaceView3D.draw_handler_add(
            self.draw_HUD, (args, ), 'WINDOW', 'POST_PIXEL')
        self.VIEW3D = bpy.types.SpaceView3D.draw_handler_add(
            self.draw_VIEW3D, (args, ), 'WINDOW', 'POST_VIEW')

        # time handler
        self.TIMER = context.window_manager.event_timer_add(
            0.1, context.window)

        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def execute(self, context):
        self.active = m3.get_active()

        # create the stash
        self.main(context, self.active)

        return {'FINISHED'}

    def main(self, context, active):
        mode = active.mode
        sel = context.selected_objects

        print()
        print("%s's stashes" % (active.name))
        for s in active.MM.stashes:
            print(" »", s.name)

        if mode == "EDIT" or (mode == "OBJECT" and len(sel) == 1):
            if mode == "EDIT":
                # make sure the current edit mode state is saved to active.data
                active.update_from_editmode()

            # create the stash and stashobj
            stash = create_stash(active=active, source=active)

            return "ACTIVE", None, None, stash.name

        elif mode == "OBJECT":
            sel.remove(active)

            sourceobjsnames = []
            stashobjs = []
            stashnames = []

            for obj in sel:
                stash = create_stash(active=active, source=obj)

                sourceobjsnames.append(obj.name)
                stashobjs.append(stash.obj)
                stashnames.append(stash.name)

            print()

            return "OTHER", sourceobjsnames, stashobjs, stashnames
Esempio n. 28
0
class LuxCoreConfigPhotonGI(PropertyGroup):
    enabled: BoolProperty(
        name=
        "Use PhotonGI cache to accelerate indirect and/or caustic light rendering",
        default=False)

    # Shared settings
    photon_maxcount: FloatProperty(
        name="Photon Count (Millions)",
        default=20,
        min=1,
        soft_max=100,
        precision=0,
        step=10,
        description="Max. number of photons traced (value in millions)")
    photon_maxdepth: IntProperty(
        name="Photon Depth",
        default=8,
        min=3,
        max=64,
        description=
        "Max. depth of photon paths. At each bounce, a photon might be stored")
    # I use 0.049 as default because then glossy materials with default roughness (0.05) are cached
    glossinessusagethreshold: FloatProperty(
        name="Glossiness Threshold",
        default=0.049,
        min=0,
        max=1,
        description=PHOTONGI_GLOSSINESSTHRESH_DESC)

    # Indirect cache
    indirect_enabled: BoolProperty(
        name="Use Indirect Cache",
        default=True,
        description="Accelerates rendering of indirect light")
    indirect_haltthreshold_preset_items = [
        ("final", "Final Render", "Halt Threshold 5%", 0),
        ("preview", "Preview", "Halt Threshold 15%", 1),
        ("custom", "Custom", "", 2),
    ]
    indirect_haltthreshold_preset: EnumProperty(
        name="Quality",
        items=indirect_haltthreshold_preset_items,
        default="final",
        description=PHOTONGI_HALTTHRESH_DESC)
    indirect_haltthreshold_custom: FloatProperty(
        name="Halt Threshold",
        default=5,
        min=0.001,
        max=100,
        precision=0,
        subtype="PERCENTAGE",
        description=PHOTONGI_HALTTHRESH_DESC)
    indirect_lookup_radius_auto: BoolProperty(
        name="Automatic Lookup Radius",
        default=True,
        description="Automatically choose a good lookup radius")
    indirect_lookup_radius: FloatProperty(name="Lookup Radius",
                                          default=0.15,
                                          min=0.00001,
                                          subtype="DISTANCE",
                                          description=LOOKUP_RADIUS_DESC)
    indirect_normalangle: FloatProperty(name="Normal Angle",
                                        default=radians(10),
                                        min=0,
                                        max=radians(90),
                                        subtype="ANGLE",
                                        description=NORMAL_ANGLE_DESC)
    indirect_usagethresholdscale: FloatProperty(
        name="Brute Force Radius Scale",
        default=8,
        min=0,
        precision=1,
        description=PHOTONGI_INDIRECT_USAGETHRESHOLDSCALE_DESC)

    # Caustic cache
    caustic_enabled: BoolProperty(
        name="Use Caustic Cache",
        default=False,
        description=
        "Accelerates rendering of caustics at the cost of blurring them")
    caustic_maxsize: FloatProperty(
        name="Max. Size (Millions)",
        default=0.1,
        soft_min=0.01,
        min=0.001,
        soft_max=10,
        precision=1,
        step=1,
        description=
        "Max. number of photons stored in caustic cache (value in millions)")
    caustic_lookup_radius: FloatProperty(name="Lookup Radius",
                                         default=0.075,
                                         min=0.00001,
                                         subtype="DISTANCE",
                                         description=LOOKUP_RADIUS_DESC)
    caustic_normalangle: FloatProperty(name="Normal Angle",
                                       default=radians(10),
                                       min=0,
                                       max=radians(90),
                                       subtype="ANGLE",
                                       description=NORMAL_ANGLE_DESC)
    caustic_periodic_update: BoolProperty(
        name="Periodic Update",
        default=True,
        description=
        "Rebuild the caustic cache periodically to clean up photon noise. "
        "The step samples parameter controls how often the cache is rebuilt")
    caustic_updatespp: IntProperty(
        name="Step Samples",
        default=8,
        min=1,
        description=
        "How often to rebuild the cache if periodic update is enabled")
    caustic_updatespp_radiusreduction: FloatProperty(
        name="Radius Reduction",
        default=96,
        min=1,
        soft_min=70,
        max=99.9,
        soft_max=99,
        subtype="PERCENTAGE",
        description="Shrinking factor for the lookup radius after each pass")
    caustic_updatespp_minradius: FloatProperty(
        name="Minimum Radius",
        default=0.003,
        min=0.00001,
        subtype="DISTANCE",
        description="Radius at which the radius reduction stops")

    debug_items = [
        ("off", "Off (Final Render Mode)", "", 0),
        ("showindirect", "Show Indirect", "View the indirect light cache", 1),
        ("showindirectpathmix", "Show Indirect/Path Mix",
         "Blue = cache is used, red = brute force path tracing is used", 3),
        ("showcaustic", "Show Caustic", "View the caustic cache", 2),
    ]
    debug: EnumProperty(
        name="Debug",
        items=debug_items,
        default="off",
        description=
        "Choose between final render mode or a debug representation of the caches"
    )

    file_path: StringProperty(
        name="File Path",
        subtype="FILE_PATH",
        description="File path to the PhotonGI cache file")
    save_or_overwrite: BoolProperty(
        name="",
        default=False,
        description=
        "Save the cache to a file or overwrite the existing cache file. "
        "If you want to use the saved cache, disable this option")
Esempio n. 29
0
class ExportMultipleObjs(bpy.types.Operator, ExportHelper):
    """Batch export objects as obj files"""

    bl_idname = "export_scene.batch_obj"
    bl_label = "Batch export OBJ's"
    bl_options = {"PRESET", "UNDO"}

    # ExportHelper mixin class uses this
    filename_ext = ".obj"

    filter_glob = StringProperty(
        default="*.obj;*.mtl",
        options={"HIDDEN"},
    )

    # List of operator properties, the attributes will be assigned
    # to the class instance from the operator setting before calling.

    # context group
    use_selection_setting: BoolProperty(
        name="Selection Only",
        description="Export selected objects only",
        default=True,
    )
    use_animation_setting: BoolProperty(
        name="Animation",
        description="Write out an OBJ for each frame",
        default=False,
    )

    # object group
    use_mesh_modifiers_setting: BoolProperty(
        name="Apply Modifiers",
        description="Apply modifiers (preview resolution)",
        default=True,
    )

    # extra data group
    use_edges_setting: BoolProperty(
        name="Include Edges",
        description="",
        default=True,
    )
    use_smooth_groups_setting: BoolProperty(
        name="Smooth Groups",
        description="Write sharp edges as smooth groups",
        default=False,
    )
    use_smooth_groups_bitflags_setting: BoolProperty(
        name="Bitflag Smooth Groups",
        description=
        "Same as 'Smooth Groups', but generate smooth groups IDs as bitflags "
        "(produces at most 32 different smooth groups, usually much less)",
        default=False,
    )
    use_normals_setting: BoolProperty(
        name="Write Normals",
        description=
        "Export one normal per vertex and per face, to represent flat faces and sharp edges",
        default=False,
    )
    use_uvs_setting: BoolProperty(
        name="Include UVs",
        description="Write out the active UV coordinates",
        default=True,
    )
    use_materials_setting: BoolProperty(
        name="Write Materials",
        description="Write out the MTL file",
        default=True,
    )
    use_triangles_setting: BoolProperty(
        name="Triangulate Faces",
        description="Convert all faces to triangles",
        default=False,
    )
    use_nurbs_setting: BoolProperty(
        name="Write Nurbs",
        description="Write nurbs curves as OBJ nurbs rather than "
        "converting to geometry",
        default=False,
    )
    use_vertex_groups_setting: BoolProperty(
        name="Polygroups",
        description="",
        default=False,
    )

    use_blen_objects_setting: BoolProperty(
        name="Objects as OBJ Objects",
        description="",
        default=True,
    )
    group_by_object_setting: BoolProperty(
        name="Objects as OBJ Groups ",
        description="",
        default=False,
    )
    group_by_material_setting: BoolProperty(
        name="Material Groups",
        description="",
        default=False,
    )
    keep_vertex_order_setting: BoolProperty(
        name="Keep Vertex Order",
        description="",
        default=False,
    )
    axis_forward_setting: EnumProperty(
        name="Forward",
        items=(
            ("X", "X Forward", ""),
            ("Y", "Y Forward", ""),
            ("Z", "Z Forward", ""),
            ("-X", "-X Forward", ""),
            ("-Y", "-Y Forward", ""),
            ("-Z", "-Z Forward", ""),
        ),
        default="-Z",
    )
    axis_up_setting: EnumProperty(
        name="Up",
        items=(
            ("X", "X Up", ""),
            ("Y", "Y Up", ""),
            ("Z", "Z Up", ""),
            ("-X", "-X Up", ""),
            ("-Y", "-Y Up", ""),
            ("-Z", "-Z Up", ""),
        ),
        default="Y",
    )
    global_scale_setting: FloatProperty(
        name="Scale",
        min=0.01,
        max=1000.0,
        default=1.0,
    )
    path_mode_setting: EnumProperty(
        name="Path Mode",
        items=(
            ("AUTO", "Auto", ""),
            ("ABSOLUTE", "Absolute", ""),
            ("RELATIVE", "Relative", ""),
            ("MATCH", "Match", ""),
            ("STRIP", "Strip", ""),
            ("COPY", "Copy", ""),
        ),
        default="AUTO",
    )

    def execute(self, context):

        # get the folder
        folder_path = os.path.dirname(self.filepath)

        # get objects selected in the viewport
        viewport_selection = context.selected_objects

        # get export objects
        obj_export_list = viewport_selection
        if self.use_selection_setting == False:
            obj_export_list = [i for i in context.scene.objects]

        # deselect all objects
        bpy.ops.object.select_all(action="DESELECT")

        for item in obj_export_list:
            item.select_set(True)
            if item.type == "MESH":
                file_path = os.path.join(folder_path,
                                         "{}.obj".format(item.name))

                bpy.ops.export_scene.obj(
                    filepath=file_path,
                    use_selection=self.use_selection_setting,
                    axis_forward=self.axis_forward_setting,
                    axis_up=self.axis_up_setting,
                    use_animation=self.use_animation_setting,
                    use_mesh_modifiers=self.use_mesh_modifiers_setting,
                    use_edges=self.use_edges_setting,
                    use_smooth_groups=self.use_smooth_groups_setting,
                    use_smooth_groups_bitflags=self.
                    use_smooth_groups_bitflags_setting,
                    use_normals=self.use_normals_setting,
                    use_uvs=self.use_uvs_setting,
                    use_materials=self.use_materials_setting,
                    use_triangles=self.use_triangles_setting,
                    use_nurbs=self.use_nurbs_setting,
                    use_vertex_groups=self.use_vertex_groups_setting,
                    use_blen_objects=self.use_blen_objects_setting,
                    group_by_object=self.group_by_object_setting,
                    group_by_material=self.group_by_material_setting,
                    keep_vertex_order=self.keep_vertex_order_setting,
                    global_scale=self.global_scale_setting,
                    path_mode=self.path_mode_setting,
                )
            item.select_set(False)

        # restore viewport selection
        for ob in viewport_selection:
            ob.select_set(True)

        return {"FINISHED"}
Esempio n. 30
0
class CleanUp(bpy.types.Operator):
    bl_idname = "machin3.clean_up"
    bl_label = "MACHIN3: Clean Up"
    bl_options = {'REGISTER', 'UNDO'}

    remove_doubles: BoolProperty(name="Remove Doubles", default=True)
    dissolve_degenerate: BoolProperty(name="Dissolve Degenerate", default=True)
    distance: FloatProperty(name="Merge Distance",
                            default=0.0001,
                            min=0,
                            step=0.01,
                            precision=4)

    recalc_normals: BoolProperty(name="Recalculate Normals", default=True)
    flip_normals: BoolProperty(name="Flip Normals", default=False)

    delete_loose: BoolProperty(name="Delete Loose", default=True)
    delete_loose_verts: BoolProperty(name="Delete Loose Verts", default=True)
    delete_loose_edges: BoolProperty(name="Delete Loose Edges", default=True)
    delete_loose_faces: BoolProperty(name="Delete Loose Faces", default=False)

    dissolve_redundant: BoolProperty(name="Dissolve Redundant", default=True)
    dissolve_redundant_verts: BoolProperty(name="Dissolve Redundant Verts",
                                           default=True)
    dissolve_redundant_edges: BoolProperty(name="Dissolve Redundant Edges",
                                           default=False)
    dissolve_redundant_angle: FloatProperty(name="Dissolve Redundnat Angle",
                                            default=179.999,
                                            min=0,
                                            max=180,
                                            step=0.1,
                                            precision=6)

    select: BoolProperty(name="Select", default=True)
    select_type: EnumProperty(name="Select",
                              items=cleanup_select_items,
                              default="NON-MANIFOLD")
    planar_threshold: FloatProperty(name="Non-Planar Face Threshold",
                                    default=0.001,
                                    min=0,
                                    step=0.0001,
                                    precision=6)

    view_selected: BoolProperty(name="View Selected", default=False)

    def draw(self, context):
        layout = self.layout
        box = layout.box()

        col = box.column()

        row = col.split(factor=0.3, align=True)
        row.prop(self, "remove_doubles", text="Doubles")
        row.prop(self, "dissolve_degenerate", text="Degenerate")
        r = row.row()
        r.active = any([self.remove_doubles, self.dissolve_degenerate])
        r.prop(self, "distance", text="")

        row = col.split(factor=0.3, align=True)
        row.prop(self, "delete_loose", text="Loose")
        r = row.row(align=True)
        r.active = self.delete_loose
        r.prop(self, "delete_loose_verts", text="Verts", toggle=True)
        r.prop(self, "delete_loose_edges", text="Edges", toggle=True)
        r.prop(self, "delete_loose_faces", text="Faces", toggle=True)

        row = col.split(factor=0.3, align=True)
        row.prop(self, "dissolve_redundant", text="Redundant")
        r = row.row(align=True)
        r.active = self.dissolve_redundant
        r.prop(self, "dissolve_redundant_verts", text="Verts", toggle=True)
        r.prop(self, "dissolve_redundant_edges", text="Edges", toggle=True)
        rr = r.row(align=True)
        rr.active = any(
            [self.dissolve_redundant_verts, self.dissolve_redundant_edges])
        rr.prop(self, "dissolve_redundant_angle", text="Angle")

        row = col.row()
        row.prop(self, "recalc_normals")
        r = row.row()
        r.active = self.recalc_normals
        r.prop(self, "flip_normals", text="Flip", toggle=True)

        box = layout.box()
        col = box.column(align=True)

        row = col.row()
        row.prop(self, "select")
        r = row.row()
        r.active = self.select
        r.prop(self, "view_selected")

        row = col.row(align=True)
        row.active = self.select
        row.prop(self, "select_type", expand=True)

        if self.select_type == 'NON-PLANAR':
            row = col.row(align=True)
            row.active = self.select
            row.prop(self, "planar_threshold", text='Threshold')

    @classmethod
    def poll(cls, context):
        return context.mode == "EDIT_MESH"

    def invoke(self, context, event):
        self.coords = Vector(
            (event.mouse_region_x, event.mouse_region_y)) + Vector((10, 20))
        return self.execute(context)

    def execute(self, context):
        sel = [
            obj for obj in context.selected_objects
            if obj.type == 'MESH' and obj.mode == 'EDIT'
        ]

        removed = {}

        for obj in sel:
            bm, elementcounts = self.clean_up(obj)

            if self.select:
                self.select_geometry(bm)

            cleanedcounts = self.get_element_counts(bm)
            bmesh.update_edit_mesh(obj.data)

            if elementcounts != cleanedcounts:
                removed[obj] = (elementcounts[0] - cleanedcounts[0],
                                elementcounts[1] - cleanedcounts[1],
                                elementcounts[2] - cleanedcounts[2])

        if self.select and self.view_selected:
            bpy.ops.view3d.view_selected('INVOKE_DEFAULT',
                                         use_all_regions=False)

        if removed:
            verts = 0
            edges = 0
            faces = 0

            for counts in removed.values():
                verts += counts[0]
                edges += counts[1]
                faces += counts[2]

            text = f"Removed:{' Verts: ' + str(verts) if verts else ''}{' Edges: ' + str(edges) if edges else ''}{' Faces: ' + str(faces) if faces else ''}"

            extreme = any([c >= 10 for c in [verts, edges, faces]])
            bpy.ops.machin3.draw_label(text=text,
                                       coords=self.coords,
                                       center=False,
                                       color=yellow if extreme else white,
                                       alpha=1)
        else:
            text = "Nothing to remove."
            bpy.ops.machin3.draw_label(text=text,
                                       coords=self.coords,
                                       center=False,
                                       color=green,
                                       alpha=0.5)

        # self.report({'INFO'}, text)

        return {'FINISHED'}

    def clean_up(self, active):
        bm = bmesh.from_edit_mesh(active.data)
        bm.normal_update()
        bm.verts.ensure_lookup_table()

        elementcounts = self.get_element_counts(bm)

        if self.remove_doubles:
            bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=self.distance)

        if self.dissolve_degenerate:
            bmesh.ops.dissolve_degenerate(bm,
                                          edges=bm.edges,
                                          dist=self.distance)

        if self.delete_loose:
            self.delete_loose_geometry(bm)

        if self.dissolve_redundant:
            self.dissolve_redundant_geometry(bm)

        if self.recalc_normals:
            bmesh.ops.recalc_face_normals(bm, faces=bm.faces)

            if self.flip_normals:
                for f in bm.faces:
                    f.normal_flip()
        return bm, elementcounts

    def get_element_counts(self, bm):
        '''
        return tuple of vertcount, edgecount and facecount
        '''
        return len(bm.verts), len(bm.edges), len(bm.faces)

    def delete_loose_geometry(self, bm):
        if self.delete_loose_verts:
            loose_verts = [v for v in bm.verts if not v.link_edges]
            bmesh.ops.delete(bm, geom=loose_verts, context="VERTS")

        if self.delete_loose_edges:
            loose_edges = [e for e in bm.edges if not e.link_faces]
            bmesh.ops.delete(bm, geom=loose_edges, context="EDGES")

        if self.delete_loose_faces:
            loose_faces = [
                f for f in bm.faces
                if all([not e.is_manifold for e in f.edges])
            ]
            bmesh.ops.delete(bm, geom=loose_faces, context="FACES")

    def dissolve_redundant_geometry(self, bm):
        '''
        dissolve redundant verts on straight edges
        dissolve redundant edges on flat faces
        '''

        if self.dissolve_redundant_edges:
            manifold_edges = [e for e in bm.edges if e.is_manifold]

            redundant_edges = []

            for e in manifold_edges:
                angle = math.degrees(e.calc_face_angle(0))

                if angle < 180 - self.dissolve_redundant_angle:
                    redundant_edges.append(e)

            bmesh.ops.dissolve_edges(bm,
                                     edges=redundant_edges,
                                     use_verts=False)

            # dissolving with use_verts enabled can cause problems in som cases, so it's better to check the left over edges for 2 edged verts, and remove those in a separate step
            two_edged_verts = {
                v
                for e in redundant_edges if e.is_valid for v in e.verts
                if len(v.link_edges) == 2
            }
            bmesh.ops.dissolve_verts(bm, verts=list(two_edged_verts))

        # also run vert removal after edge removal to ensure verts from symmetry center lines get removed properly
        if self.dissolve_redundant_verts:
            two_edged_verts = [v for v in bm.verts if len(v.link_edges) == 2]

            redundant_verts = []

            for v in two_edged_verts:
                e1 = v.link_edges[0]
                e2 = v.link_edges[1]

                vector1 = e1.other_vert(v).co - v.co
                vector2 = e2.other_vert(v).co - v.co

                angle = min(math.degrees(vector1.angle(vector2)), 180)

                if self.dissolve_redundant_angle < angle:
                    redundant_verts.append(v)

            bmesh.ops.dissolve_verts(bm, verts=redundant_verts)

    def select_geometry(self, bm):
        for f in bm.faces:
            f.select = False

        bm.select_flush(False)

        if self.select_type == "NON-MANIFOLD":
            edges = [e for e in bm.edges if not e.is_manifold]

            for e in edges:
                e.select = True

        elif self.select_type == "NON-PLANAR":
            faces = [f for f in bm.faces if len(f.verts) > 3]

            for f in faces:
                distances = [
                    distance_point_to_plane(v.co, f.calc_center_median(),
                                            f.normal) for v in f.verts
                ]

                if any(
                    [d for d in distances if abs(d) > self.planar_threshold]):
                    f.select_set(True)

        elif self.select_type == "TRIS":
            faces = [f for f in bm.faces if len(f.verts) == 3]

            for f in faces:
                f.select = True

        elif self.select_type == "NGONS":
            faces = [f for f in bm.faces if len(f.verts) > 4]

            for f in faces:
                f.select = True