Random rotation of faces in edit mode?

I’ve done a search both here and on Google, trying to find if there is a way to randomly rotate some selected faces in edit mode to produce the sort of effect you get on shingles et al.
So far I have had no luck. I can “sort of” get some of it by randomly selecting faces, rotating, select some others, rinse & repeat. It would be nice though to just select several faces and have them rotate randomly on their individual origins.

Am I missing something obvious here?

There’s mesh -> transform -> randomize, and also mesh -> clean up -> make planar faces

Thanks, better than nothing, would be nice to have more control but I’ll take that. cheers. Just a shame you can’t isolate rotation / scaling / moving.

You can do a lot of things with Python as well, however the limitations are logical, not functional here. How would you rotate faces that share edges independently? If one face rotates, the orientation of another sharing an edge with it changes as well as if you rotated the other one the first would change. You cannot control the rotation any more precisely in a meaningful way than what JA12 described. That seems to be the best solution possible. You can also use random falloff for proportional editing to be able to refine stuff manually.

I am thinking here of isolated faces, so say you create a plane, subdivided it a couple of times, extrude individual faces, scale individual origins so you have a “choccy bar” type look. Taking some of the upper faces, I would then want to rotate them on their individual origins by some random amount, say between 5 & 20 degrees. I can get one face to rotate in python, but if there are multiple faces, they rotate around the common center, not the centre of each face.


import bpy
import random

class RandomRotate(bpy.types.Operator):
    """RandomRotate"""
    bl_idname = "object.random_rotate"
    bl_label = "Random Rotate"
    bl_options = {'REGISTER','UNDO'}
    i = bpy.props.IntProperty(
        name="iterations", 
        description="iterations of randomness", 
        default=10, 
        )
    amount = bpy.props.FloatProperty(
        name="Amount", 
        description="Amount", 
        default=1, 
        )


    @classmethod
    def poll(cls, context):
        return context.active_object is not None and context.mode == 'EDIT_MESH'

    def execute(self, context):
        bpy.ops.object.vertex_group_add()
        bpy.ops.object.vertex_group_assign()
        a=5
        for i in range(1, self.i+1):
            bpy.ops.mesh.select_random(seed=i, action='DESELECT')
            bpy.ops.transform.rotate(value=self.amount, axis=((0.5-random.random())*self.amount, (0.5-random.random())*self.amount, (0.5-random.random())*self.amount), constraint_orientation='NORMAL')
            bpy.ops.object.vertex_group_select()
        bpy.ops.object.vertex_group_remove(all=False)
        return {'FINISHED'}


def register():
    bpy.utils.register_class(RandomRotate)


def unregister():
    bpy.utils.unregister_class(RandomRotate)


if __name__ == "__main__":
    register()

The thing is it needs to run from 3d viewport to get the the rotation pivot setting from it’s context so it needs to be an operator. If you type Random Rotate into space bar menu in edit mode after running the script you will have an operator that will rotate the selected faces randomly. The controls for x y and z rotation are not working as I expected, but I don’t have time to look into it at the moment, you can control the amount from the f6 menu or the history panel or whatever it’s correct name is…

Edit: OK, its a silly mistake, controls of separate x,y and z rotation will not work unless I loop through all the selected faces, but I do not know a simple way of doing it without Bmesh so I hope this is going to be enough. I am correcting it to only have amount control.

1 Like

Thanks for that, appreciated. :slight_smile:
I ended up giving up on figuring out a tidy way of doing it and resorted to storing the selected faces, deselecting them, iterating and selecting one at a time and applying the rotation to that. Not elegant but it worked, have to have the script window open but hey ho. I’m sure someone with more talent could do better but it’s been a while since I did much coding. :slight_smile:



# Randomly Rotate Selected polygons
# Bit of a workaround, get selected, deselect, 
# select & rotate each individually then deselect again.
# ASSUMING the object is currently in Edit Mode.

import bpy
import bmesh
import math
import random

obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)

selected_faces = [f for f in bm.faces if f.select]

max_xy = 15
max_z = 35

for f in selected_faces:
        f.select = False;

for f in selected_faces:
    f.select = True
    
    my_xy = random.randint(max_xy * -1,max_xy)
    my_z = random.randint(max_z * -1,max_z)
    ro_xy = math.radians(my_xy)
    ro_z = math.radians(my_z)

    bpy.ops.transform.rotate(value=ro_xy, axis=(True, False, False), proportional='DISABLED')            ## X Axis
    bpy.ops.transform.rotate(value=ro_xy, axis=(False, True, False), proportional='DISABLED')            ## Y Axis
    bpy.ops.transform.rotate(value=ro_z, axis=(False, False, True), proportional='DISABLED')            ## Z Axis        

    f.select = False

for f in selected_faces:
        f.select = True;            ## ReSelect the original polys

bmesh.update_edit_mesh(me, True)

Even better! Seems elegant enough to me.

Hey, I wanted to randomise the leaves from the IvyGen and found this post.

I updated it for 2.8. It works but will obviously be slow for lots of faces.
Thank you for the initial code.

# Randomly Rotate Selected polygons
# Bit of a workaround, get selected, deselect, 
# select & rotate each individually then deselect again.
# ASSUMING the object is currently in Edit Mode.

import bpy
import bmesh
import math
import random

obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)

selected_faces = [f for f in bm.faces if f.select]

max_xy = 15
max_z = 40

for f in selected_faces:
        f.select = False;

for f in selected_faces:
    f.select = True
    
    my_x = random.randint(max_xy * -1,max_xy)
    my_y = random.randint(max_xy * -1,max_xy)
    my_z = random.randint(max_z * -1,max_z)
    ro_x = math.radians(my_x)
    ro_y = math.radians(my_y)
    ro_z = math.radians(my_z)
    
    bpy.ops.transform.rotate(value=ro_x, orient_axis=('X'), use_proportional_edit=False)            ## X Axis
    bpy.ops.transform.rotate(value=ro_y, orient_axis=('Y'), use_proportional_edit=False)            ## Y Axis
    bpy.ops.transform.rotate(value=ro_z, orient_axis=('Z'), use_proportional_edit=False)            ## Z Axis        

    f.select = False

for f in selected_faces:
        f.select = True;            ## ReSelect the original polys

bmesh.update_edit_mesh(me, True)
2 Likes

Just using the modeling tools, wouldn’t it be possible to hide everything but the faces you want to change, select one of them and use the random proportional editing tool with a large enough radius to affect all of them?

Unfortunately they do not rotate around the origin of each face(with individual origins selected). It basically picks up the vertices, unless I am doing something wrong.

I’m not at the computer to check, but I was thinking in face select mode, select one face with ‘individual origins’ and the proportional editing brush large enough to cover them all. And go from there.
Selecting all faces will move them all together as one, and check the proportional editing settings are not set to ‘connected’ distance if you have hidden the other faces they aren’t joined.

Sorry it doesn’t work like that for me in 2.8 or 2.81.

It would be great if you could make a short video or a gif. I might be missing something.

Ok, I see what you mean now. Random proportional editing does not respect the (Rotate on) Individual Origins of the parts it’s meant to be moving. I was thinking it would. It would be a nice feature to have though.
Trying again now, I’ve found with a grid, selecting one row* (along x) and rotating around y will get the result I think you’re looking for.
*In a single, connected, mesh you need to deselect alternate faces so each selected face rotates on its own origin. Having multiple pivot points like this avoids the big distortion of everything around one point.