|
|
@@ -1,4 +1,3 @@
|
|
|
-
|
|
|
# This code is called when instances of this SOP cook.
|
|
|
#scaleFactor = node.parm("scaleFactor").eval()
|
|
|
|
|
|
@@ -11,55 +10,52 @@ node = hou.pwd()
|
|
|
geo = node.geometry()
|
|
|
|
|
|
|
|
|
+# map user input
|
|
|
+GENERATIONS = hou.ch('generations')
|
|
|
+TROPISM = hou.Vector3(hou.parmTuple("tropDir").eval())
|
|
|
+TROPISMFACTOR = hou.ch('tropStrength')
|
|
|
+GRAVITYFACTOR = hou.ch('gFactor')
|
|
|
+SEED=123
|
|
|
+#hou.ch("falloff")
|
|
|
+
|
|
|
# the "seed"
|
|
|
+# this is the first point from which the tree will grow.
|
|
|
point=geo.createPoint()
|
|
|
pointers=[point]
|
|
|
-initVector=hou.Vector3([0,0,0])
|
|
|
-
|
|
|
-# init the point attributes to store the values in
|
|
|
-NAttr = geo.addAttrib(hou.attribType.Point, "N", initVector)
|
|
|
-BAttr = geo.addAttrib(hou.attribType.Point, "Branch", 0)
|
|
|
-GAttr = geo.addAttrib(hou.attribType.Point, "Generation", 0)
|
|
|
-BNAttr = geo.addAttrib(hou.attribType.Point, "BranchPoint", 0)
|
|
|
-BTNAttr = geo.addAttrib(hou.attribType.Point, 'NormalizedPosition', 0.0)
|
|
|
-DAttr = geo.addAttrib(hou.attribType.Point, 'Diameter', 1.0)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-point.setAttribValue("N", hou.Vector3([0,1,0]))
|
|
|
-point.setAttribValue("Branch", 0)
|
|
|
-point.setAttribValue('NormalizedPosition', 0.5)
|
|
|
-
|
|
|
|
|
|
+# init the point attributes to store the values in, as these must exist.
|
|
|
+# As we start, the first point's normal will point upward to grow in that direction.
|
|
|
+geo.addAttrib(hou.attribType.Point, "N", hou.Vector3([0,1,0]))
|
|
|
+geo.addAttrib(hou.attribType.Point, "Branch", 0)
|
|
|
+geo.addAttrib(hou.attribType.Point, "Generation", 0)
|
|
|
+geo.addAttrib(hou.attribType.Point, "BranchPoint", 0)
|
|
|
+geo.addAttrib(hou.attribType.Point, 'NormalizedPosition', 0.0)
|
|
|
+geo.addAttrib(hou.attribType.Point, 'Diameter', 1.0)
|
|
|
|
|
|
-defaultGrp=geo.createPointGroup('name')
|
|
|
-defaultGrp.add(point)
|
|
|
+# Just in case, if we need groups, this is how to do it.
|
|
|
+#defaultGrp=geo.createPointGroup('name')
|
|
|
+#defaultGrp.add(point)
|
|
|
|
|
|
-#print point.attribValue("N")
|
|
|
|
|
|
def duplicatePoint(p):
|
|
|
# hmm. maybe there is sth like this already, but i missed it...
|
|
|
+ # this duplicates a point and all it's attributes.
|
|
|
dupe=geo.createPoint()
|
|
|
dupe.setPosition(p.position())
|
|
|
allAttr=geo.pointAttribs()
|
|
|
for i in allAttr:
|
|
|
- #print i
|
|
|
holder=None
|
|
|
holder=p.attribValue(i)
|
|
|
- #print holder
|
|
|
dupe.setAttribValue(i, holder)
|
|
|
return dupe
|
|
|
|
|
|
-#dupe=duplicatePoint(point)
|
|
|
-
|
|
|
-
|
|
|
def tropism(pt,vector,factor):
|
|
|
'''Move point towards another point, as in growing towards a light source (sun)
|
|
|
or a food source (roots)
|
|
|
'''
|
|
|
P = pt.position()
|
|
|
- pt.setPosition( P + 1 * vector)
|
|
|
+ vector=vector.normalized()
|
|
|
+ pt.setPosition( P + (1*factor) * vector)
|
|
|
|
|
|
def moveAlongNormal(pt,factor):
|
|
|
P = pt.position()
|
|
|
@@ -68,7 +64,16 @@ def moveAlongNormal(pt,factor):
|
|
|
N = pt.attribValue("N")
|
|
|
N = hou.Vector3(N)
|
|
|
pt.setPosition( P + (1*factor) * N )
|
|
|
-
|
|
|
+
|
|
|
+def gravity(pt,factor):
|
|
|
+ '''Convenience function to move down a point, multiplied by diameter.'''
|
|
|
+ P = pt.position()
|
|
|
+ # The downforce D
|
|
|
+ D = (1 - pt.attribValue('Diameter'))*factor
|
|
|
+ G = hou.Vector3([0,D,0])
|
|
|
+ pt.setPosition( P - G)
|
|
|
+
|
|
|
+
|
|
|
def createRandomVector():
|
|
|
rx = (random.random()-0.5)*2
|
|
|
ry = (random.random()-0.5)*2
|
|
|
@@ -86,13 +91,21 @@ def addNoiseToNormal(pt,factor):
|
|
|
pt.setAttribValue("N", newN)
|
|
|
return pt
|
|
|
|
|
|
-def rotateNormal(pt,factor):
|
|
|
+def rotateNormal(pt,factor,seed):
|
|
|
N = pt.attribValue("N")
|
|
|
N = hou.Vector3(N)
|
|
|
- rx = (random.random()-0.5)*2
|
|
|
- ry = (random.random()-0.5)*2
|
|
|
- rz = (random.random()-0.5)*2
|
|
|
- rvec = hou.Vector3([rx*factor,ry*factor,rz*factor])
|
|
|
+
|
|
|
+ x = ( random.random()-0.5 )*2
|
|
|
+ y = ( random.random()-0.5 )*2
|
|
|
+ z = ( random.random()-0.5 )*2
|
|
|
+ print 'p random x {0} y {1} z {2}'.format(x,y,z)
|
|
|
+
|
|
|
+ x = ( hou.hmath.rand(seed+12*43)-0.5 )*2
|
|
|
+ y = ( hou.hmath.rand(seed+2+2*3)-0.5 )*2
|
|
|
+ z = ( hou.hmath.rand(seed+33*2)-0.5 )*2
|
|
|
+ print 'h random x {0} y {1} z {2}'.format(x,y,z)
|
|
|
+
|
|
|
+ rvec = hou.Vector3([x*factor,y*factor,z*factor])
|
|
|
newN = rvec + 1 * N
|
|
|
pt.setAttribValue("N", newN)
|
|
|
return pt
|
|
|
@@ -113,63 +126,56 @@ def getHighestNumericAttrVal(points,attr):
|
|
|
|
|
|
|
|
|
|
|
|
-branchgroups=[]
|
|
|
-
|
|
|
branchNum=0
|
|
|
|
|
|
-def step(pointers):
|
|
|
+def step(pointers,stepseed):
|
|
|
+ ''' step through all head pointers (aka growing branches)'''
|
|
|
updatedPointers=[]
|
|
|
for p in pointers:
|
|
|
- n=p.attribValue("N")
|
|
|
-
|
|
|
#print 'pointer is point w/ # ' + str(p.number())
|
|
|
-
|
|
|
newP=duplicatePoint(p)
|
|
|
#print 'copy is point w/ # ' + str(newP.number())
|
|
|
-
|
|
|
updatedPointers.append(newP)
|
|
|
newP.setAttribValue('BranchPoint',newP.attribValue('BranchPoint')+1)
|
|
|
-
|
|
|
# Should we branch?
|
|
|
# TODO allow multiple branches at once
|
|
|
rnd=random.random()
|
|
|
+ rnd=hou.hmath.rand(stepseed+11)
|
|
|
if rnd > 0.7:
|
|
|
-
|
|
|
-
|
|
|
# Dirty, find a better way soon!
|
|
|
global branchNum
|
|
|
branchNum+=1
|
|
|
-
|
|
|
global treeInfo
|
|
|
#treeInfo['totalbranches']+=1
|
|
|
-
|
|
|
#print 'branch'
|
|
|
branchP=duplicatePoint(p)
|
|
|
-
|
|
|
branchP.setAttribValue('BranchPoint',0)
|
|
|
-
|
|
|
b=branchP.attribValue('Branch')
|
|
|
branchP.setAttribValue('Branch',branchNum)
|
|
|
#branchP.setAttribValue('Branch',b+1)
|
|
|
-
|
|
|
-
|
|
|
g=branchP.attribValue('Generation')
|
|
|
branchP.setAttribValue('Generation',g+1)
|
|
|
updatedPointers.append(branchP)
|
|
|
-
|
|
|
- newP=rotateNormal(newP,0.4)
|
|
|
+ stepseed+=1
|
|
|
+ newP=rotateNormal(newP,0.4,stepseed)
|
|
|
# now move along normal
|
|
|
moveAlongNormal(newP,1)
|
|
|
v=hou.Vector3(0,1,1)
|
|
|
- tropism(newP,v,1)
|
|
|
- newP.setAttribValue('Diameter',newP.attribValue('Diameter')*0.9 )
|
|
|
+ tropism(newP,TROPISM,TROPISMFACTOR)
|
|
|
+ gravity(newP,GRAVITYFACTOR)
|
|
|
+ newP.setAttribValue('Diameter',newP.attribValue('Diameter')*0.7 )
|
|
|
+ stepseed+=1
|
|
|
+ print 'seed ' + str(stepseed)
|
|
|
return updatedPointers
|
|
|
|
|
|
|
|
|
-x=step(pointers)
|
|
|
+x=step(pointers,1)
|
|
|
|
|
|
-for arsch in range(15):
|
|
|
- x = step(x)
|
|
|
+seed=2
|
|
|
+for arsch in range(GENERATIONS):
|
|
|
+ #seed=1
|
|
|
+ x = step(x,seed)
|
|
|
+ seed+=1
|
|
|
|
|
|
|
|
|
|
|
|
@@ -203,18 +209,15 @@ for i in range(0,totalBranches):
|
|
|
if v>max: max=v
|
|
|
for p in getPointsByAttribValue('Branch',i):
|
|
|
bp=p.attribValue('BranchPoint')
|
|
|
- print max
|
|
|
- print bp
|
|
|
+ #print max
|
|
|
+ #print bp
|
|
|
try:
|
|
|
relpos=float(bp)/float(max)
|
|
|
except:
|
|
|
relpos=0
|
|
|
#p.setAttribValue('NormalizedPosition',1)
|
|
|
p.setAttribValue('NormalizedPosition', float(relpos))
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- print '---'
|
|
|
+ #print '---'
|
|
|
#print bp + max
|
|
|
|
|
|
#print 'branch {0} points {1}'.format(i,max)
|
|
|
@@ -225,7 +228,7 @@ for i in range(0,totalBranches):
|
|
|
# in addition to the branch 'id' we need a distance of each point of a branch towards it's parent.
|
|
|
# useful: how many 'levels' are we away from the main parent? > point needs to have parent id, increment on branch
|
|
|
# roots
|
|
|
-
|
|
|
+# DIAMETER should decrease by a step after each branch
|
|
|
|
|
|
|
|
|
|