6
$\begingroup$

I have a selection of polygons that I plan to extrude individually, but I need the distance each polygon is extruded to be proportional to the area of the polygon, so that larger polygons are extruded farther than smaller polygons.

I figure I loop through the active selection of polygons, get the area of the polygon, use the Extrude Individual and Move tool with the extrusion distance equal to the polygon area times some scale factor.

But I'm not sure where to start — I assume the selection of polygons must be accessible through context, though I haven't found it yet. And I'm not sure how to use the bpy.ops.view3d.edit_mesh_extrude_individual_move() tool either, but that too seems like it should be very straight forward, I just can't seem to find my footing.

This also seems like it would make for a good option on the extrude tools. To get really fancy we could even allow for a user entered formula to determine the relationship between the polygon area and the extrusion distance, which I suspect could lead to novel results. Recursive extrusions with arbitrary or random tilts or scaling could make for an interesting tool too, though all that is way beyond what I'm looking to do here.

$\endgroup$
5
$\begingroup$

Here's a bmesh script with adjustable factor (in redo panel):

import bpy
import bmesh

def main(self, context):

    me = context.object.data

    if me.is_editmode:
        bm = bmesh.from_edit_mesh(me)
    else:
        bm = bmesh.new()
        bm.from_mesh(me)

    ret = bmesh.ops.extrude_discrete_faces(bm, faces=[f for f in bm.faces if f.select])

    for f in bm.faces:
        f.select = False

    for f in ret['faces']:
        f.select = True
        vec = f.normal * f.calc_area() * self.factor
        bmesh.ops.translate(bm, vec=vec, verts=f.verts)

    #bm.normal_update()

    if me.is_editmode:
        bmesh.update_edit_mesh(me)
    else:
        bm.to_mesh(me)

    #me.update()


class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "mesh.extrude_faces_indiv_area"
    bl_label = "Extrude Individual Faces (area-proportional)"
    bl_options = {'REGISTER', 'UNDO'}

    factor = bpy.props.FloatProperty(name="Factor", default=1, soft_min=-100, soft_max=100)

    @classmethod
    def poll(cls, context):
        return (context.object is not None and
                context.object.type == 'MESH')

    def execute(self, context):
        main(self, context)
        return {'FINISHED'}


def menu_func(self, context):
    self.layout.operator(SimpleOperator.bl_idname, text="Individual Faces (area-proportional)")


def register():
    bpy.utils.register_class(SimpleOperator)
    bpy.types.VIEW3D_MT_edit_mesh_extrude.append(menu_func)


def unregister():
    bpy.utils.unregister_class(SimpleOperator)
    bpy.types.VIEW3D_MT_edit_mesh_extrude.remove(menu_func)


if __name__ == "__main__":
    register()

Note that it's pretty slow unfortunately :(

I worry this comes from the translate op for each face (or vec calculation?), don't think this can be made much faster.

$\endgroup$
1
$\begingroup$

AFAIK, to get the selected polygons you will have to iterate through all the faces on the mesh and check if they are selected with polygon.select. If there is a collection available through context I can't find it.

You can get the area of the polygon with polygon.area, then extrude it with bpy.ops.mesh.extrude_faces_move.


You may want to use the bmesh module for this instead of bpy, but I don't know anything about it.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.