Professional Documents
Culture Documents
Layering
So… when dealing with a lot of code, scripting can be overwhelming. Some of the best advice on
managing complexity came from Jonas Lundberg (ufo_se) who said that ‘in order to control complexity,
you need to understand simple systems… then build on layers of behaviour’.
Catalog
managed by a very regimented practice of developing and documenting a catalog of code, try to write
small snippets of code that do very particular tasks and then save them out (usually with images) to
library folders, particular to each function (e.g. point aggregation; surface generation; utilities; etc.). You
can then draw from an easily viewable library, pulling specific code and dropping in as a function or
subroutine.
code library
Reuse
That’s the next rule. Try to write functions and subroutines as often as possible – this way you can clearly
keep track of your scripts as well as economizing your code. Practicing this also leads to good coding
techniques in syntax and flow.
Although there’s a massive collection of particle systems already available for computational
investigations, I thought we’d write an introduction for grasshopper & enable a more geometric and
structural direction within particle engines.
We’ll start off with some basic techniques such as component variables, timers and counting, working our
way through vectors and multiple particle scenarios. Over the coming days / weeks we’ll also investigate
the efficiency of working with DisplayPipelines to reduce the computational load – allowing for more
intensive populations of particles / computation.
Further to this we can start to explore spatial modifiers + internal features within the particles
(nodes/agents) – including reaction to forces such as gravity and wind and the way in which constraints
and organizational patterns form emergent design.
If we declared an integer variable ‘i’ within the component’s subroutine and then adding a line to count
such as ‘i = i + 1’ we would effectively be re-declaring the variable every time the timer calls the VB
component. A GH component contains the Runscript subroutine which is just that – a subroutine that is
called every time the component is updated – and a Timer component updates a VB component.
What we really want to achieve is for a variable to be declared inside the VB component but outside of
the Runscript subroutine.
We need to the section below the ‘<Custom additional code> comment to declare a variable. We’ll call
our variable ‘i’ and should fill in the code as per below.
Dim i A s I nt3 2 = 0
A = i
i = i + 1
Which adds 1 to the value of i. Note that we added this line AFTER we output so that we don’t add one to
the value of i before we output the first element:
A = i
i = i + 1
End Sub
Now let’s attach a Timer component to the VB component and enable the Timer. You can change the
interval to 10 milliseconds.
The Timer should now be refreshing the VB component, calling the Runscript subroutine and adding 1 to
the ‘i’ variable that we have declared outside of the subroutine. Although we have declared the variable
after the Runscript subroutine > it’s ok as the VB component compiles the script before excecuting,
therefore, ‘i’ is declared before Runscript is called.
Create a new point object within Rhino and reference using a Point Param.
Drag out a new VB component, go to Input Manager, remove both x & y inputs and create an ‘inPt’ input.
Right click on the input and change type to ‘Point3d’
Connect the Pt component into the inPt input on the VB component.
canvas view
End Sub
What we have now is a single particle generated from the inPt emitter that seems* to move one unit in the
x direction every time we move the emitter or count using the Timer.
particle emission
We can now start adding features such as a run and clear command to the component and script.
Right click the component and add another input ‘run’ to the Input Manager. Change the Type to Boolean.
Drag a Boolean Param from the Special group and connect to the ‘run’ input.
canvas view
Open the script and add a new condition to the script by checking to see if ‘run’ is true. You will also need
to include an Else statement which will reset the ‘i’ count. The run condition will also skip the entire script,
furthermore, as the ‘A’ output is within the ‘run’ condition, no geometry will be output from the component:
If(r un) Th en
Dim new Pt As Po in t3d = i nPt
newP t.x = new Pt .x + i
A = new Pt
i = i + 1
Else
i = 0
End If
End Sub
Ok. Previously I mentioned we seemed* to move the point one unit in the x direction. We actually
generated a new point every count and placed it in the corresponding x position. What we want is to start
using vectors – this will eventually allow us to use multiple particles through multiple vectors. Let’s change
some code to introduce two Vector variables outside of the RunScript subroutine using:
I’m using two vectors here so that I can use one as a base vector whilst the other is the vector that we will
sequentially add the base vector to. We will then use this additive vector ‘vec’ to move a Point3d
geometry to a new location each time – I’m adding this after we output the first vector movement.
ne wP t = n e wP t + vec
‘Alternatively we could be utilizing the new Rhinocommon Rhino.Geometry.Point object in which we can
use the newPt.Translate method.
Lastly we will unitize the vector ‘vec’ each time we reset the script – this should be added within the Else
statement.
v ec . Un i t i ze
If(run) Then
Dim newPt As Point3d = inPt
newPt = newPt + vec
A = newPt
vec = vec + baseVec
Else
vec.Unitize
End If
End Sub
Ok. Let’s now say that we want to emit a number of particles from the inPt emitter. We need to then add a
list variable to the Custom additional code area so that we can output a list of points rather than a singular
agent.
Just add a few lines of code to reflect the new list generation. The first should be written in the custom
section:
now add the newPt to ptList below where we have moved the point by the vector (just above the ‘A’
output):
we now need to change the output data to ptList so that it sends out the list rather than the newPt:
A = ptL ist
And finally we clear the list so that every time we reset, the list will be refreshed – this will be added under
where we untize the vector in the ‘Else’ option.
If(run) Then
End Sub
particle list
Great – so now we have a long list of particles. Rather than plotting each one out along an additive
vector, we can introduce a spray effect on the particle emission to create a varied distribution on the
system. Let’s now create a random double (number) between 0 and 5 and then redefine the baseVec’s Y
position by the resulting double – code this just above where we add vec + baseVec:
You’ll now notice that you have a particle that’s only interested in wandering in the Y axis in a positive
direction. If we wanted this to move between positive and negative in the Y axis, you will need to amend
yPos declaration as:
This should produce a wander in the x direction, both in the positive and negative y axis.
5 – 2 = -3
5 – 10 = - 5
5 – 0 = -5
So why are the particles static once they have been aggregated in the list? Well, they are under no further
force to propel them once they have been populated. We would need to cycle through each point in the
list and effectively move them one by one with a vector. We can simply add a ‘For i’ loop after we add the
point to the list – this will move each ptList particle per RunScript update.
It’s getting better… However, we are forever increasing the vector every time we add a new point to the
list, therefore increasing each point in ptList by the growing vector each time we refresh the component.
What we need to be implementing is a vector list in which each new vector will correspond to each new
point. This means we can loop through each ptList(i) point per refresh and pull it’s paired vecList(i) vector
– an easy way to keep track of particle counts.
Let’s start by firstly creating a new list of vectors in the Custom code area:
We should also remove the vector addition to the point as we will do this in a loop after (so delete the line
newPt = newPt + vec). You can also remove any line that has baseVec (including the Custom code area)
as we won’t be working with a secondary vector.
Ok – now for a new vector – cut the yPos declaration & paste below where we declare the variable newPt
– we can follow this by a vec declaration – so cut the Custom code vec declaration and paste it to just
below the yPos declaration.
Now it’s time to move each point in ptList by it’s corresponding vector in vecList – so change the loop line
to:
Lastly, if we are going to use the clear function on the ptList when we stop the particle generation, we
should also clear vecList – write this code in the Else statement:
End Sub
So that’s it! Particles are now being generated from the single emitter point. Right – so next session we’re
going to look at controlling the spray along with particle acceleration methods, lifespan and containment.