Procedural weight painting?

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.

Am I missing something?

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.

If your just trying to achieve a result and it doesn’t HAVE to be procedural

In edit mode circle select several areas that are part of the “flat” zones

Select similar (shift g) by co-planer - use the “less” option and slide up the threshold value till you have what you want

Now switch to weight paint mode and with a weight value of 1 “shift k” apply weight

Done

Attachments


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. :frowning:

If you want any other functionality or something isn’t working right, let me know, I’m sure I can throw something together.

I believe you just edit the first post and change its subject line to include “[SOLVED]” now.