Vous êtes sur la page 1sur 10

u r b a n f u t u r e o r g a n i z a t i o n

particles for GH3D 101: part 1

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’.

This one quote really led to a good coding rule of thumb.

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.

Now what about particle system in general?

u rb a n f ut u re o rg a ni zati o n ● 1 8 4 s t j o h ns road. gl ebe. nsw. 2037 ● + 61 295716336 ● www. au -urbanf ut ure.org


u r b a n f u t u r e o r g a n i z a t i o n

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.

Implementing a Timer Component to count


Let’s say for example that we wanted to attach a timer to a VB component in order to count integers as
the timer ticked away. In a typical counting procedure, you would be looking to implement a loop within
the body of the component in order to count an integer – this would result in the full loop being executed
before grasshopper can pass the information out of the subroutine and into the viewport.

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

We should then add two lines of code to the RunScript sub.

A = i

Which outputs the value of ‘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:

Priv ate Su b R un Sc ript ( By Val x As O bjec t, ByV al y As Obj ect , B yRe f


A As Ob jec t )

A = i
i = i + 1

u rb a n f ut u re o rg a ni zati o n ● 1 8 4 s t j o h ns road. gl ebe. nsw. 2037 ● + 61 295716336 ● www. au -urbanf ut ure.org


u r b a n f u t u r e o r g a n i z a t i o n

End Sub

‘<Custom additional code>


Dim i As Int32 = 0

Now let’s attach a Timer component to the VB component and enable the Timer. You can change the
interval to 10 milliseconds.

canvas view – timer component = counting

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.

Creating an Emitter and a Single Particle


Right, so now let’s apply the same technique but to a point3d geometry.

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

Open the VB component and code into the script:

u rb a n f ut u re o rg a ni zati o n ● 1 8 4 s t j o h ns road. gl ebe. nsw. 2037 ● + 61 295716336 ● www. au -urbanf ut ure.org


u r b a n f u t u r e o r g a n i z a t i o n

Dim pt As Poi nt 3d = i nPt

The script should now read as:

Priv ate Su b R un Sc ript ( By Val in Pt A s Po int 3d, By Re f A As Ob jec t)

Dim newPt As Point3d = inPt


newPt.x = newPt.x + i
A = newPt
i = i + 1

End Sub

‘<Custom additional code>


Dim i As Int32 = 0

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

What if we now want to clear the results of the particle’s movement?

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.

u rb a n f ut u re o rg a ni zati o n ● 1 8 4 s t j o h ns road. gl ebe. nsw. 2037 ● + 61 295716336 ● www. au -urbanf ut ure.org


u r b a n f u t u r e o r g a n i z a t i o n

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:

Priv ate Su b R un Sc ript ( By Val in Pt A s Po int 3d, By Re f A As Ob jec t)

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

‘<Custom additional code>


Dim i As Int32 = 0

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:

Dim b as e Vec As Ne w V ec t or 3d( 1, 0 ,0)


Dim vec As Ne w V ec to r 3d ( 1 ,0 , 0)

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

u rb a n f ut u re o rg a ni zati o n ● 1 8 4 s t j o h ns road. gl ebe. nsw. 2037 ● + 61 295716336 ● www. au -urbanf ut ure.org


u r b a n f u t u r e o r g a n i z a t i o n

‘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

The script should now look like this:

Priv ate Su b R un Sc ript ( By Val in Pt A s Po int 3d, By Re f A As Ob jec t)

If(run) Then
Dim newPt As Point3d = inPt
newPt = newPt + vec
A = newPt
vec = vec + baseVec
Else
vec.Unitize
End If

End Sub

‘<Custom additional code>


Dim baseVec As New Vector3d(1,0,0)
Dim vec As New Vector3d(1,0,0)

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:

Dim ptL ist As N ew Lis t( O f P oin t3 d)

now add the newPt to ptList below where we have moved the point by the vector (just above the ‘A’
output):

ptLi st. Add (ne wP t)

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.

u rb a n f ut u re o rg a ni zati o n ● 1 8 4 s t j o h ns road. gl ebe. nsw. 2037 ● + 61 295716336 ● www. au -urbanf ut ure.org


u r b a n f u t u r e o r g a n i z a t i o n

ptLi st. Cle ar

The script should read like this:

Priv ate Su b R un Sc ript ( By Val in Pt A s Po int 3d, By Re f A As Ob jec t )

If(run) Then

Dim newPt As New Point3d = inPt


newPt = newPt + vec
ptList.Add(newPt)
A = ptList
vec = vec + baseVec
Else
vec.Unitize
ptList.Clear
End If

End Sub

‘<Custom additional code>


Dim ptList As New List(Of Point3d)
Dim baseVec As New Vector3d(1, 0, 0)
Dim vec As New Vector3d(1, 0, 0)

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:

Dim yPo s A s D ou bl e = (Rn d * 5. 0)


base Vec .Y = y Po s

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:

u rb a n f ut u re o rg a ni zati o n ● 1 8 4 s t j o h ns road. gl ebe. nsw. 2037 ● + 61 295716336 ● www. au -urbanf ut ure.org


u r b a n f u t u r e o r g a n i z a t i o n

Dim yPo s A s D ou bl e = 5 – (R nd * 10 .0)

This should produce a wander in the x direction, both in the positive and negative y axis.

Say for example that the random number produces a (2)

5 – 2 = -3

or worst case scenario it produces a (10)

5 – 10 = - 5

Other end of the spectrum would result in (0)

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

u rb a n f ut u re o rg a ni zati o n ● 1 8 4 s t j o h ns road. gl ebe. nsw. 2037 ● + 61 295716336 ● www. au -urbanf ut ure.org


u r b a n f u t u r e o r g a n i z a t i o n

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.

For i A s I nt3 2 = 0 T o pt Lis t.C ou nt – 1


ptLi st( i) = p tL is t(i) + vec
Next

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:

Dim vec Lis t A s Ne w Li st ( Of Ve ct or 3d)

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:

ptLi st( i) = p tL is t(i) + vec Lis t( i)

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:

vecL ist .Cl ear

u rb a n f ut u re o rg a ni zati o n ● 1 8 4 s t j o h ns road. gl ebe. nsw. 2037 ● + 61 295716336 ● www. au -urbanf ut ure.org


u r b a n f u t u r e o r g a n i z a t i o n

The code should now read as follow:

Priv ate Su b R un Sc ript ( By Val in Pt A s Po int 3d, By Re f A As Ob jec t )


If(r un) Th en
Dim yPo s A s D ou bl e = 5 – (R nd * 10 .0)
Dim vec As Ne w Ve ctor 3d( 1, yPo s, 0 )
vecL ist .Ad d(v ec )
Dim new Pt As Po in t3d = i nPt
ptLi st. Add (ne wP t)
For i A s I nt3 2 = 0 To pt Lis t.C ou nt – 1
ptLi st( i) = p tL is t(i) + vec Lis t( i)
Next
Else
vecL ist .Cl ear
ptLi st. Cle ar
End If

End Sub

‘<Custom additional code>


Dim vecList As New List (Of Vector3d)
Dim ptList As New List(Of Point3d)

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.

u rb a n f ut u re o rg a ni zati o n ● 1 8 4 s t j o h ns road. gl ebe. nsw. 2037 ● + 61 295716336 ● www. au -urbanf ut ure.org

Vous aimerez peut-être aussi