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:
- apply the noise with given limits to the x, y, z coordinates
- 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
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()