New Script to apply random relocation to vertices

Hello,
I have created a small script which allows you to apply a random
relocation to selected vertices.
The script must be used from edit mode, and it basically has two
modes of operation:

  1. apply the noise with given limits to the x, y, z coordinates
  2. apply the noise with limits to the vertex normal, and the
    directions orthogonal to it.

Maybe you’ll find it useful, but it’s my first script, so it will not be
perfect :wink:

I used it to make walls like more “natural”.

Best regards,
Michael



#!BPY
"""
Name: 'Vertex Noise'
Blender: 242
Group: 'Mesh'
Tooltip: 'Apply random relocation to selected vertices.'
"""

__author__ = ["Michael Bischoff"]
__url__ = ("blender", "eldorado", "http://none.existing.de/blender/")
__version__ = "0.1"
__bpydoc__ = """\
Vertex Noise

Apply random relocation to selected vertices.
"""

# ***** BEGIN GPL LICENSE BLOCK *****
#
# Script copyright (C) Michael Bischoff
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------


import math
import Blender
from Blender import Mathutils, Window, NMesh, Draw, Scene, Noise
from Blender.Mathutils import *

import BPyMesh




def main():
        scn = Scene.GetCurrent()
        ob = scn.getActiveObject()

        is_editmode= Window.EditMode()

        if not is_editmode:
                Draw.PupMenu('Error! Must be in Edit mode%t|Please switch to edit mode, then call this script again.')
                return

        if ob == None or ob.getType() != 'Mesh':
                Draw.PupMenu('Error! No active mesh selected%t|You must have a mesh object selected.')
                return


        #=================================#
        # Popup menu to obtain parameters #
        #=================================#

        noise_mode_iso = Draw.Create(1)
        noise_dx = Draw.Create(0.05)
        noise_dy = Draw.Create(0.05)
        noise_dz = Draw.Create(0.05)
        noise_dn = Draw.Create(0.1)
        noise_do = Draw.Create(0.05)

        noise_falloff_exp = Draw.Create(0.0)

        noise_edge_factor_min = Draw.Create(0.75)
        noise_edge_factor_max = Draw.Create(1.25)

        # Get parameters from user

        pup_block= [\
        ('ISO mode', noise_mode_iso, 'use (dx,dy,dz) (else dn/do).'),\
        'ISO mode parameters:',
        ('dx', noise_dx, 0.0, 100.0, 'max. x relocation in ISO mode.'),\
        ('dy', noise_dy, 0.0, 100.0, 'max. y relocation in ISO mode.'),\
        ('dz', noise_dz, 0.0, 100.0, 'max. z relocation in ISO mode.'),\
        'n/o mode parameters:',
        ('dn', noise_dn, 0.0, 100.0, 'max. relocation along normal (in n/o mode).'),\
        ('do', noise_do, 0.0, 100.0, 'max. relocation perpendicular to normal (in n/o mode).'),\
        'Noise distribution:',
        ('falloff exponent e', noise_falloff_exp, 0.0, 100.0, '0 = constant noise, otherwise amplitude decreases by exp(e * D*D) where D is distance of vertex to 3D cursor.'),\
        #'Limit distance changes:',
        #('min factor', noise_edge_factor_min, 0.0, 0.999, 'any adjacent edge lenngth may not decrease by less than this factor (must be in interval 0 <= min < 1).'),\
        #('max factor', noise_edge_factor_max, 1.001, 100.0, 'any adjacent edge length may not increase by more than this factor (must be bigger than 1).'),\
        ]

        if not Draw.PupBlock('Randomly relocate vertices', pup_block):
                return

        noise_mode_iso = noise_mode_iso.val
        noise_dx = noise_dx.val
        noise_dy = noise_dy.val
        noise_dz = noise_dz.val
        noise_dn = noise_dn.val
        noise_do = noise_do.val
        noise_falloff_exp     = noise_falloff_exp.val
        noise_edge_factor_min = noise_edge_factor_min.val
        noise_edge_factor_max = noise_edge_factor_max.val


        # leave edit mode before getting mesh (suggested by Python reference)
        Window.EditMode(0)

        me = ob.getData(mesh=1)
        cursor_pos = Vector(Window.GetCursorPos())
        count = 0

        for v in me.verts:
                if v.sel:
                        count += 1
                        noise_vec = Vector(Noise.randuvec())  # required in order to use Vector * scalar
                        noise_amp = Noise.random()   # TODO: use smarter distribution (higher offsets less likely)
                        # compute factor for falloff
                        if noise_falloff_exp > 0.0:
                                # stupid, we compute the root of the diff vector and square it again
                                dist_to_cursor = (cursor_pos - v.co).length
                                noise_amp *= math.exp(-noise_falloff_exp * dist_to_cursor * dist_to_cursor)
                        noise_vec *= noise_amp
                        if noise_mode_iso == 1:
                                noise_vec[0] *= noise_dx
                                noise_vec[1] *= noise_dy
                                noise_vec[2] *= noise_dz
                        else:
                                # compute normal and orthogonal parts
                                alpha = noise_vec * v.no
                                # normal part = v.no * alpha
                                noise_vec -= alpha * v.no
                                # orthogonal part = noise_vec
                                noise_vec = noise_dn * alpha * v.no + noise_do * noise_vec
                        # noise vector done
                        v.co += noise_vec

        # update mesh data
        me.update()

        # TODO: recalc normals. according to doc, a suitable parameter to
        # me.update() should be able to do this, but this did not work in 2.42a

        # return to edit mode
        Window.EditMode(1)

        statmsg = 'Processed %i vertices|' % count
        Draw.PupMenu(statmsg)


if __name__ == '__main__':
        main()

ooops, any hints how I can preserve leading space in the post?

Best regards,
Michael

You must use the “[ code. ]” tags (the right button, looks like # ) and your code will look as code. Basically just edit your post, it’s easy.

Hi tedi,
thanks a lot, it worked!

Best regards,
Michael

Great script!

I was thinking that this would be a cool addition to the simple subdivide modifier or a cool modifier on its own. Btw, you can do something like this with modifiers by using displace and a cloud texture for displacement.

Nice script,
Its alredy possible to do random vert offsets with a modifier
Use the displacement modifier with a random texture after a subsurf.

These kinds of scripts are still realy usefull for testing different mothods of displacement and as examples.

some hints, small improvements.
v.co += noise_vec # should work rather then doing all 3 indervidualy.

Its good to avoid creating new vectors (allocating and deallocating and time spent in creation)
so you can do…
v_no= v.no # then reuse that.

Hi,
thanks a lot. I changed the component addition to the vector
addition.

I checked the existing blender displacement function -
I did not know that before. It has some other interesting
features (correlation between the vertex offsets, making
more a smooth deformation), so I’ll use that one and
my script both, I think.

Best regards,
Michael

Just yesterday broken added a new propertional falloff mode “random” so verts are randomly assigned a weight, thats mixed with linear falloff.
This probably does somthing closer to what the script does then the modifier.