of 67
8/13/2019 RF Magazine 0207
1/67
RF_magazineREALFLOW USER MAGAZINE
FLUID DYNAMICS :: PHYSICAL SIMULATION :: SCRIPTING :: CONNECTIVITY :: REALWAVE
ISSUE 02_2007
RF_magazine is brought to you by Liquidlight.tv www.liquidlight.tv
Scripting with RealFlow - Introduction
Basics of Python Scripting with RealFlow
Learn how to use Python inside RealFlow
First Steps
Accessing particles and changing parameters
Creating GUIs
Write out your own user interfaces
The Foam Project
Learn, how to create foam and spray
and many more ...
http://www.liquidlight.tv/http://www.liquidlight.tv/8/13/2019 RF Magazine 0207
2/67
RF_magazine 1
Welcome to RF_magazine 02/2007
This issue deals with scripting. With RF4, Next Limit
introduced a Python interface. Remembering the first
reactions in the old official forum, scripting wasnt verypopular at that time. But in the meantime, scripting
became one of the most important parts of the package.
On the other hand, many users are still afraid of using this
mighty tool.
When people think about scripting and programming,
many of them still have the impression that you need a
deep understanding of maths. This edition wants to show
- or even proof - that you can achieve stunning effects with
little effort. Python scripting in RealFlow is your friend, not
an enemy, because it makes life so much easier in manyways.
The principles are fairly the same with each script.
RF_magazine uncovers these techniques with lots of
examples and projects. With this issue you can discover
the advantages and power of scripting.
Next Limit chose Python, because its an easy to learn and
wide spread language. In many terms, Python almost
reads as spoken English. This feature makes Python suited
for beginners. With growing knowledge and experience,youll get a deep insight into Python and a better under-
standing of RealFlow. Altering parameters with a self-
written program is completely different from changing
values within in a Node Paramswindow.
But theres one thing, even the best book or tutorial cant
do for you: Reading carefully and trying to understand
whats going on in a particular script. The basics, like Data
Typesor simple Vector maths are very important and cant
be left out. Programming is also learning by doing!
So, dont hesitate and dive into scripting with RealFlow.
After a few hours youll be able to write your own first
script.
Sincerely yours,Thomas
Thomas Schlick (tsn)
Liquidlight.tv
Nuremberg/Germany
www.liquidlight.tv
This magazine has been certified by Next Limit:
Editorial02_2007
http://www.liquidlight.tv/http://www.nextlimit.com/http://www.liquidlight.tv/8/13/2019 RF Magazine 0207
3/67
RF_magazine 2
Editorial
Welcome to RF_magazine Page 1
The Power of Scripting
A First Glance Page 4
What is Scripting Page 4
The Advantage of Scripting Page 4
Python and RealFlow Page 5
Where to Start? Page 5
The Basics of Python Scripting in RealFlow
Variables - First Steps with Scalars Page 6
Other Types of Variables Page 7
Creating Lists Page 8
Creating Dictionaries Page 8
Appending Values Page 9
Operators Page 9
Data Types Page 11
Vectors Page 13
Calculating with Vectors Page 13
Notation and Syntax Page 16
Getting Started
Setting the Preferences Page 18
The Scripting Windows Page 19
Scripted Objects Page 20
Your First Steps
Calling Emitters and Objects Page 22Accessing Particles Page 23
Building Vectors Page 25
If & Else Page 27
Changing Attributes with Get & Set
Introduction Page 29
How to Use Get & Set Page 29
Working with Particles Page 34
Conclusion Page 36
Contents02_2007
8/13/2019 RF Magazine 0207
4/67
RF_magazine 3
Creating Graphical User Interfaces
Whats a Graphical User Interface Page 37
The Structure of RealFlow GUIs Page 37
File and Node Pickers Page 49
The Foam Project
Project Overview Page 41
The Nature of Foam and Spray Page 41
Creating Foam Page 42
Controlling Values Through Objects Page 46
Collision Based Foam Creation Page 47
Optimizing the Script Page 49
Threshold Parameters Page 50Credits Page 50
Fun with Freeze
Project Overview Page 52
Freezing Time and Particles Page 52
Circular Particle Freezing Page 53
Relaxing Particles with Freeze Page 55
Inverting the Effect Page 55
Summary Page 56
Examples and Ideas
Overview Page 57
Image Based Emitter Speed Page 57
Boxed Daemons Page 58
Exporting Position Data to AfterEffects Page 59
Appendix
Reserved and Forbidden Words Page 64
Notes
Issue 01_2008 Page 65
Legal Notes Page 65
Contents02_2007
8/13/2019 RF Magazine 0207
5/67
RF_magazine 4
Scripting with RealFlow02_2007
A First Glance
Since version 4, scripting is an important part of RealFlow.
Many well known studios asked for this feature and Next
Limit met this demand. The implementation of a scripting
interface was one of the major leaps in the developmentof RealFlow and took almost two years.
Unfortunately therere still many users around, who want
to explore the power of scripting, but often dont know
where to start. Of course, the manual is an obvious source
for information regarding scripting. Fusion CI Studio
co-founder Dr. Mark Stasiuk did a very good job, as he
explains lots of fundamental questions and ideas behind
scripting.
Anyhow I met many people in search of a compendium ora comprehensive tutorial, covering the entire range from
beginning to intermediate or even advanced scripting. At
realflowforum.com I already published a series of free
tutorials for beginners, and I had positive feedback. This
feedback encouraged me to deal with scripting in this
issue.
What is Scripting?
Scripting is the process of developing programs for customtailored applications. In our case, inside of RealFlow. For
scripting, a programming language is needed. This
language provides a set of statements and functions the
programmer can use, to write his own scripts. The main
difference between scripting and, e.g. C or Java program-
ming is the way, the code is treated:
Scripts are normally interpreted. You all know this from
web browsers. JavaScript and PHP are very popular
examples. The code (this is the sequence of statements in
your program) is often directly visible to the user. At themoment, a visitor calls a webpage, the code is sent to the
interpreter and directly processed.
Unlike scripts, programs like RealFlow are compiled. This
means, the code will be preprocessed and converted into a
completely different format. Compiling has some great
advantages and the most obvious are speed and visibility.
A compiled program is much faster than an interpreted
script, because the compiler optimizes the code for certainhardware needs. Simultaneously the program is converted
and the content becomes invisible. This helps to protect
your development. Today, there are already some compil-
ers available for scripting languages.
The Advantage of Scripting
I was talking about the benefits of compiled programs.
Now, youll surely ask, why does RealFlow use a scripting
language and not C/C++ or Java? With scripting languagesyou dont have to deal with compiling. This sometimes
can be a very heavy task to solve and you need certain
compilers for different operating systems and hardware
requirements.
With the available scripting languages you dont have to
care about all these things. You just start coding, execute
the script and the interpreter does everything else. Many
people also say that its easier to start with a scripting
language, but in my personal opinion, its also a matter
of what you want to do. Both, interpreted and compiledlanguages have clear benefits and disadvantages.
Modern scripting languages are very powerful tools with
hundreds of extensions and libraries, mighty built-in
functions and sophisticated methods, like object orienta-
tion.
Often used scripting languages are Perl, Python, Java-
Script, VBScript, PHP, Tcl and also AppleScript. During the
first years of the WWW, Perl was the main language for
online applications. After the rising of PHP and Python,Perl lost its importance, but still has a vivid and strong
community.
The Power of Scripting
8/13/2019 RF Magazine 0207
6/67
RF_magazine 5
Scripting with RealFlow02_2007
Python and RealFlow
Now, Python is an integral part of RealFlow, but there is
much more: The Next Limit developers extended the
existing Python language by hundreds of new statements
and functions. You can now directly access almost anyobject and attribute of RealFlow via Python scripting.
This fantastic development opens the door to an infinite
variety of possibilities.
RealFlow comes together with a complete version of
Python and the user doesnt have to struggle with instal-
lation directories and libraries. With the installation of
RealFlow you get the complete Python package, ready to
start.
Some of the main advantages of Python are:
Free license, even for commercial use
Common and wide spread language
Perfect for beginners
OS independent (Unix, Linux, OS X, Windows etc.)
Hundreds of online resources, books and forums are
available
Standard scripting language for many applications
Code is platform independent and easy to exchange
Python scripting in RealFlow lets you directly addressobject, daemon and emitter parameters and alter them.
Where to Start?
One of the most important questions for beginners is
where to start. Many users are doubtful and insecure
when they think about making their own scripts.
One very common prejudice is that scripts always have to
be complicated and highly sophisticated artworks.
Just discard this attitude and think of it as a normallanguage. Not every sentence has to be a poem, mostly
its better to speak in a clear and easy way.
Another misunderstanding is that you have to be a maths
genius to write good programs. Of course a basic knowl-
edge of mathematics is useful, but not mandatory. If you
just want to automate some processes, you wont need
very much mathematics.
A very good starting point for each programming novice is
to create a simple example with a great feeling of success.
Since RealFlow is a 3D application with a high visual
impact, its rather easy to find those examples. No matter
what youre doing, it will directly influence the objects on
your screen.
Maybe youve already started to learn a programming
language? Then you also might have seen the famous
Hello World program. This is always a nice start, but for
our purposes its not suitable. Were after completely
different things.
Before we can kick off, its indispensable to learn the
basics of Syntax and Notation to understand the principles
of how Python works.
The Power of Scripting
Fig 1. Script affected particles of an emitter
8/13/2019 RF Magazine 0207
7/67
RF_magazine 6
Scripting with RealFlow02_2007
Variables - First Steps with Scalars
Variables are the key to everything, independent of the
used programming language. A Variable could be consid-
ered as a placeholder. You can fill this placeholder with any
content you like. In programming languages,Variableshave to be declared. This means that you have to introduce
a name for your Variable and assign a value to it.
Imagine the following easy example. We got some infor-
mation from a person: 25,female, Claudia. Without setting
these information into a logical context, we cant capital-
ise on these data. Im sure you already started bringing
these information into an order:
Name = "Claudia"
Age = 25
Gender = "female"
Now these attributes start making sense. You assigned
certain properties to Claudia and you already declared
three Variables. The names of these Variables are Name,
Ageand Gender, their properties (or values) are Claudia,
25andfemale.
You can also see, that its very important to choose strong
and meaningful names for your Variables. In this case we
declare our Variables like this:
A = "Claudia"
B = 25
C = "female"
Formally thats absolutely correct, but the information
isnt very clear, especially when there are similar values or
properties:
A = "Claudia"
B = 25
C = "Beatrice"
D = 56
After a while, youd certainly have no clue what the
Variable names are standing for. With Variables declared
like this, its no problem:
First_Name = "Claudia"
Age = 25
Second_Name = "Beatrice"
Weight = 56
Its very important that Variables always share the same
name over the entire script, because Python and other
languages are case sensitive. In a script Genderis not the
same asgender. Variables can be declared wherever
theyre needed, but its a good idea to find common
places for your Variables and arrange them clearly. Never
use special characters for Variablesnames. The range of
allowed characters is a-z, A-Z, 0-9 and the underscore.Variables must start with a character, not with a number.
Variables are a very flexible facility. You can change their
values within the script and you can assign numbers,
characters, and strings. But each of the Variables above
can only carry one value. This type is called a Scalar.
By defining a new value for an existing Variable, the old
value will be substituted:
Name = "Claudia"
Name = "Lydia"
If we had a script to print out the variables content, the
result would be Lydia. Only the very last value will be used.
An important convention is that strings and characters
have to be written in quotation marks. With numbers this
is not necessary. If youre writing numbers within quota-
tion marks, theyll be treated as a string.
The Basics of Python Scripting in RealFlow
8/13/2019 RF Magazine 0207
8/67
RF_magazine 7
Scripting with RealFlow02_2007
Other Types of Variables
As youve learned, a Scalar can only carry one value, but
there also are Variables, you can fill with two or more
values. Python programmers differentiate between two
types: Lists and Dictionaries. A Listis something, wecertainly need very often with Python and RealFlow.
You can consider a List as a cupboard with drawers. Each
value has its own drawer, and theyre all arranged in a
fixed order. The numeration of these drawers starts with 0
(Zero). Python also starts the numeration of Lists with 0.
Lets assume that each drawer contains coloured marbles:
0 = red, 1 = blue, 2 = green, 3 = yellow, 4 = purple
By opening drawer number 2, youll have access to the
green marbles, opening number 0, will lead to red ones.
The List provides a container with a fixed sequence.
Whenever you want to have purple marbles, you have to
call position number five. But wouldnt it be nice to have
a method to arrange the marbles the way we want?The solution is called Dictionary. In a Dictionary, theres
no sequence and all contents could be disordered.
In difference to Lists, its not necessary to call the entries
via a fixed index. In Dictionaries we use search keys.
A very good example for a Dictionary is a private phone or
address book, in which we often see pairs of values, e.g.
a name and a phone number. These pairs are stuck
together and we cant identify one without the other:
Claudia : 54358
Lydia : 43663
Agnes : 65586
Susan : 94343
Imagine the phone book from your cell phone. By entering
a name, the software prints out the according phone
number. Thats exactly the way, a Dictionary is working.
It doesnt matter, where the entries are located within the
book, because theyll always be identified via a search key.
In RealFlow Dictionaries is rarely used, but nevertheless
there might be some cases, where you need them.
Now you know all three types of Variables for storing
values in Python and respectively in RealFlow: Scalar,
List and Dictionary. For Lists and Dictionariesyou have to
obey the same rules as for Scalars. The Variables names
should be meaningful and special characters are forbid-
den.
Just one final note: a List is sometimes called anArray, and
a Dictionary is also known as Hash or Associative Array.
Fig 2. A List can be used to arrange values and entries
The Basics of Python Scripting in RealFlow
8/13/2019 RF Magazine 0207
9/67
RF_magazine 8
Scripting with RealFlow02_2007
Creating Lists
Creating a List structure in Python is an easy task. An
empty List is written as:
my_list = []
If you want to define the values directly with the creation
of the List, the format is:
my_list = [value1,value2,value3, ...,value n]
For better understanding, Id like to create a List with the
colours of our marbles from page 7:
colours = ["red","blue","green","yellow","purple"]
As you can see, all colour names are between quotation
marks. You dont need these marks for numbers:
diameter = [2.0, 2.5, 3.0, 3.5, 4.0, 4.5]
In Python its easy to find elements, stored in a List:
favourite_colour= "yellow"
colours = ["red","blue","green","yellow","purple"]
if (favorite_colourin colours):
print "Your favourite colour is in stock."
else:
print "Sorry. Your favourite colour is not available."
Result: Your favourite colour is in stock.
In this short example, I introduced a Scalar Variable,
named favourite_colour. The value isyellow. Now, the in
statement goes through the List in search ofyellow.
Ifyellowhas been found, the script writes out a success
message. If the value of favourite_colour (e.g. brown) isnt
part of colours, the result would be
Sorry. Your favourite colour is not available.
The next method uses the stored indices. Since each value
has a fixed position within the List, its possible to address
a colour using this index. Remember that List indices
always start with 0.
colours = ["red","blue","green","yellow","purple"]
selection = colours[2]
print selection
Result: green
Another very important function with Lists is to find the
total number of elements. This is also called the Length of
a List. You can get it with:
colours = ["red","blue","green","yellow","purple"]
number_of_entries = len(colours)
print number_of_entries
Result: 5
Creating Dictionaries
Youve already learned that elements in a Dictionary dont
need a specific order to find them. A Dictionary uses
key/value pairs to search through the content. An empty
Dictionary can be created by typing
my_dictionary = {}
Of course you can directly start entering values and
performing a query:
phonebook = { "Claudia":54358, "Lydia":43663,
"Agnes":65586, "Susan":94343 }
print phonebook["Agnes"]
Result: 65586
Isnt that easy? You dont have to worry about indices,
numeration or positions.
The Basics of Python Scripting in RealFlow
8/13/2019 RF Magazine 0207
10/67
RF_magazine 9
Scripting with RealFlow02_2007
Analogue to Lists, its also possible to get the length of a
Dictionary. The function calls all key-value pairs and stores
the result in a predefined Scalar:
phonebook = { "Claudia":54358, "Lydia":43663,
"Agnes":65586, "Susan":94343 }
number_of_entries = len(phonebook)
print number_of_entries
Result: 4
Appending Values
Now you know how to create Lists and Dictionaries manu-
ally and how to read out specific values. In RealFlow we
often have to deal with thousands of particles. Collectingtheir data and writing them to a List by hand wont be a
good solution. For this purpose, Python provides a special
function called append.
The append function adds values to the end of a List. This
is important, since a List is working with index numbers.
There are also functions to insert values at certain
positions, but theyre rarely used with RealFlow. In most
cases you extend a List by simply appending a new value.
This is the syntax for Lists:
colours = ["red","blue","green","yellow","purple"]
new_colour = "orange"
colours.append(new_colour)
Adding a value to Dictionary is slightly different. We dont
need a fixed order and therefore the position of the new
element isnt important. An entry of a Dictionary always
consists of two elements: The key and its value. Its very
important to define which one will serve as a key, respec-
tively as a value.
phonebook = { "Claudia":54358, "Lydia":43663,
"Agnes":65586, "Susan":94343 }
phonebook["Helen"] = 22986
Its also possible to use Scalars and add their values to the
Dictionary:
new_name = "Helen"
new_number = 22986
phonebook[new_name] = new_number
For the moment this should be enough. Youll learn more
about these data types in connection with scripts.
Operators
Operators are one of the most important things in Python.
With an Operator its possible to perform basic arithmetic
calculations and comparisons. And thats truly a bless.Without Operators, you wouldnt be able to compare
particle velocities or positions against a Scalar and thered
been no way to multiply or substract values. You can find
Operators anywhere in a script and Python knows a lot of
them. The first group contains all arithmetical Operators:
+ Addition 15 + 17 = 32
- Substraction 64 - 30 = 34
* Multiplication 10 * 12 = 120
/ Division 80 / 10 = 8
** Exponentiation 12 ** 2 = 144% Modulus 28 % 7 = 0
+ String concatenation John + Doe = JohnDoe
* String repetition Hi * 3 = HiHiHi
A very nice Operator is Modulus, but it needs some expla-
nation. In general, Modulus tells you, if theres a remain-
der after performing a calculation or not. With Modulus
its possible to find out whether a number is even or not,
for example. If the result is different from 0, the number is
uneven. A result of 0indicates an even number.
The String Operators are rarely used with RealFlow and
more important for text processing applications.
The Basics of Python Scripting in RealFlow
8/13/2019 RF Magazine 0207
11/67
RF_magazine 10
Scripting with RealFlow02_2007
The next group contains Operators for comparisons:
< Less than
> Greater than
= Greater than or equal== Equal
!= Not equal
Equality is tested with ==. The single = is just used for
assignment, e.g. in Variable names:
Name = Claudia
The result you get with Comparison Operatorsis true or
false. These are the two possibilities and theres nothing
between:
velocity_a = 5.0
velocity_b = 7.3
if (velocity_a < velocity_b):
print "This is true."
By swapping the Variables, the result would be false. In
RealFlow you normally wont calculate with true or false.
Its just a means for making decisions, what should
happen with your values or parameters. It can be consid-ered as a crossover, where you also have two or more ways
to go. Lets say, you want to limit the velocity of a parti-
cle:
max_velocity = 7.5
current_velocity = 8.2
if (current_velocity > max_velocity):
new_velocity = max_velocity
else:
new_velocity = current_velocity
What happens here? The current velocity of a certain
particle has been determined as 8.2. With an Operator
were testing, if the value of the current velocity is greater
than the maximum velocity. This value is a threshold.
Whenever a particles velocity is greater than this limit,
its just cut down to 7.5. If this condition is not fulfilled,
the script calculates with the current value, stored in
current_velocity. In this example, the condition is true,because current_velocity is actually greater than
max_velocity.
Another example using the equality Operator:
max_y_position= 3.5
current_y_position = 2.9
if (current_y_position == max_y_position):
attractor_force = 25
else:
attractor_force = 10
At the moment, the observed particle reaches the
max_y_position value, attractor force will be 25. Here,
current_y_position is less than 3.5, and the condition is
false. The assigned value for attractor_force is 10.
A third group consists of so called Boolean Operators.
The keywords are:
andor
not
Youll mostly need these Operators when you have to
check more than one condition.
if (cur_vel >= threshold_1 or cur_vel
8/13/2019 RF Magazine 0207
12/67
RF_magazine 11
Scripting with RealFlow02_2007
The last class Im talking about here, areAugmented
Operators. This is a very special class and mostly used for
abbreviations. In some cases, its necessary to write
expressions like:
while (particles):
total_mass = total_mass + particle_mass
In this example, the script loops through all particles and
sums up their individual masses to get a total mass value.
This calculation could also be written as:
while (particles):
total_mass += particle_mass
The most common Operators are
+= -= /= *= **= %=
There are some more Operators in Python, but theyre not
often used with RealFlow. By knowing the discussed
classes, you already have the tools to create your own
conditional expressions and basic calculations.
Data Types
Coders have to distinguish between various Data Types.At school you probably already met most of them and
with RealFlow you will need these types again. The most
common format is surely the Integer type. Integers are
wide spread and we use them in our daily life without
thinking about them. Integers are numbers like:
-5, 2, 100, -4335, 757, 423843, -3289988, 45, 234, -775647
The set of Integers is infinite, it can be positive or negative
and it doesnt contain fractures like 3.645, -1.3333or 12.7.
Fractured elements arent members of the Integer family.Also fractures, apparently consisting of two Integers arent
valid elements: or . Though the result of such a
division can be an Integer!
There are two subtypes of Integers in Python. The first one
is called Plain Integer, or just Integer. The abbreviation of
this type is known as int. This type is not endless and
theres a maximum range. For the sake of calculation
performance its necessary to differentiate, because Plain
Integersare processed much faster. In 99% of all cases, thePlain Integertype will serve your needs. These are the
specifications:
int (Integer or Plain Integer)
2,147,483,648to+2,147,483,648
This range is also called 32-bit precision and its the
minimum for all modern operating systems. Most operat-
ing systems also support 64-bit precision. The valid range
for this type is:
9,223,372,036,854,77,.808to+9,223,372,036,854,775,808
long (Long Integer)
In Python this subtype has infinite precision, but the
effective length of your number depends on the amount
of RAM in your computer.
The next, very important type is called Float. Youve
already seen Floats (also called floating point numbers)on the left. They were introduced as decimal fractures
(1.8543). The most significant attribute of Floats is the
decimal point. Its possible to calculate with decimal
places of different length. Of course its allowed to
combine Integers and Floats together. Valid expressions
would be:
75.543 / 8.4 + 1.3 * 67.55
5.8564 * 6 + 23.98
Floats can also be negative or positive. The length orprecision of Floats strongly depends on your computer and
operating system, but most likely you wont encounter
any problems. The token in Python is simply float.
The Basics of Python Scripting in RealFlow
8/13/2019 RF Magazine 0207
13/67
RF_magazine 12
Scripting with RealFlow02_2007
The last Data Type, Im talking about, is called Complex. In
RealFlow this type will be rarely used and its only men-
tioned for completeness. Complex numbers consist of two
parts: A real and an imaginary part. The Complex type is
therefore always written as a pair of numbers. The real
number is just an Integer or a Float type, while the imagi-nary part must own ajcharacter:
(3 + 6j)
Even if the imaginary part is Zero, you have to write this
value in conjunction withj:
(12 + 0j)
With Complex numbers its possible to perform calcula-
tions as usual:
(2 + 4j) * (8 + 3j) or (11 + 1j) * (7 + 5j)
In Python, this special Data Typecan be introduced with a
complex statement.
Now youve heard about int, long, floatand complex,
but you surely have no idea, how to use these types. One
main application for Data Typesare Variables, of course.
The good thing is that you dont have to introduce each
Variable with the appropriate index. Python automaticallyrecognizes the correct type. But there are some other
cases, where you have to determine, which type youd like
to use. One of these cases are GUIs - Graphical User
Interfaces. Youll read about GUIs later, starting on
p. 37, but Id like to introduce some basic information
about the usage of Data Types:
With GUIs its often allowed and wanted, to enter custom
values for initializing a calculation. Lets assume, your goal
is to build a tower made of cubes. Within the GUI you can
type in values for the number of stacks, the width and theheight of a stack. This number has to be an Integer,
because you cant build a tower with 5.278 floors. The
width and height instead, can measure 2.5 or 7.84 units.
The used Data Typesin this example are:
levels = int e.g. 10
width = float e.g. 2.5
height = float e.g. 3.75
Another often used exercise is the conversion of Data
Types. Its possible to translate a Float number into an
Integer and vice versa. You could also translate a Long type
into a Float number. But with all these transformations,
you have to keep in mind that youre probably losing
precision. Converting a Float type number into an Integer
truncates the decimal places:
int(3.256) = 3
int(9.999) = 9
This conversion only takes the Integer part of the original
number, without caring about rounding. The same can be
observed when converting Long to Float.
The Basics of Python Scripting in RealFlow
Fig 3. A tower based upon integer and float values
8/13/2019 RF Magazine 0207
14/67
RF_magazine 13
Scripting with RealFlow02_2007
Vectors
Another Data Typeare Vectors. Vectors are not a built-in
element of Python, but there are some languages,
supporting Vectors as a Data Type. The Python extension
of RealFlow, for example, knows Vectors and theyre fullyintegrated. Since theyre not part of Pythons standard
installation, Id call them a Pseudo Data Typehere.
In RealFlow, Vectors are one of the most important
elements and this is another reason, why I chose to
discuss them separately.
A Vector could be considered as an arrow, pointing into a
certain direction. To describe a Vectors direction, we need
at least two dimensions: x and y. By drawing a Vector into
a coordinate system, we get the main properties:Direction and Magnitude. The Direction tells you, where
the Vector is pointing at, while the Magnitude is the length
of the arrow.
Vector coordinates can consist of Integers and Floats.
The graphical illustration of a Vector might help to get
an understanding, but its not suitable for calculations.
Therefore we have to find a notation. Therere some
established forms to represent a Vector, but according to
RealFlows notation, a Vector in RF_magazine is always
written as:
a= (x, y) or a = (1.0, 1.0)
In RealFlow were dealing with 3D space and the represen-
tation of a Vector needs a third coordinate:
a = (x, y, z) or a = (1.0, 1.0, 1.0)
If yourre interested in real life examples or the math-ematical background, Id suggest to have a look at physics
books or the internet, e.g. Wikipedia.
Calculating with Vectors
Its not possible to calculate with Vectors directly. The
most common calculation type with Vectors isAddition.
For performing Vector calculations, you have to use either
the individual elements x, y, z or its Magnitude. The
coordinates of a Vector are called Scalars. You alreadyheard about Scalars at the very beginning of this chapter.
a = (5.0, 2.5, 4.2)
b = (1.7, 3.9, 8.1)
In this case were looking for c = a + b. Maybe its just
c = (ax+ bx, ay+ by, az+ bz)
c = (5.0 + 1.7, 2.5 + 3.9, 4.2 + 8.1)
c = (6.7, 6.4, 12.3)
This really is the answer, and its analogue with Vector
Substraction c = a - b:
c = (ax- bx, ay- by, az- bz)
c = (5.0 - 1.7, 2.5 - 3.9, 4.2 - 8.1)
c = (3.3, -1.4, -3.9)
As you can see here, a Vector can also point into negative
directions.
The coordinates of a Vector are Scalars. For this reason itspossible to multiply the Vector components with another
Scalar. Its likely that you will use this method very often,
especially with forces.
The Basics of Python Scripting in RealFlow
Fig 4. Different vectors pointing at various directions
y
x
8/13/2019 RF Magazine 0207
15/67
RF_magazine 14
Scripting with RealFlow02_2007
Multiplication with a Scalaris calculated this way:
a = (4.8, 2.9, 1.4)
s = 2.5
b = s * ab = (s * ax, s * ay, s * az)
b = (2.5 * 4.8, 2.5 * 2.9, 2.5 * 1.4)
b = (12, 7.25, 3.5)
Another very important calculation rule is the Scalar
Product. Dont mix it up with last rule, the Multiplication
with a Scalar. These operations are completely different!
The result of a Scalar Productis a Scalar and it can be
considered as the multiplication of two Vectors:
a = (1.7, 7.3, 3.3)b = (2.4, 0.7, 5.1)
c = a * b
c = ax* bx+ ay* by+ az* bzc = 1.7 * 2.4 + 7.3 * 0.7 + 3.3 * 5.1
c = 4.08 + 5.11 + 18.83
c = 26.02
A special form of the Scalar Productis the square of a
Vector:
c = a2
c = ax2+ ay
2+az2
Extracting the square root from this term, yields to a
Vectors Magnitude (often called Norm or Length).
| c| = ax2+ ay
2+az2
As you can see clearly here, the result of this operation is a
Scalar, not a Vector. The lines around cindicate that its a
Norm. In RealFlow you wont have to worry about thisrule, because theres a built-in function for calculating the
Scalar Product. In RealFlow its called Dot Product, repre-
sented by an asterisk character ( *).
The next rule, Im talking about, is named Cross Product.
The result of a Cross Productis also a Vector. The most
common way to calculate a Cross Productis done by
multiplying the components of two Vectors:
a = (2.2, 6.1, 1.0)b = (0.7, 0.4, 3.8)
c = a x b
cx= ay* bz- az* bycy= az* bx- ax* bzcz= ax* by- ay* bx
cx= 6.1 * 3.8 - 1.0 * 0.4
cy= 1.0 * 0.7 - 2.2 * 3.8
cz= 2.2 * 0.4 - 6.1 * 0.7
cx= 23.18 - 0.40 = 22.78
cy= 0.70 - 8.36 = -7.66
cz= 0.88 - 4.27 = - 3.39
c = (cx, cy, cz)
c = (22.78, -7.66, -3.39)
This operation is also implemented in RealFlow by default
and you dont have to calculate this manually. Many
physical values can be determined with the Cross Product,e.g. the Lorentz Forceor the torisonal moment. There
surely comes a time, when you start looking for special
formulas to enhance your simulations. Then youll
certainly meet theCross Productagain. Many formulas,
dealing with the simulation of natural, turbulent phenom-
ena use the Cross Productto mimic the desired forces.
The last rule has already been introduced: The Norm or
Magnitude of a Vector. The result of this operation is a
Scalar. Youll often use Magnitudes with forces. The
resulting Scalar can be multiplied with a Vector again (seeMultiplication with a Scalar above). The Magnitude is
calculated using an old friend: Pythagoras theorem.
If you cant remember it, dont worry and turn over...
The Basics of Python Scripting in RealFlow
8/13/2019 RF Magazine 0207
16/67
RF_magazine 15
Scripting with RealFlow02_2007
Pythagoras theorem is normally used for triangle calcula-
tions. In Vector maths, where you also could represent a
Vector as an arrow, its possible to extract values by
constructing triangles from the given Vectors.
With Pythagoras theoremyoure now able to get the
Length, or Magnitude of a Vector:
Pythagoras theoremfor right-angled triangles:
a2+ b2= c2
You can get the value forcby extracting the square root:
c= sqrt( a2+ b2)
This term is also valid in three dimensional coordinate
systems and for Vectors. The Magnitude of a Vector is
always positive, because you have to square the values.
a = (3.2, 2.8, 1.5)
| a| = sqr(ax2+ ay
2+az2)
| a] = sqr(10.24 + 7.84 + 2.25)
| a| = 4.51
For fluid, smoke and fire simulations, physicians intro-
duced Vector Fields. In a Vector Field, a Vector is assigned to
each point of the considered space. The idea is to create
field of variable strength at different points. Very good
examples are gravity or the magnetic field. In reality these
depend on where you are and therefore have differentvalues.
Creating Vector Fieldsin RealFlow with Python is not
trivial. For this reason I dont want to dive into the depth
of these fields.
The maths behind Vector Fieldsis complicated and the
main problem with RealFlow is that we need the previous
and the current value to solve the equations. RealFlow
doesnt provide functions to store values over time and
substitutes the previous results.
A big variety of very interesting Vector Fieldscan beexplored here with a Java Applet:
http://www.falstad.com/vector3d/
The Basics of Python Scripting in RealFlow
Fig 5. The Magnitude of a Vector
Fig 6. 3D representation of a Vector Field with arrows
x
y
a
b
c
pos
http://www.falstad.com/vector3d/http://www.falstad.com/vector3d/8/13/2019 RF Magazine 0207
17/67
RF_magazine 16
Scripting with RealFlow02_2007
Notation and Syntax
Now youre getting closer to scripting and the theoretical
part lies almost behind you. In this chapter youll learn
how to organize a RealFlow script and what you have to
attend.
When youre writing Python scripts for RealFlow you have
to follow certain rules. Without obeying these rules, youll
receive error messages and your program wont run. The
best idea is, to avoid those errors from the very beginning.
As Ive seen in the unofficial RealFlow forum, the most
common error is related to shifting and spacing. Python
recognizes clauses, conditions and syntax groups auto-
matically. The indicators are leading tabs and blanks.
program start:
statement 1
if ( condition ):
statement 2
else:
statement 3
while loop:
statement 4
if ( condition ):
statement 5
else:
statement 6
statement 7
The example above is a typical structure of a Python script.
For each new instruction set, theres got to be a new
clause. The interpreter allows blanks as well as tabs, but
you must never use them together. Always make a
decision on one method for shifting. Id recommend to use
the Tab key. With this key you dont have to worry about
the number of blanks and this makes life much easier.
Other scripting languages, like Perl, often use brackets toseparate statements and functions. The advantage is that
you dont have to care about tabs, but you shouldnt
forget to close all branches. Otherwise youll receive an
error. This an example of a code structure in Perl:
sub function {
statement 1;
if ( condition ) { statement 2 }
else { statement 3 }
while loop {
statement 4
if ( condition ) { statement 5 }
else { statement 6 }
statement 7
} # end while
} # end sub function
Though all conditions, definitions and loops are embedded
into branches, its still a very good idea to use tabs forbetter readability. With Python its essential and especially
with copied and pasted scripts, you have to be extremely
careful. Scripts from forums, discussion boards or other
sources often dont follow these rules for leading tabs,
and this directly leads to problems.
Python is a very flexible programming language. It allows
many short forms and convoluted statements. For begin-
ners its often very hard to understand, whats going on in
scripts, made by Python pros. To grant access to everyone,
the scripts from this issue use a step-by-step technique.Thus many scripts may be longer than necessary, but
beginners can follow the code, too. I leave it to you, to find
the shortest form for a script. With growing experience
youll surely learn how to contract statements effectively.
Another issue is the spelling of Variables. Python and the
RealFlow extension use certain words for introducing
particular functions. These words cant be used for
Variables. You can find a list of the currently reserved
words on page 64. Another limitation with Variable names
is the usage of the dot character. The dot character is usedas an identifier for an objects properties, like:
emitter.getPosition()
The Basics of Python Scripting in RealFlow
8/13/2019 RF Magazine 0207
18/67
RF_magazine 17
Scripting with RealFlow02_2007
The Syntax of a script can be seen as a grammar. Violating
the rules leads to errors. Therere many definitions and
essays about Syntax and especially for beginners its not
easy to understand its importance. In brief terms:
Syntax is the logical structure of a script.
This structure is not a fixed rule type, its flexible and
theres always more than one way to achieve a result.
I think this should be enough about the nature of Syntax.
If you need further information, just have a look at the
internet.
One of the most common error messages youll receive in
RealFlow is Script Syntax error at line XX. A Syntax error
often has marginal reasons, like:
leading spaces are wrong
wrong order of statements
using Variables before assigning them
misspelling of Variable names
unmatched brackets
infinite loops
using improper operators
using reserved or forbidden words
using the wrong Data Type
The Basics of Python Scripting in RealFlow
Fig 7: RealFlow error message
8/13/2019 RF Magazine 0207
19/67
RF_magazine 18
Scripting with RealFlow02_2007
Setting the Preferences
RealFlow provides a complete scripting environment, fully
equipped with Syntax highlighting, a debugger (this is an
error detection facility) and a set of predefined func-
tions. To adjust this environment to your needs, Idrecommend to set the scripting preferences first:
realflow > Preferences > Script
After the Script tab has been selected, a new panel
appears, showing a variety of settings:
Adjusting the Syntax Coloris a matter of taste. You can
choose any colour you want. With the predefined colours,
a typical statement would look like this:
# Get the scene emitter
particle_source = scene.getEmitter("Circle01")
Highlighting certain keywords of a script helps you to keep
the code readable and its easier to differentiate the
individual elements.
The Tab sizedetermines, how many leading blanks are
inserted to structure the Python code. You should always
use tabs instead of blanks or spaces to introduce new
instructional blocks (also see p. 16). In conjunction with
this setting, its a good idea to use a so called monospace
font. Glyphs from these fonts all have a the same fixed
width, which is great for organizing a script. With mono-
space fonts its possible to arrange Variable names likethis:
pi = 3.14
gravity = 9.81
e = 2.718
ini_vel = 12
With fonts using variable widths, its not possible to align
names, numbers and other characters correctly:
pi = 3.14gravity = 9.81
e = 2.718
ini_vel = 12
Very common monospace fonts are Monaco, which is used
here for all scripting examples, and Courier. Both fonts
should be installed on most computers by default.
In RealFlow its possible to choose a directory for your own
scripts. These scripts can be filed in the toolbar of RealFlow
and you have direct access to them, just by clicking on theappropriate icon. You can either use the default path or
define another location anywhere on your harddisc(s). The
Scripts Organizerfile carries all information about the user
scripts.
The last three icons are customized and indicate some of
my own scripts. Please note that its only possible to use
Batch Scripts(see p. 19) with the toolbar. Many free scripts
already come with icons, ready to use with the toolbar.After youve made the settings, just click OK to use them
as new defaults.
Getting Started
8/13/2019 RF Magazine 0207
20/67
RF_magazine 19
Scripting with RealFlow02_2007
The Scripting Windows
The Scripting Windowsare a true obstacle for many
beginners, because they simply dont know which type to
use. In RealFlow there are three basic types: Batch, Events
and Custom. The Batch and Events Script windows can becalled via the menu bar or by pressing F10, respectively F11:
Layout > Batch Script
Layout > Events Script
Batch Scripts
Lets have a look at Batch Scriptsfirst. Whats a Batch
script and whats it used for? In Batch Scriptsyou mostly
define routines for repeating tasks. Good examples are:
Creating a brick wall
Simulating two or more scenes successively
Changing hundreds of values simultaneously
Creating a basic scene with default objects
Changing states from inactive to active
Adding constraints to multiple objects
Have you ever built a brick wall in your 3D application? You
have to set brick by brick, or use a copy and paste method.
With scripting you can define rules, how many floors thewall should have and how many bricks you want to use.
The arrangement will be done automatically while
running the Batch Scripts. After this task has been
completed, another Batch Scriptscould alter the mass of
each brick to get a more random effect, while destroying
the wall with a bullet, for example.
Whenever you need to change properties, create lots of
similar objects, export values or add features, a Batch
Scriptsis the proper choice. The way of developing Batch
Scriptsis the same as coding Events or Custom Scripts. Themain difference lies in the way, the script will be executed
by RealFlow.
Events Scripts
The second type, Events Scripts is needed, whenever you
want to influence particles or objects directly during the
simulation process. With a Batch Scriptyou dont need to
start a simulation, with an Events Scriptits crucial.
RealFlow knows a couple of predefined events:
onSimulationBegin
onSimulationEnd onSimulationStep
onSimulationFrame
onChangeToFrame
onSimulationBeginis suited for applying initial param-
eters, You can also add some basic elements to a scene
that will be used for simulation. After this initialization,
the routine wont be called again. onSimulationEndworks
analogue to onSimulationBegin. Maybe the most impor-
tant event is onSimulationStep. Here, RealFlow applies
calculations for each time step. With heavy maths, thismay result in long simulation times. Please also remember
that scripts only use one processor/core of a computer.
Fig. 8: The Batch Script window
Getting Started
8/13/2019 RF Magazine 0207
21/67
RF_magazine 20
Scripting with RealFlow02_2007
Maybe the best example for a script using an onSimula-
tionStepevent is the well known foam script. This script
will be discussed later as separate project, starting on
page 41.
With onSimulationFrameits possible to make changes oncertain frames. The actual frame serves as trigger to
switch on or off certain properties of one or more objects.
Also changes can be performed with each frame, e.g.
animating an object or exporting custom bin files.
The last type, onChangeToFrameis great for post-
processing. With this event, scripts can be applied while
playing back a cached scene. Its rarely used, but neverthe-
less a powerful means for some applications.
After opening the EventsScriptswindow, youll recognize
that these functions are already implemented.
Each function wears apass statement. This statement tells
RealFlow to simply jump over this function. By removing
pass and replacing it through your own code, RealFlow
starts executing the script. The best thing is that youre
not limited to just one of the given functions. You can
initialize a scene with onSimulationBegin, activate objectswith onSimulationFrameand perform calculations using
onSimulationStep. Thats no problem, but before youll be
able to run a script, you have to checkActive.
Scripted Objects
Custom scripts are sectioned into a couple of subtypes and
theyre surely the most powerful means to customize your
simulations. The three types are:
Scripted Daemon
Scripted Emitter
Scripted RealWave
The Scripted Daemonis probably the most often used
subtype. In simple terms, a Scripted Daemonapplies a
force to an object. For this purpose, the scripting window
provides three predefined functions:
applyForceToEmitter( emitter ):
applyForceToBody( body ): removeParticles( emitter ):
Its necessary to distinguish between particles and (rigid)
bodies. With a Scripted Daemonyou can write your own
gravity or attractor daemons, add friction to particles or
objects, bound forces or define falloffs. As youre dealing
with forces, represented as Vectors, some basic knowledge
of applied mathematics is recommended.
On page 36 and 58 you can also find two Scripted
Daemons, showing, how Vector forces are implemented.The only limitation is that forces from Scripted Daemons
seem to act a little bit different from the predefined
Daemons in RealFlow.
Fig. 9: The Events Script window
Getting Started
8/13/2019 RF Magazine 0207
22/67
RF_magazine 21
Scripting with RealFlow02_2007
Another very powerful facility is the Scripted Emitter. With
this type its theoretically possible to write your own fluid
solver, but we dont want to go that far. Maybe youre
asking, why one should use a Scripted Emitter,though
RealFlow already makes a wide range of predefined
emitters available?
The answer to this question lies deep within the way,
RealFlow solves fluid dynamic equations. Maybe youve
already tried to animate viscosity or density of a particle
stream over time? If so, you might have encountered some
serious crashes. The fluid becomes instable and the
calculation suddenly aborts. With a Scripted Emitteryou
can avoid this behaviour and define ranges for the param-
eters from an emitters Particles panel. This is truly a
mighty feature! The Scripted Emitteris not an indivdual
object you can choose from the emitter list. The ScriptedEmitter is available for each type, like Circle, Sphere, Spline
etc. All you have to do, is changing the type from Liquid to
Custom:
Emitter > Node Params > Particles > Type > Custom
After this change, a new button, named Edit appears.
To open the related scripting window, simply hit this
button.
The Custom type provides just one function to calculate
the forces:
computeInternalForces( emitter )
The last subtype is the Scripted RealWaveobject. Similar tothe Scripted Emitter, this object is also part of the different
RealWavetypes. You first have to add a new RealWave
surface and then place a new deformer viaAdd Wave.
Heres a screenshot of how you can access this feature:
Again, an Edit button appears, to open the scripting
window. There, youll also find just one function to update
the vertices of the RealWave object:
updateWave( vertices )
Please note, that only its only possible to alter the y
direction of the vertices. Translations in x or z direction will
be ignored. The best application for a Scripted RealWaveis
to import greyscale images as displacement templates.
This technique is described in detail in RF_magazine Issue
01_2007 Cinema 4D Special Edition, page 40 et seqq.
Of course its possible to develop your own formulas tocreate new, not implemented wave types.
Fig. 10. Parameter rollout for the Custom Emitter type
Getting Started
8/13/2019 RF Magazine 0207
23/67
RF_magazine 22
Scripting with RealFlow02_2007
Calling Emitters and Objects
Now your persistence and patience will be rewarded
finally, because youre about to make the first steps with
Python and RealFlow!
Start with a Circle emitter by choosing:
Edit > Add > Emitters > Circle
> Square
The Node window now shows a new object called Circle01.
To use this emitter within a script, its necessary to
address it and store it in a Variable. The Variable type,
were introducing here is a Scalar:
emitter= scene.getEmitter("Circle01")
emitter is the name of the Variable, scene tells Python to
look at the Nodes panel for an emitter named Circle01. The
basic keyword in this statement is getEmitter to fetch the
desired object.
Now add a Torus object. To get this item, we use a very
similar construction:
object= scene.getObject("Torus01")
In this case, the Scalar variable is object and with the
getObject keyword we have access to the Torus01 item
from your basic scene.
Of course, sometimes its required to change an objects
name. Lets say you want to change the name from
Circle01 to Water. To identify the emitter again, you also
have to alter the name in the script:
emitter= scene.getEmitter("Water")
The Variable name may also be subject to change. In many
cases theres more than one emitter and you need a more
meaningful name. As youve already learned, its always a
good idea to use significant names. Later were developing
a foam script. This type of script uses multiple emitters
and we have to distinguish them by name:
water = scene.getEmitter("Water")
foam = scene.getEmitter("Foam")
Please note that the names of the emitters have to be
identical with the names used in the Nodes window and
the names must be written between quotation marks.
Another possibility would be to declare Variables with
emitter names:
water_emitter= "Water"
foam_emitter = "Foam"
water = scene.getEmitter(water_emitter)
foam = scene.getEmitter(foam_emitter)
In this case were using the Variables as a substitute for
the real name from the Nodes window. To make Pythonunderstand that we want to use a Variable withgetEmit-
ter( )and not a String (= sequence of characters), we dont
write quotation marks.
With objects and other items its the same procedure:
collission_object = scene.getObject("Torus")
animated_daemon = scene.getDaemon("MainAttractor")
main_camera = scene.getCamera("Camer01")
rope_constraint = scene.getConstraint("Rope01")
fluid_mesh = scene.getMesh("Fluid")
Your First Steps
8/13/2019 RF Magazine 0207
24/67
RF_magazine 23
Scripting with RealFlow02_2007
Accessing Particles
Lets stay with emitters for a while. As you certainly know,
RealFlow is a particle based software. Each emitter type
spills out a number of particles, dependent on the Resolu-
tionparameter. Through Python you have direct access oneach individual particle. But how is it possible to read out
values, like Velocity or Position for a single particle?
The basic idea is to gather all existent particles and loop
through this amount. Fortunately RealFlow knows various
methods to detect the total number of particles and
provides direct access.
A very common construction is to look for the first particle
and then go through the total amount. As long as therere
particles in the scene, the loop will be executed:
fluid = scene.getEmitter("Circle01")
particle = fluid.getFirstParticle()
while (particle):
do something here
particle = particle.getNextParticle()
Whats happening here? First you have to identify the
emitter Circle01. The statement fluid.getFirstParticle( )
means: Search for the first particle emitted from fluid,
actually from Circle01.
Now, the script starts looping through all existent parti-
cles. With this method its possible to get information
from each particle in your scene. While the loop is
executed, youre able to perform calculations or check and
compare values.
To seize the next particle, the script replaces the current
particle Variable with the ID of following particle. The
keyword for this action is getNextParticle( ).
In some cases its recommended to skip particles for
speeding up a simulation or for testing purposes.
On page 9 I was talking about the Modulus Operator %.
This is exactly what youll need for this purpose. With this
example Im also introducing a new principle - the if
clause. Youll learn more about this later (see p. 27).
The operation you have to perform is the following:
skip = 5
counter = 0
fluid = scene.getEmitter("Circle01")
particle = fluid.getFirstParticle()
while (particle):
counter = counter + 1
if (counter % skip== 0):
do something here
particle = particle.getNextParticle()
In this example the script counts the total number ofparticles. With each particle the counter Variable will be
increased by 1. Theres also a short form available (please
see page 11) :
counter += 1
The result is exactly the same value you can see under
Node Params > Statistics > Emitted Particles
The Modulus Operator%tells you, whether the operationproduces a remainder or not. Only if theres no remainder
(in this case the result is exactly 0) the instructions below
the ifstatement will be executed. This means that the
script skips four particles, because with the fifth particle
the condition is true. The higher the skip value, the more
particles will be missed out. With a skip value of 1, the
condition is always true and all particles will be included.
Besides the while method, RealFlow also knows the
for ... inand thefor ... in rangeloop. The first one is also
often used with particles and additionally with largenumbers of objects. Amongst others,for ... inallows you to
change object properties simultaneously.
Your First Steps
8/13/2019 RF Magazine 0207
25/67
RF_magazine 24
Scripting with RealFlow02_2007
Thefor ... inloop is often used with a defined number of
particles. You have to collect the wanted data first, and
then go through them one by one. Especially when its
necessary to gather colliding particles for foam genera-
tion, thefor ... inmethod is applied.
fluid = scene.getEmitter("Circle01")
collided_particles= fluid.getParticlesColliding()
for particle in collided_particles:
do something here
As you can see from the code, you have to store the
desired particles in the Variable collided_particles.
RealFlow identifies those particles with getParticlesCollid-
ing. After the particles have been stored, the script can
read out the Variable, calling each particle individually.
With lots of particles, this method may become very RAMconsuming, because RealFlow makes a copy of the particle
set with all its values and settings.
This statement could also be read as: Perform a given
calculation for each particle from the collided_particleset.
Thefor ... inrange method works similar to thefor ... in
loop. The main difference is that you can define a stop
value for the loop. Lets say, you have a group of six
spheres, but the operation should only affect the first
three objects.
spheres = [S0,S1,S2,S3,S4,S5]
no_of_spheres= len(spheres)
stop = no_of_spheres/ 2
start = 0
step = 1
for object in range(start, stop, step):
current_sphere= spheres[object]
do something here
Whooo! Whats going on here? Well, nothing special. I just
used another Data Type. Do you remember Lists? If not,
then please have a look at page 7 and 8 again. But dont
worry, because everythings explained here, too. The first
expression is a List, containing six entries - the spheres.
The Variables in this List are named S0- S5. Since Lists
always start with 0, its better to adopt your names to this
circumstance and avoid trouble. The spheres in the Nodes
panel must wear exactly the same name.
You only want the first three objects to be affected, so youhave to find a stop value. To get the total number of List
entries, its necessary to determine the length. This value
is stored in no_of_spheres. The List carries six entries and
we need three spheres. So the stop value is:
6 / 2 = 3
Of course you simply could write stop = 3, but here I
wanted to illustrate how to deal with Lists and their
entries. And in some cases it might be useful to get start
or stop values directly from a List.
To read out the current_sphere, youre using the current
value of the loop as a reference on the List containing the
spheres:
current_sphere= spheres[object]
Since were starting with start = 0, in our example wed
get these expressions (actually we cant see this term, but
this is the way it looks like internally):
current_sphere= spheres[0] ( S0)
current_sphere= spheres[1] ( S1)
current_sphere= spheres[2] ( S2)
After youve stored the sphere in a Variable, youll be able
to perform calculations. With current_sphere= spheres[3],
the loop ends. Id suggest to make a few tests with this
method to get a better understanding.
The step value indicates an increment. So with each
step the loop adds 1 to the current_sphere Variable.
The increment hasnt got to be 1 necessarily. Other Integer
values are also allowed, but with different steps, you
might have to change the stop value!
Your First Steps
8/13/2019 RF Magazine 0207
26/67
RF_magazine 25
Scripting with RealFlow02_2007
The List expression shows the names of all objects. On
page 8, I explained that names have to written between
quotation marks. In this case, the entries of spheres serve
as Variables, used by RealFlow to identify the objects in the
Nodes window. In RealFlow, quotation marks with Lists are
a rarely used.
spheres= [S0,S1,S2,S3,S4,S5]
This notation would cause a Syntax error:
spheres= ["S0","S1","S2","S3","S4","S5"]
The creation of loops is a crucial task, used with almost
any Events or Custom Script (e.g. Daemon or RealWave).
Even Batch Scriptsoften show loops, especially in conjunc-
tion with Lists.
Building Vectors
Vectors are one of the most important Data Typeswithin
RealFlow. Theres already been a detailed introduction on
page 13 et. seqq. Here, youll learn how to use Vectors in a
script and how to extract a Vectors components.
All RealFlow calculations are done in 3D space. The posi-
tions of a particle, emitter or object can be described with
their x, y, and z coordinates. Starting at the origin of a
scenes coordinate system, these three values can be
considered as an address, where you can find the object.
So itd be possible to draw an arrow from the origin to the
objects position. This arrow is the graphical representa-tion of a Vector. But not only positions can be written as
Vectors. This is also possible for forces or velocities.
The mathematical representation of a Vector is:
a = (x, y, z)
In RealFlow its possible to determine Vectors simply by
writing a series of three values to a Variable. The complete
Python statement for initializing a new Vector is:
my_first_vector = Vector.new(x, y, z)
In RealFlow its often required to extract the x, y, zvalues or further calculations, sometimes you may also
just need the y or z component of a Vector. The elements
of a Vector are called Scalars:
position = (1.0, 3.3, 2.7)
Now we want to calculate new y and z positions for a
single particle. But how could this be realised? Theres got
to be a way to split the Vector into its elements. Indeed,
RealFlow knows such a method:
position_x = position.getX()
position_y = position.getY()
position_z = position.getZ()
Fig. 11: Velocity vectors in RealFlow
Your First Steps
8/13/2019 RF Magazine 0207
27/67
RF_magazine 26
Scripting with RealFlow02_2007
In most cases youll deconstruct a Vector, perform a
calculation, and then build a new Vector using the fresh
values. The process for performing this operation is finally
always the same. Similar to the loop methods, you just
have to remember a few fixed steps:
Events Script: ParticleNewPos.rfsfluid = scene.getEmitter("Circle01")
particle = fluid.getFirstParticle()
while (particle):
# 1. Get global position data in Vector format
pos_g= particle.getPosition()
# 2. Get components from the position Vector
pos_x= pos_g.getX()
pos_y = pos_g.getY()
pos_z = pos_g.getZ()
# 3. Calculate the new coordinates individually
new_pos_y = pos_y + 0.01
new_pos_z = pos_z + 0.01
# 4. Build a new Vector
new_pos_g= Vector.new(pos_x, new_pos_y, new_pos_z)
# 5. Use the new Vector for position change
particle.setPosition(new_pos_g)
particle = particle.getNextParticle()
This is already a complete script. To show you whats
happening here, I want to deconstruct this little proggie.
The first part uses a well known method to loop through
the emitters (Circle01) particles.
The first step is to get vectorized value, in this case the
script reads out the global position Vector and stores it in
the pos_g Variable.
In a second step, the script disassembles the x, y, and z
components from the pos_g Vector.
The task in this program is to alter only the y and z values,
while the x component remains untouched. The new
position values have to be calculated individually as well,
and theyre based upon the old pos_y and pos_z values.
The new_pos_y, new_pos_z, and the unchanged pos_x
values provide a basis for the new global position vector.
The Vector.new statement puts everything together.
Of course this Vector has to be stored again in a Variable
(new_pos_g) for further use.
The last steps assigns the new_pos_g Vector to the
particles using a setPositioninstruction. Youll learn more
about theget and set functions later. Here, just put up
with the fact that these instructions are responsible forgetting and setting positions.
The last line of the script simply calls the next particle.
The representation in RealFlow isnt very spectacular, but
the script implements most of the principles, introduced
so far.
Fig. 12: The result from the Events Script ParticleNewPos.rfs
Your First Steps
8/13/2019 RF Magazine 0207
28/67
RF_magazine 27
Scripting with RealFlow02_2007
If & Else
When youre writing a script, its often required to set
certain conditions or alternative ways. Differentiations can
be achieved with if and else statements. The Syntax of this
function is rather simple and well known from your dailylife: Im sure you love new and fast computers, but money
is always the obstacle for buying the latest killer machine.
You have to calculate to get the maximum out of the
available money. This example is well suited for an if-else
construction:
available_money= 2500
computer_price = 3200
if (available_money< computer_price):
cant buy computer
else:
go to computer store
In this case, the amount of available_money is less than
computer price. The condition for this example is true, and
youre not able to buy the new computer. But Variables
can change over time and some new decisions can be
made:
available_money= 2500
computer_price = 3200
grannies_gift = 750
if (available_money + grannies_gift < computer_price):
cant buy computer
else:
go to computer store
Here, Granny saved your day, because 2500 + 750 = 3250.
As you can see, comparisons are not only limited to oneVariable, its also possible to perform calculations within
the if clause.
Another, equivalent notation would be:
total_money= availabe_money + grannies_gift
if (total_money < computer_price):
cant buy computer
else:
go to computer store
You could also reverse the comparison:
if (total_money >= computer_price):
go to computer store
else
cant buy computer
As you can see from this example, if-elseconditions are
mostly connected with comparisons. There are also ways
to compare more than one value:
ram = 200
my_money = 250
birthday_gift = 210
if (my_money >= ram or birthday_gift >= ram):
set max_particles to 50,000,000
else:
set_max_particles to 100,000
Its also possible to use an and statement. This is often
needed for setting a certain limit:
ram= 200
gpu = 350
if (ram
8/13/2019 RF Magazine 0207
29/67
RF_magazine 28
Scripting with RealFlow02_2007
Another effective method for multiple queries is the elif
statement. The elif expression is an abbreviation and
stands for else if. You can use (almost) as many elif state-
ments as you want to:
if mandatory onceelif optional mutliple
else optional once
This time you want to sell your old computer. The decision
chain could be like this:
offer = 475
retail_price= 500
min_price = 400
if (offer >= retail_price):
sell computer immediatly
elif (offer >= min_price and offer < retail_price):
contact customer for further negotation
else:
dont sell computer
In this case, the customer will be contacted, because offer,
lies between retail_price and min_price. elif statements
mostly need a second criteria to complete a decision.Have a look at this example:
offer = 520
retail_price = 500
min_price = 400
if (offer >= retail_price):
sell computer immediatly
elif (offer >= min_price):
contact customer for further negotiation
else:
dont sell computer
The result from this example is ambiguous. The first
criteria is fulfilled, since 520 is greater than 500, but the
second condition is also true, because 520 is greater than
400, too. To avoid such an inconsistency, you have to
introduce a second requirement, like in the first example
on the left.
In Python (and all other programming languages) its
allowed to construct convoluted if-else-conditions:
offer = 540
retail_price = 500
zip = 90482
if (offer >= retail_price):
if (location == zip):
shipping_cost = 10
else:
shipping_cost = 25
else:
dont sell computer
With nested if-else constructions, its possible to assign
case dependent values to a Variable. Having a look at the
example above, youll recognize that the computer has
been sold (offer is greater than retail_price). The secondclause is used to determine, whether the customer is
located in your hometown or not. The shipping_cost value
directly depends on the customers location.
Your First Steps
8/13/2019 RF Magazine 0207
30/67
RF_magazine 29
Scripting with RealFlow02_2007
Introduction
You already know the basics of Python scripting in
RealFlow. Youre able to loop through an emitters parti-
cles, youve heard about building Vectors and else-if
clauses. The coming chapter is about getting and settingvalues directly from RealFlow. This is the quasi-core of
RealFlows Python extension. With theget and set state-
ments, you have direct access to all properties of an
emitter, object, daemon etc.
The variety ofget and set statements seems to be endless.
So its necessary to sort the instructions, to keep an
overview. In this issue, were dealing with the most
common get and set directives. RealFlow also provides
commands for getting and setting vertices, polygon faces,
animation keys, image pixels and more.
Youve already met a few statements:
getEmitter( )
getPosition( )
getFirstParticle( )
getNextParticle( )
These instructions had been used to find a scene emitter,
to have access to individual particles or make use of a
particles Vector position data. With differentget instruc-tions, youll receive different values and results,
e.g. Integers, Vectors, Floats and Strings.
The online manual shows a rather long index of different
get and set commands. These commands are written in a
particular format, like:
Emitter getEmitter( string )
Object getObject( string )
The first word describes the allowed object type, likeemitter, object (primitive), camera, mesh and so on. The
second part is the specificget command, available for
many parameters and RealFlow objects. The next expres-
sion determines the Data Typeyou have to use with this
particular instruction. The Data Typealso specifies, how
the argument will be treated:
Particle getParticle( int )
This operation can only be used with particles and the
input value has to be an Integer. Using it with a daemon
and a string, like Gravity01, would cause an error.
The manual sometimes gives more hints:
Emitter [ ] getEmitters( )
The brackets [ ]tell you that the resulting Data Typewill be
a List. Do you remember? With a Scalar its only possible tostore one value, while Lists can carry two or more entries.
All descriptions of the available commands are working
the same way, as the examples above. With a little experi-
ence, youll be able to forecast the used object and Data
Type, but if youre not sure, you can always refer to the
manual:
Help > Contents... (opens a new application) > Index
Help > Contents... > Contents > Scripting Reference
The second source contains a more structured compila-
tion, sorted by object types.
How to Use Get & Set
The concept behind theget and set statements is simple,
but very clever, because its directly connected to
RealFlows user interface. The commands share exactly
the same names you can see in the Nodes and Node
Params windows. The main difference is the number andtype of arguments, aget or set command needs. The
commands are not limited to loops, they can be used
anywhere.
Changing Attributes with Get & Set
8/13/2019 RF Magazine 0207
31/67
RF_magazine 30
Scripting with RealFlow02_2007
In this example, a Cone had been added to the scene.
The parameter rollout above contains everything you need
to access the objects properties. The most interestingparameters are certainly located within the Node tab. Here
you can find basic attributes, like Position, Rotation or
Scale.
The online help describes the correspondingget
commands as follows:
any getParameter( any )
This notation tells us that we can use any object or Data
Typewith thegetParameter command. This operation isnot limited to primitives, emitters or cameras. Also the
arguments can be an Integer, Float, Vector etc.
The Data Typeyou receive with thegetParameter
command can also be read out from the Node tab. When-
ever you see a triplet of values, the result will be a Vector:
Position 0.0 0.0 0.0
Rotation 0.0 0.0 0.0Scale 1.0 1.0 1.0
Pivot 0.0 0.0 0.0
Please note: The individual values of the Vector are Floats.
Even Color is represented by three values for red, green
and blue (RGB). The Data Typesfor Simulation and Dynam-
ics are Strings. The fields can contain words or expressions:
Simulation Active
Dynamics No
If WetDry Texturewas set to Yes, wed also have some
Integer values, like
@ resolution 256
The values for @ filter strengthand@ ageingare Float
types again.
As already mentioned, its crucial to know, which Data
Typeaget command spits out, because in the reverse
process with setParameter, you need exactly the sameData Typeagain to alter the appropriate value. Let me
show you an example:
cone = scene.getObject("Cone01")
pos_global = cone.getParameter("Position")
The result is a Vector, consisting of three Floats. After a
calculation has been finished, you can build a new Vector.
This new Vector must carry three Floats (Integers are
allowed, too) again. You cant replace the Floats with
Strings. This would cause a Syntax error:
pos_new = Vector.new("left", "up", "right")
Changing Attributes with Get & Set
8/13/2019 RF Magazine 0207
32/67
RF_magazine 31
Scripting with RealFlow02_2007
The next example is a complete script, ready to use within
RealFlow. The program adds a value of 0.2 to the y position
of a Cone with each new frame:
Events Script: ChangeConeYPos.rfs
def onSimulationFrame():
cone = scene.getObject("Cone01")
# 1. Get global position data in Vector format
pos_g = cone.getParameter("Position")
# 2. Get components from the position Vector
pos_x= pos_g.getX()
pos_y = pos_g.getY()
pos_z = pos_g.getZ()
# 3. Add 0.2 to the y component
new_pos_y = pos_y + 0.2
# 4. Build a new Vector
new_pos_g= Vector.new(pos_x, new_pos_y, pos_z)
# 5. Use the new Vector for position change
cone.setParameter("Position", new_pos_g)
This script is very similar to the Events Scripton page 26
(ParticleNewPos.rfs). There, the script adds values to the y
and z positions of all particles. Here, were just using a
single object. The process of getting, splitting and assem-
bling the Vectorsis finally the same. The main difference
lies in the last statement:
cone.setParameter("Position", new_pos_g)
With the particle method, its just
particle.setPosition(new_pos_g)
Particles dont use the sameget and set commands as
physical objects in RealFlow. For an emitter or a mesh, its
possible to see values directly in the corresponding Node
Paramswindow. Position or Velocity values arent
displayed at all. Theyll be used internally. For faster access
and better distinction, the particle attributes dont use theParameter keyword.
And theres another difference: ThegetParameter
command only takes one argument, named Position. The
setParameter shows Position and new_pos_g. So, with
setParameteryou have to tell RealFlow which type of
parameter you want to change (Position, Pivot, Rough-
ness...) and the new value using the correct Data Type.
The changing values can be monitored in the Node Params
window during the simulation. Just give it a try and watchthe y component of the Position value.
Tip
Dont copy and paste scripts to from the original source toRealFlow. Different fonts, character sets and spaces or
blanks will cause errors almost any time. Its better to type
scripts manually and think about whats happening.
Fig. 13: The Cone performs a constant movement in y direction
Changing Attributes with Get & Set
8/13/2019 RF Magazine 0207
33/67
RF_magazine 32
Scripting with RealFlow02_2007
WithgetParameter and setParameteryou can have lots of
fun, since you can alter, change or turn off and on almost
everything. Some tasks could also be solved manually and
with easy means, but scripting is much more accurate.
Especially with collisions its sometimes not easy to get
exactly the moment of the first interaction between twoobjects or particles. With a Python script, the solution is
just a few lines of code away. This is the initial situation:
Our goal is to deactivate the objects, after theyve hit thefloor. All items have different positions. Deactivating them
manually could be an ungrateful job. This scene just uses
three objects, but imagine 20, 30 or 60 items.
According to the methods you have seen so far, we always
called objects individually, but with more than three items,
this could get rather annoying. To ease this task, RealFlow
provides mighty tools for object selection. The operation,
Im going to use here is named:
getSelectedNodes()
With this command, you just select the objects you want
to be affected by the script from the Nodes window.
RealFlow recognizes your selection and stores all items in a
List object. So the correct expression is:
items = scene.getSelectedNodes()
Just for remembrance: With a selection of the threeobjects Cone, Cubeand Cylinder, the entries of items
would be internally:
items = [Cone,Cube,Cylinder]
The next step is to collect all objects, colliding with the
Floor item. RealFlow also knows a function for this
purpose. The Data Typecreated with this command is
again a List, because theres more than one object to
collide with Floor:
floor = scene.getObject("Floor")
colliding_objects = floor.getCollidingObjects()
Now we have to browse through the list of collided objects
and deactivate the appropriate primitive:
if (colliding_objects != []):
for object in colliding_objects:
object.setParameter("Simulation","Inactive")
The if condition checks, whether the List colliding_objectsis empty or not. The expression
if (colliding_objects!= []):
means: If the List colliding_objects is not (!= ) empty, then
do something. An empty List is written as [ ]. Another idea
is to check the length of the List.
If a collided object has been detected and written to
colliding_objects, the Simulation parameter will be set to
Inactive. In other words: As soon as an object hits the floorcompletely, itll be set to Inactive and the enclosed fluid
can be released. On the next page youll find the listing for
this script.
Changing Attributes with Get & Set
8/13/2019 RF Magazine 0207
34/67
RF_magazine 33
Scripting with RealFlow02_2007
Events Script: InactiveOnCollision.rfs
def onSimulationBegin():
items = scene.getSelectedNodes()
for object in items:
object.setParameter("Simulation", "Active")
object.setParameter("Dynamics", "Rigid body")
def onSimulationStep():
items = scene.getSelectedNodes()
floor = scene.getObject("Floor")
colliding_objects = floor.getCollidingObjects()
if ( colliding_objects != [] ):
for object in colliding_objects:
state = object.getParameter("Simulation")
if (state == "Inactive"):
pass
else:
object.setParameter("Simulation", "Inactive")
object.setParameter("Dynamics", "No")
The first function initializes the selected items and makes
them active. This is useful in case of starting multiple
simulation passes, because you dont have to switch back
each time you want to simulate the scene.
This program identifies all objects colliding with the floor
item and writes them to a List Variable:
colliding_objects = floor.getCollidingObjects()
The last if clause is just a little construction for checking,whether the Simulation state has been changed. So if the
Simulation state is already set to Inactive, then the script