0% found this document useful (0 votes)
35 views176 pages

User Guide

Uploaded by

Sundeep Parmar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
35 views176 pages

User Guide

Uploaded by

Sundeep Parmar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 176

RF4

User Guide v1.1


Written by Next Limit Team

Beatriz Lorenzo Botella


Jorge Medina Alix (tutorials 5, 7)
Luis Miguel Mora (tutorials 4, 6)

and Fusion CI Studios

Mark Stasiuk

© Next Limit SL. 2006


Acknowledgments

Next Limit wishes to thank Dr. Mark Stasiuk of Fusion CI Studios for contributing ideas and sections of
writing in the user guide, and in particular for writing the scripting user guide.
Index
01. WELCOME

02. INTRO TOUR


02.1. What is RF4?
02.2. Basic concepts
02.2.01 Simulation
02.2.02 Rendering
02.2.03 Stages within simulations
02.2.04 3D Space
02.2.05 3D Scene
02.2.06 Time
02.2.07 Objects
02.2.08 Particle Systems
02.2.09 Vectors
02.2.10 Forces
02.2.11 Meshes
02.2.12 Vertex maps
02.2.13 Objects Dynamics vs. animation
02.2.14 Camera
02.2.15 Scripting
02.2.16 Connectivity

03. TUTORIALS
03.1. RF concepts
03.1.01 Project hierarchy
03.1.02 Interface
03.1.03 Navigation
03.1.04 Elements
03.1.05 Interactions
03.1.06 Animation
03.1.07 Exporting simulations
03.1.08 Simulation
03.1.09 Optimization
03.1.10 Messages
03.1.11 Batch script
03.1.12 Event script
03.1.13 Preferences
03.2. Tutorial 1. Getting started: Geyser
03.3. Tutorial 2. Fluids: Two glasses.
03.3. Tutorial 3. Meshes: Two glasses II.
03.4. Tutorial 4. Dumb particles and daemons: Twister.
03.5. Tutorial 5. Rigid bodies dynamics: Demolition of a bridge.
03.6. Tutorial 6. RealWave: Sailing boat
03.7. Tutorial 7. Soft Bodies: Trampoline

04. CONNECTIVITY

05. APPENDIX
05.1. Resources and references
05.2 Expressions library
05.3 Shortcuts card

06. SCRIPTING IN RF4


06.1. Introduction
06.2. Preliminaries: Get Python

07. OVERVIEW OF PYTHON SCRIPTING IN RF4


07.1 Areas of scripting in RF4
07.2 Order of scripted operations
Index
07.3 Limitations
07.4 Basics of Python
07.5 Need-To-Know Python: loops, conditional statements, lists and dictionaries
07.6 Creating Your Own Functions
07.7 A Selection of Important Built-In RF4 Functions
07.8 Where to do scripting tasks
07.9 Making Scripts Artist-Friendly
07.10 Additional resources: importing modules
07.11 Some inspiration: examples of scripting results

08. SCRIPTING TASKS EXAMPLES IN RF4


08.1 Simulation Tasks: Scripted Daemons
08.2 Simulation Tasks: Create a Customized Wave Pattern
08.3 Simulation Tasks: Particle Spawning
08.4 Simulation Tasks: Emitter Orientation

09. EPILOGUE
01
Welcome
Hello from the team at Next Limit, and welcome to the learning path for RealFlow !

RealFlow 4 is a powerful physics simulation program available for 32 and 64 bits for
Windows, Macintosh and Linux, that enables 3D artists to create an amazing variety of
real-world, and unreal-world physical effects; for example, fluid dynamic simulations and
rigid-body simulations. But that isn’t all. There’s a lot more you can do in RealFlow, and
we are excited to be able to bring you this User Guide that will launch you off on a long
creative road of spectacular visual effects.
This User Guide, created by the same team that built RealFlow, including a great deal
of input from talented studio professionals, will lead you on a learning journey, revealing
the important basics- from basic theory through to full project workflow. You’ll soon find
out that RealFlow is a kind of personal 3D art-laboratory where you can explore, discover
and enjoy the artistry of physical simulation without having to be an expert in physics or
numerical methods.
In this guide you’ll find important information, explanations, and tutorials, structured so
that you can get up and running with RealFlow quickly, and also understand it. Unlike a
manual that simply describes buttons and settings, or a mechanical recipe-like tutorial
set, or a list of tips to work around difficult issues, the focus here is on using RealFlow in
proven workflows, and simultaneously developing an intuitive understanding of how to
achieve what you want. By working with users, we’ve found the “understanding factor” to
be a crucial element that allows artists to use RealFlow independently. Follow this guide
and, in a remarkably short time, we are confident that you’ll be using RealFlow in your
own unique ways to create the most organic, stunning visuals in your portfolio.

The contents are divided in two main parts:

Part one is about RF4 and will guide you through the basic contents of the program.
It will cover a series of topics more specifically focused on the visual effects industry. The
tutorials in this part will cover the basic topics and workflow, and will show you examples
of everyday work.
The second part is about scripting. What is it, how to get started and the capabilities of
RF4 scripting within the program.

Understanding the program, using the program, making terrific effects with the program…
that’s what we want you to do! Have fun with this guide and open your eyes to the rich,
new world of physically simulated animation.

All the best,

NL team.
02
Intro tour
02.1. This year’s release of RealFlow is aimed at helping studios to achieve high-end physical
simulation effects, and is the direct result of Next Limit listening carefully to professional
What is RF4? users.

The development process is still ongoing, as a number of selected “beta studios” continue
to give feedback on the application of the package to real production work, but RF4 is
already a very effective tool. In fact, the RF4alpha already produced some amazing water
effects for feature films. Those accustomed to the software will see that most of the old
limitations have now dissolved away, so you can now do a lot of what you used to only
imagine. The biggest themes of the new version are: control and efficiency.

Closely tied to these themes is the most innovative addition to the package: scripting. In
terms of efficiency, there has been an overhaul of the interface so that it’s now far better
suited to managing complex scenes, and much quicker to use overall. There are native
objects, cameras that you can add at will, and you can now group scene components
together, so you can simplify scene hierarchies and make changes to the parameters of
many scene components simultaneously.
The export and management of your simulation assets has also changed dramatically.
There’s a new custom particle file format, an automatic file naming option, and a frame
numbering system that works with your studio’s conventions.

There’s also been a whole range of optimizations within the fluid and rigid body solvers,
making more RF processes multi-threaded, and simulations more stable.

RF4 combines a powerful set of features for physical simulation including fluids, particle
systems, meshing utilities, rigid bodies, soft bodies, constraints, wave generation and
buoyancy, and scripting. All elements can be connected together in a scene giving the
user the power to produce a tremendous range of technical and creative results.

RF4 is a 32 and 64 bits cross-platform application working for Windows, Macintosh and
Linux, and at the same time RF4 provides full compatibility with the most popular 3D ap-
plications on the market.

Features
• New fully customizable user interface.
• More consistent and improved workflow
• More multithreading process.
• 32 and 64 bits cross-platform (Linux, Windows)
• New rigid bodies dynamics engine solver.
• New softbodies
• New tools
• New scripting system
• New exporting options and formats
• New RF native objects and cameras
• Improved RealWave surface
• Graphic user interface and command line versions
• Fully integrated Help Menu
• Texture mapping (wetmaps and foam maps)
• Computational Fluid Dynamics solver
• Rigid Body constraints
• Mesh generation engine
• Particle and mesh texturing options
• Integration with the 3D platforms
• New fully undo function
• …and much more
02
Intro tour
New fully customizable user interface
RF4 tool set has been reorganized, based on the logical use of the program, in order to
have a clear workspace with nothing to disturb you. Layout customizing is very fast and
dynamic. You will have the tools that you need when you need them.

More consistent and improved workflow


The new workflow’s efficiency is a result of Next Limit’s listening to users. From scene
creation where everything is automated, to the possibility of choosing a custom output
that fits your pipeline. We have made the workflow faster and easier for you, and included
more preferences to it.

More multithreading process


More RealFlow processes have been multithreaded to optimize the use of your resources
and multi-CPU systems.

32 and 64 bits cross-platform (Linux, Macintosh and Windows)


RF4 takes advantage of the majority of the technology on the market to widen simulation
possibilities and hence, user’s control.

New rigid bodies dynamics engine solver


The new RBD solver includes improvements in some areas like primitive creation and
scene loading. In addition, thanks to the new collision detection and propagation routine,
the accuracy and speed of simulations has improved without loss of quality. Now we can
have simulations of any kind with hundred of objects combined in a tight schedule.

New softbodies
Soft bodies function now as an entity inside RealFlow. They are very efficient thanks to the
broad range of parameters, and the control that they allow. A pin system is also included
for making not only softbodies, but cloth.

New tools
Apart from the existing tools like Curve Editor, some other functions have been developed
such as Initial State (for all elements) or Particle Interpolation (to increase fluid resolution
as a post-process).

New scripting system


This is the biggest addition in RF4. You can now apply Python language scripts to five
areas of RF: batch runs, events, daemons, waves and fluids. Next Limit has designed a
full palette of functions that gives users almost total control of simulations, opening up
endless possibilities.

New exporting options and formats


Apart from the usual scene exchange workflow through the plugins and SD format, RF4
provides an advanced feature aimed at optimizing resources and saving memory; new
.md and .pd file formats. An SDK is available for these two formats, so anybody can cre-
ate their own translator.

New RF native objects and cameras


RF4 includes some basic primitives that can save users a lot of time on some scenes. Fur-
thermore, creating and including cameras in the simulation makes RF4 an innovative tool
for new possibilities in effects visualization.

Improved RealWave surface


RealWave includes some new features to broaden the possibilities of your simulations,
such as defining the depth of the sea bottom to control the wave’s shape or a current.

Graphic user interface and command line versions


RF4 is available in both its standard, complete version, and Simulation Node versions.
That means that you can run your standard version of the software on one computer and
02
Intro tour
launch different simulations on others, setting different parameters and testing the re-
sults of your animation on as many computers as you have available.

Fully integrated Help Menu


RF4 maintains the same philosophy of having a completely integrated user manual in the
form of an extended, complete Help Menu and Functions Guide. Just hit F1 on any of the
parameters in the software’s interface and you can immediately find definitions, functions,
tips and examples of how to use each and every feature and parameter.

Texture mapping (wetmaps and foam maps)


As in RF3, particles are able to “paint” an object on RealWave’s surface and produce a
texture bitmap with the same UV mapping. Effects like “wet” or “painted” objects can be
easily obtained, and together with scripting, this feature becomes much more powerful
and allows new “wet” interactions.

And much, much more...

02.2. We at Next Limit frequently hear the following question:


Do I need to know physics and math to use the program?
Basic concepts
Real Flow is based on many algorithms and complex math, but fortunately, we do not
need all this knowledge to use it. Our imagination and a bit of practice will do.
Of course we need a basic knowledge on geometry, math or physics, but when working in
3D, the core concepts we need to know become effortless. Don’t think about this as a long
day in front of a book, trying to understand abstract and difficult concepts. It’s not! While
you go through the book you will assimilate the basics almost without noticing it.

So, let’s go through the very basic stuff.

02.2.01 Features
The very first thing we should know about a program like Real Flow prior to using it is that
it is a simulation program. But what does this mean exactly?

Formally speaking, to simulate is to imitate or to estimate how things might happen in a


real situation. So, to simulate is to make an artificial situation. We could refer to it as role
playing, but we are talking about using technology and math, and we are talking about
computer simulation.
So, as you will be analyzing reality quite frequently, we recommend you store up some
references to be able to create believable sequences- like staring at a fountain, or buy-
ing some hi-speed photography shots, recording waves on the beach… anything you can
think of.

The second thing you need to know is that in a simulation process we have to go step by
step? we cannot simulate a frame without having first simulated the previous one. This
may sound strange, but it is quite important to remember that a simulation is a calcula-
tion process. It will take its time, and it will go its own way. In RF4, we find that the frames
are subdivided in sub-steps that have to be calculated sequentially, and this subdivision
02
Intro tour
will allow us to optimize the simulations making them more accurate or faster.

Finally, a simulation imitates the internal processes, and not only the results of the event
that is being simulated. But even so, we are not in a process that can be measured. We
are in the VFX field, and the art director might want something special and far removed
from reality, so the artist must be in complete control of the situation.
And here is when RF4 stands up on its own, because, although RF4 is simulation program,
it is artist friendly. This means that you will often find yourself using tricks to create a
physical effect rather than trying to provoke the conditions for it to happen, perhaps be-
cause of deadlines or other reasons.
So, once you know all this, you know you do not have to be stuck in reality; you can
imagine whatever effect and reproduce it in the computer, even if it is not a real physical
effect.

02.2.02 Rendering
Rendering is the calculation that a computer does to visualize a computer generated en-
vironment. We mention it prior to explaining more basic terms, because it differs from a
simulation. It is a completely separate process.

There are other packages that actually render (as RF4 does not) like Maxwell (www.max-
wellrender.com).

02.2.03 Stages withing simulations


When producing a simulation, we have to go through various processes until we can show
the final sequence. We do not mention here any of the processes that involve creation
(like taking references), only the computer related ones.

First stage of a would be simulation.


What we need here is the input data (objects, animations, deformations, UV maps…)
- that will come from your favorite 3d application,
Then we will set the scene up within RF4 (adding emitters, daemons, scripts…) and
we will go through a phase of testing and updating parameters. Once this is done,
we will simulate.
The output data will then be transferred into our 3d application.

The second stage takes place in our 3d application, this is called the rendering stage, and
we will take the output data from the simulation and render it.
When it comes to rendering meshes or objects, we will add materials in the regular
way.
But when rendering particle clouds, we find many methods by which to do it: tex-
tured quads, single pixels, meatballs, etc. and to imitate natural effects we often
find that we have a lot of particles. To render a large quantity of particles can be-
come a problem if not planned. If we want to give a realistic appearance, we might
also have to look for a special method for rendering.

In this book we are going to take a look at the first stage, as it is the one that involves
RF more directly.
However, we do recommend that when you to plan your simulation, you take the render-
ing stage into account. This is not only to prevent unpleasant surprises at the end, but
because the way you plan to render can affect the way you simulate.
02
Intro tour
Simulation and rendering
stages of the same scene

02.2.04 3D Space
The simulations we intend to create with RF4 will take place on the computer, in a 3d en-
vironment, so let’s see what it is….

3d space is all around us, you just have to look at the corner of the room you are in to
imagine it. Everything can be worked out by using this corner as a reference. You can
specify the distance of every object from this point, thanks to the planes that intersect
(the walls and floor). Moreover, you can tell how the objects are shaped just by making
references from the surface of the object to this corner.

We can measure where the table is by referring to the corner, and we can measure the
distance of the low end and the high end of the table referring to the corner, so that we
know how long it is.

The table can be located Ok, the reference point


and described from the
doesn’t have to be the corner
corner of the room
of the room, it could be any-
where, what matters is that
there has to be a point of ori-
gin somewhere.
So, we have seen that the 3D
space is defined by a point
that is called the origin, and
that there are three axes that
are at 90 degrees to each oth-
er- these axes are called x, y
and z.
If we follow these three axes
in one or the other direction
from the origin we will have
positive or negative values
(coordinates).

So, in short, this is the 3d en-


vironment in which we need to place our scene and work on it.
02
Intro tour
Cartesian axes

02.2.05 3D Scene
The scene is built in our 3d environment, and consists of several elements put together. It
is our workspace, where we will set up the parameters for simulation, and where we will
move objects to their correct locations, make animations, light the scene, render, etc.

It normally includes a camera in order to render the scene and get the final visualization.
In the simulation step, this camera is not always needed, but it is a useful tool. For ex-
ample we can make it to follow a specific element of the simulation, or simply check the
simulation from the sequence’s final view point

It also includes a grid to let the user know where the origin is, or (0,0,0) point (from
where we refer to every coordinate in the scene), where the floor is, and what is the size
of the scene.

Typically, in a 3d scene for simulation we will find particle emitters, objects, daemons and
other elements that make up the scene and the movement within it.

02.2.06 Time
In the video and computer generated (which we will refer to as CG) world, time is divided
to show a certain number of frames in a second. So, we do not only count the time in
seconds, minutes or hours, but also in frames.
For example, we can show 24 images per second, as with cinema, or 25/ 30 as with televi-
sion. This is what is called frames per second (the FPS rate). It is also the most efficient
way to count the time in computer graphics.

In computer simulations this is interesting because the output is going to be into some
kind of graphic media. So, at the time of simulating, we will have to decide how much of
the simulation time is going to be calculated, and the speed (FPS) of the simulation. This
is typically done with a timeline bar spaced in frames.
02
Intro tour
02.2.07 Objects
When working in three dimensions it is necessary to have objects, in order to represent
reality. Let’s say we want to fill a glass with water, well in order to achieve it, we are of
course going to need the glass.
Using a more technical approach, we can say that an object is a group of polygons and
vertex that we can place in our scene to represent something.
Typically we would place them, animate them, light them, render them, etc. In Real Flow
we will use these objects as rigid or soft bodies to interact with our fluids and surfaces,
or with other bodies.
The way we get these objects in RF4 is either by importing or creating them.

Rigid body: A rigid body is an object whose geometry does not change within a simulation;
it remains the same before and after the application of any forces and/or obstacles.

Soft Body: A soft body is an object that simulates the dynamic behavior of non-rigid bod-
ies, they move and deform according to the effects of physical forces and obstacles.

Fluid colliding with some


objects, rigid bodies and
soft body example

02.2.08 Particle system


Particles are another element that we will frequently use. A particle is a point in the
space that has some kind of motion, and property parameters such as mass or velocity.
Together, a group of particles define a cloud, and the characteristics of these particles will
make this cloud behave like a particular fluid.

The particle systems are always referred to an emitter, which allows us to give the same
02
Intro tour
Cloud of particles simu- properties to the entire cloud so that creating, con-
lating liquids trolling and eliminating particles become easier. In
RF4 every particle belongs to an emitter, so every
particle obtains its properties from the emitter it
belongs to.

When working with particles, we have to control


them. It is not a matter of picking particles one by
one, but of moving and controlling these clouds by
means of forces, collisions etc.

In RF4 we will use particle systems to simulate ef-


fects that include irregular natural structures such
as fire, water, smoke, fog, clouds, explosions…

02.2.09 Vectors
Though we will not use vectors as an element in its own right, knowing about them is very
helpful when using particles.
Vectors are basically “arrows” that point from one thing to another, straight line segments
with a defined length (magnitude), and a particular orientation in space (direction). A
vector’s magnitude and direction are not interdependent, so you can have a particular
direction with any length, or vice versa.
In 3D space - that is, (x,y,z) - a vector has 3 components: the x component, y component
and z component, and it is normally seen written in the following format: [x,y,z].
The length of a vector can be worked out with basic trigonometry, and increases with the
magnitude of the components.
One particular kind of vector is called a position vector. This expresses the position of
something in space, as a vector that goes from the origin (world origin) to that some-
thing.
Velocity is another vector - for that, the magnitude is the speed, and the direction is the
direction of travel. The velocity vector is quite important when working with particles as it
defines the position, velocity and travel direction of the particle. Visualizing vectors when
working with particles is often very helpful to check the simulation and its stability.

02.2.10 Forces
When working on simulations, we will need some kind of force to control what is happen-
ing in the scene. For example, if we want the elements to fall to the ground, some kind
of gravity is needed.

These forces are called Daemons in RF4, and allow us not only to assign an acceleration
but also to create other effects such as deleting or splitting particles.

In general, we say that these forces modify the speed vectors of the simulating elements,
by adding a vector, multiplying them by a factor, or by performing some kind of math-
ematical operation. They can often be represented as vectors themselves.
02
Intro tour

02.2.11 Meshes
A typical mesh is an object that is built up from a cloud of particles. It’s rather like an
organic shaped cover.
In RF4, the user will find not only this kind of mesh, but also other types of meshes – like
the one seen in the picture below.

Mesh types:cloned geom-


etry, m-polygons and
metaballs

In RF4, meshes are generated either during the simulation process or after it, and allow
us render an object instead of a cloud (which is usually less problematic).

Meshes are typically used for liquid type effects, rubber or jelly elements… but of course,
we would love you to invent new uses for it!.

A different use of a mesh


02
Intro tour

02.2.12 Vertex maps


Any polygonal object that is formed by polygons, can have additional information in its
vertex. This information can vary: color, weight… and will be used to group vertex, to
assign importance to some vertex for later operations, or to assign a coordinate in an
image.

In the case of RF4 we will be handling weight maps (vertex have a value typically between
0 and 100) for mixing fluids (only available for 3DSMax, XSI and LightWave),
and UV maps (UV coordinates are assigned so that a 2d image can be projected in 3d
geometry) for making wet-dry or foam effects.

Thanks to the vertex


maps, we can make wet-
dry effects or map fluids.

02.2.13 Objects Dynamics vs. animation


What is the difference?
When animating, the user has to move/rotate/scale the objects directly so the objects
react. There is no need to calculate/simulate anything.
When using dynamics, the user has to apply forces, conditions and constraints so the
objects automatically move in a physical certain way. The computer will then process that
data to give us the resulting motions.
This does not mean that either animation or dynamics is better than the other, they both
have their uses. It is a question of what we want to achieve, and what we need.

In RF we can make motions for the objects in both ways. We can use the curve editor to
animate using envelopes or expressions, and we can use the dynamics engine to simu-
late dynamic motions. This dynamic motion can be edited in your 3d application later on,
though it is not normally needed.

02.2.14 Camera
As mentioned before, a camera is needed at the time of rendering, but it is often used at
the simulation stage. You might be wondering why.
Well, in the CG world it is said that the things we do not see through the camera are the
things we do not have to bother about (no need to calculate them). This is true most of
the time in some way. So, there are obvious advantages for simulating from the final point
02
Intro tour
of view which is the one that the user is going to see through. Thanks to the camera, the
artist will perceive the feeling of the simulation from the very beginning.
In RF4, there are other advantages of having a camera in the simulation scene- it can get
involved in the simulation and chase a particle or object, or even move within a flow of
particles. There are many possibilities.

02.2.15 Scripting
Python is scripting the For those of you who do not have a clue
language in RF4. what a script is- scripting is basic pro-
gramming. Some advanced program-
mers have created a special program-
ming language with several functions
and utilities to use straight away; this
is a scripting language.

So, scripting as a tool might require a bit of programming and math knowledge, but
scripts as tools require none. Isn’t that good news?

Why someone would need scripting anyway?


Well, scripting tools allow users to program their own tools (within certain limits) and to
solve certain program limitations or specific scenes. This obviously makes the program
much more powerful. Imagine for example, that you have to create and arrange one hun-
dred elements, wouldn’t it be easier to have a script that makes it for you?

