Hi guys i am trying to create a grass generator that take a cone, deform it, duplicate it, and then spread it randomly on the geometry that i selected, using maya python.
i am a beginner, i only reached to the duplication part, how can i spread the blades(grass) on a surface ???,thank you !
import maya.cmds as MC
from random import uniform as RN
blade = MC.polyCone( sx=3, sy=5, sz=0, r=0.04, h=1, ax=(0, 1, 0))
MC.setAttr (blade[0] + '.translateY', (.5))
MC.delete(ch=True)
MC.polySoftEdge ( a=0 )
#adding deformer
bend = MC.nonLinear( type='bend', lowBound=0, highBound = 2,
curvature=30)
vtxPos = MC.xform(blade[0]+'.vtx[0]', q=True, t=True, ws=True)
MC.xform(bend, t=(0,vtxPos[1], 0))
MC.select (blade[0])
MC.delete(ch=True)
MC.makeIdentity(apply=True, t=1, r=1, s=1, n=0)
groupblades = MC.group(empty=True, name=blade[0] + '_grp#')
for i in range(200):
obj = MC.instance(blade[0])
MC.move(RN(1,-1), 0, RN(1,-1), blade[0])
MC.rotate(0, RN(0,360),0, blade[0])
MC.parent(obj, groupblades)
There's definitely lots of different approaches you can take to scatter objects on a surface. You can use geometry and normal constraints. There's MASH's framework. But I think using a follicle is easy enough and requires less overhead. The only catch is that the surface must have uvs as this is how we'll move the follicle around.
So here's what I'm suggesting:
Here's a full example:
import maya.cmds as cmds
import random
surface = "pPlane1" # Specify the object you want to scatter on.
fol_shape = cmds.createNode("follicle") # Create a new follicle object.
fol = cmds.listRelatives(fol_shape, f=True, parent=True)[0] # Get the follicle's transform.
# Below we are connecting the follicle to the surface so we can control it with its uvs.
cmds.connectAttr("{}.outMesh".format(surface), "{}.inputMesh".format(fol))
cmds.connectAttr("{}.worldMatrix[0]".format(surface), "{}.inputWorldMatrix".format(fol))
cmds.connectAttr("{}.outTranslate".format(fol_shape), "{}.translate".format(fol))
cmds.connectAttr("{}.outRotate".format(fol_shape), "{}.rotate".format(fol))
cmds.setAttr("{}.simulationMethod".format(fol_shape), 0)
# Begin creating blade of grass.
blade = cmds.polyCone(sx=3, sy=5, sz=0, r=0.04, h=1, ax=(0, 1, 0))
cmds.setAttr(blade[0] + '.translateY', .5)
cmds.delete(ch=True)
cmds.polySoftEdge(a=0)
# Setting wirecolor to green so it's easier to see.
cmds.setAttr(blade[0] + ".overrideEnabled", True)
cmds.setAttr(blade[0] + ".overrideRGBColors", True)
cmds.setAttr(blade[0] + ".overrideColorRGB", 0.06, 0.2, 0.06)
bend = cmds.nonLinear(type='bend', lowBound=0, highBound=2, curvature=30)
vtxPos = cmds.xform(blade[0] + '.vtx[0]', q=True, t=True, ws=True)
cmds.xform(bend, t=(0, vtxPos[1], 0))
cmds.select(blade[0])
cmds.delete(ch=True)
cmds.makeIdentity(apply=True, t=1, r=1, s=1, n=0)
groupblades = cmds.group(empty=True, name=blade[0] + '_grp#')
for i in range(400):
obj = cmds.instance(blade[0])
# Randomly set the follicle's uv so it's jumps somewhere else on the surface. Value needs to be between 0.0-1.0
cmds.setAttr("{}.parameterU".format(fol_shape), random.random())
cmds.setAttr("{}.parameterV".format(fol_shape), random.random())
cmds.matchTransform(obj, fol) # Make grass match follicle's position/rotation/scale.
cmds.rotate(-90, random.random() * 360, 0, obj, r=True) # Rotate it upright and give it random twist.
cmds.move(0, 0.4, 0, obj, r=True) # The grass's pivot is in the center, so need to offset translation a bit up.
cmds.parent(obj, groupblades)
cmds.delete(fol) # Follicle no longer needed, so delete it.
There's one part where I need to move the grass up a bit because the pivot point is at the grass's center. This is a minor hack and the real solution would be to build the grass with the pivot point at its base. Doing that would solve any floating grass and make randomizing scaling easier.
Here's what it will output: