Is there a way in Blender (currently using 2.69) to generate weights in a vertex group procedurally?
Scenario: I have an island. I want the particle-system-generated foliage to be thicker where the ground is flatter and sparser where it is steeper.
For materials i have achieved different shadings for flat and sloped by creating a node set that takes the dot product of the normal with the vertical vector (0,0,1). This has worked well. Now I would like to use the same trick to weight vertices in a vertex group to control the density of “hairs” (will be scrub vegetation in practice). I can’t see a way to bring the membership of a vertex group under node control.
This may be accessible via bpy, but I wouldn’t know first hand. Try asking in python support if they could give you some tips on a script which could utilize the normal data.
I’ve been teaching myself python, though I have been programming c, java,php… for years. This is a script cobbled together using some code from another BA post which is credited in the script. About half of the lines I wrote myself. It uses the dot product. Instructions for use are in the script, as well as the 3 parameters you can change. I haven’t done much testing on it, but it seems to work well for terrian type meshes.
import bpy
import random
import operator
# THIS SCRIPT WEIGHT PAINTS A VERTEX GROUP USING Z COMPONENT NORMAL DATA
# FLAT AREAS GET RED, STEEP AREAS GET BLUE
# MUCH OF THE CODE IN THIS SCRIPT WAS MODIFIED USING CODE FROM THIS URL
# http://blenderartists.org/forum/archive/index.php/t-202503.html
# WRITTEN BY TrumanBlending, MODIFIED BY blenderallday 12/21/13 Blender v2.69
# TO USE: CREATE AND ASSIGN A VERTEX GROUP CALLED 'normalweights' . SPELLING MUST BE EXACT
# SELECT YOUR OBJECT
# OPEN A TEXT EDITOR WINDOW, CLICK THE 'NEW' BUTTON
# PASTE THIS SCRIPT INTO THE TEXT EDITOR
# CLICK 'Run Script' (ALT-P)
# THERE ARE 3 PARAMETERS WHICH YOU CAN SET, 'offset' , 'randomness', and 'invert' read below:
# TO CHANGE THE VALUES, Change them, CLICK Text menu, 'Save' and then 'Run Script' button
offset = 0 # THIS PUSHES ALL WEIGHTS EQUALLY, TO MAKE EVERYTHING MORE RED USE POSITIVE E.G. .25, FOR MORE BLUE USE NEGATIVE
randomness = 0 # THIS ADDS RANDOM NOISE TO THE VALUES , 0 FOR NO NOISE, USE POSITIVE 0-1, E.G. .1
invert = 0 # SET TO 1 TO MAKE FLAT AREAS BLUE, AND STEEP AREAS RED. MUST BE EITHER 0 OR 1
vertexGroupName = 'normalweights' #THE NAME OF THE VERTEX GROUP TO WEIGHT PAINT
obj = bpy.context.active_object
bpy.ops.object.mode_set(mode='OBJECT',toggle=True)
mesh = obj.data
selVerts = [v for v in mesh.vertices]
indexVal = obj.vertex_groups[vertexGroupName].index
for v in selVerts: #loop over all verts
for n in v.groups: #loop over all groups with each vert
if n.group == indexVal: #check if the group val is the same as the index value of the required vertex group
zvec = (0,0,1.0)
dotproduct = sum(p*q for p,q in zip(v.normal, zvec))
newweight = dotproduct
newweight = newweight + offset
plusorminus = random.randint(0,1)
randomvalue = random.uniform(0,randomness)
if (plusorminus == 0):
newweight += randomvalue
if (plusorminus == 1):
newweight -= randomvalue
if (newweight > 1):
newweight = 1
if (newweight < 0):
newweight = 0
if (invert == 1):
newweight = 1 - newweight
n.weight = newweight #ACTUALLY SET THE WEIGHT OF THE VERTEX
bpy.ops.object.mode_set(mode='WEIGHT_PAINT',toggle=False)
Perfect! Thank you so much. If I knew how to I would mark this thread as “solved”.
For future readers who come here later I will only add a reminder to check the directions of your normals if everything seems to be coming up weighted as 0.0.
I guess I’ll assume you are thanking me, in which case, you’re welcome. Marking threads solved these days seems to require programming knowledge. It used to be so easy.
If you want any other functionality or something isn’t working right, let me know, I’m sure I can throw something together.