In RF4 we will be dealing with Python scripting. Python is an interpreted, interactive, ob-
ject-oriented programming language.
It has got an open, friendly community, with lots of documentation, and though its imple-
mentation is copyrighted (http://www.python.org/doc/Copyright.html); it is freely usable
and distributable, even for commercial use. (www.python.org).

02.2.16 Connectivity
If you are new to RF, you might have heard this term without knowing exactly what it
means. It refers to the workflow between RF and your favorite 3d application.

As mentioned at the beginning of this section, for making a complete simulation we need
the simulations to generate output data to render in our 3d application, and probably
some input data to make the simulation. It can be created within RF4 or imported from
your 3d application. If it is the latter, there is a need for a connectivity workflow. But there
is always a need for a connectivity plug-in, as the output must always be taken back to
the 3d application.
Next Limit offers various plug-ins together with RF that will work with the main appli-
cations in the VFX industry fields (3DSMax, Maya, LightWave, Cinema4d, Houdini and
XSI).
02
Intro tour

Typical workflow scheme.

In addition, Next Limit offers not only these plug-ins, but also an SDK for developing your
own connectivity plug-ins for some file types (.pd and .md).
For more information on connectivity, please go to the page 106.
03
Tutorials
This is the section where you will finally get your hands on the program, so sit comfort-
ably, switch your computer on, and start testing things out whilst you are reading.

Although you will be probably tempted to skip some of the tutorials and go to the ones you
like the most, we recommend that you go through the entire set of exercises, as they are

Splash window

designed so that you learn the program step by step. The explanations and uses become
progressively more complex as we go on.

The first thing you see when you open the program is the “splash window”. This is not a
actual function, but it tells you which version of the program you are using. Remember to
check the RF site from time to time to know if there are any new patches or a new ver-
sion available.

The next section, RF concepts, is important for following and understanding the exercises
smoothly.
If you are new to RF we recommend you to read it carefully. However, if you already know
RF and its core concepts, then you can skip this section, and just use it as a reference. If
you come across a new concept, refer back to the RF concepts to learn more about it.

At the end of each tutorial there are also notes giving useful tips, potential problems and
alternative approaches, which are useful for any user. Some of them have also got an ad-
vanced section, so that once you have gone through the guide, you can do the exercises
again, and try to make them a little more complex.

If you are looking for help whilst following the tutorials, you can check the manual for
more technical explanations on parameters under Help>Contents in the program.
03
Tutorials
Online help.

Before getting started, let’s define the common abbreviations that will be used in the
text:

LMB / MMB / RMB = left, middle and right mouse button, respectively.
Ctrl = the control button on your keyboard.
Alt = the alt button on your keyboard.
Shift = the shift button on your keyboard.
1,2,3,4,Q,W,E,R = refer to the equivalent buttons on your keyboard (e.g., W = the
W button on your keyboard).

03.1. 03.1.01 Project hierarchy


RF concepts
The project management window always comes up first when opening RF, and besides its
main function (that is create a new project or opening an existing project), it dictates the
organization of scenes within RF4. It is recommendable to get used to it, as it is the logical
way to organize RF4 simulations.
It is also important to remember that a project is not a single file, but a collection of files
and folders created automatically by the program. It has a main .flw file (the scene file),
and several directories which contain the simulation data.

The lower window will allow the user to double click on any of the recent projects used,
in order to open it.
03
Tutorials
If the Project Management window is closed, you will be able to work anyway, but the
program will ask you for a project name when trying to save a simulation.

So, in order to create a new project, it is necessary to set a Project name and a specific
Location (otherwise it can be left to default path). Then, check Full path, and if everything
is correct, click on Create a new project.

If you type a project name that already exists in your projects folder, RF4 will over-write
the pre-existing .flw file, but nothing else on the directory. Once you do this be aware that
depending on the name of scene items, you might be over-writing a previous simulation
when simulating.

In short, the basic structure of a project consists of a folder named as the project, let’s
say: MondayTest.
Under the MondayTest folder, there will be MondayTest.flw and then the subsequent fold-
ers:

• Images: Where image sequences will be stored corresponding to wet-dry tex-


tures, foam maps, textures and color plane daemon images generated during the
simulation.
Initial State: RF4 will store any initial state in this folder, this has nothing to do with
exporting the simulation and it is meant for RF4 internal purposes.
• Log: Where a text document will be stored with all the information of the simula-
tion and simulation times.
• Meshes: Where the meshes generated during the simulation or during the play-
back time of the simulation will be stored. The format of these sequences depends
on the user’s choice.
• Objects: In this folder we will typically place our resources, but if we focus on the
output of the simulation, the animation, deformation, real-wave surfaces, camera
and objects are going to be stored here.
03
Tutorials
Particles: This folder will contain all the particle file sequences generated during the
simulation.
• Preview: Where image sequences corresponding to active viewport generated
during the simulation or during the playback time of the simulation will be stored.

Project files.

03.1.02 Interface
Containers Now that you know how to create a
project, let’s have a quick look at the
interface.
The interface is fully customizable; it
is divided into windows that can con-
tain any kind of information, except
timebar, playback and simulation con-
trols, that are fixed in the lower part
of the screen.
It is possible to split these windows,
resize them, assign them contents, to
undock them and to minimize them by
double clicking on the title bar. Every
option is easily accessible as you can
see in the picture below.
You can also create and store your
own layouts with the options available in the Layout menu.

The upper toolbar can be configured too, right click on any empty space on the bar to
activate or deactivate tool gro
ups.
03
Tutorials
Upper toolbar can be
configured by right click-
ing on it.

03.1.03 Navigation
The next step is to learn some basics about view ports and keyboard shortcuts.
Viewports show the graphical elements of the current scene. These windows use OpenGL
graphics; take this into account when configuring your graphic card.
Put simply, viewports are our workspace, where we will usually manage the scene from.
Therefore it is very important to navigate in a fluent manner and to learn the shortcuts
to gain working speed.
You can also print or use the shortcuts card in the guide.

In order to manage the views click on

Alt + LMB for rotating,


Alt + MMB for panning and
Alt + RMB for zooming.

Managing the view-ports

Select a view by clicking on it, and its name (on the upper left part) will turn green, and
some information will be also displayed. All the views display the three axes (x, y and
z) on the left bottom corner so that you can keep track of the orientation at every mo-
ment.

Change the view by either right clicking on a view and choosing View or by using 1, 2, 3,
4 keys.
03
Tutorials

If you are using a Quad View you will be able to magnify the selected view by Alt + W.
During simulation is recommended to have only one (or better none), by deactivating it
using Alt + D keys. This will improve speed.

To select elements directly from a view, just click on them or drag a window clicking on
the LMB.

Another important feature in RF4 is the RMB menu; we will be using it all the time (not
just for the view setting), so take a look at it. Right click on any of the viewports, and you

Right click on a viewport


displays the RMB (right
mouse button) menu.

will be prompted with the menu seen below:

The vieweing of the different elements can vary depending on the display properties ap-
plied, but for the polygonal elements we can use these shortcuts to display the view them
in different ways:

7 -> Bounding box view.


8 -> wireframe view.
9 -> Flat Shaded View.
0 -> Smooth Shaded View.
D -> Switch between shading modes of the selected objects.

There are more tools to configure navigation, like View > Scene > wireframe backfaces to
see the interior of an object from behind; or Edit > Back culled selection for a customiz-
able polygonal/ vertex selection type.
03
Tutorials
Shading types.

03.1.04 Elements
Elements are the items in the scene; the ones we use in order to get the effect we are
looking for. Any type of element can interact with the other types, and be part of the
simulation.

There are many ways of adding elements, but the most efficient will be probably the RMB
menu, shown in the “Navigation” section of the guide.
You can also try

Ctrl + 1 for adding emitters


Ctrl + 2 for daemons
Ctrl+ 3 for native and imported objects
Ctrl + 4 for constraints
Ctrl + 5 for mesh
Ctrl + 6 for camera
Ctrl + 7 for RealWave
Filters on the nodes list
Or you can simply use the icons on the upper tool-bar.
Within all the different types of elements that are avail-
able, there are categories and types. As this guide is not
a technical manual, we will not be covering every single
one, but it doesn’t mean that you can’t go ahead and test
and practice on your own. Moreover, you should test and
practice a lot on your own, experimentation is the key! You
will have the background for it after going through the tu-
torials. We will however cover the most versatile and used
ones in the guide.

All the elements added to a scene will be listed in the


Nodes window, by right clicking on it you will be able to
filter some type of elements. You can also group a bunch
of elements for a better understanding of the scene by
selecting them and right clicking. And, as a rule, every ele-
ment can be right clicked from the Nodes list to access to
various options.
03
Tutorials
Emitter
Emitters generate particles, and their settings dictate the basic behavior of the fluid. Many
emitters can coexist in the same scene. Each emitter carries its own properties, like ori-
entation vectors and particles properties.

Emitters’ list and some


emitters

There are many types of emitters; the geometrical ones are referred to as basic, and
are the most versatile, but there are also other special ones like Object Emitter or Bin
Loader.

Particle types

As previously mentioned, emitters generate particles. RF4 offers five different par-
ticle state equations that govern the motion and interaction among particles.
With these five particle types you will be able to create every effect you want, but
do not get too stuck on the names- learn about their properties to know when to
use each type.

• Dumb: Dumb particles do not interact with each other, so there is no possibility
of creating volume with them. The advantage in using them is that RF4 will handle
a large amount of dumb particles without much effort. They are quick to calculate
because the Max substep can be decreased due to the absence of pressures in the
particle cloud.
Dumb particles are not affected by other particles or particle systems, but they do
03
Tutorials
interact with objects, and can affect other kinds of particles like fluid or gas.
Dumb particles are typically used for sprite type effects such as dust, fire, smoke,
water spray, splashes, etc. They also work well adding rich detail to turbulent
flows.

• Liquid: Liquid type represents an incompressible liquid using a collection of co-


herent particles which sample the properties of the a liquid volume. Each particle
represents an element of liquid mass (the amount of mass depends on the size of
the volume and the resolution used) and is also an irregular sample of real physical
fields, which define the liquid’s dynamic behavior, such as pressure, velocity, ac-
celeration, density and viscosity.
Unlike dumb particles, these particles are “active” in the sense that they interact
with one another, continually attracting, repelling and undergoing viscous interac-
tions, they are subject to the effects of pressures.
These interactions ensure that RealFlow’s “liquid” particles maintain a good sam-
pling of the incompressible liquid volume, and provide an accurate representation
of the liquid’s dynamic properties.
Liquid particles are typically used for fluid and liquid bodies like water, honey, choc-
olate, etc.

• Gas: Gas particles share the same properties as liquid particles, but they do not
behave in the same way. A gas will lose its energy (internal pressure or tempera-
ture) trying to expand and to fill as much volume as it can. For this reason, a gas
heats if compressed, and gets colder as it expands. Gas shares heat with objects
and other gases.
Gas particles are typically used for accurate gas behaviors.

• Elastics: Elastic particles share properties with dumb particles, they are quick
to calculate, and do not have any pressure to make them form a volume. However
their elastic property comes from a spring-mass system between particles, that
creates a flexible structure for supporting the particles. Springs can also be set to
break or lose their elastic properties.

• Custom: Custom fluid has got a lot of potential, as the behavior is dictated by
the user via scripting.

Daemon
Daemons
03
Tutorials
Daemons allow you to selectively add effects, like forces, that control and sculpt the mo-
tion of particles and objects. Many daemons can be applied to the same item, and a single
daemon can affect multiple items.
All the daemons work for particles and objects with the exception of killers (with a letter
k before its name) that only work with particles.

Mesh
A mesh is a polygonal cover for a particle cloud. It unifies the cloud to make it look more
like a compact fluid, like a liquid type of fluid. Each individual mesh can include any num-
ber of fluid emitters.

Mesh

Objects
Objects inside RF4 RF4 interprets objects as groups of vertex and three sided
polygons. RF4 can create simple geometry but will accept
complex geometry created in external 3d applications.
Objects can interact with the elements in the scene, be-
ing rigid or soft bodies or simple walls for particles and
objects.

The objects can be deformed or animated outside or inside


RF4.
03
Tutorials
Constraints

Constraints

Constraints are elements that restrict the movement of an object. They can be artificial
like restricting a velocity, or can be the result of the inclusion of a joint, like a hinge.
Constraints are meant to be used with dynamic objects, ie. objects that can react to the
forces in the scene. Of course, using constraints lead to more complex dynamic environ-
ments.

Fluid surface (RealWave)


Fluid surface is a tool for creating surfaces where waves can be propagated. Other el-
ements can interact with a fluid surface creating waves, buoyancy effects, splashes...
Waves are always vertically displaced.
Many kinds of deformers can be attached to the real-wave surface, to mix them for creat-
ing more complex wave patterns. These waves can be created by the collision of an object
or particle, can be created by vibrating points, a fractal or spectrum pattern, or by a user
defined pattern via scripting.

Fluid surface
03
Tutorials
Cameras

RF4 can create cameras, but it can also accept cameras created in external applications.
Having a camera as an element in RF4 allows its inclusion inside the simulation, attached
to a particle or an object for example.

03.1.05 Interactions
The gravity is affecting The old Scene Tree is gone forever,
the red emitter while the it has been replaced by two windows
wind is affecting both that function together with the Nodes
emitters.
window on a drag and drop basis, the
Global Links and the Exclusive Links.
These two windows are much more
consistent than the old Scene Tree,
and do not have multiple exceptions
like the old Scene Tree used to have.
However there is still one partial ex-
ception- objects will interact with
other objects depending on the sta-
tus of their Dynamic property, BUT a
dynamic object will only interact with
the elements that the Links windows
command.

The Global Links window will make all


the elements inside interact with one
another.
The Exclusive Links allow interaction groups to be made. For example, two emitters and
a gravity, with the gravity affecting just one of the emitters.

You can remove an item from the Links by clicking on it and pressing Delete key, and you
03
Tutorials
can add an item simply by drag and drop from the Nodes list. All these lists (Nodes, Global
links and Exclusive links) can be filtered by right clicking to show and hide a particular
type of element.

Every element that is added to the scene is automatically placed in the Global Links by
default. However there is an option in the RMB menu for deactivating this automated be-
havior (Add to Global Links).

03.1.06 Animation
Animation in RF4 comes in two forms: imported or native.
Imported animation is the one that comes from our 3d application and native means the
animation is made within RF4.
In RF4 we can animate a lot of parameters, not just position, rotation and scaling of ele-
ments. For any animation, you can use playback controls to watch it. The playback con-

Playback controls

trols are located next to the time-bar.

There are two ways of animating within RF4: Key frames or expressions.
For key-framing you set values at particular frames, and control the style of interpolation
between those frames. Using expressions means setting values in some mathematical or
procedural way. Expressions in RF4 can give you sophisticated and precise control; if you
are not familiar with them, check the expressions library in the guide to find out more.
Most parameters can be animated in RF4 without numerical limits, and this is a good
thing, but it also means that you have to be careful. RF4 does however prevent values
that don’t make sense from some parameters (like 0 or negative mass).

When a parameter is animated, it will display its value in an orange box.

In general terms, elements and parameters can be animated in several ways.


When animating with key frames we have several possibilities:

- To use the RMB menu directly from the view ports (for position, rotation and scale of
elements).
- To use the Key frame tools (K icon) for position, rotation and scale of elements.
- Also from the keyboard shortcuts for position, rotation and scale of elements.
- To use the Node Params window by right clicking over the name of the parameter, for
any kind of parameter.

Animating a parameter
from the Nodes Param
window
03
Tutorials

- And of course, through the Curve Editor you will find a more complete way of animating
any kind of parameter.
- The only way to animate through expressions however, is by using the Curve Editor, so
let’s have a look at it.

Curve Editor

The Curve Editor is a window that allows us to access to the animatable parameters to
make them change over the time. You can access it via a container (window), by pressing
the F9 key or through the Tools menu.

In order to edit a curve, there are some steps you can follow to have it available in the
curve editor, but probably the most efficient way to do it is to double click on the name of
the parameter you want to animate. The curve will be automatically displayed on the main
window of the curve editor. This main window is called graph, and it represents the value
of the parameter in the vertical coordinates, and the time (frames) in the horizontal.

To adjust the curve in the graph you can use

Alt + MMB for panning


Alt + RMB for zooming (notice that moving the mouse vertically or horizontally ad-
justs the zooming vertically and horizontally)

To add a key frame, simply right click on the graph and choose Create Key, or double click
on the point where you want the key frame to be. To edit the key frames you can move
them by click and drag, or do it numerically in the Envelope tab.

Curve Edition
03
Tutorials
Explore the different options of the curve editor a bit, take a look at fitting, scaling and
panning.
Each key frame can be set to be a different type of node, you can choose among TCB,
Bezier and Linear by both right clicking on the graph, or via the Envelope tab.
TCB: stands for Tension, Continuity and Bias; three controls that allow the user to change
the tangency of the curve in that point, controlling the interpolation with the previous key
frame.
Bezier: Bezier has got two handlers that can be modified directly from the graph view. Its
objective is to control the interpolation between key frames as well.
Linear: Linear will draw a straight line from the previous key frame to the selected one,

Nodes types in key-


frames

meaning that there will be no acceleration on the animation.

Copying a curve can be done in two ways:


To save the curve to the disk and load it in another curve: (File menu) or to right click on
the parameter’s name (Node Param window), and choose Copy Curve to from the menu.
However this last option only applies when the two curves have been given the same
name.

There are some limitations within the Curve Editor that you should be aware of too, for
example multi-edition of curves is not directly supported, though it can be done via script-
ing. And the node types are not saved with the curve.

03.1.07 Exporting simulations


Every time you click on any saving option you will be saving the .flw scene file. But this
scene is not the simulation you will be using in your 3D software. For that you will soon
discover that other kinds of files are saved, depending on what you are simulating.
03
Tutorials
Export central

By using the Export Central (Export> Export Central or F12) you will access the exporting
panel itself. This is the tool for saving your simulations, not the .flw scene file, but the files
you need later to import the simulation to your 3d application.

There is a lot of information we can save from the simulation, and it can vary depending
on the element that is being simulated. We are not going to get too technical here talking
about file formats; instead we will try to learn the features RF4 offers you.

RF4 gives visual clues


when expoting a
simulation
03
Tutorials

Every time a simulation is exported, the timebar will be show up in orange.


Emitters: When the particles from an emitter are being saved, a blue square appears at
both sides of the timebar, as a visual clue.

The output of a particle simulation is a files sequence that stores information useful for
shading, like the velocity or the pressure of particles.
RealWave: When there is anything related to a RealWave simulation that is going to be
saved, a blue square appears at both sides of the timebar, as a visual clue.
We will be able to get the geometry, deformation and foam maps sequence generated by
objects or particles colliding.

• Cameras: The camera stores the animation curve of the camera. That can be
applied or linked afterwards to the camera in our favorite 3d application. When a
camera is being saved, an orange square will appear at both sides of the timebar.
Daemons: daemons do not have an output, however there is a daemon called Color
plane that allows us to store a text file or a bitmap sequence with a color scheme
for some fluid properties, like a planar graph.

• Objects: The animation, geometry, and deformation of an object can be stored


on a scene basis or on a single object basis. We can also obtain the wet-dry maps
sequence generated by particles collision as an output. When an object is being
saved, an orange square will appear at both sides of the timebar.
Meshes: RF4 allows us to save polygonal meshes in multiple formats. When an ob-
ject is being saved, a purple square will appear at both sides of the timebar.

• Log: Log is a text file that tells us about scene messages and simulation times.
It’s perfect for tracking any problem that may have occurred.

• Preview: Preview stores an image sequence, a screen grab from the selected
view. It’s useful for making previsualization videos. When a preview is being saved,
a green square will appear at both sides of the timebar.

Another useful function is the ability to change simulation file names. Double click slowly
on the Name/Prefix field and simply type the new name. Or set a prefix to store different
versions of the simulation within the same project with the File Name options... button.
Tip: if you set $(SCENENAME) as a prefix, RF4 will automatically set the scene name as a
prefix for the simulated files.
Note that you can also change the padding among various other options, to adjust file-
names to the studio requirements.

File name options


03
Tutorials
03.1.08 Simulation
On the lower bar, we have some playback controls together with two buttons that read
Simulate and Reset. Click on Simulate to start the simulation (A key), and click on it again
to pause the simulation (A key again). When paused, the simulation can be continued
from a middle frame or from the last simulated frame.
When a simulation is stored you can either go back to frame 0 to start the simulation
again, or hit Reset (Ctrl + A). What should you do? It’s up to you, but Reset will take some
time depending on the scene (like spring creation on softbodies).

Use the playback controls to see the simulation any time you want. It is automatically
recorded, as you will see by the orange color of the time-line.

Simulation is done on a frame per frame basis; the point is that each individual frame is
subdivided internally for calculation. These divisions are called sub-steps. The time that a
sub step takes to calculate is called Time step.
Time step is by far one of the most important concepts in RF4.

Next to the Simulate button you will find a little arrow that displays some of the simulation
options per scene. No matter what the default simulation parameters (preferences) are,
if we set a different value here, it will remain with the scene.
We can tick on Fluid Dynamics or Objects Dynamics to simulate the scene per passes.
It is very useful if we do not need a coupled interaction between particles and objects
dynamics.
There are some options as well:

Simulation options of the 1. General: where we can state the FPS rate of
scene the current scene.
2. Integration: Where we can setup the time
step type for the simulation. Adaptive time step
will automatically set the number of sub-steps
needed according to the simulation state, and
Fixed state will let us choose a fixed number for
every frame.
3. Rigid Body solver: When stacking is un-
checked, collisions are solved by the Pairs
Solver, when checked, they are solved by the
Propagation Solver. With this option we can
graduate the speed/quality solver, the higher
the quality, the lower process speed.

03.1.09 Optimization
Optimization of simulation times is one of the most important steps when creating a scene
with RF4, as it can allow us to save a lot of time.
There are several ways of optimize a scene, and it will depend on the kind of scene you
are dealing with. Here we will show you some basics.
The first thing you can do is to reduce the polygon count when using objects in RF4,
typically any proxy objects that are built especially for the simulation. They have fewer
polygons than the final version of the object.
Also, by increasing the collision distance between particles and objects you can gain some
speed, you might want to consider creating offset models.
Another useful way to reduce computation time is to reduce the number of particles, but
this is not always possible.
Reducing pressures can allow us to lower the number of sub-steps, and this can speed up
the simulation too.
03
Tutorials
Do not let the particles get lost and fly away from your simulation either, if they’re not
on the camera shoot, because that would increase simulation time; instead try using de-
struction daemons such as ~Volume or ~Isolation.
If working with dynamics, try to keep the objects’ size similar to the grid square. Use
Global scale if necessary.

However, one of the most useful controls for speeding up simulations is the time step.
Low time steps (high sub-steps value) will lead to slower simulation times. On the other
hand, high time steps (low sub-steps value) will force RF4 to work faster, but with a cer-
tain risk of instability.
It is recommendable to set the Adaptive option to default. More accuracy is achieved by
increasing the MIN sub-steps, and more speed is achieved by decreasing the MAX sub-
steps. Alternatively, the simulator can be forced to use a Fixed step. In this case, try to
set the minimum value of sub-steps that keep the simulation stable. Remember that the
more the sub-steps, the more accurate the simulation will be, but it will take more time.

Similar controls apply to Rigid Body options that are exclusive of the RBD solver. Typi-
cally, to gain speed on these Rigid Bodies simulations, we will use a Fixed Time Step and
Stacking solver if needed. In this last case, we should try to adjust the Stacking Quality to
the minimum number that ensures the simulation quality. Remember that the lower the
number, the faster the simulation.

If you face a “double coupled” simulation where particles and rigid body interact, the best
option for optimization is set the Time Step to Adaptive rather than Fixed (although it is
not as fast) to avoid particle penetration. To gain speed in these cases, you can try lower-
ing the Max substeps and raising the Min substeps.

03.1.10 Messages
RF4 will give us messages to let us know how is everything going.
At the lower part of the screen a Message bar can always be seen, and it’s useful to keep
an eye on it as it can give us alerts and hints. It will turn red sometimes to get your at-
tention. You can also click on it to see previous messages. When doing this, the Messages
window will appear. This window can be located in any container, and it is useful because
it shows times and messages given by RF4.

When scripting, this window will also give us errors that might have occurred. So it is
highly important to check it when scripting in RF4.

03.1.11 Batch script


This window can be located in any container, and will allow the user to type a script and
execute it whenever he or she wants by hitting Ctrl + Enter keys sequence.
The idea is that the user can run scripts that would otherwise be tedious work.
The Batch Script is executed in the context of the current scene when running the RF GUI
version, and the use of the batch script is not restricted to the current scene but to the
whole RF session.
The Batch script can also be called from the command line with the “-script” command.
03
Tutorials

03.1.12 Event script


This window can be located in any container, and will allow the user to type a script and
execute it whenever he or she wants by hitting Ctrl + Enter keys sequence.
You can write a code that is executed in response to simulation events. These type of
functions that you can fill-in in response to those events are commonly known as callback
functions.

03.1.13 Preferences
It is always good practice to configure these settings to your needs so that you do not
have to change them in every new scene. However, some of these options can be changed
“on the fly” while we are working, and that will be kept within that particular scene.
Go to File>Preferences. A pop up window with several tabs will appear. Let’s have a look
at the more interesting options. Do not forget to check the help section of the program
to find out more.

Preferences

General Tab
Under Scenes Folder we can change the default location path. This is where all your
projects will be stored. Make sure that you point to a place with enough space to store
simulation data.

If you want to recover the path RF4 gave you, just press Default button.
03
Tutorials

Axis setup is quite an important option, and must be changed prior to the simulation. It
will change the orientation of the axis and other internal settings for you to work con-
sistently with your chosen 3D application. The environment and the target 3D platform
that will load the simulation data must match. Otherwise the data could be incorrectly
imported into the 3D platform.

File Cache is the maximum amount of memory in megabytes that will be used to read
cached bin files.
Default Scale is also an important parameter. It can be varied per scene though, as it has
a field in the upper toolbar in the main interface. This global scale defines the working size
inside RF4 and it’s typically set to 0.1 when working with Cinema4D or 3DSMax.
It is nor related to scaling objects, but to workspace. When importing objects from some
platforms, the user may find the objects very large in comparison to the grid size, and this
generally speaking not convenient (although we can make use of it at an advanced level),
and we can use scene scale to fix it.

Max frames is the default number of frames that will be simulated. Again, this is a default
parameter for new scenes. To change the current scene length, it can be done directly
from the interface (second number on the right side of the timeline).
Font allows the user to change the font that is used in the program. It can come in handy
when working in a platform other than Windows. By default is set to Tahoma normal size
8.

Simulation Tab

Preferences general tab

The FPS (Frames per second) rate can be set by the user. This means that we will be able
03
Tutorials
Preferences general tab to produce different effects, like simulating at slow motion.
Num Threads is automatically detected by the program, but you can change it if you need
to.
Compress param is a reducer for the vertical forces in the calculation of particles,
and determines the compression level of the fluids. It could help us to avoid vibration or
bouncing effects, because a high value means that the fluids are less elastic.
Time Step- we have already talked about the time step in Simulation and optimization
above. This option will allow you to change the default parameters for new scenes, but
remember that you can change it within each scene using the simulation button in the
main interface.

Stacking: When it’s unchecked, collisions are solved by the Pairs Solver, when it
is checked, they are solved by the Propagation Solver. When solving collisions by pairs,
the transmission of momentum between objects in contact is random, on the other hand
when the Propagation Solver is activated, the collisions are solved such in a way as to
ensure a transmission of momentum more akin to reality, and in this respect the simula-
tion has more quality. You can use the propagation solver in any situation, but the effect
is more noticeable in scenes with stacking objects.

Stacking Quality: As the Propagation Solver produces a higher quality outcome


than the Pairs Solver, it is slower, because the collision pairs must be ordered. Several
pairs could be solved at the same time however- this is a chain collision. With this op-
tion we can graduate the speed/quality solver, the higher the quality, the lower process
speed.

Display Tab

Display Tab
03
Tutorials
You can change the colors and the grid size if you want.
Click on Display info if not checked, as it will give us some information about the scene
directly on the selected viewport.
And remember that you can go to the technical manual that comes along with the pro-
gram to find out more about a specific parameter.

Backup Tab

Backup Tab

Backup tab is very interesting. It is strongly recommended to make backups of your proj-
ects and files. But we are sure you already knew this, as you are working with comput-
ers!
Set Auto Backup to on, and choose the type of save that you want to do. It will depend
on the type of project you are working on, but a general setting could be to autobackup
every 50 Frames, keeping just three files (Number of files = 3) on disk.

Notify Tab
Why not to receive an email when the simulation has finished? You can ask for an email
after every specified number of frames (Frame step).
03
Tutorials
Notify Tab

Script Tab
Choose a default path for storing and loading the scripts you want to use or create.
Also change the font.
Font allows the user to change the font that is used in the scripting windows.
Tabs customizes the tabulation size, and Syntax Color customizes the visual clues for
scripting (String, Keyword and Comment).

Export Tab
Exporting options have been discussed previously in the Exporting section above. Here
you can set some of these options by default.

Export Tab
03
Tutorials
Layout Tab

Layout Tab

Set the Layouts folder and Default layout of your choice.

Undo Tab
Undo Tab
Depending on your comput-
er’s memory, you can enable
and disable the Undo option
and set a number of actions
to be undone.
03
Tutorials Getting started: Geysser

03.2. Objectives
Getitng started:
In this first project we are going to create a scene of a jet of fluid that models a geyser,
A geyser which is the starting point for a number of common fluid effects like rocket engine ex-
haust, or a fountain.
It is a simple scene to set up and it involves particles, daemons, dynamics and basic
workflow. It will also allow you to experiment with the fluid motion, so you can go on and
produce more exotic or fun effects.

The aim of this exercise is to become comfortable with the software in terms of work-
ing, and to learn the basics of the program (interface, exporting simulation, animation,
etc…).
As this exercise follows the correct use of the program, it will be very useful for those of
you who are new to the program, as well as those that come from previous versions of
RF.

The work is focused on fluid features and controls, and also includes other areas of RF4
like the wet maps, use of objects, and interface or the simulation preferences.

The scene consists of a geyser that shoots particles upwards, it has a basal spray, and
the floor gets wet from the effect of the geyser. Check in the exercise folder of the guide.
You will find a video of the resulting simulation, together with the files needed for the
tutorial.
03
Tutorials Getting started: Geysser

Initial setup and user interface

To begin with, create a new project named “geyser” or similar.


For the moment we will use the Default layout, so that you can follow the exercise smooth-
ly.
Now, let’s set the preferences prior to adding items to the scene. You can find out more
about this on RF concepts section on page 37.
The Axis setup is very important, choose the platform you will be working in to avoid any
kind of unwanted rotation of the scene.
In addition, set the correct Global scale, typically set to 0.1 when working with Cinema4D
or 3DSMax and 1.0 for all other platforms.
To find out more about working scale go to the concepts section on page 21.

Note: if you decide to use the floor object that comes along with the exercise, set the
scale to be 1.0, even if you are working with 3DSMax or Cinema4D (you can scale it back
up to your platform).

Set Auto Backup so that it is on, and choose the type of saving you want to do. For the
moment choose every 50 Frames and let’s keep just three files on disk (Number of files
= 3).

Finally, set the numbers on the right of the timeline at 250. The first number indicates the
number of frames that are going to be shown when you hit play, and second number is
how long the simulation is going to be.

Main Emitter
Now, as we want to have a kind of water fountain, we need an emitter in the scene.
So, RMB menu and click on Add> Emitters> Circle.

The emitter must shoot upward, as with the natural direction of geysers. Now click on
the emitter to select it (or select it from the Nodes list) and use either the Node Params>
Node> Rotation or the rotate tool (E key – rotate icon) to rotate it by 180º.
The Node sub-panel might not be expanded, so expand it by clicking on the Node sub-
panel’s title area in light grey.
Remember you can undo any unwanted movement with the Ctrl +Z hotkey or Edit> Undo
tool.
03
Tutorials Getting started: Geysser

Different ways to rotate


an element.

As we will be adding more emitters later on, it is convenient to rename the items to have a
clear structure in the scene. So select the emitter and from the Nodes panel click on RMB
to select Rename. Change its name to “Water”.

Now that we have an element in the scene, let’s simulate, so hit Simulate or A key. Let
the simulation run for 20 frames or so, enough time to realize the particles are not fall-
ing down to the floor like a geyser would do. It does not look very realistic or impressive
yet!.

Particles do not fall down


03
Tutorials Getting started: Geysser

Exporting the simulation


Use the playback controls to see the simulation as many times as you want. It is auto-
matically recorded, as you can see from the orange color on the time-line.
In fact, if you go to Export> Export Central (F10) you will see the exporting panel itself
with the emitter option checked. Take a look at the type of files, by default we are saving
a sequence of .bin particles that are actually the kind of format that RF4 can read from
the cache.

You can play the simulation at any time with the preview export option activated (no need
to simulate); and RF4 will save a sequence of bitmaps so that you can make a clip just to
playback the simulation. Its very useful for looking at your simulations with the correct
FPS rate.
However, this is usually done after the simulation so disable it if it is not already so.

TIP: It is easy to create a video file from a bitmaps sequence with any edition program,
and there are also some programs that let you play bitmap sequences at a set FPS rate.

Daemons
Now we need to add some forces to interact with the particles. So again, right click on any
view to display the RMB menu Add> Daemons> Gravity.
We usually change daemons position, making them easier to select. Be careful with the
direction of the arrow because this will be the direction of the gravity force!

Now, if you go back to the first frame and click Simulate (A key); you will see that the
particles go up and then fall down again quite quickly.

Particles falling
03
Tutorials Getting started: Geysser

Interaction
The Daemon is changing the motion of the particles due to the automated interaction in
the Global Links window. Check the image below.

Global links

Objects
Now we have the emitter and the gravity force (that still to needs be adjusted of course),
but let’s add another important element: an object to represent the floor.

Prior to bringing it into RF4, we have to model it in our 3d application, and export it as an
.sd file. As we will be wetting it with the geyser water, we need its UV coordinates as well,
so remember to add a bitmap (sample.jpg from the exercise folder) to the object prior to
exporting it. This bitmap won’t have any effect on the final render, so don’t worry about
its poor quality.
The object must have a central hole of 1 m in diameter, and it must be an uneven surface.
Remember it is useful to make a proxy object (a simplified version) of your objects with
the least amount of polygons possible for faster simulations.
For better organization, we recommend keeping your objects and resources within the
project, so put your .sd file in the “objects” folder and the bitmap under “images”. These
are the folders that RF4 will look into when failing to find an external file.

There are some requisites that the geometry has to fulfill, for example that only triangles
are used. For more information on exporting scenes go to Connectivity> RF Input> Ge-
ometry on page 106.

In order to import a scene you can either do Ctrl + I or RMB menu> Add> Objects> Im-
port. Add the floor object or select geyserfloor.sd from the exercise folder.

Note that the geyser floor has got few polygons. This is because the geyser floor is an
optimization of the real floor for rendering purposes.
03
Tutorials Getting started: Geysser

If you need to change the position/ rotation/ size of an object in an .sd file, you will have
to click on SD <-> Curve button in the Node properties to bake its location or animation
into RF curves, ready to edit.
If you are using single objects like .obj or .lwo files there will be no problem editing them
(but keep in mind that single objects cannot get UV info into RF4).

For our exercise you won’t need to do any of the above, as the floor has been modeled
taking into account the default size of a Circle emitter (diameter = 1m).
So, place the emitter so that it is over the hole on the floor.

Remember that you can reorganize your layout and right click on a view-port to to visual-
ize the scene from the camera’s view point.

In order to visualize the scene better, use the shortcuts (7, 8, 9, 0) or right click on any
viewport to change the shading of objects. In this case, we have set the objects to be
smoothed and textured.
Not being able to see the sample texture on the object can indicate a bad exportation
process.
If this is the case, you should check that you have applied a texture in your platform and
that you followed the necessary steps to export UV coordinates. Check the online manual
to know more about your platform plugin.

Floor is in the scene


03
Tutorials Getting started: Geysser

Global links window: Interaction


everything’s interacting
If you now hit Simulate you will see that the particles collide with the floor automatically,
this is due to the fact that everything is interacting with the other elements You can read
about this in the global links window.

Setting object - particle interaction


Floor particle interaction
Now that we have an object in the scene,
parameters
let’s learn some more about the interac-
tions between particles and objects.
Select the object and go to Node Params>
Particle Interaction, from where we will be
managing the interaction of particles with
this particular object. Normally we would
be adjusting these parameters every time
an object is in the scene, to imitate its
surface.

As the object is supposed to be a rough


floor, probably part frozen, we are going
to change some values to get the effect
we’re after
Bounce tells us about elasticity of the
object’s surface, and this parameter goes
from 0.0 to 1.0, so let’s set a medium-low elasticity as the surface is a partly frozen ter-
rain, let’s say 0,4.
Roughness is self-explanatory and also goes from 0,0 to 1,0, Let’s set a high value like
0,6.
We do not want the water to get stuck on the floor, but to move along the surface, and
that’s why we won’t change the friction value (normal values between 0,001 – 0,01). And
of course, the surface is not sticky so, sticky parameter is set to 0.0.
03
Tutorials Getting started: Geysser

Setting basic parameters for the geyser


Now we can go back to the geyser, and start tweaking some parameters to get the result
we are looking for.
The first thing we notice is that the water spurt is not going as high as we would want. So,
select the emitter and let’s check the Circle properties.
The first two parameters relate to the emission type; you can choose to create particles
in a volume or to create particles by speed, like a faucet.

Try setting a volume of 4 and hit Simulate. This is not what we are looking for, but you can
now see the difference between Speed and Volume emission.

The more speed, the more particles per second. Obviously, if the particles are faster, they
have more velocity and gravity make them fall later, so the spurt goes higher.
Try setting a higher value, let’s say 5.

Our simulation is getting there now, but it still lacks a bit of realism. Let’s animate the
emission; the water spurt will rise up slowly and then suddenly will stop, letting the re-
maining water to fall down to the ground.

For the moment, let’s open the curve editor by double clicking on the title bar. Double click
on the Speed parameter of the Water emitter to open curve. The curve will be automati-
cally displayed on the main window of the curve editor.

By setting key frames (double click on the graph), try to reproduce the curve on the im-
age. If you have doubts about how to manage the Curve Editor, go to the RF concepts
chapter on page 30.

TIP: Change the curve color by right clicking on its name and choosing Change color.

Water speed curve


03
Tutorials Getting started: Geysser

Optimization

If you try and hit Simulate, you will notice the simulation is quite slow. Depending on your
computer, this could be taking ages. This is quite normal, as we haven’t performed any
optimization process yet.

It is now necessary to start optimizing, so right click in a view and Add> Daemons> ~Vol-
ume. These kind of daemons are called destroyers and only work with particles. They are
really useful to get rid of the particles that are no longer needed, and that are wasting
precious computation time. As you can imagine, you will be using destroyer daemons a
lot.

More specifically, ~Volume daemon will kill particles outside its volume, defined by a re-
sizable box. Click on its properties (Node Params) and press Fit to scene, or Fit to object,
and the volume will automatically resize to encompass the whole scene/ object, however
in this case we will have to make use of the move/ rotate/ scale tools (W, E, R respec-
tively) to adjust the volume to the correct height.

We have a lot of particles in the


scene, and that may also slow the
simulations down. If we needed a
high motion detail, it would be nec-
essary to put the emitter resolution
at 1.0 or even higher, but not in this
case.
So, go to Node Params > Particles
and change the resolution to 0,5 to
have less particles. Note that when
lowering the resolution we are set-
ting a higher mass for the particles
(check it in Node Params > Statis-
tics).
Resolution is an important concept
so, remember: “resolution not only
changes the number of particles
but also their mass!”

Another parameter that comes in


now is Max particles, also in Node
Params> Particles. This is the max-
imum number of particles that this
emitter can generate, and it is used
for controlling either the number of
particles or the emission.

To obtain more speed when simu-


lating, disable the view (Alt+D).

Go to simulation options (arrow next


to the simulate button) and change
the Max. steps gradually. Try lowering the values bit by bit, and set the lowest value that
will keeps the simulation stable. You will soon realize if the value is too low, because the
simulation will get suddenly stuck. Let’s try with Max 100 substeps, and if the simulation
is stable, try to lower this to the minimum possible stable value. But bear in mind that we
will be adding more elements to the scene, and it might get necessary to change it again
later on, to make the simulation stable with the new elements and collisions.
03
Tutorials Getting started: Geysser

Setting the external pressure (Node Params> Particles) to 0.0 can help us reduce the max.
steps a bit more. The external pressure is an overall force that affects all of the particles
in the fluid. It will tend to keep the fluid compact, avoiding the tendency to expand.

Another thing we can do to accelerate the calculation is to set a bigger collision distance
from the object, this is possible because our object is a plane, and we can move it down to
be able to get the same effect with a higher collision distance. In other exercises we might
want to model an offset version of the original model just to use it in the simulation.
So, move the object down by 0,1 and add 0,1 to the collision distance on the Object>
Node Params> Particle Interaction.

Hint: Remember that the object is coming from an .sd file and it might be necessary to hit
SD<-> Curve button on the object’s Node properties to be able to change its location.

If we want to know if the optimization process is producing results, it’s is very easy, just
keep an eye on the numbers at the bottom of the selected view; the first one tells you
time code (TC) and the second one is the overall simulation time (ST).

Test and Tweak

Ok, let’s continue. Very soon in the simulation, around frame 50, you can see that the
emission is too regular to look convincing RF particle emission is always discontinuous so
some randomness is therefore often needed. Go to Node Params> Circle and set some V
and H random, set at 10% of the maximum speed to start visualizing the random effect;
we finally we have to go to 4,0 and 3,0 respectively, for a good, wild spurt.

Two other important parameters that can change the look of the fluid are the viscosity and
surface tension (Node Params> Particles).
Try a few runs at different viscosities, say between 0.1 and 10. Higher values give a bet-
ter development of the cap, as you might expect from the effect of viscosity, making the
03
Tutorials Getting started: Geysser

particles more “sticky”. Be careful because this “Sticky” behavior will result in RF4 having
a hard time jamming out the particles from the emitter.
The stickiness of the particles allow clouds to stick together, just like real fluids, and also
generates particle-to-particle friction as they attempt to slide past each other. This sliding
friction between particles is a good way to imagine fluid viscosity.
By setting a high surface tension, the geyser will look more like a coherent fluid, trying to
form thin films and blobs of fluid.

We have settled on a value of 4,0 in viscosity and 25,0 in surface tension because we
wanted a nice cap, and to have it look more like a coherent fluid. If you wanted something
more water or vapor-like, then use a lower viscosity. Also adjust the maximum speed in
the Curve Editor to get good motion if necessary.

Geyservis_1.mov (Viscosity 1)
Geyservis_4.mov (Viscosity 4)
Geyservis_10.mov (Viscosity 10)

Remember you can store different versions of your simulation with the File Name Options
in the Export menu.

File name options

Secondary emitter

Ok, let’s carry on. We now add a second emitter. What for? We want to give more realism
to the motion of the water. So, clone the current emitter by Edit> Clone selected, but read
on before you hit Simulate.

Now we have two fluids interacting with each other. As they will interact with each other,
we have to be careful with the placement of these two emitters. We must avoid ugly in-
teractions with the new emitter particles as they are created. Wherever there is disconti-
nuity in RF4, it is where you may hit sources of instability. The creation point of particles
is one place where sudden changes are likely because particle creation is, by definition,
not continuous. One frame there is no particle, the next there is. If another emitter places
particles at the same place on creation, you get an instantaneous overlap that produces
huge forces between the particles and launches them off at hyper speeds.
You can see these instabilities in your scenes as totally chaotic motions of particles, and
you’ll also notice that RF4 will slow down enormously as it tries to track things, and it
may crash. There are ways to get through these tough patches but it’s best to avoid them
03
Tutorials Getting started: Geysser

entirely by giving emitters a bit of space.

So, scale the emitter up a bit. Let’s say 1,1 in the three axis.
Also change the type to dumb and lower the resolution to 0.2 to have fewer and heavier
particles. Set Side Emission to Yes and, finally, let’s change its name to “Spray”.
Now we have a circle emitter named Spray that only generates particles on its contour.

water parameters/ spray


parameters

On page 24 you will find more technical information about particle types. But just a quick
note to make it clear that dumb particles do not interact with themselves, and that will
change the path of liquid particles but the other way round. This means that Spray will be
affecting Water motion, but Water will not affect Spray motion.

Now set a lower speed curve; although this step may seem unnatural to you right now,
you will soon be thinking in terms of mass of particles and fluid motion, so don’t worry too
much.. You can try things on your own, again experimentation is the key

Ok, let’s think about the emission. We


have particles with different masses
that are thrown from the same point,
ones that will push the others mak-
ing the spurt less uniform. If we also
reduce a bit the speed of the heavier
particles, these ones will be “sup-
porting” the lighter ones, like a base.
As you can see, we have set some
waves on the curve too, so this base
goes up and down, to imitate a non-
constant emission.
Try this curve and any others you can think of to learn more about emission.

However, the emission is still too regular, so let’s add some random. In this case we are
going to set only vertical random (V random). So, instead of putting a single value, we are
03
Tutorials Getting started: Geysser

going to animate the parameter as seen in the picture below.

Random speed curve

Well, but... what for?


As you see if we start the emission with no random, the first particles will deliver a circled
regular shape. The results can look very interesting.

Wetting the floor

Wetmap textures Another thing we can simulate is the fact


that the floor changes when the water from
the geyser hits its surface; it becomes wet,
therefore there are some attributes that
change too, like the color and the reflection.

In order to do this, select the object and go


to Node Params> Texture and enable Wet-
DryTexture. The object will suddenly go black
but that’s normal, as there is no wet zone
calculated yet.
Aside from setting the parameters, press
Simulate to see what this black and white
mask looks like.

It looks cool, but still has to be adjusted.

Tip: You will not be able to playback this effect in RF4 as bitmaps are not stored in the
03
Tutorials Getting started: Geysser

cache.

In @resolution, set the resolution you want the output images to have. Note that a single
particle is going to leave a mark of one pixel no matter what the resolution is, so do not
set it to be too high if you want a visible mask. Let’s set it to 512; this will make the output
images 512 x 512.

Filter loops and filter strength are going to apply a Gaussian blur over the mask. If you
want a general blurred spot, set strength to high and filters to 1 or 2, but if you want
the mask to be more like little impacts, set the a lower strength and a higher number of
loops.
Do some tests and decide for yourself. We have chosen 0,5 so that the spot can expand
a little, and looks blurred.

Ageing is the parameter that controls the drying speed of the wet map. 0 means no drying
and setting higher values means the surface expends more time on drying. Let’s leave it
to 0.0.

Finally set the pixel strength by default (255) so that the spot is white colored. 0 means
the spot is black and 255 means white, and in between we have the grey scale.

Wetmap textures
03
Tutorials Getting started: Geysser

Exporting wetmaps
The wet-dry effect is going to create a sequence of black and white images to use as a
mask when shading. Once they are calculated, you can find them under images folder
inside the project.

Go to Export Central (F12) and expand all objects; check on the Wetmap texture box and
choose the .jpg format (for now) at the right of the export central.

Export central

Final simulations
Now the scene is completely tested and set, make your final simulation.

Remember that you can increase simulation speed a lot by using a RF4 simulation node
(check the manual to find out how) or by de-activating the graphic user interface (GUI)
(Alt+D).

Connectivity
Now that we have finished the simulation we need to take it back to our 3d platform.

Assuming that you have your hi-res floor matching the proxy object you have used for
the simulation, you’ll need to set it into your scene. You can use the proxy object for this
anyway.
03
Tutorials Getting started: Geysser

The goal is to put all the simulation elements together; and add more elements if you
want, like an environment for the geyser.

Import the particles from the two emitters. These particles are two sequences of bin files
located under the particles folder in the project folder.
The process will vary depending on your platform, so please check section 106.
For rendering these particles, use the specific particle shading module within your applica-
tion. If you do not know how to do it, please consult your application help.

When it comes to texturing the floor, use the wetmaps .jpg sequence as a mask for mak-
ing wet effects such as darkening of color. These wetmaps are located under the project
folder, in a folder named images.
All the platforms can use a sequence of bitmaps as a texture, if you do not know how to
do it, please consult your application help.

Problems / Help
1. The object does not show the wet map or the texture:
Make sure you have correctly exported UV information (check page 35), and make
sure you have the latest drivers of your graphic card installed. Also, check the simu-
lation folders to see if there are any wet maps stored.
2. Particles explode:
This can be due to very low substeps value or to high pressures. For the first case
raise Max. Substeps, and for the second case check that the two emitters interact-
ing are not overlapping.
3. Simulation is terribly slow:
Check that the particles are not exploding (see above). Lower the number of par-
ticles and try to optimize the scene. See page XXX.
4. The wetmap flickers:
Set the ageing higher.
5. My objects are very little in my 3d application. I’m using 3DSMax or Cinema
4D:
This is because you used an object that comes on the CD that was modeled in an-
other platform, and you did not have to change the global scale in RF. 3DSMax and
Cinema4D has a huge working scale compared to the one in RF, and that’s why we
normally set the scale to 0.1 in RF when working with this two platforms.
To fix it, just scale up the scene (in this case), or scale up the floor prior to using
it in RF.
6. I cannot rotate/scale smoothly from the view-ports, nor zoom a view:
Move the cursor mouse from top to bottom when rotating/scaling items from the
viewport or zooming view. Do not do it from side to side.
7. It seems that my emitter stops emitting particles prior to the speed curve being
0.0:
You might need to set higher Max particles. Check the Node Params> Statistics and
make sure Emitted Particles has not reached the Max particles count.
8. The program crashes:
This can be due to very low substeps.

Advanced
Try the following on your own:

- To add some smoke to the geyser.


- To set in some stones to be moved away by the water.
- To make the water to either evaporate or to filter to the ground.
03
Tutorials Getting started: Geysser

Rendering suggestions
This scene will look good with white sprite particles and a lot of motion blur rather than
blobs.
It will simulate the air in the water spurt, giving some kind of high pressure look to the
fluid.
03
Tutorials Fluids: Two glasses

03.3. Excercise objectives


Fluids:
Two glasses This exercise consists of two parts, and its final aim is to obtain a water-like liquid that
pours from one glass into another, and the receptor glass has got some particles in it
simulating some kind of dirt that will end up floating over the liquid.
Check the exercise folder to get a feel for what we are going to do.

Objectives

In this first part of the exercise we will be filling up a glass and pouring its content into
another glass. The receptor glass has some particles simulating some kind of dirt that will
be floating afterwards.

The aim of this exercise is to have a deeper look at fluids and how they interact with other
fluids and objects. We will go step by step to adopt a correct workflow in fluid simula-
tions.
This tutorial assumes you have a basic knowledge of the program in terms of selecting,
moving, rotating and doing the basic operations.

Initial setup and initial optimization

First of all, create a new project and call it Pouring (for example). Set the default layout
and choose your preferences just like we did in the previous exercise. We will be simulat-
03
Tutorials Fluids: Two glasses

ing 500 frames.

For our purpose, we will need to model two glasses and to animate them in our 3d ap-
plication in a way that makes one of the glasses pour its content into the other glass in
approximately 180 frames. You can also use the .sd file in the exercise folder.
Be aware of scales and export it as an .sd file. Although we are not going to use wet-maps
in this exercise as the vessels are to be made of glass, don’t forget to apply a texture to
the glasses in your 3d platform if you want one.
If you have no scale constraints at the time of modeling, try to model the glasses to be
same size as the RF squares grid (around 3 m height). In the event of being stuck with
a smaller or larger scale, use the global scale in RF4 to adjust your objects to the grid
size.

In the previous exercise we went through the optimization stage right before the testing
values. Now that we know a bit more about optimization, we have to start thinking about
it right from the beginning.
From what we have learned, we should model a proxy glass with less polygons (just the
interior polygons facing inwards in this case) to reduce the polygon count inside RF4.
We could model these glasses to be a bit bigger than those we are going to render in order
03
Tutorials Fluids: Two glasses

to set a higher collision distance between particles and surfaces.


And finally, we could try with a lower substep.

As you might have guessed thanks to the first exercise, optimization is not a direct pro-
cess, but a matter of test and tweak.
Sometimes we put the simulation steps so low that we have to do the simulation again
with a higher sub-step. This can be annoying so, the way to work at this stage is to test
and tweak over a part of the simulation, but not through the entire scene. Do not spend
your time running the entire simulation if you do not need to. And use the disable view
command to accelerate these tests (Alt+D key).

Optimize your scene, and try some adaptive sub-step values. We will finally set it to 80
( Simulate button> Simulation options> Max substeps) , but experiment with different
values on your own to learn more as you go along.

Ok then, import the Two Glasses.sd file (or whatever you have called it) into RF4. Hit play
and you will see your animation running.

First thing we will do is to fill up the upper glass. So, create a sphere emitter, rename it
“Main”, locate it on top of the glass, and fill it up with particles by hitting the Fill Volume
parameter. This is the same as creating particles by Volume instead of Speed emission.
Add a gravity daemon to make these particles fall.

For the “Main” particles, set the internal pressure to 5.0 in order to fill a higher volume
with the particles, and do some tests with different values too. Notice that increasing the
internal pressure also makes the fluid to have more energy and it becomes more difficult

Tests with different


values for internal
pressure

to control. A too high value in internal pressure could make the fluid explode.

Also make some tests with different values for external pressure. We will set it to 0.0 so
there are less forces to compute and the sub-steps of the simulation can be lowered, but
make some tests and check the results to see if how this parameter affects the motion of
the particles.
03
Tutorials Fluids: Two glasses

For the lower glass, add a circle emitter, name it “secondary” and restrict its Max particles
to 200, in order to have a thin film of particles at the bottom of the glass.
Also, set the density to 300, and this will make the fluid lighter than the fluid on the upper
glass. This will make it float when mixed.
Check the statistics to see how the mass has changed when you change the density. Re-
member that density = mass/ volume.

Hit Simulate.

Exactly! The upper glass is moving, and we cannot fill it up while it’s moving!!!
03
Tutorials Fluids: Two glasses

Interaction

Just a quick reminder of why the interactions are happening. It is automatically setup so
everything is in the Global Links window; this mean that both the fluids interact with each

Global links

other and the glasses. Gravity is also affecting the particles.

As this linking process is automatic in a lot of scenes, it can be easy to forget about it. Do
not do so, as it is a powerful and often necessary tool.

Locking animation

Let’s introduce another utility within RF4 - it’s the Lock animation button (to the left of
the timeline).
This useful tool will not take into account the animation of any parameter, so that when
we hit Simulate, the glass will not move, and we will therefore be able to fill up the glass
and relax the particles.

Relaxing particles

At this point we now need the upper glass to be filled up with relaxed particles. Relaxing
particles implies spending some simulation time on letting the fluid to settle down.
However, there are some things we can do to speed up this process.
We can use the k_Speed daemon to remove some energy from the particles.
This step is not compulsory but it will accelerate the relaxation.

k_Speed daemon will kill particles that come out of a specified speed range (Min Speed
and Max Speed parameters). But it has a Limit & Keep option that when set to yes will
make the daemon act like a speed limit instead of a particle destroyer.
Normally there is a way to relax particles by gradually reducing the Max Speed to 0.0. The
03
Tutorials Fluids: Two glasses

problem is that as Lock is enabled we cannot take advantage of any kind of animation.
Therefore another system of relaxing particles is needed.

You can enable and disable the k_Speed daemon at a specific point in the simulation to
remove some energy from the particles. Min Speed and Max Speed should be both set to
0. Set Limit & Keep to Yes. Animate the curve (not possible now as we have lock enabled)
or stop the simulation at some point to enable the daemon, then simulate a couple of
frames and disable it again.
You will find yourself doing this step frequently, so keep it in mind; it is a useful trick to
relax fluids and to remove the bouncing effects of particles.

Setting the initial state

Now that you have both fluids set down in the glasses, stop the simulation disable lock,
and store the current state as the initial state.

Initial state

Reset to initial state Go to the Node Params> Initial state for both
emitters and click on Make Initial State. This
action will store the current condition as the
initial state (as indicated in the messages bar).
Now set to Yes the Use Initial State param-
eter.
While using the initial state, enable Reset to
Initial State in the Reset button and Reset will go back to this state rather than to the
setup state we had at the beginning.
03
Tutorials Fluids: Two glasses

Testing

In this scene we have tried to simulate a water-like behavior, so the default parameters
were ok.
However, it’s always good to try making different fluids. You can test with the fluid param-
eters (viscosity, density, surface tension, pressure or resolution) to try to imitate another
kind of fluid. But be aware that when changing fluid properties you have to re-do the
initial state stage, so the solver doesn’t get confused with the current properties and the
initial state properties.

Another important point in the fluids scene is the interaction with the surfaces, for ex-
ample: is the glass surface polished or is it rough? Is it already wet?
The answer to these questions is directly related to the Particle Interaction Tab on the
object’s properties.

If you are testing different settings on just one of the emitters; let’s say for example you
are tweaking the density of the secondary fluid, just deactivate the main fluid so as not
to calculate its initial state every time (as it will be the same). Do this by setting Node
Params> Node> Simulation to Inactive.

As you can imagine, this phase can be time consuming, but it is the key to getting the
feel for the parameters.

Let’s first try to adjust the viscosity. As mentioned in the previous exercise, raising vis-
cosity will make the fluid move more slowly, more like honey or liquid glue. And lowering
the viscosity will make the fluid to look more chaotic and not coherent, like spray. Normal
values range from 0,1 to 10 and usual values for scenes like ours (water-like) are around
3.0 or less. Take into account that the current volume of the fluid is huge, so it will tend
to move slower that you would initially expect.

Another important parameter for the fluid feel is Density. Density controls the fluid’s
weight, together with the Resolution parameter. It is important in order to define the
reaction speed of the fluid. Lighter particles will react faster to sudden movements while
heavy fluids will not.

As in the previous exercise, Surface Tension is another key parameter for the look of the
fluid (and at high values also for the behavior). At very high values Surface Tension will
almost act like a high viscosity, stopping the fluid spread apart.

There are more parameters to explore, but let’s just start with the basics. Do some tests
to see how the above explanations take shape. You can also have a look at the previews
in the exercise folder.

Remember that you can make and store versions of your simulation with the File Name
Options on the Export menu.

Exporting the simulation

Let’s continue. Make sure everything that you need is going to be exported. Just .bin se-
quences of both emitters.
By having a look at both sides of the time-line can give us a clue as to what kind of infor-
mation is being exported, as RF4 has got an automatic setup of the export central, you
will have a blue indicator for particles and an orange one for objects. However, in this
particular case we will not need to save the motion/ location of the objects as we already
have it in our platform. So, go to Export Central (F12) and deactivate it.
03
Tutorials Fluids: Two glasses

Final simulation

The scene is completely tested and set, so do your final simulation.

Connectivity

In this scene we are going to take a look at the mesh (polygonal objects that cover the
particles). As this step is explained in the next exercise there is no connecting stage
now.
Follow the next tutorial to finish the exercise.

Problems / Help

1. Particles explode:
This can be due to very low substeps value or to high pressures. Check the
two interacting emitters, don’t superimpose them.
2. Simulation is terribly slow
Check that the particles are not exploding (see above). Lower the number of
particles and try to optimize the scene. See page 35.
3. My objects are very small in my 3D application. I’m using 3ds Max or Cin-
ema 4D.
This is because you used the object that comes on the cd that was modeled
in another platform, and you did not have to change the global scale in RF.
03
Tutorials Fluids: Two glasses

3DSMax and Cinema4D has a huge working scale compared to the one in
RF and that’s why normally we set the scale to 0.1 in RF when working with
these two platforms.
To fix it, just scale up the scene (in this case), or scale up the floor prior to
using it in RF.
4. The program crashes.
This can be due to very low substeps.
5. I would like to have more detail in the fluid motion.
In this case, make your simulation with a higher resolution for both fluids,
take into consideration that heightening the resolution will lead to a higher
number of particles, therefore a slower simulation (you might have to change
the Max particles parameter).
6. The glass will not empty or the particles jump over the glass.
In this case you will have to set the fluid properties again by doing things like
lowering the density or to raising the resolution, tweak internal and external
pressure...
7. Fluid flickers while it settles down.
This problem can be detected in early stages of simulation when making a
preview of the simulation, and show up as particle trembling when the fluid
settles down. You might not have encountered this problem before, as the
majority of shots require fluids in motion, which have no stability problems.

Fluid can flicker for many reasons, it is mainly due to extreme parameters
configuration that lead to internal numerical instabilities (like a very high
blending factor on the mesh or a very high or low resolution on particles). For
this reason it is very difficult to track and therefore, to solve.

Our tests show that ideally resolution should be kept between 1 and 10,
and changing the particles can make a difference with the global scale of
the scene. There are also some works around, like the speed daemon trick,
explained in the faq #2, or some use of scripting, but we cannot guarantee
that they function in every case, as the flickering can be caused by many
combined factors.

Advanced
- Try on your own the following:
- To add some smoke to the geyser.
- To make the particles falling get dirty when in contact with the dirt particles in the
bottom glass.
- To make the falling fluid represent different liquid types such as chocolate, water
or honey.
- To make the dirt particles distribute in a ring shape on the brim of the fluid vol-
ume.
03
Tutorials Meshes: Two glasses II

03.4. Meshing, binary loader


Meshes:
Two glasses II Objectives
In this exercise we will continue working on the previous scene. We are not going to simu-
late anything but to calculate a mesh for the particles. Note that this is a different process
and we make it after the simulation.
In RF4 separating the scenes in stages is a common way to work, so keep the following in
mind: first particles’ simulation, then meshing.
Moreover, meshing huge scenes can sometimes take more time than the simulation it-
self.
And it also has some other advantages, like being able to generate meshes in a farm, or
to generate different versions of meshes from the same particles.

So, even if we do not need the particles (we are not going to render them) it can be in-
teresting to store them just to generate different meshes afterwards. On the other hand,
if we make a simulation and only store the meshes we can get into the situation whereby
03
Tutorials Meshes: Two glasses II

we have to re-simulate and re-calculate everything.

The most important thing prior to the meshing stage is to have a fluid that behaves the
way that we want, mesh can contribute to the feel of the fluid but not to the motion it-
self.
So the correct way to work would be to have the particle simulation the way we want it
to be. If this is not the case, go back to the previous exercise and make some more tests
until you reach the desired motion for particles.

Now let’s have a look at the current scene.


We have two glasses with some fluid in, one is pouring its content into the other, making
the secondary fluid react. As this secondary fluid is less dense, it will float on top of the
main fluid.

Initial setup
We already have the initial state as our simulation is already calculated, and we have the
particles in cache and that’s all that we need regarding the particles.
So we have two options, mesh directly on our scene, or introduce an additional step at
this point (which can be handy sometimes): the use of a binary loader.
We will choose the second option. So in order to use the binary loader for meshing, let´s
create a new empty scene and call it Pouring_meshing.

Binary loader
Binary loader is a type of emitter that loads a sequence of pre-calculated particles instead
of emitting particles itself.
Let’s have a look at how it works.
First of all create a binary loader type of emitter in your Pouring meshing scene.
Go to Binary Loader properties, choose BIN sequence and point to one file of the previous
exercise’s bin particle files. Typically it will be under your project folder> Particles.
Now hit play. The particles’ motion is being shown without need to calculate it. If you go
back to the first frame and hit Simulate, the same thing occurs. RF4 does not calculate
the particles but just reads them from the disk.

As our previous exercise is formed by two emitters, we will have to do this operation once
more, so create another Binary Loader choosing the secondary emitter bin files this time
(BIN sequence).

If you now hit play you will see your entire previous simulation.

Creating the mesh


A mesh is a polygonal object that covers the cloud of particles. Our aim is to create a
sequence of meshes to import them into our 3D application and render them as we would
render any other polygonal object.

So, let’s move on.


Click the right mouse button over the view and select Add > Mesh.
This will create a mesh, as you can see in the nodes list. Right click on the mesh name
and choose Insert all fluids. You will notice that by doing this, Mesh01 has got a + symbol
at its left. Click on it to expand it and check that Binary_Loader01 and Binary_Loader02
have been automatically placed under it. This means that the mesh is going to be gener-
ated with both clouds of particles.
We are going to make the mesh from the two emitters to avoid having holes in the final
03
Tutorials Meshes: Two glasses II

mesh.

Now, as we have said before, meshing is not a simulation process and it can be done as a
post simulation process, so once you have the particles (like we have), we can generate
the mesh without the need to hit Simulate. So right click on the nodes list >Mesh01 and
choose Build .
Depending on your computer and the number of particles, it will take some time to gen-
erate the mesh, but finally it will appear covering the cloud of particles. For now, we are
only generating the mesh for one frame, it will be after adjusting the mesh parameters
that we will generate the mesh for the whole sequence, so choose a frame to start tweak-
ing the mesh.
Remember you can cancel meshing process at any time by pressing Esc key.

Adjusting Mesh parameters


Due to the nature of our scene, we need the glasses for adjusting the mesh, because oth-
erwise we wouldn’t have a clue if the mesh penetrates into the glass or not.
So, import your .sd file with the proxy object.
You could also import the final objects, it is really up to you and your needs. In this par-
ticular case we have the interior of the glasses, so it is enough with the proxy objects,
(and also faster).

Now that we have the particles, the mesh and the objects, let’s have a look at the different
display options to get a better visual understanding of the scene.
Right click on any view and choose Shading. A menu will come up with different options:
Bounding box, Wireframe, Flat and Smooth. Go through every option to see how the dis-
play changes.
Remember you can also do this by hitting keys 7, 8, 9 and 0, to change the shading of all
the elements, and hitting d repeatedly to change the shading of the selected elements.
Anyway, let’s choose the objects with the Smooth shading on. You will probably have
some trouble figuring out how the mesh looks inside the glass, so go to View menu on
the top bar, choose Scene> Wireframe Back Faces and you will get something similar to
the image below.
Re-build the mesh if necessary (right click on the Mesh01 on the nodes list and choose
Build).
03
Tutorials Meshes: Two glasses II

Now go to Mesh Node Params > Display and set a bright color and some transparency,
(0,3 for example). The reason for doing this is that we need to know if the mesh has any
holes in its interior, which we don’t want (can cause flickering at render).

Let´s move on, and make a nice, adjusted mesh.


When the mesh is selected you will notice there are some parameters, but if the emitter
inside the mesh is selected, there are others. We are going to work with both because
both are necessary for our purposes.

Meshes in RF4 are commonly built from metaballs that create a cohesion field to connect
them. The main parameters to adjust while working with these types of meshes are Ra-
dius, Blend Factor, Polygon size and Filters. The first two are closely related so it is com-
mon to tweak them at the same time.

So, move to frame 75 and build the mesh. Notice how the polygons from the mesh
are built far away from the particles
themselves, and it is easy to see
that mesh is penetrating the glass-
es too.
Select both emitters inside the
mesh and let’s lower their radius to
half. This will make the blobs small-
er, and that might make the fluid to
lose cohesion. Try to build the mesh
now.

Note that you can set different pa-


rameters for each emitter for more
flexibility.

As we said before, Blend Factor is


working in conjunction with Radius,
03
Tutorials Meshes: Two glasses II

so let’s raise its value to increase cohesion. Try different parameters and build the mesh
every time you change a value. We have decided to put it at something around 150.

The mesh is starting to take shape, but we can see that polygon size is not enough and
therefore the mesh looks faceted.
Go to the mesh parameters and change its polygon size to a smaller value. Do not set it
too small as it could take a long time to calculate, and remember that you can cancel this
process by pressing Esc key. Let’s set it to nearly half of the initial value, let’s say some-
thing around 0,04.
You can go to a frame with little sin-
gle groups of particles to check if it’s
small enough.

It still doesn’t look quite right, mainly


because the mesh is too blobby.
So, let’s go to the mesh parameters
and enable Filters Method. This op-
tion lets you add two different types
of filters to smooth and reorganize
the mesh polygons (Relaxation and
Tension respectively).
By default it adds 0,1 relaxation filter
in 64 steps. So build the mesh again
to see what it makes.

Why use a binary loader?


03
Tutorials Meshes: Two glasses II

So, if this is the same as meshing the particles directly from the previous simulated scene,
why would I want to use an extra step by making a new scene with a binary loader?

Using a binary loader can be useful when generating meshes over a network. You have a
place where the particles are stored and centralized.
You prevent the original scene being changed or corrupted by accident.
And more importantly, you can get a better mesh using more than one binary loader. Let’s
have a look at this second reason.

Adding an extra binary loader


Now it looks great, be aware that a lot of holes are often not desirable in a mesh, so you
might want to test some more settings to get a more coherent fluid.

Once more we reiterate that you will not be able to get a super detailed mesh if the particle
count is not sufficient. Ideally, you would have simulated your scene with more resolution
(more particles) obtaining fine details and motions. Or you could use the Interpolation
feature (system script on the top bar) to raise the resolution, but we do not recommend
it right now as it is a more advanced technique that could require some scripting. Check
Emitters in the manual to find out more about it.

The technique we are going to use to increase particle count without having to simulate
the whole scene again is adding an extra binary loader.
It basically involves duplicating the binary loaders using the same parameters (or not, but
that’s down to you). Use Clone tool (Ctrl + D) for duplicating the emitters and set mesh-
ing options by hand.
In the next image, we have already done that for both emitters and generated the mesh.
Check out the difference, the left image represents one binary loader per particle se-
quence, and the one on the right has got an extra binary loader used. You can clearly see
the difference on the holes on the bottom on the lower glass.
Also note that the higher the particle count, the more time needed to generate the
mesh.

You might want to do some more tweaking to adjust the mesh to the glass more tightly.
03
Tutorials Meshes: Two glasses II

Just bear in mind that the smaller the radius, the more Blend factor is needed for a co-

hesive fluid.
There are multiple combinations, look at an example.

Exporting the mesh

Once you have set the mesh to your needs, and prior to making the whole sequence, we
have to make sure that what is being exported is what we actually need. So let’s open the
Export Central and check the mesh files (.lwo if you are using LightWave and .bin if you
are using any other of the 3d supported packages).

It is not necessary to export the emitters, as the particle sequence remains the same.
So disable the emitters’ checks.
03
Tutorials Meshes: Two glasses II

Generating the whole sequence


Generating the whole sequence of meshes is done through a system script provided with
RF4 called Build Meshes. It has an icon on the upper toolbar. Just select the mesh and
press it, and it will generate the meshes for the range specified with the slider and the
simulation end number. Take a look at the image.

Remember that meshing can be done after the simulation, as we have just done. So if
you have a farm, use the RealFlow node license (non GUI) to assign meshing tasks to
other computers. Use the command -range to do so (check the online manual for more
03
Tutorials Meshes: Two glasses II

information on commands).

Preview.mov

Connectivity
Now that we have finished the meshing we need to take these objects back to our 3d
platform.

Assuming you have your hi-res glass that matches the proxy glasses you have used for
the simulation, you’ll need to set it in your scene. You can use the proxy object for this
anyway.
The goal is to put all the simulation elements together; and add more elements if you
want, like an environment, or a table.

Import the meshes (bin files or lwo files if you are in LigthWave) located under the meshes
folder in the project folder.
The process will vary depending on your platform, so please check page 106.
For rendering these meshes, use any shader you like as they are standard geometrical
objects.

Import the dirt particles and set an object on every particle (something small like a ball
will do). You can do this by instancing an object in most of the platforms, but check your
plugin and software specification to find out more.
You will see the little objects representing some kind of dirt go up to the brim of the fluid
with the turbulences.
Of course you could try to render these particles as voxels or volumetric effects, but firstly
it would be interesting to know the limitations of your render engine (refract a volumetric
effect, etc). This kind of render will take more time for sure.

Problems / Help
1. My mesh does not generate when I press the button
This can be due to the radius being too small. Try setting this parameter a
bit higher.
2. My mesh appears too blobby.
Apply some relaxation filters to make the mesh tighter and/or try to adjust
blend factor and/or a smaller radius.
3. The mesh overpasses the glass.
Try tweaking the radius and the blend factor. And use relaxation filters and
steps. You may find that making the mesh inside the glass makes the mesh
totally full of holes. In this case its better to scale the glass because it might
be due to a lack of particles in the simulation (not enough).
Also, a good rule to follow for avoiding penetration is to set the radius to be
less than the collision distance.
4. The timeline does not show up in colors when the Build mesh on play script
is being executing, so how do I know the files are being stored?
This is normal. The build meshes function is done through a script and can-
not call the timeline element from the interface. Storing files in cache is only
made during simulation and not during playback. You can easily check your
files are being saved by looking at the messages bar.

Advanced
Try on your own the following:
03
Tutorials Meshes: Two glasses II

- Make different settings for the mesh and compare how the different parameters
influence the result.
- Try to stretch the mesh based on its speed.
- Use the UVW mesh mapping to get different effects on the shading process.

Rendering suggestions
This scene can be complex to render depending on what we want to do.
We have thought of the dirt particles being little objects; and the pouring liquid a single
polygonal mesh.

This way the refraction or scattering of the pouring liquid does not have to handle with
voxels or other volumetric shaders eventually used for the dirt particles.
As long as you keep the rendering process like this, you should not have any difficulties
because all the render engines can easily
manage geometry.

The things you have to think of are more re-


lated to shadow casting of the little objects,
and their size and shape.

Also, do not forget to set motion blur for the


shot.

The mesh carries information about the two


emitters’ influences on its vertex, so if your
platform allows it, you could use this infor-
mation to set a different aspect to the main
and dirt emitter areas (like two fluids mixing
in a single mesh).

When rendering transparent fluids there are


some aspects that we should take care of,
like refraction, and reflections. Make sure
you have an environment to reflect/ refract
because otherwise the liquid will look dull
and bad. Nice bright reflections are good to enhance the fresnel effect.
Scattering is another point to take into account, especially if the shot is back lighted.
Some liquids that present this effect are milk or soap.
03
Tutorials
Dumb particles and daemons: Twister

03.5. Objectives
Dumb and
In this project we are going to create a scene with an animated tornado that advances
daemons: through space. This space can be some 3D model that we have constructed previously.
Twister
In this scene we will use emitters, daemons, dynamics and other basic functions of the
program. You will be able to experiment with the emitters and the interaction with differ-
ent forces that will affect the system of our tornado as well as different elements in the
simulation.

This project is orientated around the handling of emitter characteristics, as well as other
areas of RF4 like the particle engine. The scene consists of a rough sea in which a boat
sails while as it leaves the wake and hits against the water surface.

Initial setup and user interface


First off, we will need to create a new project called “tornado”.

Next, we will establish the number of frames that we want for our animation. We’ll put
300 in the field of the right of timeline, considering that the first field is the time range,
in frames, that the animation will run, and the second displays the duration of the anima-
tion.

Note: The number of frames may vary based on the time of animation that we need.
For this exercise we will leave the global scale to 1.

Once we’ve created the project and established the number of frames, the next step will
be to begin constructing the scene.

Emitter
It is important that first we know exactly what we want to achieve in order to decide what
is needed. A scene can be done in several different ways, but knowing what we may need
can make the job easier. In our scene we needed to create a particle system that solves
the growth of the tornado, its motion, and the way it advances through the space.

For this, let’s observe the particle systems which we have (see fig1).

Fig. 1 Fig. 1 We can see that the spline emitter suits our needs more
closely for the task of making the tornado, since with this emitter
we can control different points from the line of emission, add more
points, as well as indicating the emission direction (see fig2)
03
Tutorials
Dumb particles and daemons: Twister

Fig. 2

Fig.2 The first thing we imagine when thinking of a tornado may be its points of emis-
sion. A tornado has an emission point that begins close to the ground, and steadily grows
until its circumference increases. Therefore, we can see that the spline emitter arranges
3 control points by default. That will be sufficient to define the tornado’s starting point
and it’s width.

If we push the button we can see that the particles leave through the line, following the
direction vector (see fig3). Hit to clean the cache.

Fig. 3 Fig. 3 We must adjust the parameters so that


the particles generate the effect of the tornado.
Therefore, we select spline and we go to its pa-
rameters. In the Spline tab we mark the EDIT op-
tion that allows us to control the control points of
our spline. Once we have selected the EDIT op-
tion, we’ll mark the point from where the tornado
is going to divide and we modify the parameters
that define the control points as in figure 4.
03
Tutorials
Dumb particles and daemons: Twister

Fig. 4

Fig 4 Figure 4 show several options such as CP index, that denotes the node which we
are working. Other options include the CP radial, vortex, radius and rotation that are
forces that will affect to the emission of the particles from the control point that is indi-
cated in index.

Note: The parameters are for reference. You can modify them to obtain better results.

Once we have played with the parameters, we hit and we can see that the forces are
acting on the point that we finished modifying. Now the particles are born from the CP
index 1 turning on the spline. So, now we still have to fit both the remaining points. Select
the points in the viewport or we can directly assign CP index 2, or CP index 3 to pass the
following points and to vary its parameters (see fig5)

Fig. 5 Fig 5 Hit to clean the cache, click


again and we will be able to see
our tornado is taking shape.

The problem now is that we must


further separate the control points
so that there is more distance be-
tween them and it can more close-
ly resemble a tornado. The control
points can be moved when the
button EDIT button of the spline
parameters of pressed, but is not
advisable to do it this way. The
best way to do this is to use NULL
objects.
03
Tutorials
Dumb particles and daemons: Twister

Objects in RF4
A NULL object is simply an “assistant” who is going to allow to us to move and animate the
spline’s control points. For this, we go away to the icon and we will create a first NULL.
(see fig6)

Fig. 6

Fig. 6 We will locate this NULL in the first control point by moving it. Once we have it put it
in place of the of the first control point, we select the SPLINE and click on the parameters
of the spline EDIT button. Once we have the activated options of the control point 1, se-
lected CP_LINK and we marked the NULL object that we created which remains linked to
it. Now we can move the NULL object and the control point will move with it (see fig7).

Fig. 7

Fig. 7 The process of being able to control both points is the same as the previous one.
We will create two more NULL objects and we will locate them with their control points.
Next, we selected to the control points and the link to the NULL next to them. Well, now
we will be able to increase the distance between the NULL points that we have created.

Note: It is recommended that we increase the resolution of particles to be able to see


more on screen (see fig8)

Fig. 8

Fig. 8 Note: In the display tab we can activate the particle visualization like arrows in
the Show arrows option. This is useful to see how the particles are behaving and in which
direction they are turning.
03
Tutorials
Dumb particles and daemons: Twister

This is the result that we now obtain by hitting (see fig 9)

Fig. 9

Daemons
The problem which we may have with our tornado is that some particles escape of the
centre of emission. The easiest way to eliminate these uncontrolled particles is by creat-
ing daemon that allows us to do so. For this, we hit the icon and we click on K Volume
daemon. This daemon allows us to eliminate the particles that are not within the box that
surrounds them.
03
Tutorials
Dumb particles and daemons: Twister

If we reset the animation and we go back to we’ll see that the particles that previously
escaped are now eliminated by the K volume daemon. (see fig 10)

Fig. 10

Animating the tornado


The first thing we must consider, is that if we move the tornado, all the elements must
move with it. Therefore K volume daemon must also be linked to one of Nulls, preferably
to the one in the middle. This is because it’s the one that moves least. In order to link it,
we select it the daemon and we go to its node parameters. In the Parent option, we will
mark the middle Null as the object to link. Now when we make the animation, the daemon
moves with the tornado and it eliminates particles throughout the animation.

Now we must animate our tornado. We will animate the NULL so that our tornado moves.
Hit and we’ll find ourselves at frame 0. Select the NULLs that we have created and Add
Key to position by right clicking. Go to frame 50, move the Nulls and we Add Key to posi-
tion. Go to frame 100 and do the same, and repeat these steps until we have the complete
animation (see fig 11)
03
Tutorials
Dumb particles and daemons: Twister

Fig. 11

Note: In order to improve the animation, we will vary the Nulls’ positions of so that paths
are different and the tornado curves as it advances. This will give it s more realistic look.
Simply select the null that we want to curve, go to frame 50 and we move so as to later
add another position key. Repeat these steps for the whole animation (see fig12)

Fig. 12
03
Tutorials
Dumb particles and daemons: Twister

Exporting the simulation


We’ll use PLAY to see the simulation as many times as we want. By default, the animation
is stored, as indicated in the Time-line bar, whenever we started simulation.

In fact, if we go to the Export > Export Central menu (fig 13) we can see the options
we have checked so that they are automatically stored and be able to check them to
see which interest us or not. If we open Export Central (F12), we see that by default, in
objects, the options corresponding to the objects that we have in the scene (in format
sd, scene data), as well as ANIMATION are checked so as to include all the set of objects
and simulation made for those objects. In our case, the Nulls do not have to be saved, as
they only serve as support to animate the scene and to obtain a final result, so we can
deactivate it.

The particles of our tornado are located in the emitters and they are saved in a .bin that
can later be loaded in our 3D platform.

Final simulation
Now that the scene is created and ready we will finalize the simulation. Remember that
you can increase the speed of simulation using an RF4 simulation node or deactivating the
graphical interface (GUI) (Check manual to know how).

Connectivity
Now that we have finalized the simulation we needed to import it into our 3D program.
The process of importing of particles that make up the tornado will vary depending on the
3D platform. For details, check page 106.
03
Tutorials
Dumb particles and daemons: Twister

In order to render the scene we will use the appropriate module within the 3D application.
If you do not know how to do it, consult the help of your application. For some practical
advice, use polygons to represent particles and use a map with transparency on, much
like a clipmap in every particle. If, in addition, you apply motion blur it will look more
realistic.

Problems / Help
1. I cannot select the nodes of the spline emitter
To select the nodes of the spline emitter and to activate its parameters we
must press the EDIT option.
2. The control points do not move with the corresponding Null
Be sure that the control points are linked with the CP Link Option to each Null
that it corresponds to it.

Advanced
Try the following on your own:

- Add objects to the scene that exert or are affected by the tornado and are
dragged around.
03
Tutorials
Rigid bodies dynamics: Demolition of a bridge

03.6. Objectives
Rigid bodies
In this new exercise we will focus on the dynamics engine of RF4 and the new Stacking
dynamics: Options. We are going to create a scene where we can see an industrial chimney demol-
Demolition of a ished by a ball.
bridge
In this scene we will not be working with particles but with objects, and the work will be
focused on the dynamic properties of objects as well as how to manage a big scene.
Check in the guide folders, you will find a video of the result along with the necessary
objects/scenes.

Initial setup
First of all, create a new project named “IndustrialChimney” and set the preferences to
your needs.

Remember that if you are using Cinema4D or 3DSMax, you might want to change the
scale to 0,1 if you are using your own models, and if you use the models we provide for
you in the CD, then set the global scale to 1.0. Once the project is finished, scale up the
scene in your 3d application.

Set the timeline to 200 for this scene.

Prior to bringing the objects into RF4, we have to model them in our 3d application and
export them as an .sd file. This is because there are a lot of objects, and so it is not worth
going one by one as with single files like .obj.
Basically the scene consists of an industrial chimney made of circular bricks. The chimney
can be made with 8 bricks per layer, and 25 layers. That makes 200 pieces in total, which
is not many, but enough to start with. (See the figures to understand the structure).
03
Tutorials
Rigid bodies dynamics: Demolition of a bridge

You could also use the IndustrialChimney.sd file provided on the exercise folder.

So, import the scene into your project.


The first thing to do is to arrange the scene- when importing scene
data file (.sd), all objects are imported as a list. To improve the man-
agement and to adjust the values of the objects, we will group to-
gether set of objects with similar properties (fig. 5). This is useful
because in this way we only need adjust the group node, and all its
values will be automatically transferred down to the hierarchy.

Now we are going to tweak the dynamic properties of the grouped


objects. When importing to RF, a value for the mass of the objects is
assigned automatically, this is calculated internally by default.
Select the group and set Node>Dynamics to Rigid Body. You can
change de colour of alternate layers of bricks for better observation
of the simulation (fig. 6). Set Rigid body>Primitives to Convex hull
and activate Dyn motion.

Add a gravity daemon to the scene and simulate. As you can see, the simulation is too
slow, so the first thing we are going to do is disconnect the cache for simulations. Go to
Export Central (F12) and press “Export None” and “Done”. Now simulate again, this time
the simulation is a little bit faster. This is because RF is not writing the cache data files for
deform and particle animations. Let’s add a floor to the scene, for instance a “Plane”. Set
to “Rigid body” and “Plane” primitive, and set “Dyn motion” to NO, so that the floor will
be not affected by the gravity and the dynamics in the simulation. Simulate some frames,
but not all.

Yes, it’s crumbling without doing anything! Depending on your


modelling, it’s possible that some pieces are intersecting with
the floor plane (Fig. 8) So,
select only them, and deactivate from the simulation, setting
Dyn motion to No. Now these pieces are static, but still contrib-
ute to the simulation.

In the simulation you can see that the stability is very poor, and
03
Tutorials
Rigid bodies dynamics: Demolition of a bridge

as a result, many objects are interpenetrating them-


selves, and making undesired movements that are un-
provoked by any event, and the chimney is collapsing
all by itself.

These kind of simulations are called Stacking simula-


tions- where a large number of objects are piled up, or
when a huge number of objects are present, hundreds
or thousands. These simulations may have been impos-
sible to calculate in the past in many cases, but with the
new RF Solver, it is be possible.

Optimization
03
Tutorials
Rigid bodies dynamics: Demolition of a bridge

Go to Simulate>Options… by default the Rigid Body Solver is not activated. Activate


Stacking. By default Stacking Quality is 10, so reduce it to 1. Integration is set to Adap-
tive, so now set to Fixed and the leave the FIXED substep how it is. Then simulate. Now
it’s taking less to calculate, and collapse itself. This causes the simulation to be less accu-
rate, because of lower integration numbers, and so the solver can’t achieve stability. So,
by increasing these numbers we will increase the quality of the simulation, and of course,
the time it takes to process.
But we don’t want RF to simulate nothing, so let’s add an event, for example a ball crash-
ing against the base of the chimney.

Add a sphere to the scene; adjust its scale and position (Fig. 10) set as rigid body, Primi-
tive Sphere, and Dyn motion to Yes.
Now we need a force to throw the ball against the chimney, so in this case it will be -10
in the Z axis.

Now, Simulate!!!

Test and tweak


We can see some interpenetration between objects- you try increasing these values until
you get good results. This is the workflow to obtain simulations in a short time with ac-
ceptable results. Sometimes we’ll need more accurate results than others, so the higher
the FIXED substeps and Stacking Quality, the higher
quality simulation you get. See the comparative below and click on the movies examples
included.

Exporting
Before to process the final simulation you have to prepare it for exporting it to the 3D
platform you are using. So, open Export Central, and in the objects list we can see two
options for exporting. One is exporting all the objects in one animation file ANIMATION
(.sd). or a sd file for each object. Keeping in mind that we have 200 objects, the best op-
tion is to export the howl scene animation in one sd file and check it. You have the option
for exporting camera animations from RF. Remember to check it if you have a camera
animation. Now you only have to simulate the scene. You can import the sd file into your
3D platform.
03
Tutorials
Rigid bodies dynamics: Demolition of a bridge

Problems / Help
1. I find false collides.
The biggest problem you can find in this kind of simulations are false collides,
this is objects that penetrate others, you can avoid them rise the value of
integration time.
2. My objects are very small in my 3D application. I’m using 3ds Max or Cin-
ema 4D.
This is because you used the object that comes on the cd that was modeled
in another platform, and you did not have to change the global scale in RF.
3DSMax and Cinema4D has a huge working scale compared to the one in
RF and that’s why normally we set the scale to 0.1 in RF when working with
these two platforms.
To fix it, just scale up the scene (in this case), or scale up the floor prior to
using it in RF.

Advanced
Try on your own the following:

- Try to demolish with a fluid.


- Make the pieces more elastic to provoke exaggerated bounciness in the floor.
- Add some particles to simulate debris.

Rendering
This scene can be modelled, textured and lighted previously, therefore this simulation
could be used as a proxy simulation for your high-res scene. In the other hand you can
use these objects as proxies to remodel and texture later in your 3d applet.
03
Tutorials RealWave: Sailing boat

03.7. Objectives
RealWave:
In this project we are going to create a scene of a boat sailing through the sea on a swell,
Sailing boat leaving a wake as it travels, and with water splashing against the side of the boat.

In this scene we will be able to practice the set-up, which will include the use of RealWave,
daemons, dynamics, amongst other basics of the program. You will be able to experi-
ment with RealWave and its interaction with objects as well as the other elements of the
simulation.

This project is oriented towards the handling of, and the characteristics of RealWave, as
well as other areas of RF4 like the dynamics engine, and the interaction of RealWave ele-
ments with the objects in the simulation.

The scene consists of a boat sailing on a rough sea, leaving a wake and causing the water
to splash against its side.

Initial setup and user interface


The first thing we will need to do is to create a new project called “boat”. The next thing
will be to establish the number of frames that we want for our animation. For that, we
need to put 300 into the field on the right hand side of timeline, (the first field is the time
range in the number frames that the animation will run for, and the second is how long
the animation is actually going to last).

Note: We will be able to vary the number of frames according to the time of animation
that we need.

Note: One field that you particularly need to think about establishing in the preferences
is the setup of the 3D platform axes that we have used to model our object, in this case
“boat”. We will have to establish this in order to avoid any kind of unwanted rotation or
displacement in the scene.

Note: When we import an object, we establish the global scale of the scene, normally 0,1
if we are using Cinema4D or 3DSMAX, and 1 for all other platforms.

For this exercise we will leave it at 1, since the scale we will previously have used in our
3D platform to model the boat, is factor 0,01.
Note: It is advisable that, once the model has been created, you create another similar
model of lower resolution (in order to avoid lengthy calculation times). In addition, you
should click on reset x form in order to avoid rotations and displacements when exporting
the elements into RF4. (to see fig1)

Fig. 1 Fig. 1
Once the project is created, the next
thing to do will be to bring our boat from
the 3D platform in which we made it,
and export it into any format accepted
by RF4. From menu file \ import object
we select the exported file (see fig2).
03
Tutorials RealWave: Sailing boat

Fig. 2

Fig. 2 The imported object “boat” is now in the RF4 scene, ready to be manipulated.

Note: In order to apply transformations to the objects that we have imported, we will
need to select them, and in node parameters we click on . Now we will be able to move,
turn and scale the objects.

The first thing we have to do is look at what the simulation is going to comprise of. In
our case, the boat will be the thing that interacts with the water, whereas the SAIL and
the WOOD of the mast should follow the movement of the boat. We will have to link both
these objects to the boat, by selecting the WOOD of the mast, and the SAIL, and in their
node parameters click Parent to, and select the object BOAT (to see fig3).

Fig. 3 Fig. 3 If we selected either one of


the two elements WOOD or SAIL,
we can see that in their node pa-
rameters in Parent to, both are
linked to the object BOAT, which if
we now move the object BOAT, will
move all the elements together.
03
Tutorials RealWave: Sailing boat

Fig. 4 Objects in RF4


Once we have loaded our object BOAT into RF4, we also need to include the other parts
of the simulation that we are going create in RF4 itself, like the water. For this, we go to
the icon “to add Real wave to the scene” . Once we click on the icon, the Real Wave object
will appear in the scene (fig 4).

Fig. 4 In Nodes tab we need change the name RealWave object, so we right click on the
name “RealWave”, click Rename and we are going to call it “SEA”. (fig 5)

Fig. 5 Fig. 5 Note: We can click on the name of the object once to se-
lect it, and again to change the name, and you can also do it by
hitting the right button of the mouse and selecting the Rename
option.

Next we are going to create the waves for the sea. We right click
on the object “SEA”, and we select Add wave \ Fractal. (fig6)
03
Tutorials RealWave: Sailing boat

Fig. 6

Fig.6 In order to see the result of our sea, we go to simulate . We can adjust the param-
eters of the swell as you can see in fig 6. Once the parameters are adjusted and the sea
is created, we click Reset to clean the cache .

The next thing to do will be to scale our sea, since we are going to make the boat travel
through it. We select the scale tool, and we scale the RealWave object that we have called
“SEA”.
Note: Click on again to see how it adjusts to the size of the fractal parameters of the
swell.

Once we have done this, we can select and move the object BOAT a little over the sea.
In its parameters we set it as a Rigid Body, so that it interacts with the sea (by clicking
Dynamics and choosing the option Rigid Body). In the parameters of Rigid Body, we also
set the Dyn motion option to yes. This will allow the Boat to be affected by forces that
we will later add, such as gravity. We are also going to dictate that the primitive, (that
is going to calculate the collision shock) will be the boat’s own mesh, mark Mesh in the
primitive option. (see fig 7).

Fig. 7
03
Tutorials RealWave: Sailing boat

Daemons
If we were to click simulate now, the boat wouldn’t fall onto the water. This is because
we need to apply a force that makes it fall and interact with the sea, and so to do this, we
introduce a gravity daemon .

Now click simulate to create the simulation.


It is possible that when we simulate, our boat sinks. This is simply because it weights too
much. In order to be able to control this, we will have to select the object BOAT, and in
its parameters of Rigid Body, we see (in this case) “@mass = 245,06” . It has to be less
than the shown value (see fig 7).

Note: In order to find out among which values you can vary the mass of an object so that
it doesn’t sink, we can select the object, go to the menu tools, and select the last option
Measure utility. It will appear as a window in which it tells us, amongst other things, the
volume of the object. The right mass value for the object so that it does not sink will be
more or less half the value marked in volume.

In the case of the object BOAT we should adjust it to “@mass = 110”. Click and now we
can see that our boat remains afloat (to see fig9)

Following a route
What we are going to create now is path so that the boat sails through the water. We need
to create a constraint of “path follow” .

Once we have created the constraint, we create the animation of the route. Select Path
Follow and locate it where we want that the animation to begin. Introduce a key of the
03
Tutorials RealWave: Sailing boat

position in frame 0, by right clicking on the object of path follow and adding key. Then
we go to frame 20, we move the constraint, and we return to add a key of the position
in that frame. We repeat these steps until we have animated the entire path. If we move

Fig. 10

now to the timeline we can see the animation that we have made with path follow. (to
see fig10)

Now we select the boat and we will locate it at the beginning of the route, moving it and
orienting it in the same direction as the path.
Ok, so now we have to make the boat follow the path. In the parameters of path follow we
go to Child, and then select the object that is going to follow the path, which in our case
is the BOAT. If you click simulate now, nothing will happen. This is because we need to
specify in path follow how fast the object will travel down the path, which at the moment
is defaulted to zero in the Engine property (to see fig11)

Fig. 11 Note: We need to adjust the


value of the Engine according
to our object. Very high values
could cause the boat to sink
because of the speed that the
object acquires with respect to
the path, and very low values
could mean that the reaction
is slow.

In addition to this, we need


to activate Free height, which
will avoid our boat becoming
flooded with water. What Free
height does is to release the
vertical movement of the ob-
ject, so that it holds its posi-
03
Tutorials RealWave: Sailing boat

tion with respect to the path follow, but in addition, the fact that our boat is a rigid body
will make it collide with the water without taking into account the vertical of constraint of
the path follow.

Another option that we need to activate is Oriented. Oriented aligns the object with re-
spect to the path. We should already have aligned our boat in frame 0 with the direction
of the path (see fig11).

Click . Now we can see how our boat follows the path with more or less speed depending
on the set value of Engine.

Note: The constraints require a child to be an object which has the characteristics of that
constraint.

Creating the wake


Once we have created the movement of the boat, we need to make the wake that it leaves
as it sails across the sea.

Select the object SEA, and in its parameters we activate the option calculate texture (see
fig12)

Fig. 12

Fig. 12 When we select calculate texture, four more options will appear that allow us to
adjust the parameters of the wake. The first thing we must do after selecting calculate
texture is go to Fit texture, and fit the texture of the wake within the object SEA ,thus
indicating where it has to draw the texture. We then put a value of 1,5 in propagation.
This, depending on its value, will cause the wake to be more or less is blurred. We now
put 0,8 in the parameter Ageing. This value will dictate how long the wake will remain in
the water before disappearing. Low values will increase the time the wake remains, and
high values will make the wake dissipate more quickly. We now go to frame 0, we empty
the cache by clicking and then we click .

Now we can see our boat advancing across the sea, leaving the wake behind it (see fig
13)
03
Tutorials RealWave: Sailing boat

Fig. 13

It is important to play with the parameters of figure 12 to adapt the wake to achieve ex-
actly what we want.

Exporting the simulation


We can use play to see the simulation however many times we want. By defect, the ani-
mation is saved, as indicated by the Time-line bar whenever we clicked on simulate.

Fig. 14

In fact, if we go to the menu Export \Export central (fig 15), we can see what options we
have ticked so that they are automatically stored, and we can tick according to what in-
terests us or not. If we open export central, we see that by default in objects, the options
corresponding to the objects that we have in the scene (in format sd,scene dates) are
ticked, likewise with ANIMATION which includes the whole set of objects and the simula-
tion together.

For the RealWave object “SEA”, mark particle cache, as well as the options surface defor-
mation and foam texture.

The wake is a texture that is applied to the RealWave object, and therefore it is not stored
in the cache, but it remains saved as maps if it is indicated in the export central window
03
Tutorials RealWave: Sailing boat

(to see fig15). So that this is saved, we need to tick on the RealWave object SEA option
foam, and indicate on the panel on the right the image format in which we want it to
keep.

Fig. 15

Final simulation
Now that the scene is completely is created and established, we can make the final simu-
lation.

Remember that you can increase the speed of simulation using a node of RF4 simulation
or deactivating the graphic interface (GUI) (Check the manual to find out how).

Connectivity
Now that we have finished the simulation we need to transport it to our 3D program.

So now we have to import the scene. The complete scene can be found as ANIMATION.
sd in the objects folder of the project. This file contains all the elements of the scene that
we have ticked in Export Central.

The import process of the scene will vary depending on your 3D platform, to find out more
see section XXX. In order to render the scene, you will be using the specific module within
the 3D application. If you do not know how to do it, please consult help in your applica-
tion.

When you give texture to the sea, use the sequence foam.tga as a mask to create the
effect of the wake, using a more off-white material than the water. The foam sequence is
in the project folder, in folder images.

All platforms can use a sequence of bitmaps as a texture, but if you do not know how to
03
Tutorials RealWave: Sailing boat

do it, please consult help in your application.

Problems / Help
1. The boat does not fall onto the sea when we hit simulate:
Check that the Dynamics option of the object is on Rigid Body, and that in
the parameters of Rigid Body, Dyn Motion activated (Yes).
2. The objects “MAST” and “SAIL” do not fall with the boat:
Be sure that in the object option parent to, the objects are linked to the
boat.
3. The objects do not move.
Select the objects and click . If you linked before clicking the button, it will
be necessary to unlink them again first.
4. The boat sinks:
Check the mass of the object BOAT in Rigid Body properties, and adjust it
until the boat floats.
5. I have the boat linked to path follow and it doesn’t move:
The Engine value is 0 or very low.
6. The boat does not leave a wake:
Check that the Calculate texture option of the object SEA is activated, and
that the propagation and the time of the wake have correct values.

Advanced
Try the following.

- Add collision particles to the boat so that it hits the sea with RW_Splash.
- Make the sail move in the wind by creating a Soft Body.
03
Tutorials Soft bodies: Trampoline

03.8. Objectives
Soft bodies:
In the next exercise, we will set up a scene with Softbody and Rigidbody interactions. We
Trampoline are going simulate the dynamics of a trampoline with objects falling over.

In this scene we will be working with the dynamic properties of objects. Check in the guide
folders, you will find a video of the result along with the needed objects/scenes.

Fig. 11

Initial setup
First thing, create a new project named Trampoline and set the preferences to your
needs.

Remember that if you are using Cinema4D or 3DSMax, you might want to change the
scale to 0,1 in case you use your own models and if you use the models we provide you
in the CD, let the global scale to 1.0 and once the project is finished scale up the scene
in your 3D application.

Set the timeline to 200 for this scene.

Prior to bringing the objects into RF4, we have to model them in our 3D application and
export them as an .sd file.
Basically the scene consists on a square trampoline made of plane with enough polygon
resolution. The Trampoline can be made with 30 polygons subdivision (Fig.11).

Export in sd format with the Export Deformation deactivated. Now is not needed. Import
the object in RF and sect it, if you exported it with Export Deformation, no problem, select
sd<->Curve button in Node Params properties (Fig.12). Now the object is released for
dynamic deformations.

Now we are going to prepare


the surface behaviour, so select
the plane, and change the Dy-
namics properties to Soft body
(Fig.12). Spread out the Soft
Body sub-panel and press the
Select pins button, select the
four vertexes from the corners,
these will change the colour to
red, now these vertexes are
hooked in their initial position,
set mass to10 (Fig.13).
03
Tutorials Soft bodies: Trampoline

Add a Gravity daemon, and simulate.

You can see the plane is curved in the spring’s direction, this is quite important because
the simulation will depend on how the model was built. Try with your own different poly-
gon distribution.
Next step is adding colliding objects, for instance a sphere and a cube. Put them over the
plane so that they will fall over it. In.

Problems / Help
In simulation mode it’s possible that you observe the objects go through the
plane, this can be caused because the Collision distance is too low, tweak
until you get good results (Fig. 14). If this causes the plane to be too de-
formed, it is due to the fact that the mass value was too high, so lower them,
to achieve a soft deformation.
Activating the Rigid body solver you will improve the intersections between
the objects and the plane.
03
Tutorials Soft bodies: Trampoline

Exporting
You can export the sd animation as in the previous exercises.

Advanced
- Try to make a soft body affected by a fluid on your own.
- Try to simulate a blanket falling over a table.
04
Connectivity
This section will guide you though the workflow needed to integrate the simulations made
with RF4 and your 3D scenes.
During the tutorials in this user guide we will not focus on the steps too much as it is a
bit of a clockwork job; however it is interesting and important to check this section to find
out what you and the plugins can do. Read through the explanations and check the RF4
manual (online help) to find out more about your favorite 3D software plugins.

The main workflow will be:


3D app -> RF4 -> 3D app
Or even
RF4 -> 3D app

These steps can be made thanks to the plugins that Next Limit offer, together with the
program. The plugins are easy to use, and are available for the following platforms:
3DS Max, Maya, LightWave, XSI, Houdini and Cinema 4D.

Installing the plugins is quite easy, as it is done in the same way as any other plugin in
your 3D application, but if in any doubt, you can either consult the RF4 manual or your
3D application’s help files.

Please note that not all the plug-ins have the same functions, and that will it also depend
on the SDK (system developer kit) provided by the software company. Of course, all the
plug-ins have the basic functions needed for the correct workflow.

RF4 Input
What we call input is the data that is loaded into RF4. For example, if we want rain that
wets an animated character, we will need the character to be loaded into RF4. Remember
that RF4 is not a modeling program or a complete 3D application, and although it is pos-
sible to create geometry within RF4, it is not possible to model.

In this section you will find some specifications about file formats.

3D APP -> RF4: Exporting your objects/scene


So as we said, we can create objects in RF4, but it is not possible to model and therefore
the geometry will frequently be imported
into it.
There are several file formats that RF4 can
read, and each of them has its own speci-
fications.

As the user can see, the scene data file (sd


proprietary format) is the most powerful,
and of course is the one that we recom-
mend, but don’t forget you can also use
the single object formats as they some-
times come in handy. For example, let’s say
you want to add another object that wasn’t
previously planned to the corridor you are
flooding. Instead of re-exporting the whole
.sd, you might want to add a single object.
And remember you can load as many as
you want into RF4, without the “one .sd per
scene” restriction.
04
Connectivity
The animation and deformation is normally read by the plugin without the need to do
anything special, apart from perhaps choosing an option in the plugin interface. However,
the UV coordinates need some work prior to exporting them. It normally entails applying
a bitmap to the color texturing channel in you 3D application.
Again, check the online manual to find out all your plugin details.

Exporting objects from some of the platforms might require the user to set the RF global
scale to 0.1 or 0.01, so that the objects do not appear too large in RF4 in comparison to
the grid. This mainly applies to Cinema 4D and 3DSMax.

RF4 Output
What we call output refers to the data that is calculated within RF4 and that is loaded into
your 3D application. For example, you have to render a hose wetting the floor; you will
need the meshes and the wetmaps for rendering a believable scene in your 3D applica-
tion.

We strongly recommend that you to take a look at the Export Central section of the man-
ual and guide (page 32) as this is the main tool for specifying what part of the simulation
is going to be stored within RF4.

RF4 -> 3D APP: Exporting particles


There are several formats in which the user can export a sequence of particles; the most
common is .bin, as it’s the one that the plug-ins provided can read. But .pd format has
been added to RF4, which is very powerful and can optimize the users’ resources. To use
it however, an SDK is provided in order to write the plug-ins needed.

Bin files store more information apart from the position and velocity of the particles, like
pressure or density. You can normally make use of this at the shading stage.
Bin particles are interpreted as standard particles in the majority of platforms when talk-
ing about motion blur, so you will be able to render them in a realistic manner.

Note: Do not think of mesh .bin files as particles .bin files, although they have got the
same extension, they do not have the same information.

RF4 -> 3D APP: Exporting geometry, animation and deformation


The motion and deformation of objects can be exported from RF4 through an sd file. This
sd file can be created per object or per scene, and the motion can be any type of motion
(keyframed animation or rigid body dynamics), deformation will come as a result of soft
bodiy simulation.

In all the platforms, the plugin will match items per name, meaning that the simulation
geometry should keep the same name as the original scene. However, some of the 3D
applications will generate the geometry if it does not exist in the scene (mainly Maya and
3DS Max).

RF4 -> 3D APP: Exporting RealWave


RF4 can generate a wavy surface called RealWave, where the objects and particles can
float, create waves and interact.
There are several formats in which we can export this surface, but the most common is
04
Connectivity
an SD file.

You can create a particle layer for the RealWave and this layer will be exported as stan-
dard particles (.bin files by default).

Some plugins allow you to import this sd as a standard sd (see RF4-> 3DAPP: Exporting
geometry, animation and deformation) but some platforms have their own way of import-
ing RealWave surfaces (mainly LightWave and Cinema 4D).

RF4 -> 3D APP: Exporting uv maps


RF4 can generate black and white bitmaps using the uv coordinates imported from each
platform (see RF4 INPUT for more information on this).
The bitmaps can be generated in an objects uv coordinates because of the impact of par-
ticles, or in RealWave surfaces because of the impact of particles or objects.
Remember that the object must have UV coordinates, check your platform plugin in the
manual to know more about it. RF4 native objects already include a set of UV coordi-
nates.

Using the bitmap sequence to make texturing effects is as easy as using a single bitmap
in any of the platforms.
You can use this white/black sequence as a mask to make different effects like wetting
surfaces, corrosion of surfaces, foam, etc.

RF4 -> 3D APP: Exporting meshes


There are several formats in which the user can export a sequence of meshes; the most
common is .bin, as it is the one that provided plug-ins can read. But in RF4 the .md format
has been added, which is very powerful and can optimize the users’ resources. To use it
however, an SDK is provided in order to write the plug-ins needed.

Meshes store more information besides the geometry, that can be used for shading- like
the velocity. It also carries UV information and weights representing the contributing
emitters, though this last option is only available for some platforms (mainly Lightwave,
3DS Max and XSI). Motion blur is also available for all the platforms.

Note: Do not use particles .bin files as meshes .bin files, though they have the same ex-
tension, they do not have the same information.

RF4 -> 3D APP: Exporting cameras


One of the new features in RF4 is the ability to create cameras within the scene. The ani-
mation of these cameras can then be translated to any of the connected 3D applications.
The output is an .sd file that when translated, will bake its animation on an object.

Please refer to the “RF4 -> 3DAPP: Exporting animation and deformation from RF4” part
of the connectivity section to find out how to import an sd file into an object.

Hint:
If the 3D platform does not allow you to import the sd directly to a camera, you can bake
the animation into a null object and link the camera to it.
04
Connectivity
Other interesting output

Log file

There is another interesting output in RF4 - it is not directly related to taking the simula-
tion in your favorite 3D application, but it can come in handy when controlling simulation
times and scenes- it is the log file.
The log file is a .txt file with information about the scene editing and the simulation.
Find an example below:

>18:03:32: Max time step: 0.0333333 seconds


>18:03:32: Min time step: 0.0001001 seconds
>18:03:32: -- New scene --
>18:03:32: Workspace version: 2016
>18:03:32: Setting up scene
>18:03:32: Loading C:/RF4 betatesting/test/test.flw
>18:04:47: Reading SD file
>18:05:54: Replace SD
>18:05:54: Reading SD file
>18:05:54: Found already existing object: Box01

Color plane daemon

The color plane daemon is a tool that allows the user to visualize in a plane certain proper-
ties of the fluid. These color planes that are generated once per frame can be exported as
images (.jpg, .tga, .bmp) that can be used for visualization/ comparison purposes.
It can also export the numerical data (TXT file) for same the purposes.
05
Appendix
05.1. When trying to simulate dynamic behavior such as fluid motion or soft/rigid body dynam-
ics it is very important to have a good reference in order to make it believable.
Resources and Reference is very important, and we really mean it. If you are working in CG graphics, we
references are sure you already know this.

When creating VFX, it is not as easy to get a good reference as it would be in other areas
of CG, such as lighting. This is usually due to the speed of effects, and to the kind of con-
ditions that generate those effects.
For example, you can record your friend dancing for examining human motion, but you
cannot create a huge explosion at home. You could also go to the window and watch the
sea to get an idea of the real motion of waves; but then again, perhaps you can’t!
In order to reproduce any effect realistically, we also need to know what exactly is hap-
pening, not just how we perceive it. When we see a tornado for example, are the particles
going up or down? We have to understand what we are going to reproduce.

So, in this section, we want to give you with some tips so you can explore by yourself and
look for useful references for your simulations.

High speed photography


We have discovered this to be one of the best resources for fluids, explosions, soft bodies,
smoke…etc
When watching videos recorded at high speed, we will see them in very slow motion,
therefore we are able to carefully examine what exactly is happening.
There are some photographers who specialize in this kind of photography (Dave Palmer or
Stephen Dalton for example) and there are some image banks where you can find these
kind of resources.

NASA, meteorology and Universities


There are many institutions that do a lot of research on fluid and chaotic motions like
explosions or storms. They usually have papers published with explanations on these
phenomena, and perhaps images or videos.

Documentaries
Of course, documentaries are a good way to obtain references. There are so many, and
the choice is so varied that you will always find one that suits your production. Do not
search for a specific topic (like explosions) but look for something related (historical
battles for instance).

Films and video clips


Although we recommend getting your references from real life, films and VFX are getting
better all the time, so you can have a look at the most impressive ones to get a feel for
where the industry is going, and what is important to get a good effect.
It is always a good idea to analyze other peoples work as well as your own, in order to
improve.
05
Appendix
05.2. Expressions are part of RF4 curve editor. They are mathematical functions that combine
numbers, variables, or constants using operators which allow the user to set the behavior
Expressions of a parameter over time. The expressions are the representation of the values of the
library parameter we set it to.
You can read more about setting expressions in RF4 in page 30.

Not everyone in 3D uses expressions, but they are quite handy in RF4 and that’s why we
want to dedicate a special section to it.
The use of expressions will save time when tweaking simulations. It is also quite normal
to animate RF4 parameters using expressions, as we do not usually need a very special or
detailed curve but more of a general behavior, like increasing the parameter smoothly and
changing to 0 in frame x. Imagine that you also have to change several points of a curve,
this could take some time. With expressions you might be changing just a number, so it
becomes faster. The advantage of expressions, besides the obvious of being able to use
other parameters to drive values, is that they can also achieve nice, smooth transitions
and precise results without fiddling with individual key frames.

So, we have established that an expression is a mathematical function that depends on


a variable. A variable is an element of the formula (proposition or algorithm) that can be
substituted by any value; this value can be set within a range. However, there are also
dependant (D-Vars) and independent variables (I-Vars), the latter cannot be defined as
they evolve over time, and the dependant variables are defined by their constants (de-
pendent and independent variables).
For example, sin(t) - where time in seconds is the variable, and sin is the function. You
can substitute t for any value (1,2,3 etc…) to draw the function graphically, but RF4 will
do that for you.

You can also substitute the independent variable time for a dependant variable, for exam-
ple sin(Circle01.Position_X).That means that the functions cannot be drawn graphically
until we know the x position of Circle01 over time, and that happens whilst simulating.
The sin function depends on another animation curve, the x position of Circle01.

Besides this, we have other kinds of functions to define the animation curves:
Unary functions, that have got just one variable. Binary functions, with two variables and
tertiary functions.

It sounds very complicated when read, but check the graphics below to understand how
they work.
05
Appendix

Unary functions
05
Appendix
05
Appendix
Binary functions
The basic operations are:
Addition: 3 + t
Multiplication: 3 t or 3 * t
Division: 3 / t
Exponentiation: t ^ 2
Inequalities: t > 0 t

The operations are evaluated following a priority plan:

Boolean < addition < product < division < Exponentiation.

Terciary functions
If function can be found in the Terciary Functions.
It works as follows:
if ( ‘arg1’, ‘arg2’, ‘arg3’ )

If ‘arg1’ is TRUE (differs from zero), then ‘arg2’ is returned, or else ‘arg3’ is returned.
For example: if(f>50,2,0) which means that for frame numbers over 50, the value of the
parameter is 2, for any other frame number, the parameter’s value is 0.

Functions modifiers
Once you start using expressions, you will be gradually making them more complex. Nest-
ing expressions will hold no secrets for you.

However, let’s start controlling the basic ones. We will pick a unitary function as it is
sin(t).

The modifiers we can add to this expression will help us to control the curve to reach the
values we want.
05
Appendix

D+A*sin(d+(f*t))

Displacements (offsets or shiftings):

D is the vertical displacement and it is added or subtracted from the function.

2+sin(t)

d is the horizontal displacement and it is added or subtracted from the variable (time
shifting in this case).

sin(2+t)
05
Appendix

Multipliers

A is the amplitude, and it multiplies or divides the function.

2*sin(t)

f is the frequency, and it multiplies or divides the variable.

sin(2*t)
05
Appendix

Negative values and inversed functions

Note that you can invert any function or value by applying 1/x, and that you can use nega-
tives values to change the direction of curves.

Standard and inverse function

Exp11 standard and negative function

Combination of functions

So, let’s see how this will work for a more complex expression.
if(f>50,1,sin(t))
05
Appendix

Homework: Study the expressions below.


if (t<0.75/f,D-A,if(t>1.25/f,D+A,D+A*sin(2*pi*f*t)))
1.7*(sin(2*3.14*0.3*t)+0.7*sin(2*3.14*0.5*t)+0.4*sin(2*3.14*0.9*t)+0.2*sin(2*3.1
4*2*t)).

05.3. Hint:
LMB= Left Mouse Button
Shortcuts card MMB= Middle Mouse Button
RMB= Right Mouse Button

Some of the shortcuts have a focus, meaning this the user has to set the cursor onto the
right place before pressing the key combination.
This is typical for shortcuts like Alt+D that enables/disables the viewport. normally it is
needed to click on the viewport prior to press the keys.

File Menu

CTRL+N -> New project.


CTRL+O -> Open project.
CTRL+R -> Revert project.
CTRL+S -> Save.
CTRL+SHIFT+S -> Save as.
CTRL+U -> Update SD scene.
CTRL+SHIFT+I -> Summary Info.

Edit Menu

Supr/Del -> Delete the current selected element/elements.


CTRL+Z -> Undo.
CTRL+Y -> Redo.
W -> Move mode.
E -> Rotate mode.
R -> Scale Mode.
05
Appendix
CTRL+D -> Clone selected.
CTRL+B -> Back culled sellection.

Point of view

ALT+LMB -> Orbit in the perspective view, Zoom to area in the curve editor tool.
ALT+MMB -> Pan.
ALT+RMB -> Zoom.

Panel

F1 -> Current selected parameter help.


RMB -> Subpanel help when clicking on the subpanel button..
RMB -> Context and animating menu when clicking on the parameter.
MMB -> Panel scroll up and down.

View Menu

7 -> Bounding box scene view.


8 -> Wire frame scene view.
9 -> Flat shaded scene view.
0 -> Smooth shaded scene view.
CTRL+ALT+F -> Enable/Disable textured objects.
1 -> View top.
2 -> View front.
3 -> View side.
4 -> View perspective.
5 -> View camera.
F -> Fast view.

Layout Menu

F2 -> Launch a Single View panel.


F3 -> Launch a Quad View panel.
F4 -> Launch a Node panel.
F5 -> Launch a Exclusive Links panel.
F6 -> Launch a Global Links panel.
F7 -> Launch a Node params panel.
F8 -> Launch a Curve Editor panel.
F9 -> Launch a message window panel.
F10 -> Launch a Batch script panel.
F11 -> Launch an Event script panel.

Export Menu

CTRL+E -> Export All.


F12 -> Launch Export Central.

Adding elements to the scene

CTRL+1 -> Emmiters list to be added to the scene.


CTRL+2 -> Daemons list to be added to the scene.
CTRL+3 -> Object list to be added to the scene.
CTRL+4 -> Constrains list to be added to the scene.
CTRL+5 -> Add a mesh to the scene.
CTRL+6 -> Add a camera to the scene.
CTRL+7 -> Add a Real Wave surface to the scene.

Shading
05
Appendix

D -> Cycle shading mode.


ALT+D -> Enable/Disable the viewports.
ALT+W -> Maximize/minimize current viewport.
SHIFT+V ->Toggle to show particles arrows or points

Selection

Q -> Select mode.


LMB -> Single selection.
RMB -> Context pop up menu.
SHIFT+LMB -> Multiple selection by drawing area, adds or substracs particles to
selection in the particle selection tool.
ALT+L -> Lock current selection.

Simulation

A -> Start/Stop action.


CTRL+A -> Reset.
Space -> Start/Stop play.
K-> Creates a keyframe.
LEFT ARROW -> Frame backward.
RIGHT ARROW -> Frame forward.
DOWN ARROW -> Frame begin.
UP ARROW -> Frame end.

Curve Editor

File

CTRL+L -> Load curve.


CTRL+S -> Save curve.

Options

Alt+S -> Set Range.


Alt+R -> Reset view.
Alt+I-> Load image.
Alt+C -> Fit view.
Alt+H -> Fit horizontal view.
Alt+V -> Fit vertical view.
Alt+T -> Show time.
Alt+F -> Show frames.
Scriptingbyin RF4
Mark Stasiuk
06

06.1. I am not a software engineer.


Introduction Chances are, that is what you are saying to yourself as you see the words “Scripting
Guide”, and it is certainly what I said to myself when I first heard, a few months ago,
that one of RealFlow 4’s main new features would be built-in Python scripting. The other
thing I said to myself when I heard this was: “what the heck is Python?”

So feel neither frightened of programming nor embarassed by your lack of knowledge


of the software engineering world. Instead, I hope you’ll be attracted by the possibilities
offered by scripting in RealFlow: the ability to precisely control what happens in your
simulation scenes. That’s what grabbed my attention, and it turned out to be true to
such an extent that, after months of work with scripting and many successes at a very
high level on commercial and feature film projects, I can see no end to the possibilities.
The addition of scripting to this package is a huge new step, as you’ll soon see.

On the technical topics of Python and programming, well, don’t worry. This guide is a
beginners manual to both the Python programming language and to it’s applications
in RealFlow, so you’ve come to the right place to start. Fortunately, Python is a good
language to work with because it is firstly quite easy to learn and understand at least
to the level that will allow you to do almost miraculous things in RealFlow. Second, it’s
a core component of the worldwide “open source” movement so there’s a vast amount
of free stuff about Python available on the web. In fact acquiring standalone Python for
your use is entirely free from www.python.org, where you’ll also find great documenta-
tion and tutorials. I started with the tutorials and documentation on that website, and
I’m happy to disclose that I’ve never needed to go significantly beyond that material.
Sure, you could learn all about the intricacies of Python and put it to even more as-
tounding use within RealFlow, but you certainly don’t need a computer science degree to
use Python to carry your physical simulation work to entirely new places.

If you are a software engineer or maybe know Python already, this guide is still a good
place to start for knowing how to use your expertise within RealFlow. There’s an abun-
dance of information on what works well and why, which is particular to RealFlow rather
than Python.

The focus of this guide is on getting going in using Python in your simulations, particu-
larly within a production environment, not on learning all about Python. I cover basic
syntax, structures, methods and functions of Python so you’ll understand what is going
on, but I don’t attempt to re-create the great documentation already freely available
from python.org. If you want further clarification on Python issues, start by going to
that site and the larger Python community.

This guide is meant to get you started and should be used together with the Python ref-
erence manual of RealFlow scripting functions, which you can find in the documentation.
After familiarizing yourself with Python via this guide, it’s worth going to the reference
and browsing through to know the kinds of functions you can make use of.

Part I is an overview and context-building section, where we’ll go over the most relevant
aspects of Python and where they fit in RealFlow 4. Part II dives into particular kinds
of tasks that are well-suited to scripting, and tasks that can’t be done any other way.
Finally Part III gives basic descriptions of the scripts included in the RealFlow 4 scripting
library, as of the initial release of RealFlow 4. This library is just a modest beginning and
will grow with time; probably by the time you read this, Part III will be well out of date.
Finally, in the Appendix you’ll find a number of definitions and descriptions of math-
ematical things that are worth being familiar with, such as vectors and very basic vector
math. Given that you’ll be wanting to control the direction and velocity (both vector
quantities) of fluid particles with your scripting, if you don’t know what such things are
then it’s worth referring to the appendix.
Scriptingbyin RF4
Mark Stasiuk
06

06.2. Python is installed as a part of the RF setup. You don’t have to take any further steps to
get python working in RF but is good to know how RF deploy Python on your machine so
Preliminaries: you don’t have interferences with any other python installations.
Get Python
Python comes with a lot of useful modules that you can use in your scripts. You can
make use of any command, function, module and feature of Python within RF, from
opening, reading and writing formatted files to image processing. The Python commu-
nity is an active player in the open source movement so Python is free to download and
use, and so are a huge number of Python modules containing additional functions that
can save you remarkable amounts of time.

The functionality of some of the modules that comes with the Python installation de-
pends on the Python version. That’s the reason why RF installs all the modules that
works with the Python version RF is using (2.4.1).

At starting time RF is looking for the modules in the folder $RF4PATH/lib/python. Once
it has found the modules there RF imports the module site. Any advanced python user
knows that the first thing a python interpreter does is to import the site module. We
want RF follows the same procedure. The import of the site module is quite important
if you want to add your own or third-party modules folder to the default search path.
Say that you have downloaded a module for doing image processing and you want to
use that in RF. You have installed the modules in /home/realflow/image_processing_py-
thon_modules and you want to make the modules seen by RealFlow. The standard way
to proceed is to edit the sitecustomize module and add the path using the standard sys.
path.append(string) function. The sitecustomize module is imported by the site module
so once RealFlow is started you have access to all the modules in the image processing
library. The content of the sitecustomize.py file might be as follows:

Import sys
def main():
sys.path.append( “/home/realflow/image_processing_python_module” )

main()

Aside from setting the paths for your own and third-party modules in the sitecustomize
module you can always run the sys.path.append(string) function in the RF batch script
editor and the modules will be accessible during the RF session but when you close and
open RF again the paths are gone. This is the reason why the sitecustomize might be a
better choice to put the paths for additional modules.

Because RF is overriding the basic Python start up you will see a message at RF starting
up time saying “import site” failed … You have to disregard this message because the
import of the site module is done automatically by RF afterwards.
Overview
of Python Scripting in RF4
07

07.1. RealFlow 4 (RF4) has Python scripting running throughout its architecture. You can
control just about any process in RF4 with scripting. In fact, in keeping with the spirit
Areas of of RealFlow, you can control so much that you can easily make the package do things
scripting in RF4 it was never intended to do. This is actually a good thing as it leaves you unconstrained
and able to develop methods to deal with all kinds of awkward production situations.
One function of this guide is to let you know what kinds of scripting actions can cause
unstable behaviour.

In short, there are 5 “places” where you can use scripting in RealFlow 4:

- events
- daemons
- RealWave
- fluids
- batch / command line

Let’s briefly look at each of these.

First, “events” scripting.

Hitting F11, going to Layout>Events Script, or left-clicking on the square icon in the
upper left of any RF4 window and selecting Events Script, will take you to the events
scripting window. This is really just a list of Python functions that are called to be
performed at particular times during the running of the scene, or more in the scripting
lingo, the functions are executed on the occurrence of particular events. During simula-
tions, the choice of events are at the start and end of simulations, at each frame, or at
each simulation step. The default state of these functions is empty, with just a “pass”
statement that means “do nothing”. But if you replace any of those pass statements
with lines of Python code, that is what will happen when the relevant event occurs.
There’s an infinite number of uses for events scripts and I find it the most commonly
used scripting area. Simple uses include sending information to the scene messages
window so you can track various things happening in your scene. More advanced uses
include initializing global variables so they are accessible to other scripting areas such
as scripted daemons, and moving particles between emitters based on exceeding some
condition. These will be covered in more detail later.

Next, daemons.

When adding a daemon to your scene, you’ll now see that there’s a new choice at the
bottom of the list: scripted. In the sub-panels of this daemon is an edit button, which
opens a scripting window similar looking to the events script. There are 3 functions here
that you can use: applying forces to particles, killing particles, or applying forces to
scene objects.

I can’t say enough about the value of scripted daemons. Anyone with significant Real-
Flow experience knows that for a particular scene, they inevitably end up struggling to
get the native RF daemons to do just what the VFX supervisor wants. Using scripted
daemons, you can easily achieve exactly what is required. Say you need to apply drag
to fluid particles but only in the vertical direction. This is easy with a scripted daemon
and impossible with the native RF daemons.

Third, Realwave.

Here I’m referring to scripted waveforms. After adding a RealWave surface to your
scene, when you go to add a wave to that surface you’ll now see, in addition to the clas-
sic fractal and sinusoidal type wave fields, a scripted wavefield. The parameters for this
include an edit button that opens a scripting window, where you can script in the vertex
positions of the wave surface as a function of time. What you put in is entirely up to
Overview
of Python Scripting in RF4
07

you. Perhaps the most obviously useful thing to do is to use a sequence of grayscale im-
age maps as the source of the wave field, and just map these images onto the realwave
surface. This is remarkably easy to do and we will in fact do this as an exercise later on.
This technique means you can use image maps rendered from an orthographic camera
in your 3D package, or texture map sequences, to create RealWave waves.

Fourth, batch / command line scripts.

In addition to the events scripting window, you’ll notice you can select a batch scripting
window. This brings up an empty window into which you can import or simply type lines
of Python, and then you can execute the code using ctrl-return or from the script>run
menu selection, or by calling on the command line version and using the -script option
with the path to the script .rfs file. This area of scripting is deceptively powerful. From
here, you can load scenes, save out new versions, or create scenes from scratch via
scripting. You have access to all parameters within a scene, can add emitters, daemons
and objects, and can run a simulation substep by substep, or jump to particular frames.
Using this area, you can create such useful things as a batch script that runs a file for
a variety of slightly different conditions, producing numerous versions automatically so
you can figure out the effect of settings very quickly. You can think of the batch script
area as an outer shell or command line control of the RealFlow simulation environment,
within which all the usual RealFlow calculations happen.

Lastly, scripted fluid behaviours.

You can create your own fluid behaviour via scripting, to get inter-particle behaviours
different from fluid, dumb, elastic. Simply choose “Custom” from the drop-down menu
of particle types, and access the scripting window in the parameters subpanel.

07.2. Although most of the time you use scripts in RF scenes it won’t really matter what hap-
pens in what order, sometimes it does and a knowledge of it can help you resolve a situ-
Order of ation where your scripts aren’t doing what you expect.
scripted
operations Scripted daemons are applied every simulation substep in the same way and at the same
time as RF built-in daemons like gravity. These are therefore computationally intensive
(which is why it’s such an advancement in terms of speed that all the built-in daemons
are multithreaded in RF4).

In the events script, which is where the order of operations is most important, the script
in the onSimulationStep section gets executed at the end of every calculation substep --
after all the daemons and interparticle forces have been calculated.

When the calculation reaches a frame boundary, the order of operations is first the calcu-
lations of the simulation substep, then the onSimulationStep script, then the particle and
other data is written out (e.g., creating the particle .bin files), then finally the onSimula-
tionFrame script is run.

One important and fairly general situation where this order is important is when you want
to do something to the particles every frame, prior to saving them. Let’s say you want to
kill off some particles based on their speed, and that you loop them every frame to check
their speed, kill those that exceed some condition, then write the data out. If you have
the particles set to export in Export Central, the data will get saved out each frame before
Overview
of Python Scripting in RF4
07

you have a chance to run your script in the onSimulationFrame section, so you’ll end up
with data that is always 1 frame “out of synch” compared to what you want. Knowing the
order of operations, you can resolve the situation by setting the particle data to not export
in Export Central. Then, in your script, when you’ve finished doing your checks and killing
particles, you simply use the emitter.export() command (see the scripting reference for
usage details) to force a data export exactly when you want it.

07.3. Although you can do an a bewildering array of tasks with scripting, you can’t do every-
thing and there are limits it is worth knowing about. There are places in scripting where
Limitations you can’t perform certain operations, or where it’s unwise to do so. Although not exhaus-
tive, the main scripting limits encountered by users are listed below :

• Within an events, realwave, daemon or fluid script, you cannot create or load a
new scene, nor jump to other frames, nor simulate individual or ranges of time sub-
steps or frames. These can only be done within a batch script.This reasons for this
should be obvious, since jumping to an entirely new scene in mid-simulation doesn’t
make a lot of sense and is likely to confuse both you and your workstation.

• As Python is not yet an automatically multithreaded language, Python-scripted


operations will be limited to a single thread (single core or singe CPU). As a result,
using a lot of scripted tasks within a scene can slow down simulations tremendous-
ly. This is offset by the amazing things you can achieve so the wait is often worth it,
but you have to weigh that against production shedules. This limitation emphasizes
the importance of being clever about how and where you apply your scripts; e.g.,
if you can do some operation every frame rather than every simulation time step
(subframes), you should.

• There are a variety of parameters that you cannot set via scripting, such as pref-
erences, fps and adaptive stepping settings. Most of these are not very important to
getting results, and the ones that are related to simulations (e.g., adaptive steps)
are not accessible on purpose, to avoid confusing the solver.

• Although it is possible to use a batch script to create a scripted daemon or script-


ed realwave in a scene, it isn’t yet possible to import or alter the scripts within these
nodes via scripting. This is possible for events scripts, however. This limitation will
be removed in a near-future update.

• It is not yet possible to create a scene object and add your own parameter fields
to it. This limitation will soon be removed. The advantage of this would be to allow
you to create, name, and control parameter values that scripts access, to make al-
terations to values easier on the user. Currently, you have to either open the script
and edit the lines of code, or have the script read values from a dummy object (e.g.,
a null) where you assign, say, the object’s x-position to be equal to the strength of
your scripted force daemon.
Overview
of Python Scripting in RF4
07

07.4.
Basics of Generalities
Python If you wish, you can avoid thinking of Python as a scary programming language and
instead view it as just a way of giving RealFlow commands to take actions, similar to
clicking on a button in the GUI. You need not worry over the details of reading or writ-
ing files, complex algorithms or numerical methods. So much of that is taken care of by
the RealFlow solver and associated software, or by the built-in scripting functions, that
you just have to remember the correct ways to give the commands. A Python script in
RealFlow is then just a sequence of commands and the algorithms in the scripts are just
groups of these commands given in a particular order. A script, however, can be as short
as a single line.

Python is considered to be a “high level” programming language. To the average non-


programmer this can be loosely translated as “easy to read and understand” because the
syntax, commands and functions look a little like English, perhaps spoken by somebody
who doesn’t speak it very well (!). This is considered high level; low level programming
languages are far more difficult to read and hence less easy to use.

Another thing that makes Python “high level” is that it is highly structured. The Python
interpreter, the thing that reads the scripts you supply and then executes the commands,
is quite picky about how you place your lines of script and the syntax you use. If you get
the syntax not precisely correct, the interpreter gets confused, sends an error message
to you, and doesn’t do any other commands in your script. You will at times find this
wonderful, and at other times totally irritating. However it will always keep your scripts
moderately readable and so other users will at least have a fighting chance to figure out
what your scripts are doing.

This brings us to an important point: try to make your scripts understandable not just
to others, but to you. Weeks after writing a script you may want to go back and revise it
to do something a little different. If you wrote it without explanatory comments or with
oddly named, cryptic variables and methods, you’ll spend a lot of time trying to figure out
what the script does. Some clear comments and scripting style go a long way. To insert a
comment into any Python script, which is just a line that the interpreter knows to ignore
(rather than try to interpret as a command), you simply start the line with a “hash” sym-
bol: “#”. Such as this:

x = 2.0
# now check to see if x is bigger than a, and if so replace a with x
if x > a: a = x

In any RF scripting window, a line starting with a hash will go a different colour (default
is yellow) so you will know you’ve got it right. Other colour coding is used for other kinds
of script, a useful visual indicator. And you can set the colour coding to your own liking by
going to file > preferences and then the scripting tab.

Another way to keep your scripts understandable to both you and your co-workers is
to use meaningful variable names. Variable names like “x” and “b” don’t mean much,
whereas names like “xpos” and “boxvel” are still quite short but more meaningful (say,
for x-position and box object’s velocity). In my scripts I make an effort to follow some
principles that help me keep my variable names organized, for example I try to make
objects always end in “obj” (e.g., cubeobj) and vector variables always end in “vec” (e.g.,
posvec). When you develop scripted production tools with 10 or 20 parameters for artists
to use, this kind of approach becomes really valuable.
Overview
of Python Scripting in RF4
07

Getting objects and their attributes


The first thing to know about Python is that it is object-oriented. Objects, or if you want
“things” in Python scripts, such as emitters, particles, scene objects and vectors, all have
associated attributes and functions based on what type of thing they are. You will very
frequently need to be able to retrieve information about objects, for example you’ll want
to get the velocity or position of individual particles, or the rotation of a scene object. Not
all attributes are the same for all objects and it’s important to get familiar with what you
can retrieve or set for what kinds of objects, plus what kinds of functions you can use to
control objects. These attributes and functions are what make up the tools in your script-
ing box. As an example, imagine that we needed to emit particles from an object, but
only for the polygons facing upward. If we had no way to access the individual polygons
making up the object, we would probably be unable to achieve the goal.

There’s a particular way of accessing attributes of objects in Python. Basically, you get
or set attributes using a dot followed by a particular wording for the attribute, and often
you follow with brackets enclosing parameters and / or values. For example, let’s say you
have a cube in your scene called “cube01” in the node parameters window, and you want
to find out it’s position. To do this, you first get the cube using a “getObject” command
for the “scene” object:

scene.getObject(“cube01”)

You can think of this line of Python as being equivalent to the cube01 object. For any
other polygonal object in the scene, you can access it with the same scene.getObject
command followed by the name of the object in brackets and enclosed in quotes, exactly
as it appears in the Node parameters window. On executing this command, the Python in-
terpreter looks through the nodes in your RF scene until it finds the object (not daemons,
emitters or anything else) with name exactly equal to the one you supply in quotes. Any
set of characters in quotes in Python is called a “string”. Whenever you supply a string
parameter to a command, it has to be enclosed in quotes or the interpreter will think it is
a variable called cube01. This will get clearer a little later.

Other types of objects in your scene can be grabbed in the same way, for example you
can use scene.getDaemon, scene.getEmitter, etc. Check the scripting reference under the
scene category for the full list of possibilities. If you mis-type any of these commands,
you will know it immediately because the automatic colour highlighting won’t work until
you get it just right. If you try to execute the script you’ll receive an error message in the
messages window.

There’s a heirarchical nature to the objects in RealFlow, meaning that you have to access
objects via a sequential series of commands starting with the highest level object: the
scene. So, you can’t get to an object’s vertices unless you’ve first gotten to the object it-
self via the scene object. You might think of this as similar to selecting vertices on polygo-
nal objects in your 3D software package, where you first select the object, then you select
that object’s vertices. The same goes for any other attribute of our cube01 object, you
have to get the object first from the scene object, then access it’s attributes. The scene
object has numerous useful commands so you’ll use it a lot, such as for obtaining the cur-
rent scene time or frame, the list of all emitters in the scene, loading scenes, simulating
scene, and saving scenes. These are all listed in the scripting reference manual.

Assigning variables
In Python like in many programming languages, an “assignment statement” appears like
a mathematical equation; in fact what you are doing is allocating some memory space,
and the “command” for doing this is just an equal sign (“=”). So you can create a variable
called “myval” with a value of 2.3 like this:
Overview
of Python Scripting in RF4
07

myval = 2.3

This statement both assigns the value to the variable myval, and also creates the variable.
After this, you can use myval in calculations:

newval = myval * 3.0 + 4

But if you use myval in a calculation before it gets created (or “declared”), you’ll get an
error message from the interpreter saying that it doesn’t know what myval is. Python
has a nice, relaxed way of creating variables, much less formal than older languages that
require you to start off your script with a declatration block, listing all the variables and
their type. This makes Python scripting easier to bang out fast, but has the downside that
you can forget what variables exist, and what they mean, because they are defined all
through your script. As a compromise I like to name my variables something sufficiently
meaningful that I can more likely remember them for when I go to use them later.

In the above assignment statements, both myval and newval get created as floating point
variables (decimal numbers), as opposed to strings or integers for example. If we had
said:

myval = 2

then it’d be stored as an integer value. You need to be aware of what your variables are,
since Python is sensitive to types. For example if you declare myval as a floating point and
then go to use it as the index of a list, Python will return an error. You can’t get the 2.5th
member of a list. You can convert between types using the built-in Python commands
float(), int() and str() to convert integers to floating point, floating point to integers, and
floating point or integers to strings, respectively.

If you have a few variables to assign, Python allows you to compress this to one line of
script. So you can either say:

a = 3.0
b = 5.0
c=a+b

or you can say:

a,b,c = 3.0,5.0,a+b

where the assignments happen from left to right, so when c gets assigned, a and b already
have their values. This is certainly a compressed way of writing series of assignments, but
I like to avoid this shortcut because I find it makes scripts less easy to read and de-bug.

Assignment statements can be used for anything object in your scripts. It’s often con-
venient and clearer to re-label things, although it’s an optional step. You can give new
names to any object or value in your script, which is the same thing as creating variables.
So continuing with our example from the previous section, you can rename the cube01
object :

box = scene.getObject(“cube01”)

Now the variable “box” has the same meaning as scene.getObject(“cube01”). It’s obvi-
ously easier, faster and shorter to type “box” whenever you want to refer to the cube01
object, so if you’re going to refer to the object in various places in your script it’s usually
a good idea to make the definition at the start of the script. Doing this also means that if
you change the name of the node in the RF node parameters window to, say, cube02, then
all you have to do to make the script work right is change the definition statement to:
Overview
of Python Scripting in RF4
07

box = scene.getObject(“cube02”)

and the rest of the script will work fine because now the definition of box has changed.

You can of course make the variable name anything you want, such a “f2a01x”, “yab-
badabba” or even the very imaginative “cube01”. Obviously, the best name is whatever is
short and meaningful to you.

Now if you want any of cube01’s attributes, our script has the object in memory so we can
access the attributes using various other commands. For the position, we can say:

box.getParameter(“Position”)

The other style of writing this command avoids using variable names, and just chains
together the commands like so:

scene.getObject(“cube01”).getParameter(“Position”)

This is useful to do for one-off calls for attributes or in simple lines of script, but not so
great when you are using the command in a long operation like a calculation.

In the case of both the getObject and getParameter commands, RF will return to you a
result which can be assigned to a variable. This isn’t the case for all commands. Some
commands return nothing to you, but just affect the object they are applied to. We’ll see
an example of this shortly, when we go to set our cube’s position. Any command that
“gets” an attribute will return something to you. If you’ve made an invalid request, you’ll
trigger an error with the Python interpreter and an error message will get printed in the
scene messages window. So let’s say you type this in your script:

box = scene.getObject(“cube_01”)

whereas in fact your cube is called “cube01” in your RF scene. When you run the script,
the Python interpreter sends this line to the messages window:

>17:23:24: Node “cube_01” not found.

The number before the error statement, by the way, is just the current time.

In the case of getting the cube’s position, what gets returned to you is a vector object.
Check in the appendix for what a vector is if you aren’t clear about it. In RF, a vector is
a 3-element sequence of floating point (decimal) numbers, in the order x-, y- and z-co-
ordinates. So if the cube’s position is currently x=2.0, y=0.0 and z=0.0, then the vector
returned to us when we call for the position will be (2.0,0.0,0.0).

Vector objects come along with a variety of their own attributes and functions just like
other objects in RF. You need to know about vectors because many attributes are vec-
tor quantities, such as a scene node’s position, rotation and scale, any velocity, and any
force.

You can create an entirely new vector with a command particular to vector objects, like
this:

posvec = Vector.new(4.0,0.0,0.0)

So now we can change the position of our cube to a new position by using the setParam-
eter command:

box.setParameter(“Position”,posvec)
Overview
of Python Scripting in RF4
07

This command does not return anything, it just does what you tell it to do: sets the posi-
tion of the box object (in this case, equal to the cube01 object in our scene) to the vector
posvec. The same thing could be achieved with either of the below commands:

box.setParameter(“Position”,Vector.new(4.0,0.0,0.0))

scene.getObject(“cube01”).setParameter(“Position”,posvec)

It’s worth remembering that for any node in the RF scene, you can getParameter and
setParameter for any of the parameter values that appear in the node’s subpanels, and
you refer to them exactly as they are labelled in the GUI. For example, to retrieve the y-
rotation value of our box and assign it to a variable called “yrot” :

yrot = box.getParameter(“Rotation Y”)

So now here’s the full script that sets a new position for our cube; if you want to test it
out, just copy the script and past it into batch script window, and then go Script > run.
Make sure you have an object in your RF scene called “cube01”, of course.

box = scene.getObject(“cube01”)
posvec = Vector.new(4.0,0.0,0.0)
box.setParameter(“Position”,posvec)

And here’s a little warning about a feature you need to be aware of, when it comes to
assignment statements. This seems to mainly arise with vectors in RF applications but it
would apply to any analogous situations. If you have a vector variable, and you want to
make use of it’s normalized version (more on what this is in the vector section below), you
can obtain the normalized version like so:

myvec.normalize()

But this permanently alters the length of myvec to make it 1.0, effectively “losing” the
original data of its magnitude. You might think, if you wanted to preserve the original
value, to just assign a new vector and then normalize that, like this:

calcvec = myvec
calcvec.normalize()

So now calcvec is the normalized version, and myvec is the original, right? Sorry, wrong.
What you’ve done above is simply renamed the vector object myvec, or created a sort of
proxy for it, so when you normalize calcvec you also (still) affect myvec. To do this, you
need to create a new vector object that is independent of the original, but has the same
values for its components. To do that, you could type:

calcvec = Vector.new(myvec.x,myvec.y,myvec.z)
calcvec.normalize()

And this would work like you wanted. The “connectivity” of renamed objects is important
to remember to avoid having your scripts produce unexpected results. As you might
imagine, if you didn’t know this and then went to use myvec elsewhere in your script,
you would be using something different than expected and could get odd results, which
might be quite difficult to track down since there would probably not be any Python errors
generated.
Overview
of Python Scripting in RF4
07

Pass statement
You will see a particularl statement frequently when using RF: the “pass” statement. This
is a “do nothing” statement that just fills space in the functions where there is no code in
places like the daemon script and the events script. If you want to add a script to these
places, just delete the text “pass” and type in your script.

Messages
A very useful RF command is:

scene.message(string)

where “string” is a string variable you intend to output to the messages window of RF. This
is useful for debugging or just tracking what is happening in your scene, since you can
output variable values whenever you want them. For example, if you want to check to see
what the speed is of an object in your scene, you can write it out to messages every frame
by just inserting the following text into the onSimulationFrame section of the events script
(assuming we have determined the speed elsewhere; more on that later) :

scene.message(str(objectspeed))

The “str” command converts any numerical value to a string of characters, which is what
the scene.message command expects to have.

You could also type:

scene.message(“The object speed is : “ + str(objectspeed))

If the objectspeed was, say, 10.0, then in the messages window you’d see:

The object speed is : 10.0

So you can combine strings of text with the “+” symbol and get clearer output to better
understand what is happening in your script during the simulation.

I’ll say more about the messages window and debugging later, but you should know that
when you write a script and attempt to execute it, if there’s an error the Python interpret-
er will send you a message in the messages window and stop any further execution of the
script. So, the messages window is something you need to keep an eye on for guidance
on getting your scripted scenes working right. Watch for flashes of red at the bottom of
the RF interface; that’s where there’s a single line view of the messages window, and any
error messages get highlighted in red as they are output.

Variable types
As said above, Python has classifications of variables, or variable types, that are important
to know about. Single value variables come in the following types:

integer (e.g., 1, 5, 126)

float (decimal values, such as 1.2, 0.5)

bool (true, with value of anything except 0, and false, with value 0)

character (an ASCII value, such as “a”)


Overview
of Python Scripting in RF4
07

Python also has a variety of data sequence types where you can store a large number
of variables. Two very useful types are lists and dictionaries. Lists are just that, lists of
values. A list can be a sequence of any type of values, so it can be a mix of characters,
integers, floats, objects and even other lists. You’ll run across this type of data structure
frequently because a number of important RF Python commands return lists of things, like
particles. There will be more on lists in a later section.

Dictionaries are sequences of data pairs, normally referred to as key:value pairs. The idea
of a dictionary is that these pairs travel together, so you can retrieve a value by calling the
dictionary with the key. Dictionaries can be very useful for such things as storing certain
attributes of particles, and keeping track of which particle the attribute is for using the
particle’s unique ID value.

Finally, there are two broad kinds of any of these variables: local and global. The only
difference between these is accessibility by other Python scripting areas in RF to those
values.

A local variable is only known about by the script or script function where it is defined. So
to revisit the above example for our cube, in this script:

box = scene.getObject(“cube01”)
posvec = Vector.new(4.0,0.0,0.0)
box.setParameter(“Position”,posvec)

Both box and posvec are local variables. If we used this script in the events scripting area,
say in the onSimulationBegin section, it would get executed at the start of the simula-
tion. The variables box and posvec, however, would not be “seen” by other sections in the
events script such as onSimulationFrame, or by the batch script area, or by any daemon
script. In these other sections you could have entirely different variables with the same
names and all would work fine. But if you wanted to use the same values in other script
sections, you couldn’t until you defined the variables as global. To do this, you use the
following scene object command:

scene.setGlobalVariableValue(“box”,box)

This saves the box object (our cube) to a memory space that can be accessed elsewhere,
and stays valid so long as you are in the same session of RF. So if you now put this script
into the onSimulationBegin section of the events script:

box = scene.getObject(“cube01”)
posvec = Vector.new(4.0,0.0,0.0)
box.setParameter(“Position”,posvec)
scene.setGlobalVariableValue(“box”,box)

Then in the onSimulationFrame section you could retrieve the same variable this way:

box = scene.getGlobalVariableValue(“box”)

Even if you stop a simulation, you can still access global variables through the batch script
window. This is what is meant by the same “session” of RF; until you quit RF, you can ac-
cess these variables. This can be very useful for checking on the values of variables when
debugging scripts. In a more general sense, it’s worth using global variable declarations
at the start of a simulation because it means you don’t have to revise scripts in other
areas when you change things in your scene. If you have cube01 in your scene and it is
referred to in various script areas, you could just setup the global variable box as we’ve
done above and then refer to that box variable everywhere else. If you change the cube01
object to a car object called bmw_model_01, all you have to do is open the events script
and change the text in the first line from “cube01” to “bmw_model_01”, and then you can
Overview
of Python Scripting in RF4
07

run the simulation. Otherwise you’d have to find every place where that object was called
for in the scene and change the name.

Calculations
Performing calculations in Python scripts is easy as it uses the same sort of syntax and
priority as many common calculator programs, with just a few important things to re-
member.

Here’s some examples of calculations:

# addition:
a=b+c

# subtraction:
a=b-c

# multiplication:
a = b*c

# division:
a = b/c

# priority, using brackets: addition done first, then multiplication


a = b * (c+d)

# priority, without brackets: multiplication is a higher priority than addition so is


done first
a = b * c+d

In Python, there is a short-form way of incrementing values. The long way is:

a=a+1

and the short way is:

a += 1

You increment by any value, not just 1.

07.5. Python is an extensive, well-developed language and so one could go on and on about
Need to know commands, functions, data structures, etc. But let’s not.

Python: loops, The reality is, you can do a huge number of fabulous things in RF with scripting and only
conditional need to know a small amount of Python. I’d encourage you to learn as much Python as
statements, list you can, but don’t worry if you don’t have time to become an expert.

and dictionaries In RF, you’ll find that you are constantly needing to do the following 3 things:

(1) Loop through long lists of things, usually particles, and apply some operation to
Overview
of Python Scripting in RF4
07

them

(2) Check to see if some condition is true, and if so then do something

(3) Make use of lists. This could be simple lists, or “associative lists”, or dictionaries.

Loops
There’s two ways to cycle through a list of things: “for” loops and “while” loops. Let’s look
at both in the context of a very common task, that of looping through particles and apply-
ing a force to them, in a very simple force daemon script.

First, imagine we have an emitter in our RF scene, and say we want to apply a super basic
wind force to the emitter’s particles via a scripted daemon, with the wind pushing in a
direction parallel to the +z axis. After adding a scripted daemon to the scene and applying
it to the emitter in either the global or exclusive links window, you can open the daemon’s
scripting window and start creating the script in the section titled apply force to emitter.

The sections of the scripted daemon are in fact function definitions. Function names in
Python scripts are defined by the “def” keyword, and after that defining line, all the lines
making up the body of the function have to be indented by a single tab so the Python
interpreter will know where the function ends. In the events script window, again all the
sections are functions. This is not the case for the batch script window. I’ll say more about
creating your own functions in a later section.

In the scripted daemon, the function definition already has a name for the emitter it is
applied to, called simply “emitter” as shown in the brackets. So long as the daemon is
applied to the emitter in your scene, whatever script you type here that refers to the par-
ticles of “emitter” will affect the particles as you’d expect. You don’t have to call on the
scene.getEmitter command.

We’re going to cycle through all the particles, and to each one we are going to apply a
force. So let’s define the force, which is a vector, as this:

windforce = Vector.new(0.0,0.0,5.0)

This is a vector pointed just in the +z direction and with length (magnitude) 5.

Now let’s get all the particles currently in existence for the emitter, so we can cycle
through them and apply our windforce. You can do this two ways, either by getting a list
of all the particles, or just start by getting the first one and get the others later:

partlist = emitter.getParticles()

or

particle = emitter.getFirstParticle()

The variable partlist and the variable particle could of course be called anything you
wanted, such as “particle_list” and “myemitterparticle”. These names are entirely up to
you. I usually shorten particle to p since it’s short, but you might find that confusing so
I’ll try to stick with particle.

First let’s look at cycling through the list of particles. This turns out to be the slower of
the two ways for looping through particles. In general, just moving one by one through
a long list of anything is the slowest way. RF stores particles in a special data structure
that is more rapidly accessed using the second method of looping below, and the speed
Overview
of Python Scripting in RF4
07

difference becomes substantial when you start dealing with large numbers of particles.
However there are lots of times when you have no choice but to cycle through a list so
we’ll show how to do it.

Here’s 3 different ways to loop through the list of particles (or through any list) :

# first, a for loop:


for particle in partlist :
# apply force to particle

# a second kind of for loop:


for i in range(0,len(partlist)) :
particle = partist[i]
# apply force to particle

# third, a while loop


i=0
particle = partlist[i]
while i<len(partlist) :
# apply force to particle
i=i+1
particle = partlist[i]

In all 3 loops you use a predefined statement that the interpreter recognizes, to move
step by step through any sequence. In all cases you give a starting statement that de-
scribes a condition for moving through the sequence, end that statement with a colon
(“:”), and then give an indented block of script that gets repeated with each step.

In the first 2 cases, the for loops, you use the keyword “for”, followed by a variable that
takes on the value of the consecutive members of the list, followed by the keyword “in”
and then the name of the list to cycle through. If you just want to move one by one
through the list, then the first variety is the simplest to write. The second loop uses one
of Python’s built-in functions (“range”), which returns a list of integer values that the vari-
able i will take on. It also uses another built-in function “len” that returns the number of
members in the list (the list’s length). In the loop body, you have to remember to define
the particle each loop according to the variable that is being incremented (i). In the loop
examples this does exactly the same thing as the first one, which appears simpler. The
second one becomes really valuable, however, when you want to move through the list
by steps greater than 1, or perhaps in the reverse direction. The range function has an
optional third argument, left out in the above statement, that defines the size of the step.
So if you want to go in increments of 2 through the list, you can type:

for i in range(0,len(partlist),2) :

And of course you could also just go through a limited number of the particles, by cycling
over a range less than the full length of the particle list. Doing this kind of thing might be
useful in RF if you want to apply a force to just some fraction of the particles, which might
be good for generating types of noise in the flow of a fluid.

The third loop, the while loop, defines a condition and keeps sequencing through the in-
dented block of code while the condition remains true. The initial statement indicates that
the tasks should be executed so long as the variable i is less than the total number of
particles. Crucial in a while loop is that you must step the variable i forward. If you don’t, i
won’t change and you’ll end up in an infinite loop. It’s very common to make this mistake
and you’ll know it because RF will hang indefinitely.

According to some online sources in the Python community about optimizing the speed
of Python code, while loops are the fastest of the loop types so if you want your loops to
go as fast as possible, you can stick to that kind of loop. In practice, this often appears
Overview
of Python Scripting in RF4
07

to make little difference to the speed of an RF simulation, unless the number of things in
the list gets very large.

Now let’s move on to the other method of looping through particles, where we’ll use the
internal data structure that RF creates for particles. This is in fact the fastest way to cycle
through particles, and should be the default method you use in your scripts, unless you
need to use a different way.

First, as said above, we get first particle using the RF built-in command emitter.getFirst-
Particle() to create get the first particle object:

particle = emitter.getFirstParticle()

Next, we apply a while loop, and within the while loop we increment to the next particle
using another built-in RF command: particle.getNextParticle() :

while particle :
# apply force to particle
particle = particle.getNextParticle()

You’ll observe that the built-in commands are the type that don’t take any parameters in
brackets. There are many examples of such commands that you’ll be getting familiar with.
It’s important to remember that these commands still require the empty brackets as part
of their correct syntax.

In the above script block, the while statement works because it just needs to know if the
condition is true or false, and anything that exists is considered to have a boolean value of
true. If particle was a “NoneType” object, ie. if it did not exist, then it would be considered
false. So in the script, we increment to the next particle in the emitter’s data structure by
re-assigning the value of particle, and keep going until the getNextParticle command re-
turns nothing, and then we exit from the loop. Again, if we forget to include the statement
for getting the next particles, we’ll end up in an infinite loop and RF will appear to hang.

The last thing to do to complete this task is to apply the force to the particle. This isn’t
part of learning looping but it does show you an important command for scripted daemons
that apply forces. The RF built-in command is:

particle.setExternalForce(vector)

which can only be applied to an individual particle. The vector is a vector object that you
define, whose direction is the direction of the force and whose length is the force’s mag-
nitude or strength. In the case of our scripted daemon, the complete script block would
then be:

# first, a for loop:


windforce = Vector.new(0.0,0.0,5.0)
for particle in partlist :
particle.setExternalForce(windforce)

# a second kind of for loop:


windforce = Vector.new(0.0,0.0,5.0)
for i in range(0,len(partlist)) :
particle = partist[i]
particle.setExternalForce(windforce)

# third, a while loop


i=0
particle = partlist[i]
windforce = Vector.new(0.0,0.0,5.0)
Overview
of Python Scripting in RF4
07

while i<len(partlist) :
particle.setExternalForce(windforce)
i=i+1
particle = partlist[i]

# fourth, RF internal data structure particle looping


particle = emitter.getFirstParticle()
windforce = Vector.new(0.0,0.0,5.0)
while particle :
particle.setExternalForce(windforce)
particle = particle.getNextParticle()

Note that we could have placed the assignment of the windforce vector inside the loop
structures. However, this would add one more operation for every particle. It’s always
best to minimize the number of operations within a loop. In this case it wouldn’t matter
much because an assignment is a pretty simple and fast operation. On the other hand if
we were doing some complex calculation, it could make a big difference to the simulation
time especially when the number of particles gets large.

Conditional statements
Frequently you’ll need to check whether some value fulfills a condition before doing some-
thing. It might be that you want to apply a force to particles only if they are higher than
a certain y-value, or if they are closer to an object than some given radius. Or you may
wish to turn off an object’s dynamics once it leaves the field of view of a camera. Or turn
on an emitter after a certain time. Chances are that for every script you write, you’ll use
at least one conditional statement. These kinds of statements can also be referred to as
“if” statements, or “if-then” statements.

Like loops, condition statements follow a particular syntax and structure in RF. You can
write these statements in a few different ways, which are really just variants of the same
thing:

# a basic if statement
if [condition] :
# do some stuff

# an if - else statement
if [condition] :
# do some stuff

else :

# do some other stuff

# an if - else if statement
if [condition] :
# do some stuff
elif [condition] :
# do other stuff
elif [condition] :
# do yet other stuff
Overview
of Python Scripting in RF4
07

else :

# do some different stuff again

The colons and indentations are required for the Python interpreter to understand what to
do if the conditions turn out to be true.

Note that you can write “elif” as a short form of “else if”, a particularity of Python.

You can of course nest if statement structures (and also loops) so you can develop com-
plex logic trees. It’s worth being very careful with nested if statements, usually this re-
quires a fair amount of testing to make sure you have considered all the possibilities, oth-
erwise you may find pieces of code get executed or not when you don’t expect it. Nested
structures, however, can be really useful when you want to avoid doing something unless
absolutely necessary, for example if the task to be executed is very time consuming such
as a nearest neighbour count on particles.

The condition statments can vary from being extremely simple, to extremely complex
and compound in nature. It’s worth keeping these as simple as possible so they can be
understood by others, and even you at some later time when you re-open the script. For
simple situations where you want to do just one thing if some condition is met, you can
write it all on one line like this:

if a : b = 2*a

Here’s a list of conditional statements and what they mean:

if a :
This means “if p exists / is valid”. p could be an object, like a particle, or a number, like
5.2. You can use this as a filter when p might not exist under certain conditions and you’d
get an error if the next statment gets executed. The statement “b = 2*a” would return
an error if a didn’t exist.

if a > b :
If the variable a has a value greater than b, this is true. You can use “>” for greater than,
and “==” for equal to. The double equal sign is to differentiate between a condition and
an assignment statement where you set something to a value. You can also use “!=” for
“not equal” and “>=” and “<=” for greater than or equal to, or less than or equal to.

if not a :
This is true if a is not valid or does not exist. The “not” keyword can be used in front of
any statement to invert it’s boolean value.

if 2*a <= b and b < 0 :


If twice a is less than or equal b, and simultaneously b is less than 0. This is a compound
statement where we need two conditions met at the same time for it to be true. You can
bring together as many of these as you like to make complex compound statements.
The alternative to the “and” keyword is “or”, which indicates that the conditional state-
ment will be true if the statement on either side of the “or” is true. The “and” and “or”
statements have lower priority than the structures on either side, which means they are
evaluated after the surrounding statements. You can ensure the priority order you want is
followed by applying brackets to group pieces of the statement.

Let’s see what a conditional statement looks like in action, by revising the wind force dae-
mon we built in the previous section.

Imagine we want a strong wind blowing on the particles in our simulation, but we only
want it to affect the particles a few seconds after they’ve been emitted, so they have a
Overview
of Python Scripting in RF4
07

chance to flow around a little in our scene prior to being pushed by the wind. This might
be the kind of behaviour we’d want for a fountain, where we wanted the water to shoot
up straight before being blown over. This kind of effect can be achieved in a few ways, but
one simple way is to apply the wind only when the particles clear a certain height. Let’s
say this height is 2 metres.

What we need to do then, is check on the height of the particle, and if it is greater than a
chosen value we apply the force. To find the position of a particle object (call it “particle”),
we can use the getPosition command:

posvec = particle.getPosition()

where posvec is a variable that gets assigned the vector object returned by the getPosi-
tion function.

Given any vector object, we can retrieve the y-value, which corresponds to the particle’s
height when we are talking about a vector describing a thing’s position (a position vector).
This value is retrieved with the following command:

heightvalue = posvec.y

Similarly you could retrieve the x or z value of the particle’s position with posvec.x and
posvec.z. So now we can use these statements in our daemon’s script:

particle = emitter.getFirstParticle()
while particle :
posvec = particle.getPosition()
heightvalue = posvec.y
if heightvalue > 2.0 :
windforce = Vector.new(0.0,0.0,5.0)

else :

windforce = Vector.new(0.0,0.0,0.0)
particle.setExternalForce(windforce)
particle = particle.getNextParticle()

You can see we’ve defined the windforce based on the particle height, within the loop.
Another way to do this would be:

particle = emitter.getFirstParticle()
while particle :

windforce = Vector.new(0.0,0.0,5.0)
if particle.getPosition().y < 2.0 : windforce = Vector.new(0.0,0.0,0.0)
particle.setExternalForce(windforce)
particle = particle.getNextParticle()

In this case we’ve compressed some statements and it has a more streamlined appear-
ance. It should run a bit faster since a little less is done in the loop. My own preference for
readability would be the first version, although for a simple case like this it doesn’t make
much difference. For more complicated scripts, adhering to the more explicitly structured
approach of the first version can make a big difference to the readability of your code,
even if it makes the script considerably longer.
Overview
of Python Scripting in RF4
07

List
Lists and dictionaries are two particular kinds of sequence data structures that you’ll end
up using frequently, particularly lists. This is because a number of RF commands return
lists, for example:

partlist = emitter.getParticles()

gives you a list of all the current particles from “emitter”. Similarly:

objlist = scene.getObjects()

gives you a list of all the objects in your scene. You can also get the list of all emitters
and all daemons.

As said above, looping through large numbers of particles is better done via the RF par-
ticle data structure rather than just stepping through a list. But there are times when you
will not have a good alternative. In addition, lists make a good way of storing sequences
of related data, for manipulating in some way.

Let’s say that you have an object in your scene and you want to place an emitter at the
highest of the object’s vertices. I’ve run across a number of good production applications
of this kind of calculation so it isn’t as odd as it might sound. Imagine the object in our
scene is called “myobject”.

We first get the object:

obj = scene.getObject(“myobject”)

Next we get a list of all the object’s vertices:

myverts = obj.getVertices()

“myverts” is now a list of all the vertex objects that make up myobject. Now we loop
through the list of vertices and obtain the height of each one, creating a list of these
heights:

heightlist = []
for v in myverts:
heightlist.append(v.getPosition().y)

Note that we first initialized the list of heights “heightlist” as an empty list. This kind of
thing is always a good idea to make sure you are starting with a clean slate. We added
to heightlist using the “append” command. You can see all the list functions in the Python
documentation, but this is one that I use constantly.

Now we apply a Python builtin command for getting the highest value:

maxheight = max(heightlist)

You could use min(heightlist) to get the minimum value in the list.

Although there are lots of other functions and manipulations of lists possible (check the
Python documentation), one other that is particularly important is the “in” keyword, for
membership checking. If you create a list of objects or values, and you need to know if
your list contains a particular object or value, you could say:

if x in heightlist :
Overview
of Python Scripting in RF4
07

This is obviously a lot faster than moving through the list step by step in a loop, and
checking if x is equal to the value of the ith member of the list.

When you want to grab a particular value in a list, you do so by referring to its index.
Indexing in Python uses a notation called a “slice notation”. You can consider the indices
to refer to the spaces between a list’s members, rather than the members themselves. So
for example let’s take a list:

mylist = [1,4,8,12,16]

This is how you create a basic list, with comma separated values.

This list has five members. You can get individual members using index notation, where
the index value starts with 0:

scene.message(str(mylist[0]))

which prints out:

scene.message(str(mylist[3]))

prints out:

12

If you want to refer to a section of the list (more than 1 member), you use the indices
like so:

scene.message(str(mylist[2:4]))

which prints out:

[8, 12]

You can think of this notation as referring to the numbers of the gaps between members,
where the 0th gap is the one in front of the first member.

Strings are a type of list, so if you have are manipulating bits of text you can grab parts
of it with index notation. Imagine you have gotten the list of objects in a scene, and you
want to do find one object that starts with the string “cube”. In this case you could loop
through the list of objects, get the name of each one, and see if the name is right:

myobjectlist = scene.getObjects()
for obj in objectlist:
objname = obj.getName()
if objname[0:4] == “cube”:
# do some stuff

List objects have a number of Python functions that are useful. Four of the most frequent-
ly needed in RF applications are:

list.append(list_item)

This appends or adds list_item to the list. An uncomplicated way to build a list in a loop.

list.count(list_item)
Overview
of Python Scripting in RF4
07

This returns the number of times that list_item occurs in the list. A great way to check if
your list has a value in it yet, in an if statement such as: if list.count(list_item) == 0: list.
append(list_item)

list.index(list_item)

This returns the index of list_item in the list. Very useful when you know the item and just
need it’s position in the list.

del list[i]

This deletes the ith member of the list.

Dictionaries
Dictionaries are sort of like double-barrelled lists, or if you want 2-column arrays. How-
ever, this isn’t really accurate since dictionaries are unsorted data structures, without
a particular sequencing. Instead, they are “key:value” pairs where the “key” is a list of
unique individual values (integers, floats, strings) that can be used to call up the corre-
sponding values. You use dictionaries wherever you have an associated data set. A typi-
cal programming example would be names and telephone numbers. Here’s an example,
showing how to create a dictionary:

dict = {“boy”:”young”, “man”:”old”, “woman”:”pretty”}


scene.message(dict[“woman”])

which prints out:

pretty

In RF, dictionaries are useful for tracking attributes that go with particular particles, so
you can use the particle ID number as the key, and the attribute as the value. Then you
can retrieve the value any time by just calling for it with the dictionary using the ID.

When using dictionaries, you can check to see if you’ve already got a key in it using the
“has_key” function:

dict.has_key(“boy”)

which would return a boolean value of true, for our example above.

If you had a list of particle IDs as keys and their speeds as values, and you were using
their speeds in some calculation, you could check to see if the particle was in the list be-
fore trying to call for its speed by saying:

if speeddict.has_key(part_id):
speed = speeddict[part_id]
# and then do your calculation

Otherwise you’d get an error message when attempting to use a non-existent key.

For dictionaries, the equivalent of the append command for lists is just an assignment
statement with a key value:

dict[key] = value
Overview
of Python Scripting in RF4
07

Remember that keys have to be unique, so if the key value already exists, then the previ-
ous value will just get overwritten by the above statement.

If you want to remove a key:value pair from a dictionary, you can use the del command
again:

del dict[key]

07.6. If you want to re-use sections of a script that do some useful thing, or even if you want
to shorten your main block of code to make it easier to work with, it’s often a good idea
Creating you
to create your own functions.
own functions
To do this, at the start of your script you place a statement that defines the function
name and list of arguments, then an indented block of script that are the tasks the script
achieves with the arguments you provide, and then a return statement to indicate the
end of the function.

A function definition statement starts with “def” and ends with a colon “:”.

A useful, simple example is a function that I like to use to output messages to the mes-
sages window, to let me know values of certain parameters during a simulation for debug-
ging and optimization purposes. I like to put in some formatting so it’s easier to read over
during or after the run, and it’s a pain to keep typing the formatting over and over again
in the script. So I create a function, called something simple like “output”, that contains
the formatting, and just requires the parameter and a bit of text. Let’s say I want to use
this in the events script for tracking things on a frame basis. Then at the start of the on-
SimulationFrame section we put this to create and define the function:

def output(infostring,value) :
scene.message(“ ===============”)
scene.message(infostring + “: “ + str(value))
scene.message(“ “)
return

Now in my script, whenever I want to see what the value of some variable is, let’s say
“myvar” which has a value of 3.0, I can just say:

output(“variable myvar is”,myvar)

and in the messages window we’ll see the formatted lines:

===============
variable myvar is: 3.0

In the case of the function above, it sends a message to the messages window but it
doesn’t return any value to you. If you want it to compute a value and return it for your
use, you just add that after the return (think of it as a command to return to you the
value). For example, imagine we want a function that takes an input vector, and multiplies
it’s length by some value and returns it. Here’s the function:
Overview
of Python Scripting in RF4
07

def multvec(vector,multval) :
magvec = Vector.new(multval*vector.x,multval*vector.y,multval*vector.z)
return magvec

And when I want to double the length of a vector in my script, called say myvectorvar, I
just say:

newvec = multvec(myvectorvar,2.0)

which is a lot easier to type frequently in your script than the fussy line of script in the
function.

If you accumulate some useful functions that you find you are using in many of your
scripts, you can turn them into your own module for importing rather than cutting and
pasting into all your scripts. To find out how to do this, check the Python documentation
that comes along with the download of Python from www.python.org.

07.7. To get a full list of the very large number of builtin functions available to you, check the
scripting reference documentation. I list here just a small subset of these commands,
A Selection of which are particularly useful to be aware of, and are worth a little extra explanation. In
Important addition I focus mainly on the classes scene, emitter, particle and vector, since these
Built-In RF4 are the most commonly used when dealing with fluid simulations and also contain some
of the more unique and noteworthy functions. The functions are separated according to
Functions their “class”, e.g. “scene” is a class and has a number of builtin functions particular to
it. In software engineering jargon you’d say that the function is a member of the scene
object class. If that is meaningless to you, forget it and just go on to check the usages
and think of these as commands, the same as you think of buttons on RF’s GUI. Worth
knowing, however, is that you always use a function or command in association with its
class object; even if you’ve renamed an object it still carries the functions of its class. For
example if an emitter in your scene is called a default name like “Circle01” and you call
on it in a script like this:

my_em = scene.getEmitter(“Circle01”)

then “my_em” is now an object in the emitter “class” and you can use all the emitter func-
tions with it, such as:

my_em.getParticles()

for getting the list of the particles so far emitted by Circle01. So, let’s say you have an
emitter in your scene called “fluid03”, and it currently has 300 existent particles. In your
script you could write:

myemitter_fluid = scene.getEmitter(“fluid03”)
particleslist = myemitter_fluid.getParticles()
scene.message(str(len(particleslist)))
scene.message(myemitter_fluid.getParameter(“Existent Particles”))

and what you’d see in the messages window is:


Overview
of Python Scripting in RF4
07

> 300
> 300

Meaning: the list variable particleslist contains the 300 particles currently existing in the
emitter.

Another important aspect of functions is that they can either calculate something and
return a value, or they can affect something. For example, scene.getObject(“object01”)
returns the object in the scene called object01, but doesn’t do anything to it. On the other
hand the vector function vector.normalize() returns nothing, and instead alters the vector
it is applied to. You need to be aware of which functions affect the object they are used on,
or you may inadvertently change something you wish to use later in original form.

Keep aware that the list below is just a subset, and although it covers a lot of very useful
functions, it leaves out many that are commonly needed. In particular you should check
out in the scripting reference what is available for objects (polygonal object geometries,
that is). Not only can you get and set attributes for the object as a whole, but you can
also import objects, create them vertex by vertex, and access many useful attributes of
their individual faces and vertices. These functions tend to be useful in more advanced ap-
plications, such as creating customized emission of particles from geomery or deforming
geometry via scripting, which is the main reason why they aren’t a focus here.

Common functions
Many of the RF scene object types come with the same functions, which have the same
usage for each type of scene object. Here are some you will probably use often:

object.getParameter(param_name_string) / object.setParameter(param_name_
string,value)

Any object that appears as a node in the node window of the GUI can have it’s param-
eters (shown in the node params window) accessed with these functions. This means
you can get any of these values to use in your script calculations, as well as set most of
them. The ones you cannot set via scripting are generally the same that you can’t set in
the GUI (e.g., in the statistics window for emitters). When you set a parameter, nothing
gets returned. When you get a parameter, that parameter (value and type of variable) get
returned. So, these are valid usages:

cube.setParameter(“Position”, Vector.new(1.0,2.0,0.0)) # sets the position of the


object you’re calling “cube” in your script
emres = myemitter.getParameter(“Resolution”) # gets the resolution of the emitter
you’re calling “myemitter” in your script, assigns the value to variable “emres”
currtime = scene.getCurrentTime() # assigns the current time value to a variable
“currtime”

getExportResourcePath(int) / setExportResourcePath(int,path)

These two functions work with any RF node for which you can export data, such as emit-
ters, meshes, RealWave surfaces and dynamically animated objects. You use them to set
the path to where you want the data written out to, and if you specify a directory that
doesn’t yet exist, they very conveniently create it for you. These are most useful in batch
scripts that do such things as automatically versioning scene files.

The “int” variable above can either be an integer signifying the order that the different
types of data format appear in Export Central, or you can use the all-caps built-in string
variables indicated in the documentation; the functions will understand both. The “path”
Overview
of Python Scripting in RF4
07

variable is a string that is the path leading to your data location.

For example, say we are creating a new version of a file and we want to write the data
from an emitter to a different folder than the default “particles” folder. Here’s what we can
type in our batch script:

emitter = scene.getEmitter(“Circle01”)
emitter.setExportResourcePath(1,”C:/rf_projects/myproject/particles_version02”)

so now the particles in .bin format (1 = first format in the list in Export Central, which are
.bin files) will be placed in the folder particles_version02 rather than in the default folder
particles.

Equally we could use:

emitter = scene.getEmitter(“Circle01”)
emitter.setExportResourcePath(EXPORT_PARTICLES_BIN,”C:/rf_projects/mypro-
ject/particles_version02”)

The built-in constant EXPORT_PARTICLES_BIN is not a string variable so don’t enclose it


in quotations; the path, on the other hand, is a string so it has to be enclosed in quota-
tions. Check the scripting reference for all available built-in constants under their object
types (e.g., for the variables relevant to meshes, look at the mesh scripting reference).
A nice way of keeping your data organized is to use this kind of function within a batch
script, that is set to run by hitting a button on the GUI. We’ll explore this task in Part II.

activeExportResource(int,bool)

This function again deals with the data your scene is exporting, and it allows you to acti-
vate or de-activate the export of that data. It gives you an ability to select via scripting the
data that is exported and is important in tasks such as initializing a scene exactly as you
want it, to minimize the chances of user errors. Experienced users of RF will know how
common it is to finish a long simulation, and then realize that no data was set to export.
By using the function above to activate the data export whenever a simulation begins, you
can make sure no such mistakes happen.

As an example, let’s activate the export of mesh data:

mymesh = scene.getMesh(“Mesh01”)
mymesh.activeExportResource(1,bool(1))

or you could type:

mymesh = scene.getMesh(“Mesh01”)
mymesh.activeExportResource(EXPORT_MESHES_BIN,bool(1))
In this function, the “int” can be either an integer indicating the order of the export
format type as seen in Export Central, or a built-in constant as given in the scripting
reference. The “bool” variable signifies a boolean quantity. Booleans are either true
(same as bool(1)) or false (same as bool(0)). If we typed:
mymesh.activeExportResource(EXPORT_MESHES_BIN,bool(0))
then we’d be de-activating the export of the meshes (so nothing would get saved
when we meshed our data).
Overview
of Python Scripting in RF4
07

Scene
You can think of the scene functions as the top level of scripting functions, or perhaps as
the “entry point” to accessing things in your scenes via scripting. This is part of the hei-
rarchical nature of objects in Python scripting. To get at any node in your scene, you first
have to refer to the scene to get the node, then you can access node parameters and any
objects that are “part” of that node. For example, to access the particles of an emitter, you
first use scene.getEmitter to get the emitter object, then use the emitter functions to get
the particles, and only then can you access the attributes of the particles. An exception
to this tree-like structure of access is within scripted daemons, where the script sections
are already aware of the emitter, so you can go skip “getting” the emitter and just start
accessing particles. For polygonal objects, you use scene.getObject to get the object, then
access the object’s faces and/or vertices by calling on object functions, and only then can
you find out the attributes of the faces and vertices.

A number of the scene functions can only be used in batch scripts, where they are very
important:

scene.load(path)

This loads the scene located by the path string “path”. You would use this in a batch script
to load a previously created scene file. We’ll do this as part of a versioning batch script in
Part II. Here’s 2 examples of usage:

scene.load(“C:\RF4\mytest\mytest.flw”)

or

directorypathstring = “C:\RF4\mytest”
scene.load(directorypathstring + “\mytest.flw”)

scene.save(path)

This saves the scene to the path “path”. You can use this either to overwrite the currently
open file or create a new version (with a new name).

scene.simulate(a,b)

This simulates the scene (rather than just playing it) from frame a to frame b. This is very
handy while testing scenes, if you just want to simulate a scene for 10 or 20 frames but
maybe want to grab a coffee rather than watch over your computer. In that case, just
open a batch window, type in the command and go to the menus of that window to se-
lect script>run; or type ctrl-enter. The other time this is useful is when you are running a
simulation involving scripts with long loops, like through a lot of particles. Stopping such
simulations can take a while if you use the escape button. But if you use the scene.simu-
late command, you can run exactly what you want.

scene.getCurrentFrame()

This returns the current frame that the simulation is on, and is useful in any script where
you want something to happen only for certain frames. This function takes no argue-
ments (leave the brackets empty); such functions have the brackets just because Python
requires it of any function.
Overview
of Python Scripting in RF4
07

For example, if we wanted to know how many particles an emitter had on frame 50, we
could put the following lines into an events script, in the onSimulationFrame section:

framenum = scene.getCurrentFrame()
if framenum == 50 :
myemitter = scene.getEmitter(“Circle01”)
scene.message(str(myemitter.getParameter(“Existent Particles”)))

scene.setCurrentFrame(a)

Jumps to frame a in the timeline. Useful in batch scripts.

scene.getCurrentTime()

Returns the current, exact time (sub-frame) of the simulation (not the true current time,
ie. your time of day). This is useful for calculating functions in your scripts that are time-
dependent.

As an example, imagine we want to control the speed of emission of an emitter, and to


have it increase in a linear way with time in the scene, such that the increases like twice
the time (at 1 second, speed is 2; at 6 seconds, speed is 12). In this case, we could put
the following script into the events script, within the onSimulationStep section:

scenetime = scene.getCurrentTime()
myemitter = scene.getEmitter(“Circle01”)
myemitter.setParameter(“Speed”,scenetime*2.0)

scene.getObject(name) / getDaemon(name) / getEmitter(name) / getMesh(name) /


getConstraint(name)

These commands return the objects they call for, at which point you can start using those
objects and getting or setting their attributes. Similar functions allow you to get lists of all
the objects, daemons, emitters or meshes in the scene.

scene.getRootPath()

When you need to set a different path for the output of simulation data, it can be ex-
tremely useful to be able to get the path to the scene that is currently open. We’ll use this
in Part II with a versioning script.

scene.getFileName()

As for the previous function, you would use this to get the name of the scene file, and
then could use the string that gets returned as the basis for creating new versions of the
file with slightly modified names.

scene.getAxisSetup()

This function is for somewhat more advanced applications where you want to write a
script that can be used by people who are using RF in conjunction with a different software
platform than your own. For example, if you use Lightwave, but want Maya users to be
able to use your scripts, you will probably need to take into account that the axis system
is different for the two platforms. If you don’t, then Maya users will find your special grav-
Overview
of Python Scripting in RF4
07

ity daemon points in a totally wrong direction. Using this function in your script, you can
check for the axis system and then set your vectors up correctly.

scene.loadEventsScript(path_string)

This function will load an events script from a .rfs file located by the path string you pro-
vide as an argument to the function. This is useful where you are running a batch script
that creates template RF scene files, and you need to be able to load in an events script.

scene.getAxisSetup()

This function determines which axis system you are using in your scene.

If you are familiar with RF, you’ll know that it is designed to be able to work with all the
most common 3D software platforms (Maya, Lightwave, 3DSMax, Cinema4D, Houdini,
Softimage XSI). These do not all have the same axis systems for 3D space, so in some
cases the y-axis is vertical, and in others the z-axis is vertical. You can see the choices
under file > preferences in the general tab.

Since your scripts will often involve vectors, it’s important to keep clear about which way
is up. Most of the scripting described in this user guide assumes we are working in the
Maya / Houdini / XSI axis system, where the y-axis is up, so a gravity force vector point-
ing vertically downward would be:

gravity_vec = Vector.new(0,-9.8,0)

but in the Cinema4D axis system where the z-axis is vertical this would be:

gravity_vec = Vector.new(0,0,-9.8)

Now if you are writing a script that you want other users to take advantage of, you need
to build in to your script an ability to set the vectors according to the axis system. The ge-
tAxisSetup function returns this to you, as one of 3 built-in variables (AXIS_SETUP_YXZ,
AXIS_SETUP_ZXY or AXIS_SETUP_YZX). In your scripts, you can use an if statement to
check which system your scene uses and then assign vectors accordingly.

Emitter
The emitter class of scripting functions is fundamental because it gives you access to in-
dividual particles, plus an ability to add and remove particles. Again the functions listed
below are only a subset of what’s available to you. For the complete list, see the scripting
reference manual.

emitter.getParticles()

This function returns a list of all the particles currently “inside” the emitter; that is, all
the particles so far emitted and still existing for the emitter. Once you get this list, you
can loop through it and apply forces or remove specific particles that meet criteria of your
choosing. The length of the returned list is the current number of particles. Each member
of the returned list is a particle object and thus open to use of the particle functions (see
the next section).

Note that, if you want to loop through the particles, it is better to make use of the internal
data structures by using the emitter.getFirstParticle() and particle.getNextParticle() func-
Overview
of Python Scripting in RF4
07

tions.

A typical usage would look like:

partlist = circle.getParticles()

emitter.getFirstParticle()

A function that returns the “first” particle of an emitter, for use when you want to loop
through an emitter’s particles as fast as possible. In reality, this turns out to be the last
particle emitted, but for looping purposes this really does not matter. The point is that it
makes use of the internal data structure for particles in RF.

Typical usage would be:

p = square.getFirstParticle()

emitter.getParticle(part_ID)

A function that allows you to obtain a particular particle when all you know is it’s ID value.
The usefulness of this function comes into play when you have filtered an emitter’s par-
ticles according to some criterion, and then want to keep in memory a subset of particles
in order to apply further calculations, perhaps at a later time or in another part of RF. You
could keep a list of particle objects, or you could keep a list of their unique IDs. Because
the ID’s are unique numerical values, they can also be used as keys in a dictionary, where
the values are some attribute of the particles.

emitter.getParticlesColliding()

In a scene where there are polygonal objects that the particles collide with, RF applies an
attribute to all particles that have just collided with any object to indicate it is a colliding
particle. This function allows you to quickly obtain the list of all colliding particles. This is
useful because often it is collision that forms the triggering event for further effects. For
example you may wish to spawn additional particles on collisin, or kill particles on colli-
sion, or convert them from one emitter to another.

It’s important to keep in mind that this list is highly ephemeral, and will only be valid for
a given colliding particle for (probably) 1 simulation step, for particles that bounce off ge-
ometry. In addition, this function will always return an empty list if the emitter is not set
to interact with the geometry in either the exclusive or global links windows.

For usage, see the next function.

emitter.removeParticle(ID_value)

A function for removing a specific particle from an emitter, where the argument is the
particle’s unique ID value. The most common place to use this is where you loop through
an emitter’s particles and, based on some criteria that you specify, you kill off a subset
of particles.

Adding or removing particles is a slightly risky proposition in a particle simulator where


the particles occupy volume and apply forces to their neighbours. This is because particles
can only be created or deleted in a discontinuous way; a particle is there on one simula-
tion step, and gone on the next. This can generate discontinuous or rapidly spiking forces
in the rest of the particle cloud and lead to large accelerations, which generally trends you
Overview
of Python Scripting in RF4
07

toward a loss of stability.

RF is designed for you to apply this function most stably in a scripted daemon, where a
specific section of the daemon is called when RF “judges” it is safest to remove particles
without losing stability. In fact, you can also apply this function in the scripted events with
a fair degree of confidence, since RF has sufficient stability to deal with particle deletion
quite well. However, if you are using this function and experience crashes in your simula-
tion, it could be a source of problem.

As an example, let’s say that you want to kill off particles on collision with geometry in
your scene. To do this in the onSimulationStep section of the events script, you could
write:

myemitter = scene.getEmitter(“Circle01”)
coll_list = myemitter.getParticlesColliding()
for particle in coll_list :
pid = particle.getId()
myemitter.removeParticle(pid)

Alternatively you could use a scripted daemon applied to the emitter, and in the function
for removing particles:

coll_list = emitter.getParticlesColliding()
for particle in coll_list :
pid = particle.getId()
emitter.removeParticle(pid)

Note that in the script above, I used “emitter” instead of the label “myemitter”. This is
because in the scripted daemon, within the functions (each section) the label “emitter”
represents whatever emitter the daemon is applied to.

An advantage of using the events script for this is that you could put the collision-kill script
in the onSimulationFrame section, and thus not run the script on every simulation step.
The result is that fewer particles are killed, but the scene runs faster.

If you are familiar with RF you probably know that you could just use a “native” RF colli-
sion daemon instead of a scripted one; the native daemons all run faster than equivalent
Python operations because of greater multithreading efficiency so this is always advisable
if you can. However, with the Python script you would then have the ability to add condi-
tions that cannot be incorporated into the native daemon. An example of this would be
add the condition that particles on collision be killed when they also have greater than
some threshold amount of force being applied. A major source of instability in RF are
particles that get caught between intersecting geometries and get squeezed until they
shoot off at huge velocities, and produce large forces on nearby particles. A script that
kills colliding particles that are getting overly “forced” will selectively remove problem
particles and thus act to increase stability. This is the kind of application where scripting
really shows its worth.

emitter.addParticle(position,velocity)

With this function you can add a particle to any emitter whenever you want, just by speci-
fying its position and velocity (both vectors). This allows you to script your own emitters
or supplement native emitters with additional particles added for custom conditions. To
make your own custom emitter, just add an emitter to the scene, set the properties, and
make the Max particles setting equal to 0. This means the emitter will not do any of the
usual particle emission, instead it will sit passively and act as a container for particles you
add. Any particle you add will have the properties (viscosity, density, resolution, surface
tension) of the emitter.
Overview
of Python Scripting in RF4
07

Even more so than for the emitter.removeParticle function, the addParticle function is
subject to causing instability because you can add particles anywhere you want. If you
happen to add a fluid particle right on top of another one, the two will feel huge forces
acting very suddenly and will probably shoot off at high speeds. If the emitter is dumb,
this doesn’t happen of course because dumb particles occupy no volume. But for all other
particle types, you can easily make your scene unstable.

There are two ways to ensure that particle addition is done stably: First, if you are re-
placing other particles with your added particles, you can delete the other particles while
adding the new particles at the same location and with the same velocity, and just need
to make sure that the new particles have the same or greater resolution than the originals
(same size or smaller). An example of this kind of particle addition will be given in Part II.
Second, you use the next function below to establish how safe it is to add a particle.

The addParticle function returns the particle object for you to make use of. So after adding
a particle, you can immediately call for its ID or other attributes.

emitter.testPositionForParticleInsertion(position,relaxfactor)

If you are adding particles to your scene according to some algorithm or reasoning you
are imposing, rather than replacing existing particles that are already simulating in a
stable way, then there’s a good chance your scene will go unstable because you’ll place
particles on top of one another. This function was designed to stabilize this process. For a
given emitter, you call it and indicate the position where you want ot place the new par-
ticle, and a “relaxfactor”. The factor should be a value between 0 and 1. Essentially, the
relaxfactor is a stability criterion, where 0.0 indicates that you require a stable result after
adding the particle, and 1.0 indicates you are willing to ignore the stability criterion. The
function returns a boolean value (True or False), where True means the particle position
passes the stability criterion for the given relaxfactor.

Normally, you will want the relaxfactor to be 0.0. However, if you must have particles
added somewhere, you can increase the relaxfactor and take a chance.

The usage for this might be:

if emitter.testPositionForParticleInsertion(posvec,0.0) :
emitter.addParticle(posvec,velocityvector)

Make sure you use the same emitter and same position vector in both statements.

emitter.createVoxelization(bool_value)

For all liquids except Dumb, RF creates an efficient data structure, described as “voxel-
ized”. If you have Dumb particles or if you are working with particles that have been load-
ed from a previously simulated sequence via a binary loader emitter, this data structure
will not exist. The function makes RF create the data structure. You apply this function
wherever you want to loop through a lot of particles, because the voxelized data struc-
tures make looping much faster -- usually by about a factor of ten -- then simply going
through a list of the particle objects.

However, remember that you don’t have to use it if you are working with fluid particles as
they are simulating, since they will already have a voxelized data structure.

The boolean value (True or False) simply indicates that RF must voxelize the data (True,
or bool(1)), or that RF will use an existing structure or create one if no data structure yet
exists (False, or bool(0)).
Overview
of Python Scripting in RF4
07

This function is usually called just before entering a loop through the particles.

Note that the voxelized data structure can be a dominant use of RAM in RF. RF sacrifices
RAM for speed, creating a faster structure by using more RAM. It does this by creating
a rectangular bounding box around the particle cloud and subdividing it, reserving RAM
memory for each subdivision. The size of the subdivisions depend on the resolution of the
emitter, and the amount of them depends on the volume of the box around the cloud. So
if you’re particles are widely dispersed, or you go to high resolution, you may find that the
above function pushes you through your workstation’s RAM limits very suddenly.

Particle
particle.getNextParticle()

An absolutely fundamental function that you will use again and again and again. It is
the statement that obtains the “next particle” in an emitter’s stream of particle data and
makes use of RF’s internal data structure, the fastest way to access large numbers of
particles. Here’s how you will use it in a loop:

myparticle = emitter.getFirstParticle()
while myparticle:
nextparticle = particle.getNextParticle()
# do things with the current particle
myparticle = nextparticle

Note that the .getNextParticle() function is called in the first line within the while loop.
This is the “safe” way to do it. If you happen to be deleting particles for some critical
condition, and you haven’t yet called for the next particle in the data sequence, when you
delete the current particle it’ll be lost from the data structure and you won’t be able to get
the next particle. So getting it early allows you to do whatever you want in the loop.

Do your best to avoid forgetting that last assignment statement where the current particle
gets assigned to be the next particle. If you do forget it, you’ll know it as soon as you start
to run your scene because that loop will be infinite and RF will hang -- it won’t crash, just
sit there looking like it is simulating but in fact just looping endlessly on the same particle.
It’s bound to happen to you so keep an eye out for the hang-up and then check all your
particle while loops.

particle.getPosition() / .setPosition(position)

These 2 functions are useful in many scripts where actions depend on where particles are.
An example is a scripted attractor daemon, where the particles are attracted to a particu-
lar point. For this daemon -- which we’ll create in Part II -- you have to determine a vector
from the particle to the point of attraction and to do this you need to know the particle’s
position. The setPosition function is less commonly used because forcing particles to a
particular position generally means you’ll be fighting forces that are trying to push the
particles around, so can lead to instability. But for dumb particles and under some condi-
tions, like keeping particles still and in a particular spot, this can be extremely useful.

The argument for the setPosition function is a position vector, which is the position you
want the particle to be.
Overview
of Python Scripting in RF4
07

particle.getVelocity() / setVelocity(velocity)

Another useful couple of functions, especially the getVelocity function because a particle’s
velocity is such a fundamentally useful piece of data. Using this, you can create all kinds
of useful scripts like scripted drag daemons, or kill daemons that act only when particles
exceed a certain velocity or move in a certain direction.

Like the setPosition function, the setVelocity function is less common and can lead to a
force conflict because forces in your scene will be pushing the particles to go a certain
speed, whereas this function sets the value. Best to use it sparingly.

The velocity argument for setVelocity is a vector representing the velocity you want the
particle to have. This vector will have a direction that you want the particle to be moving,
and a length reprensenting the speed of the particle.

particle.getNeighbors(radius)

This and the next function are two of the most interesting functions for particles in RF, be-
cause they allow you to filter particles according to whether they are close to the outside
of the particle cloud (the surface of the fluid). The getNeighbors function returns to you
a list of all the particles for the particle emitter, within the radius value you supply as an
argument. You can then do things selectively to the nearby particles, or if you want you
can just count how many neighbors there are and decide if the particle is relatively more
or less isolated in the fluid. Particles near the fluid surface, at corners, or splashing out
by themselves, will have fewer neighbors than those deep in the fluid. Using a threshold
radius value, you can find a subset of relatively isolated particles and do what you want
with them -- for example, you can delete relatively isolated particles. This makes a nice,
more controllable alternative to the built-in isolated killer daemon.

One important note to keep in mind: this function is relatively slow. Searching through the
particle data structure for the nearby particles takes some time and if your particle count
is high, this can really slow down simulations. Best to think carefully whenever you think
you need this, and if you decide you really do need it then attempt to optimize as much
as possible. For example, apply the search only for selective conditions, or only on a per
frame rather than a per simulation step basis.

particle.getNormal()

This function returns a “normal” vector for the particle. The normal vector for a particle
is analogous to the local gradient of particle density. For particles on the boundary of the
fluid, this vector points away from the interior of the fluid and has a length of about 1.0.
For more interior particles, the vector becomes less regular in direction and shorter in
length. The vector’s magnitude can work well as a sort of proxy for the nearest neighbor
count, but in practice it is somewhat less reliable / regular. If you need a measure of how
“surficial” the particles are, then this is a good (and faster) attribute to use before jump-
ing into the getNeighbors function.

vector
Vector objects are fundamental to most things you’ll do in scripting because you are work-
ing in 3D space, and commonly will need to work with vector quantities such as forces,
directions, normals and velocities. It’s important to get familiar with them. If you aren’t
sure what a vector is, check it out in the Appendix and if needed seek more information
on the web.
Overview
of Python Scripting in RF4
07

For scripting purposes, there are a number built-in Python functions that you need to
know about as you’ll often need them. These are:

Vector.new(xcomponent,ycomponent,zcomponent)

This creates and returns a new vector object with the component values provided as argu-
ments. Typical usage would be something like:

myvector = Vector.new(3.0,5.0,7.0)

You’ll see that you must have this function typed as Vector.new, with a capital “V”, other-
wise the Python interpreter will think you are referring to some variable called “vector”,
and it will become confused and give you an error message. You’ll know it’s correct when
the automatic highlighting illuminates the function as you type.

Note that for any vector object, if you want to retrieve any of the vector’s components
for use in calculations that require scalar quantities (a single value, rather than a set of 3
values like a vector), you can use just the functions:

vector.x
vector.y
vector.z

For example, say you want to print to the messages window the values of a vector’s com-
ponents, to check what the vector is. If you say:

scene.message(“The vector is: “ + str(myvector))

Then what you’ll see is something like:

>17:30:27: vector is:<RealFlow Vector object at 0x026AA128>

because the vector is an object, rather than a numerical value. Instead, you should write
something like this:

scene.message(“The vector is: “ + str(myvector.x) + “, “ + str(myvector.y) + “, “


+ str(myvector.z))

which will print:

>17:32:53: The vector is: 3.0, 5.0, 7.0

vector.module()

Module is another way of saying magnitude, and that’s what this function provides: the
length or magnitude of the vector it is used on. Unlike for Vector.new, this function will
take any vector variable, and there are no arguments. It simply returns the vector’s
length (the square root of the sum of the vector’s components). This is useful in lots of
situations, such as when you want to know the speed of an object; the speed is just the
length of the object’s velocity vector. Here are some examples of usage:

testvec = Vector.new(10.0,0.0,0.0)
testvecmag = testvec.module()
scene.message(str(testvecmag))

which prints:
Overview
of Python Scripting in RF4
07

>17:47:55: 10.0

Or you could do this:

length = Vector.new(2.0,4.0,1.0).module()
scene.message(str(length))

which prints:

>17:49:24: 4.58257569496

vector.distance(vector)

This function calculates the distance between two points in space, where the positions are
defined by “position vectors”. Position vectors go from the origin to a point in space (the
position). The function returns a scalar value (the distance).

Imagine you are creating a scripted attractor daemon, where the strength of the force is
proportional to the distance of the particle from some object in your scene. To do this, you
need the distance so you could write:

objectpos = myobject.getParameter(“Position”)
particlepos = particle.getPosition()
dist = particlepos.distance(objectpos)

and then you could use dist in some mathematical expression to determine the strength
of the force.

The distance function shortens the calculation from this version:

differencevec = objectpos - particlepos


dist = differencevec.module()

and of course if it wasn’t for the module function, the distance calculation would be even
longer...

vector.normalize()

A function that affects the vector with which it is used -- worth remembering. This function
takes a vector and “extracts” its magnitude, reducing the vector to a unit vector (length of
1.0) with the same direction as the original vector. You can think of this function as giving
you back just a direction, although what you are really getting is a vector with the same
direciton and length 1. Mathematically this function is dividing each component of the
vector by the vector’s original length. If you wanted to do this explicitly you’d type:

unitvector =
Vector.new(myvec.x/myvec.module(),myvec.y/myvec.module(),myvec.z/myvec.
module())

Remember that this function doesn’t actually return anything, it just normalizes the origi-
nal vector. If you wanted to preserve the original and have a variable with a normalized
version, do this:

unitvector = Vector.new(myvec.x,myvec.y,myvec.z)
unitvector.normalize()
Overview
of Python Scripting in RF4
07

Vector rotations
There are 3 functions that deal with vector rotations. These are useful for orienting ob-
jects and emitters, for example to target an emitter at a particular thing in your scene.
We’ll look at how to do this specific task in Part II. These functions allow you to get the
“Euler angles” to bring one vector into alignment with another vector (the Euler angles to
rotate a vector into alignment with another vector are equivalent to the rotation of nodes
given in the node params); to rotate a vector by a set of 3 Euler angles; and to rotate a
vector around another vector (used as an axis).

07.8. Given that you have various places where you can put scripts (events, daemons, batch,
realwave, fluid) it’s a logical question to ask where it is best to do certain things, and
Where to do also where certain things should definitely not be done. You’ll be pleased to know that
scripting tasks most scripting tasks can be performed in most scripting “areas”. There are however some
things that cannot; once you think about it a bit, you’ll understand why.

Particle Creation and Deletion


The best place for particle creation is in the events script. Ideally you should create par-
ticles in the onSimulationStep section because particle creation is already a discontinuous
process that will tend to encourage instability. Handling this at the substep level will help
stabilize the effects of adding particles. However, for a lot of substeps this can slow down
the simulation. It’s worth trying particle creation in the onSimulationFrame section and
seeing if you can get away with it, as that will mean the process will not happen every
substep.

Particle deletion, formally speaking, is safest done in the particle deletion section of a
scripted daemon. This is applied when it is most likely to be stable. However, this will be
applied every substep and again could be time consuming. In practice particle deletion
appears to be reasonably stable when done in the events script, in the onSimulationStep
and onSimulationFrame sections.

Force Application
Forces on both particles and objects are best applied in a scripted daemon. This produces
the most stable, smooth results. Trying anywhere else tends to lead to instability.

Creation and Moving of Objects


If you need to import or create objects, this is best done at the start of a simulation, be-
fore any real calculations happen. To do so, you can use the events script and the onSimu-
lationStart section, or a batch script prior to simulating anything. You can in fact import
or create objects in any scripting area, but if you do so during a simulation you need to
take care. Your object may get created on top of particles and that could lead to sudden
force spikes and unstable results.

Objects can be moved wherever and whenever you wish. The best place to do this in the
Overview
of Python Scripting in RF4
07

events script or batch script on a simulation substep basis, to keep things smooth and
stable. However you can usually just move things on a frame basis (onSimulationFrame).
If your objects move around very quickly, you’ll want to manipulate them in the onSimu-
lationStep section.

Initializing Settings and Global Variables


You can set parameters and initialize global variables anywhere you like, but the best
location is in a batch script prior to simulating, or in the events script in the onSimulation-
Start section. This sets things up prior to the simulation and ensures no awkward changes
in mid-simulation.

07.9. To most artists, scripting is scary stuff and it doesn’t help if you set up a simulation file
that’s run via complex scripts with bizarre variables and no documentation. When you
Making Scripts create scripts, try to make them so others could easily use them by imagining that you
Artist-Friendly are creating software tools for a production team -- if you’re working on a production,
there’s a good chance this is exactly what you are doing. The first rule when doing this is
to put explanatory comments into your scripts so others will have a chance to figure out
what is happening. The second rule is to give your variables non-crazy names, so people
will understand what they are. Below are a few more pointers on how to turn your scripts
from arcane jibberish to cool tools.

Control parameters: using global variables


No doubt your scripts will have some controlling parameters, like “magnitude” and “falloff
rate” for force daemons. If you are leaving the variable assignments within the script, you
should think about putting them all in one place, at the start of the script. I typically try to
list all of these with explanatory comments in the events script, in the onSimulationStart
section, and then initialize them all as global variables. Then in other scripting areas I
call for all the global variables and use them. For the user, to make changes in parameter
values they just have one place to go: the events script where the variables are assigned.
Otherwise, they have to know all the places where you’ve put scripts and variables.

As an example, imagine that we have a scene with a scripted daemon, which applies a
wind with strength “windstrength” to particles older than some age “agelimit”, and a grav-
ity daemon. Let’s set up the scene so the controlling variables are altered in one place so
we don’t have to open up multiple windows. The place to do this is in the events script, in
the onSimulationBegin section. This means any values will get initialized every time you
start the simulation, which is usually when you want them to be initialized.

In the onSimulationBegin section of the events script, we first create and assign values
to the variables; this is also where the user will go to revise the values for new test runs.
We’d type:

windstrength = 4.0
agelimit = 2.5
gravitymag = 12.0

then we create equivalent global variables and assign these to them:


Overview
of Python Scripting in RF4
07

scene.setGlobalVariableValue(“windstrength”,windstrength)
scene.setGlobalVariableValue(“agelimit”,agelimit)

When we go to run the simulation, these get set in a memory location accessible to all
other scripting areas. We don’t need to make a global variable for gravitymag because
we’re going to assign it right now.

To do so, we next add lines of script like this:

gravdaemon = scene.getDaemon(“mygravity”)
gravdaemon.setParameter(“Strength”,gravitymag)

So the value in our daemon gets set as soon as we start the simulation.

Next, we’d open the scripted daemon’s scripting window, and in the apply force to par-
ticles section we start the script by calling up the variables we need in the script:

windstrength = scene.getGlobalVariableValue(“windstrength”)
agelimit = scene.getGlobalVariableValue(“agelimit”)

and then proceed with the rest of the script that creates and applies the wind force.

Now we can run tests, and to make changes we can keep coming back to the events script
to make changes in just that location.

Using the GUI dialog


If you want to get more sophisticated about making your scripts user-friendly, take ad-
vantage of the GUIFormDialog object, another builtin RF object with its own set of func-
tions. This object is designed especially for you to get easy access to scripting values,
without being forced to open a script window. The functions allow you to create a simple
dialogue window that lists parameters and gives the user a chance to set values. These
values will then be accessed by your scripts.

To use this functionality, say for our example above, either in a batch script or the on-
SimulationBegin sectio of an events script, you could enter something like this:

myscriptinfo = GUIFormDialog.new()

This creates the GUI form object in memory, and assigns it to myscriptinfo. It does not
create (or show) the dialog on screen yet, that comes later.

Next we create the fields we want in the form:

myscriptinfo.addFloatField(“windstrength”,4.0)
myscriptinfo.addFloatField(“agelimit”,2.5)
myscriptinfo.addFloatField(“gravitymag”,12.0)

The numerical values following the variable names are just default values that will appear
in the dialog, to give the user a hint as to the sorts of numbers to put in. And finally we
show the dialog with a command that holds RF in a suspended state until the user hits
one of the buttons on the dialog:

if myscriptinfo.show == GUI_DIALOG_ACCEPTED :
myscriptinfo.getFieldValue(“windstrength”)
myscriptinfo.getFieldValue(“agelimit”)
Overview
of Python Scripting in RF4
07

myscriptinfo.getFieldValue(“gravitymag”)

And then you can follow up with the same global variable assignments as before, to make
these values accessible to the rest of RF.

Adding Your Own Batch Script Buttons to the RF GUI


When you’ve created a useful batch script that you are likely to re-use over and over
again, you can add the script to a user script library, and then run it using keyboard short-
cuts, place a button on the interface, or access it via the scripting>user menu. Check out
the manual documentation on how to do this, and access the script organizer window via
the scripting menu of RF.

Using Control Objects


This is a slightly more advanced way of making scripting parameters accessible to the
user via the RF GUI. The advantage of this method is that you can animate the param-
eters via the the curve editor just like anything else in RF. The disadvantage is that you
have to remember which parameters are which.

In this case, you can add a “dummy” object to your scene, for example a null or other
native object. Keep this object out of either links window since you probably don’t want
it to be part of the simulation. Now you use some of the object’s parameter fields, such
as the position or rotation fields, as holders for the parameters in your scripts. Then, in
the scripts, you just call for this object, and then call for the parameters and assign their
values to your script variables. It’s a simple process and just requires that you remember
that the x-position of object “null01” is the value of your scripted daemon’s wind strength.
This kind of arrangement can be (understandably) confusing to new users so if you use
this, be sure to carefully document how your scripts function.

07.10. When you download Python, it comes along with an array of “extra functions”, that come
Additional in convenient themed packages called “modules”. You can see what these are in the “mod-
ule docs” that come with the standard installation. In your scripts, it is simple to make use
resources: of the functions within any of these modules. For example, say you want to calculate the
importing cosine of an angle in your script. There’s no built-in function for this, to do it you need to
modules get access to a function in the math module. To get that, at the very start of your script
just type:

import math

Then, wherever you want to use the cosine function, just say:

value = math.cosine(anglevariable)

Any of the functions within the math module are accessed the same way.

Another very useful module is the one for generating random numbers: the random mod-
ule. This contains a very useful function called uniform that determines a random number
between two limiting values you provide as arguments:
Overview
of Python Scripting in RF4
07

import random

randomfactor = random.uniform(-2.0,6.0)

In this randomfactor will be a random number between -2.0 and 6.0. This is very useful
for adding random variations to things like particle positions or velocities.

07.11. On the CD you’ll find some quicktime movie clips illustrating what some more advanced
scripting can do. Below are brief descriptions of these. In some cases further details will
Some be given in production case studies.
inspiration:
examples of bubbletrail
scripting results Done for a Miller beer commercial where a CG ball had to be travelling fast through beer,
with an interesting trail of bubbles behind it a little like the bubbles behind a torpedo.

For this, a script was built that


- looked at the ball velocity and figured out which polys were facing backward (these were
then used as the particle emission surfaces)
- emitted “bubble” particles from the back faces, proportional to the ball speed and with
controllable biases in direction, parallel to face normals versus randomly

Also created was a force script that applies a toroid-shaped vortex force to the particles,
and that follows behind the ball, to generate the interesting propellor type motions.

Each script worked out to be 20 - 40 lines of code.

Time to develop the scripts, test and deploy to the pipeline: 1 - 2 days.

Foam
In this clip the emitter shoots “water” fluid particles into a tank, and the fluid pushes
around a cylinder. The cylinder motion is entirely dynamic, not keyframed.

Each frame, a script loops through all the water particles and checks to see if they should
become foam. Any water particle that goes faster than a given threshold, or has few
enough nearest neighbours, gets moved from the water emitter to a foam emitter. The
foam emitter is another emitter in the scene that has more foam-like qualities (higher
surface tension, lower density).

The script also tracks the foam particles, and when they get older than a given age they
get switched back to water. The result is a fully dynamic flux between water and foam,
like in real life.

The script for this took a couple days to get working right.
Overview
of Python Scripting in RF4
07

RBD triggering
Some cannon balls blast a brick structure.

The brick structure was built procedurally with a Python script that imported cube objects
and placed them in 4 walls.

A script runs in the background and keeps the dynamics toggle turned off for all the ob-
jects that are initially still. This keeps the sim fast, and means still objects don’t jitter.
The wall structures keep their stiff, rigid look, for example and the bricks don’t shiver and
interpenetrate.

When any object that has dynamics turned on, and is moving fast enough, gets suf-
ficiently close to any still object, the script turns on dynamics for that object. So as the
balls get close to the building, the nearest bricks get dynamics turned on, then adjoining
bricks to those.

There’s also a bullet time effect, which again is script controlled. Normally you can’t do
this kind of thing in a physical simulator, because stopping the calculations for a little
while, then turning them on again, usually results in all the objects losing their momen-
tum. In this case the script records the motions for each object as bullet time starts, then
gives those motions back to them as bullet time ends.

Smoke
Three scripted force daemons are applied to a simple fluid emitter pointed upward in a
“room”.

The main scripted daemon applies a shearing force in a direction opposite to each parti-
cle’s velocity, equivalent to the shear that’d be imposed by a surrounding, ambient fluid.
If we tried simulating this with a large volume of ambient fluid actually present, it’d take
ages to get a result. The scripted force daemon fakes the surrounding fluid very effective-
ly, creating ring-like, organic vortices which are dependent on the velocity of the particles,
not the direction the emitter is pointed.

The second scripted daemon is a wind force daemon that applies a force to the particles
only on the outside of the cloud. This is a far more realistic wind force, compared to just
applying the same force to all the particles even if they aren’t really in contact with the
wind.

The last scripted daemon being applied here is a gravity daemon with strength and direc-
tion varying with particle height, so the particles of smoke are buoyant until they get to
the upper half of the room, and then they get dense. This gives the nice vertically up and
then down motions of the particles and keeps the smoke more fluffy toward the ceiling,
rather than compressing it flat there.

Spray generation: originalsim, nn10cull, spray


This sequence shows what is possible in terms of increasing scale via post-simulation pro-
cesses, run through Python scripts. It shows the basics of a spray-generation technique
that was used for a couple of ocean-based feature films.

In originalsim, there is a basic fluid simulation of a fluid being dropped in a box.

In nn10cull, we replay the simulated data and a Python script loops through the particle
data, finds all those particles with a small number of nearest neighbours, and creates du-
Overview
of Python Scripting in RF4
07

plicates of these in another emitter (essentially writing out the data for an outer shell of
particles). These particles become the seeds that spawn spray particles in the final step.

In spray, the seed particles are input and thousands of dumb particles are generated from
them. In addition, the script detects collisions with geometry and generates a second set
of dumb particles for those, giving separate control on collision-related spray generation.
The randomness, quantity and directional magnification of the spray are all fully control-
lable. The seed creation and spray creation steps are very fast because there is no fluid-
particle simulation.

Spray particles start to look most real when their numbers get large, which is why a highly
optimized method was used. On production shots, fluid simulations of 5 - 15 million par-
ticles were used to create seed particle files containing tens of thousands to hundreds
of thousands of seeds in each frame. These were then used to spawn tens of millions of
spray particles per frame. The simulation, because of the complexity of fluid particle cal-
culations, can take a few days. The post-simulation steps have a turnaround time of a few
hours to a day on high-end workstations.
Scripting Task
examples in RF4
08

08.1. Simulation Tasks: Scripted Daemons


Simulation One of the most useful things about scripting in RF4 is that you can create your own
Tasks: Scripted tailored and completely controllable daemons to apply forces to particles or rigid bodies.
Daemons It’s still best to make use of the built-in daemons as much as possible because they will
almost always be faster, but you need not be limited to these.

In this section we’ll create two different daemons: an attractor daemon with custom fall-
off, and a daemon that kills particles that are inside simple objects. These kill daemon is
more advanced than the attractor, but you’ll see that both are actually quite simple once
you conceptualize how they work.

Custom Falloff Attractor


Let’s say that we want to attract particles toward a position (call it: attractpos), but only
if they are farther away than a distance distlimit, and then we want to tail off the strength
of the attraction in an exponential way, from a maximum strength of maxmag at the dis-
tlimit.

Exponential falloffs produce very natural looking, smooth behaviour in general so they
make a good choice. The advantage, by the way, of not applying any force to particles
when they get too close to the attractor is that they don’t get pressurized against each
other. In normal particle systems where the particles don’t “feel” each other, this doesn’t
matter. But in RF, where the beauty of the resutls relies on the particles interacting,
ramming particles against each other too violently can lead to long simulation times or
instability and very high forces and velocities, that tend to not look very good. This kind
of attractor behaviour, therefore, leads to better stability and better behaviour simultane-
ously.

Let’s get started.

First, either in a text editor of your choice or in the scripting window of a scripted daemon
(add one to your scene first if you are actually working within RF), within the apply force
to particles section, let’s put down the steps to achieve this effect as logical tasks. We’ll
then work out the scripting to do the tasks.

# for each particle in the emitter, get the distance between the particle
and the attractor position
# calculate the attraction strength based on the distance
# find the direction vector for the attraction force: the vector from the
particle to the attractor position (for attraction)
# apply the force

So now let’s expand on these steps and fill in some scripting. First, obviously we’ll need
the position of the attractor, so at the start of the script we get it by calling via the scene
function and store it in a variable:

attractdaem = scene.getDaemon(“Scripted01”)
attractpos = attractdaem.getParameter(“Position”)

If we’ve just added the daemon to the scene, it’ll be called Scripted01 in the Nodes win-
dow. If you want to call it something else, you can rename it but just be sure to also
rename it in the script.

Now we’ll have to get the particles and loop through them, getting the distance between
the attractor and each particle in turn. Like this:
Scripting Task
examples in RF4
08

# get the attractor daemon position


attractdaem = scene.getDaemon(“Scripted01”)
attractpos = attractdaem.getParameter(“Position”)
# for each particle in the emitter, get the distance between the particle
and the attractor position
particle = emitter.getFirstParticle()
while particle:
ppos = particle.getPosition()
apdist = ppos.distance(attractpos)
# calculate the attraction strength based on the distance
# find the direction vector for the attraction force: the vector from the
particle to the attractor position (for attraction)
# apply the force
particle = particle.getNextParticle()

That was a bit of a mouthful so let’s dissect it before going on. If you looked at Part I of the
scripting guide, you’ll recognize the “RF particle loop”, that is, the while loop that makes
use of RF’s internal, fast data structure for looping through particles of an emitter. Within
the loop, so for each particle in turn, we get the particle’s position (a position vector). We
then make use of the built-in function vector.distance(vector) to get the distance between
the particle and the attractor.

Another way to do this same thing would be to calculate the vector that goes from the
particle to the attractor, then calculate it’s length to get the distance. Since we have to get
the vector that points between each particle and the daemon to give the force a direction,
we have to do this anyway. So here’s how we can write that:

# get the attractor daemon position


attractdaem = scene.getDaemon(“Scripted01”)
attractpos = attractdaem.getParameter(“Position”)
# for each particle in the emitter, get the distance between the particle and the attractor
position
particle = emitter.getFirstParticle()
while particle:

ppos = particle.getPosition()
diffvec = attractpos - ppos
apdist = diffvec.module()
# calculate the attraction strength based on the distance
# find the direction vector for the attraction force: the vector from the
particleto the attractor position (for attraction)
# apply the force
particle = particle.getNextParticle()

So in this case we get the vector that points from the particle to the attractor as diffvec,
and calculate it’s length using the built-in function vector.module(). The value of apdist is
the same in both methods. If we didn’t need the direction, we could just go with the first
way.

If you aren’t sure whether diffvec points at the attractor or the particle, you should do a
quick check. I *always* do this check because in more involved calculations, you don’t
want this kind of thing to be the source of an irritating debugging session while a frantic
vfx supervisor stands at your side. Do the check by re-arranging the equation:

ppos + diffvec = attractpos

Thinking in terms of arrows, this says that if you go from the origin to ppos (along the
position vector to the particle), then go from the particle along the vector diffvec, you
should arrive exactly at the attractor daemon position. So, diffvec does represent a vector
pointing from the particle to the attractor. Sometimes to really make sure I will draw a
Scripting Task
examples in RF4
08

little diagram of the arrows.

Next, let’s write down the calculation for the strength of the force, which is an exponential
decay as a function of distance. This will look like:

forcemagnitude = maxmag*math.exp(-1.0*decayrate*(apdist-distlimit))

where I’ve used the exponential function in the Python math module, multiplied it by
our maximum value maxmag, created a decayrate variable for the rate of decay of the
magnitude with distance, and also offset the function from zero using the value distlimit.
Remember that within a distance of distlimit, we want the force to be zero. This kind of
conditional situation (distance greater than distlimit means one treatment, distance less
means another) always means you’ll need to apply some kind of conditional statement.
Here’s what that part will look like:

# get the attractor daemon position


attractdaem = scene.getDaemon(“Scripted01”)
attractpos = attractdaem.getParameter(“Position”)
# for each particle in the emitter, get the distance between the particle
and the attractor position
particle = emitter.getFirstParticle()
while particle:
ppos = particle.getPosition()
diffvec = attractpos - ppos
apdist = diffvec.module()
# calculate the attraction strength based on the distance
if apdist < distlimit:
forcemagnitude = 0.0
else:
forcemagnitude = maxmag*math.exp(-1.0*decayrate*(apdist-dis-
tlimit)) # find the direction vector for the attraction force: the
vector from the particle to the attractor position (for attrac-
tion)
# apply the force
particle = particle.getNextParticle()

We are almost done. The last step calculation step is to get the direction vector for the
force, and give it the magnitude we just calculated (forcemagnitude). To do this, we need
to normalize the vector pointing from the particle to the attractor so it has the same di-
rection but only length of 1, then multiply that by forcemagnitude to stretch the vector to
the right length. RF comes with a handy built-in function for normalizing vectors to unit
length, used below:

# get the attractor daemon position


attractdaem = scene.getDaemon(“Scripted01”)
attractpos = attractdaem.getParameter(“Position”)
# for each particle in the emitter, get the distance between the particle
and the attractor position
particle = emitter.getFirstParticle()
while particle:
ppos = particle.getPosition()
diffvec = attractpos - ppos
apdist = diffvec.module()
# calculate the attraction strength based on the distance
if apdist < distlimit:
forcemagnitude = 0.0
else:
forcemagnitude = maxmag*math.exp(-1.0*decayrate*(apdist-distlimit))
# find the direction vector for the attraction force: the vector from the
particle
# to the attractor position (for attraction)
diffvec.normalize()
force = Vector.new(forcemagnitude*diffvec.x,forcemagnitude*diffvec.
Scripting Task
examples in RF4
08

y,forcemagnitude*diffvec.z)
# apply the force
particle = particle.getNextParticle()

Remember that the vector.normalize() function acts on the vector, rather than returning
a normalized vector -- so diffvec goes from having a length equal to the distance from
the particle to the attractor, to having a unit length. Such “unit vectors” are very useful
because you can think of them as representing a pure direction. The Vector.new function
used above just allows us to create a new vector, and we use as arguments each compo-
nent of the unit vector diffvec multiplied by the forcemagnitude.

Finally, we use the built-in function for applying force to a particle:

# get the attractor daemon position


attractdaem = scene.getDaemon(“Scripted01”)
attractpos = attractdaem.getParameter(“Position”)
# for each particle in the emitter, get the distance between the particle
and the attractor position
particle = emitter.getFirstParticle()
while particle:
ppos = particle.getPosition()
diffvec = attractpos - ppos
apdist = diffvec.module()
# calculate the attraction strength based on the distance
if apdist < distlimit:
forcemagnitude = 0.0
else:
forcemagnitude = maxmag*math.exp(-1.0*decayrate*(apdist-dis-
tlimit))
# find the direction vector for the attraction force: the vector from
the particle to the attractor position (for attraction)
diffvec.normalize()
force = Vector.new(forcemagnitude*diffvec.x,forcemagnitude*diffvec.
y,forcemagnitude*diffvec.z)
# apply the force
particle.setExternalForce(force)
particle = particle.getNextParticle()

And we are finished. Well, not quite. There’s a couple of things to clean up. First, we used
the math.exp function so that means we need to import the math module, or the Python
interpreter will have no idea what we are referring to and give us an error. We also need
to define values for our controlling variables distlimit, maxmag and decayrate. This is best
done right at the start of the script so they are easy to find for revising the values as you
tweak the simulation. Lastly, we add a comment to explain what the script does so when
we open it a month from now, we won’t need to figure it out for ourselves:

import math
# this script applies an exponentially decaying force to particles as a
function
# of radial distance from the daemon, starting at a distance distlimit.
# Within distlimit, no force is applied.
distlimit = 2.0
maxmag = 10.0
decayrate = 1.5
# get the attractor daemon position
attractdaem = scene.getDaemon(“Scripted01”)
attractpos = attractdaem.getParameter(“Position”)
# for each particle in the emitter, get the distance between the particle
and the attractor position
particle = emitter.getFirstParticle()
while particle:
ppos = particle.getPosition()
diffvec = attractpos - ppos
apdist = diffvec.module()
Scripting Task
examples in RF4
08

# calculate the attraction strength based on the distance


if apdist < distlimit:
forcemagnitude = 0.0
else:
forcemagnitude = maxmag*math.exp(-1.0*decayrate*(apdist-dis-
tlimit))
# find the direction vector for the attraction force: the vector from
the particle to the attractor position (for attraction)
diffvec.normalize()
force = Vector.new(forcemagnitude*diffvec.x,forcemagnitude*diffvec.
y,forcemagnitude*diffvec.z)
# apply the force
particle.setExternalForce(force)
particle = particle.getNextParticle()

And that completes our scripted daemon. If you want to test it, just copy and paste the
above text into a scripted daemon’s scripting window in the section for applying force to
particles, and be sure to apply the correct indentation -- you’ll need to insert a single tab
at the start of each line of script. The daemon will apply to whatever emitter you link it
to, just like any built-in daemon. That’s why we just specified the generic “emitter” in
the emitter.getFirstParticle command; this emitter variable is indicated in the scripted
daemon’s scripting window in the first line of the relevant section.

Custom Object Killer


Quite often when building a scene, you’ll find that the built-in kill daemons don’t really
work well for you. You find you have some object in your scene that particles are finding
their way into, and you need to remove those particles from the scene, but the shapes
of the built-in daemons don’t fit well. The obvious solution everyone wants is to kill all
the particles that lie within some special-shaped object, that you fit to the critical area of
your scene. Previous to RF4, this was just something you imagined over coffee, now it’s
a reality.

We could get very sophisticated with this script and allow objects with complex shapes,
but let’s not -- the main reason for keeping it simple is that the more sophisticated ver-
sion is time consuming since you have to hunt through all the vertices of the killer object
for every particle, and more vertices means more time. Better to use a relatively low poly,
smooth object.

First let’s think through the principles. How can we know if a point (a particle position) is
inside an object?

Well, if we can identify what side of the object’s polygons the particle is on, we can say if
it’s inside. Fortunately, the polygons of objects have faces with normals, and so long as we
can figure out if the normal points generally toward or generally away from the particle,
we can make progress.

Imagine a smooth, closed object like a sphere with poly faces all pointing outward. A
particle on the inside will have not a single normal pointing toward it. If even a single one
points toward the particle, then we know the particle is outside. If it’s outside, then the
faces closer to the particle have normals pointing generally toward it; the faces on the
far side have normals pointing generally away. It’s the same on all sides of the object. So
there is how we can figure it out.

To figure out if a particular normal points generally toward or away, we need some crite-
rion that will say either yes, or no. Here we have a very handy tool: the dot product:

dotprod = vec1 * vec2


Scripting Task
examples in RF4
08

where I’ve written it as you would in Python in RF, using the built-in RF syntax. If you want
more background on the dot product, look it up on mathematics websites or textbooks.
In short, the dot product of two vectors gives the projection of one vector onto the other.
Said another way, it gives you the length of the component of one vector that is parallel
to the other vector. Or, said yet another way, it gives you a number that is the measure of
how parallel one vector is to the other. If vec1 and vec2 are normal to each other, the dot
product is exactly zero. If one of the vectors in the dot product calculation is a unit vector
(vector of length 1), then the dot product gives the component of the other (non-unit)
vector that is parallel to the direction of the unit vector. Keep this fact in your back pocket,
it comes in enormously handy in a lot of scripts. So, if we calculate a dot product between
a unit vector and some other vector, call it vec, and the result is a positive number, we
know that vec is pointing at least a little bit in the same direction as the unit vector. If the
result is negative, we know that vec points at least a little in the opposite direction.

If the unit vector in the calculation is the normal to an object’s face, we can use the dot
product to figure out to what side a particle lies, using:

dotprod = facenormalvec * norm2particlevec

where “facenormalvec” is the face’s normal vector, and “norm2particlevec” is the vector
that points from the face to the particle. If this is positive, the particle is “outside” the
face, if negative it is “inside” (if the normals point outward, otherwise it’s vice versa).

One last thing. In RF, each object vertex also has a normal which is the average of the
normals of the faces adjacent to it. It makes more sense to use the vertex normals
because first, there are fewer of them (faces share vertices) so we won’t have to loop
through so many things. Second, vertices have precise, easily retrievable positions we
can use to get the vector “norm2particlevec”, whereas for faces we’d have to decide on
how to get a position. We could for example calculate the face center position, but that
just adds calculations to our script and slows it down. I’ll use the vertex position in the
script below.

Now we have a criteria to decide, we can write our script. First write the tasks in order:

# loop through the particles of the emitter


# for each particle, loop through the killer object’s vertices and deter-
mine if the dot product is positive or negative
# if any one dot product is positive, the particle is outside and we do
nothing to it.
# otherwise, we remove the particle

Obviously we need a particle-type loop:

em = scene.getEmitter(“myemitter”)
particle = em.getFirstParticle()
while particle:
nextparticle = particle.getNextParticle()
# for each particle, loop through the killer object’s vertices and
determine if the dot product is positive or negative
# if any one dot product is positive, the particle is outside and
we do nothing to it.
# otherwise, we remove the particle
particle = nextparticle

Note that the first thing we did in the while loop was to define a variable “nextparticle” for
the next particle in the sequence. You have to do this if you might be killing off the cur-
rent particle, because once it’s gone from the data structure you won’t be able to use the
particle.getNextParticle() function (RF will have no idea what particle you’re referring to).
If you put the next particle into memory first, you won’t have any problems.
Scripting Task
examples in RF4
08

So now we have to loop through the object’s vertices. To do this, we should first get the
object and it’s list of vertices. That’s best done outside the loop to avoid doing it for every
particle, then add a loop that moves through the vertex list, for each particle:

em = scene.getEmitter(“myemitter”)
obj = scene.getObject(“killerobject”)
vertlist = obj.getVertices()
particle = em.getFirstParticle()
while particle:
nextparticle = particle.getNextParticle()
# for each particle, loop through the killer object’s vertices and
determine if the dot product is positive or negative
for v in vertlist:
# calculate the vector from the vertex to the particle
# get the dot product and check if positive or negative
# if any one dot product is positive, the particle is outside and
we do nothing to it.
# otherwise, we remove the particle
particle = nextparticle

Now you can see why our killer object needs to be quite simple and low poly, because we
have to cycle through all the vertices for every particle.

Next, let’s add the part we discussed earlier, about the dot product, and check it’s sign. If
the dot product is positive, we’ll switch the value of a variable called “flag”, which will get
used later to determine if we should kill the particle or not. Flag gets re-set to an initial
value of 0 for each particle, prior to entering the loop through the vertices.

em = scene.getEmitter(“myemitter”)
obj = scene.getObject(“killerobject”)
vertlist = obj.getVertices()
particle = em.getFirstParticle()
while particle:
nextparticle = particle.getNextParticle()
# for each particle, loop through the killer object’s vertices and
determine if the dot product is positive or negative
# set the flag value:
flag = 0
for v in vertlist:
# calculate the vector from the vertex to the particle
v2pvec = p.getPosition() - v.getPosition()
# get the vertex normal:
vnorm = v.getNormal()
# get the dot product and check if positive or negative
dotprod = vnorm * v2pvec
if dotprod > 0.0: flag = 1
# if any one dot product is positive, the particle is outside and
we do nothing to it.
# otherwise, we remove the particle
particle = nextparticle

Finally, we can use flag and kill, or not kill, the particle:

em = scene.getEmitter(“myemitter”)
obj = scene.getObject(“killerobject”)
vertlist = obj.getVertices()
particle = em.getFirstParticle()
while particle:
nextparticle = particle.getNextParticle()
# for each particle, loop through the killer object’s vertices and
determine if the dot product is positive or negative# set the flag
value: a value of 1 will mean the particle is inside.
Scripting Task
examples in RF4
08

flag = 1
for v in vertlist:
# calculate the vector from the vertex to the particle
v2pvec = particle.getPosition() - v.getPosition()
# get the vertex normal:
vnorm = v.getNormal()
# get the dot product and check if positive or negative
dotprod = vnorm * v2pvec
if dotprod > 0.0: flag = 0
# if any one dot product is positive, the particle is outside and we do
nothing to it.
# otherwise, we remove the particle
if flag:
em.removeParticle(particle.getId())
particle = nextparticle

In the if-statement, we’ve just used the fact that a value for flag of 1 is the same as a
“TRUE” boolean value, so we only have to write “if flag”, meaning if flag’s value is TRUE.

The only remaining question is, where do you put this script? Normal usage would be to
insert the script into a scripted daemon, in the remove particle section. That section gets
applied whenever the solver judges it “safe” to remove particles and still maintain stabil-
ity. However, daemons also get applied every substep -- that’s an awful lot of looping and
could really slow down the simulation.

As an alternative, and this is something to think about in all your scripts, it’s worth con-
sidering if we can achieve the same effect on frames, rather than simulation steps. I have
found that killing off particles is very stable and effective when placed in the events script
in the onSimulationFrame section. This means some extra time will be spent simulating
particles in the killer object between frames, but that process is generally quite fast. If
your scene has strict requirements that the particles get killed immediately upon entry
into the killer object, you’d have to apply it every simulation step.

08.2. With RealWave surfaces, a limitation has always been that your are “stuck” with the
wave patterns available to you in RealFlow: spectrum, fractal and control point motion.
Simulation Although you can create a wide variety of looks and some very nice water surfaces with
Tasks: Create these, you had to build the patterns through a combination that takes some time to de-
A Customized velop. Frequently in production projects, your 3D platform will have surface deformations
that are attractive and are often the look you are targeting with RealWave. With scripting
Wave Pattern in RF4, you can get precisely that height field into your RealWave. Here’s how.

To do this, we’ll be applying a scripted wave to a realwave surface -- “scripted” is now an


option when you add waves, along with spectrum, fractal and points. You’ll then be add-
ing the script to the scripting window accessed in the Node Params window of the scripted
wave.

First, you need to get the data in some format that’s useful to the scripting environment.
The simplest way to do this is to render out a series of images from your 3D platform,
ideally as greyscale bitmaps where the lightness will correlate with wave height. So for
example you can render out an orthographic view of a planar surface with a mapped on
animated noise texture. Or, you can use the orthographic view of an object that has an
animated deformer applied, or a displacement map, and render out a depth pass.

Let’s assume that you’ve rendered out a sequence of 100 images in targa format, and that
they are located on your hard drive here:
E:/rf_rd/test_scripted_displacement/perlin
Scripting Task
examples in RF4
08

and that they have names like:

noiserender_perlin.1.tga
noiserender_perlin.2.tga
noiserender_perlin.3.tga
...

(Note: if you are going to try doing this yourself, you’ll need to match the path and file
names to your own image sequence. A sample sequence is provided in the scene files, of
Perlin noise rendered out of Maya)

Here’s the conceptualized script to make this image sequence our source of realwave
surface deformations:

# get the image file corresponding to the current frame, and open it
# loop through the vertices of the realwave surface and find the pixel in
the image corresponding to each vertex
# get the intensity of the pixel and set that as the new height of the
vertex

To do this, you need to import a module for handling images, that is included in the RF4
installation or free to download from the web (search on PIL). Once you import that, you
have access to commands for opening and manipulating image files. After importing the
module, we need to get the image file corresponding to the current frame of the simula-
tion. So we say:

frame = scene.getCurrentFrame() + 1
# set the location of the images
filePath = “E:/rf_rd/test_scripted_displacement/perlin/noiserender_perlin.”
# open the image file for this frame
im = Image.open( filePath + str(frame) + “.tga” )

Next, we need to get some information about the image file, so we can map it to our
realwave surface. Basically, we need the image dimensions in pixels. Again the image
module contains commands for easily doing this: the image.size command that returns a
2 element list of the dimensions:

frame = scene.getCurrentFrame() + 1
# set the location of the images
filePath = “E:/rf_rd/test_scripted_displacement/perlin/noiserender_perlin.”
# open the image file for this frame
im = Image.open( filePath + str(frame) + “.tga” )
# get the image dimensions in pixels
imWidth = im.size[0]
imHeight = im.size[1]

Now, we loop through all the vertices of the realwave surface and map between the uvw
of the vertices (which goes from 0 to 1) to the corresponding pixel in the image:

frame = scene.getCurrentFrame() + 1
# set the location of the images
filePath = “E:/rf_rd/test_scripted_displacement/perlin/noiserender_per-
lin.”
# open the image file for this frame
im = Image.open( filePath + str(frame) + “.tga” )
# get the image dimensions in pixels
imWidth = im.size[0]
imHeight = im.size[1]
# loop through the realwave surface’s vertices, map to the image size and
Scripting Task
examples in RF4
08

get the corresponding


# uvw-mapped pixel
for i in range( 0, len( vertices ) ):
pixelX = ( imWidth - 1.0 ) * vertices[i].uvw.x
pixelY = ( imHeight - 1.0 ) * vertices[i].uvw.z
pixel = im.getpixel ( pixelX ,pixelY )

The returned variable called “pixel” is a vector whose first member contains the colour
intensity on a scale from 0 to 255. We can then normalize it’s value to get a value going
from 0 to 1, which we use to set the vertex height:

frame = scene.getCurrentFrame() + 1
# set the location of the images
filePath = “E:/rf_rd/test_scripted_displacement/perlin/noiserender_per-
lin.”
# open the image file for this frame
im = Image.open( filePath + str(frame) + “.tga” )
# get the image dimensions in pixels
imWidth = im.size[0]
imHeight = im.size[1]
# loop through the realwave surface’s vertices, map to the image size
and get the corresponding
# uvw-mapped pixel
for i in range( 0, len( vertices ) ):
pixelX = ( imWidth - 1.0 ) * vertices[i].uvw.x
pixelY = ( imHeight - 1.0 ) * vertices[i].uvw.z
pixel = im.getpixel ( pixelX ,pixelY )
# finally set the new vertex position
vertices[i] = Vertex.new( Vector.new( 0.0, pixel[0] / 255.0, 0.0 ) )

And that’s it. Just copy this script into a scripted wave and provide some images and a
correct path, and you’ll have your own customized realwave surface. Adjust the absolute
value of the wave height using the weight parameter in the scripted waves Node Params
window.

08.3. One of the most amazing things you can do with scripting is the creation of particles from
other particles. In previous versions of RF, this was entirely impossible. Now, for example,
Simulation you can do very nice simulations of things like fireworks. Let’s do a basic version here.
Tasks: Particle
Spawning The basic idea behind this script is to launch up a handful of particles (imagine these are
our fireworks rockets) and after some period of time we blow them up into a whole lot of
other particles that shoot out radially. We’ll do this by having one emitter that launches
the “rocket” particles, and once those particles get old enough we’ll kill them off but cre-
ate a load of new particles in a separate, dumb particle emitter.

Here’s the final script, which I used in the onSimulationStep section of the events script:

import random
childnum = 300 # number of children
childspeed = 5.0 # core child velocity
randfacspeed = 0.3 # random factor (%) on child velocity magnitude
agelimit = 1.0 # age limit, at which explode particles
randfacage = 0.4 # a random factor in the age limit
emsource = scene.getEmitter(“Circle01”)
emexplosion = scene.getEmitter(“Square01”)
p = emsource.getFirstParticle()
while p:
Scripting Task
examples in RF4
08

nextp = p.getNextParticle()
page = p.getAge()
pid = p.getId()
if page > (agelimit*(1.0+random.uniform(-1.0*randfacage,randfacage))) :
ppos = p.getPosition()
emsource.removeParticle(pid)
for i in range(0,childnum):
randvec = Vector.new(random.uniform(-1.0,1.0),random.uniform(-
1.0,1.0),random.uniform(-1.0,1.0))
randvec.normalize()
pspeed = childspeed*(1.0 + random.uniform(-1.0*randfacspeed,rand
facspeed))
pvel = Vector.new(pspeed*randvec.x,pspeed*randvec.
y,pspeed*randvec.z)
emexplosion.addParticle(ppos,pvel)
p = nextp

Now let’s dissect this script a little. First, we import the random module because we’re
going to use it to add a nice, natural randomness to our exploding particles.

After that, we set some parameters that control the simulation, such as the number of
exploded particles (“children” of the initial particles), the speed of child particle ejection,
the age at which the explosions happen, and some random factor limits.

Next, we get the emitters in the scene. The Circle01 emitter is the source of initial par-
ticles, the Square01 emitter is holder emitter to which we’ll use the script to add particles
to. This emitter has it’s max particles set to 0 in Node Params, so it won’t produce par-
ticles unless our script adds them.

Finally we loop through the particles of the source, and check the age of the particles. If
it’s bigger than the agelimit, we enter the rest of the loop. Note the if-statement’s use of
random.uniform, which allows us to apply a bit of a random factor to the agelimit every
time its called. This means not all the particles will explode at exactly the same time. If
you want that to happen, you should remove the the random.uniform command.

If our particle is old enough and we get into the inner part of the loop, we kill the source
particle, and then go into another loop that goes around once for every child particle we
want to create. To create particles, we have to assign both a position, and an initial veloc-
ity. We’ll set the position to be that of the source particle. For the velocity, we’ll generate
a random direction vector (randvec), and a speed (velocity magnitude) value that is based
on the childspeed value we set at the start, modified with another random factor to give
a more natural look. We then multiply the unit direction vector randvec by the magnitude
value pspeed to get the velocity we want to assign to the child particle, pvel.

It’s then just a matter of using the emitter.addParticle command to create the child par-
ticle.

In the example scene provided, there is also a scripted force daemon applied to the
source particles, which applies a vertical upward force that decays exponentially with par-
ticle height. This then acts like a kind of explosive force to launch the source particles.

08.4. One of the things it’s nice to be able to do with scripting is control the position and orienta-
tion of things in your scene. For example, you can use scripting to make an emitter target
Simulation an object. This is great when you want to keep blasting fluid onto something no matter
Tasks: Emitter what it does or how it’s keyframed animation might get changed.
Orientation
Let’s do a simple version here.
Scripting Task
examples in RF4
08

First, here’s the script:

em = scene.getEmitter(“Circle01”)
obj = scene.getEmitter(“Cube01”)
refvec = Vector.new(0.0,-1.0,0.0)
objpos = obj.getParameter(“Position”)
empos = em.getParameter(“Position”)
pointvec = objpos - empos
rotvec = refvec.getEulerAngles(pointvec)
em.setParameter(“Rotation”,rotvec)

As you can see, one of the great things about scripting is that you can achieve a lot with
just a few lines of code.

You can run this scene as it’s provided in the extra materials, but let’s dissect the script
first.

First off, we get the emitter and the object that we want the emitter to target.

Next, we create a reference vector, which gives the direction that the emitter produces
particles when it’s rotation is 0,0,0. You can see this as the direction the emitter arrow
points when you first add it to a scene, and for the circle emitter in Maya coordinates this
is straight down. We’ll use this as a reference vector to get the angles we have to rotate
the emitter to point it at the object.

Next we get the positions of the object and emitter, and create a vector called pointvec
that points from the emitter, to the object. This is the vector we want our emitter to point
along.

Then we determine the angles to rotate the reference vector to make it parallel to the
pointing vector pointvec, using the built-in function vector.getEulerAngles. Once we have
those angles, we just use them to set the rotation values of the emitter.

We used this script in the onSimulationStep section of the events script. Note that it will
let the object and emitter have animated positions and will still work fine.
09
Epilogue
We hope you have enjoyed the first part of the journey and we really wish that you feel
like you’re at the beginning of a long road with RealFlow, realizing the many possibili-
ties you have in front of you and you are willing to keep learning and progressing. Just
thinking: The fun is about to begin!

The Next Limit team has had a great time inviting you to discover RF4. And our efforts
are paid back tenfold by your excitement and will to learn.
There are several other resources where to learn more about RF4; from commercial
DVDs to tutorials all over the net. So do not forget why took the time to open this guide
and hold on to the curiosity and interest that keeps you improving.

All the best and good luck!

Next Limit Team

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy