176
RF 4 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

User Guide 1.1

Embed Size (px)

Citation preview

Page 1: User Guide 1.1

RF4User Guide v1.1Written by Next Limit Team

Beatriz Lorenzo BotellaJorge Medina Alix (tutorials 5, 7)Luis Miguel Mora (tutorials 4, 6)

and Fusion CI Studios

Mark Stasiuk

© Next Limit SL. 2006

Page 2: User Guide 1.1

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.

Page 3: User Guide 1.1

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

Page 4: User Guide 1.1

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

Page 5: User Guide 1.1

01WelcomeWelcome

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.

Page 6: User Guide 1.1

02Intro tourIntro tour

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 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.1.What is RF4?

Page 7: User Guide 1.1

02Intro tour

New fully customizable user interfaceRF4 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 workflowThe 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 processMore 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 solverThe 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 softbodiesSoft 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 toolsApart 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 systemThis 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 formatsApart 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 camerasRF4 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 surfaceRealWave 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 versionsRF4 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

Page 8: User Guide 1.1

02Intro 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...

We at Next Limit frequently hear the following question:Do I need to know physics and math to use the program?

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.2.Basic concepts

Page 9: User Guide 1.1

02Intro 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.

Page 10: User Guide 1.1

02Intro tour

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.

Ok, the reference point doesn’t have to be the corner 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.

Simulation and rendering stages of the same scene

The table can be located and described from the

corner of the room

Page 11: User Guide 1.1

02Intro tour

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.

Cartesian axes

Page 12: User Guide 1.1

02Intro 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.

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

Fluid colliding with some objects, rigid bodies and

soft body example

Page 13: User Guide 1.1

02Intro tour

properties to the entire cloud so that creating, con-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.

Cloud of particles simu-lating liquids

Page 14: User Guide 1.1

02Intro 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.

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

Mesh types:cloned geom-etry, m-polygons and

metaballs

A different use of a mesh

Page 15: User Guide 1.1

02Intro 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.

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

Thanks to the vertex maps, we can make wet-dry effects or map fluids.

Page 16: User Guide 1.1

02Intro 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

For those of you who do not have a clue 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).

Python is scripting the language in RF4.

Page 17: User Guide 1.1

02Intro tour

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.

Typical workflow scheme.

Page 18: User Guide 1.1

03Tutorials

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

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.

Splash window

Page 19: User Guide 1.1

03Tutorials

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.01 Project hierarchy

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.1.RF concepts

Online help.

Page 20: User Guide 1.1

03Tutorials

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.

Page 21: User Guide 1.1

03Tutorials

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.

03.1.02 Interface

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

Project files.

Containers

Page 22: User Guide 1.1

03Tutorials

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.

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.

Upper toolbar can be configured by right click-

ing on it.

Managing the view-ports

Page 23: User Guide 1.1

03Tutorials

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

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.

Right click on a viewport displays the RMB (right

mouse button) menu.

Page 24: User Guide 1.1

03Tutorials

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 emittersCtrl + 2 for daemonsCtrl+ 3 for native and imported objectsCtrl + 4 for constraintsCtrl + 5 for meshCtrl + 6 for cameraCtrl + 7 for RealWave

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.

Shading types.

Filters on the nodes list

Page 25: User Guide 1.1

03Tutorials

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.

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

Emitters’ list and some emitters

Page 26: User Guide 1.1

03Tutorials

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

Page 27: User Guide 1.1

03Tutorials

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.

Objects

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.

Mesh

Objects inside RF4

Page 28: User Guide 1.1

03Tutorials

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.

Constraints

Fluid surface

Page 29: User Guide 1.1

03Tutorials

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 old Scene Tree is gone forever, it has been replaced by two windows that function together with the Nodes 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

The gravity is affecting the red emitter while the

wind is affecting both emitters.

Page 30: User Guide 1.1

03Tutorials

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-

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.

Playback controls

Animating a parameter from the Nodes Param

window

Page 31: User Guide 1.1

03Tutorials

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

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 Editor

Curve Edition

Page 32: User Guide 1.1

03Tutorials

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,

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.

Nodes types in key-frames

Page 33: User Guide 1.1

03Tutorials

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.

Export central

RF4 gives visual clues when expoting a

simulation

Page 34: User Guide 1.1

03Tutorials

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

Page 35: User Guide 1.1

03Tutorials

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:

1. General: where we can state the FPS rate of 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.

Simulation options of the scene

Page 36: User Guide 1.1

03Tutorials

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.

Page 37: User Guide 1.1

03Tutorials

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.

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.

Preferences

Page 38: User Guide 1.1

03Tutorials

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

The FPS (Frames per second) rate can be set by the user. This means that we will be able

Preferences general tab

Page 39: User Guide 1.1

03Tutorials

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

Preferences general tab

Display Tab

Page 40: User Guide 1.1

03Tutorials

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

Backup Tab

Page 41: User Guide 1.1

03Tutorials

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.

Notify Tab

Export Tab

Page 42: User Guide 1.1

03Tutorials

Layout Tab

Set the Layouts folder and Default layout of your choice.

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.

Layout Tab

Undo Tab

Page 43: User Guide 1.1

03Tutorials

Getting started: Geysser

03.2.Getitng started:

A geyser

Objectives

In this first project we are going to create a scene of a jet of fluid that models 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.

Page 44: User Guide 1.1

03Tutorials

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.

Page 45: User Guide 1.1

03Tutorials

Getting started: Geysser

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

Different ways to rotate an element.

Particles do not fall down

Page 46: User Guide 1.1

03Tutorials

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

Page 47: User Guide 1.1

03Tutorials

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.

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.

Global links

Page 48: User Guide 1.1

03Tutorials

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

Page 49: User Guide 1.1

03Tutorials

Getting started: Geysser

Interaction

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

Now that we have an object in the scene, 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 afterBounce 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.

Global links window: everything’s interacting

Floor particle interaction parameters

Page 50: User Guide 1.1

03Tutorials

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

Page 51: User Guide 1.1

03Tutorials

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.

Page 52: User Guide 1.1

03Tutorials

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

Page 53: User Guide 1.1

03Tutorials

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.

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

File name options

Page 54: User Guide 1.1

03Tutorials

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.

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

water parameters/ spray parameters

Page 55: User Guide 1.1

03Tutorials

Getting started: Geysser

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

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

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

Random speed curve

Wetmap textures

Page 56: User Guide 1.1

03Tutorials

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

Page 57: User Guide 1.1

03Tutorials

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.

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.

Export central

Page 58: User Guide 1.1

03Tutorials

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.

Page 59: User Guide 1.1

03Tutorials

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.

Page 60: User Guide 1.1

03Tutorials

Fluids: Two glasses

Excercise objectives

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.3.Fluids:

Two glasses

Page 61: User Guide 1.1

03Tutorials

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

Page 62: User Guide 1.1

03Tutorials

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

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.

Tests with differentvalues for internal

pressure

Page 63: User Guide 1.1

03Tutorials

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!!!

Page 64: User Guide 1.1

03Tutorials

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

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

Global links

Page 65: User Guide 1.1

03Tutorials

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.

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.

Initial state

Reset to initial state

Page 66: User Guide 1.1

03Tutorials

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.

Page 67: User Guide 1.1

03Tutorials

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

Page 68: User Guide 1.1

03Tutorials

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.

Page 69: User Guide 1.1

03Tutorials

Meshes: Two glasses II

03.4.Meshes:

Two glasses II

Meshing, binary loader

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

Page 70: User Guide 1.1

03Tutorials

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

Page 71: User Guide 1.1

03Tutorials

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

Page 72: User Guide 1.1

03Tutorials

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,

Page 73: User Guide 1.1

03Tutorials

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?

Page 74: User Guide 1.1

03Tutorials

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.

Page 75: User Guide 1.1

03Tutorials

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.

Page 76: User Guide 1.1

03Tutorials

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

Page 77: User Guide 1.1

03Tutorials

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 buttonThis 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:

Page 78: User Guide 1.1

03Tutorials

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.

Page 79: User Guide 1.1

03Tutorials

Dumb particles and daemons: Twister

03.5.Dumb and daemons:

Twister

Objectives

In this project we are going to create a scene with an animated tornado that advances through space. This space can be some 3D model that we have constructed previously. 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 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)

Fig. 1

Page 80: User Guide 1.1

03Tutorials

Dumb particles and daemons: Twister

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

Fig. 2

Fig. 3

Page 81: User Guide 1.1

03Tutorials

Dumb particles and daemons: Twister

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

Fig. 4

Fig. 5

Page 82: User Guide 1.1

03Tutorials

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

Fig. 6

Fig. 7

Fig. 8

Page 83: User Guide 1.1

03Tutorials

Dumb particles and daemons: Twister

This is the result that we now obtain by hitting (see 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.

Fig. 9

Page 84: User Guide 1.1

03Tutorials

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)

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)

Fig. 10

Page 85: User Guide 1.1

03Tutorials

Dumb particles and daemons: Twister

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

Fig. 12

Page 86: User Guide 1.1

03Tutorials

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.

Page 87: User Guide 1.1

03Tutorials

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.

Page 88: User Guide 1.1

03Tutorials

Rigid bodies dynamics: Demolition of a bridge

Objectives

In this new exercise we will focus on the dynamics engine of RF4 and the new Stacking Options. We are going to create a scene where we can see an industrial chimney demol-ished by a ball.

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.6.Rigid bodies

dynamics: Demolition of a

bridge

Page 89: User Guide 1.1

03Tutorials

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

Page 90: User Guide 1.1

03Tutorials

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

Page 91: User Guide 1.1

03Tutorials

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.

Page 92: User Guide 1.1

03Tutorials

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.

Page 93: User Guide 1.1

03Tutorials

RealWave: Sailing boat

Objectives

In this project we are going to create a scene of a boat sailing through the sea on a swell, 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. 1Once 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.7.RealWave:

Sailing boat

Fig. 1

Page 94: User Guide 1.1

03Tutorials

RealWave: Sailing boat

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

Fig. 2

Fig. 3

Page 95: User Guide 1.1

03Tutorials

RealWave: Sailing boat

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 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)

Fig. 4

Fig. 5

Page 96: User Guide 1.1

03Tutorials

RealWave: Sailing boat

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

Fig. 7

Page 97: User Guide 1.1

03Tutorials

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

Page 98: User Guide 1.1

03Tutorials

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

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)

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-

Fig. 10

Fig. 11

Page 99: User Guide 1.1

03Tutorials

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 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)

Fig. 12

Page 100: User Guide 1.1

03Tutorials

RealWave: Sailing boat

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.

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

Fig. 13

Fig. 14

Page 101: User Guide 1.1

03Tutorials

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.

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

Fig. 15

Page 102: User Guide 1.1

03Tutorials

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.

Page 103: User Guide 1.1

03Tutorials

Soft bodies: Trampoline

Objectives

In the next exercise, we will set up a scene with Softbody and Rigidbody interactions. We 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.

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.8.Soft bodies: Trampoline

Fig. 11

Page 104: User Guide 1.1

03Tutorials

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.

Page 105: User Guide 1.1

03Tutorials

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.

Page 106: User Guide 1.1

04Connectivity

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

Page 107: User Guide 1.1

04Connectivity

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

Page 108: User Guide 1.1

04Connectivity

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.

Page 109: User Guide 1.1

04Connectivity

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.

Page 110: User Guide 1.1

05Appendix

05.1.Resources and

references

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. Reference is very important, and we really mean it. If you are working in CG graphics, we 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.

Page 111: User Guide 1.1

05Appendix

05.2.Expressions

library

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 of a parameter over time. The expressions are the representation of the values of the 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.

Page 112: User Guide 1.1

05Appendix

Unary functions

Page 113: User Guide 1.1

05Appendix

Page 114: User Guide 1.1

05Appendix

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.

Page 115: User Guide 1.1

05Appendix

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)

Page 116: User Guide 1.1

05Appendix

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)

Page 117: User Guide 1.1

05Appendix

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))

Page 118: User Guide 1.1

05Appendix

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.14*2*t)).

Hint: LMB= Left Mouse ButtonMMB= Middle Mouse ButtonRMB= 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.3.Shortcuts card

Page 119: User Guide 1.1

05Appendix

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

Page 120: User Guide 1.1

05Appendix

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.

Page 121: User Guide 1.1

06

Scripting in RF4by Mark Stasiuk

I am not a software engineer.

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.

06.1.Introduction

Page 122: User Guide 1.1

06

Scripting in RF4by Mark Stasiuk

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 you don’t have interferences with any other python installations.

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

06.2.Preliminaries:

Get Python

Page 123: User Guide 1.1

07

Overviewof Python Scripting in RF4

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 of RealFlow, you can control so much that you can easily make the package do things 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

07.1.Areas of

scripting in RF4

Page 124: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.

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-ation where your scripts aren’t doing what you expect.

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

07.2.Order of scripted

operations

Page 125: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.

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

07.3.Limitations

Page 126: User Guide 1.1

07

Overviewof Python Scripting in RF4

Generalities

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

07.4.Basics of

Python

Page 127: User Guide 1.1

07

Overviewof Python Scripting in RF4

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:

Page 128: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.0b = 5.0c = 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:

Page 129: User Guide 1.1

07

Overviewof Python Scripting in RF4

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)

Page 130: User Guide 1.1

07

Overviewof Python Scripting in RF4

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 = myveccalcvec.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.

Page 131: User Guide 1.1

07

Overviewof Python Scripting in RF4

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”)

Page 132: User Guide 1.1

07

Overviewof Python Scripting in RF4

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

Page 133: User Guide 1.1

07

Overviewof Python Scripting in RF4

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 multiplicationa = b * (c+d)

# priority, without brackets: multiplication is a higher priority than addition so is done firsta = 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.

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

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

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

07.5.Need to know Python: loops,

conditional statements, list

and dictionaries

Page 134: User Guide 1.1

07

Overviewof Python Scripting in RF4

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

Page 135: User Guide 1.1

07

Overviewof Python Scripting in RF4

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 loopi = 0particle = partlist[i]while i<len(partlist) :

# apply force to particlei = i + 1particle = 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

Page 136: User Guide 1.1

07

Overviewof Python Scripting in RF4

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 loopi = 0particle = partlist[i]windforce = Vector.new(0.0,0.0,5.0)

Page 137: User Guide 1.1

07

Overviewof Python Scripting in RF4

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

# fourth, RF internal data structure particle loopingparticle = 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 statementif [condition] :

# do some stuff

# an if - else statementif [condition] :

# do some stuff

else :

# do some other stuff

# an if - else if statementif [condition] :

# do some stuffelif [condition] :

# do other stuffelif [condition] :

# do yet other stuff

Page 138: User Guide 1.1

07

Overviewof Python Scripting in RF4

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

Page 139: User Guide 1.1

07

Overviewof Python Scripting in RF4

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

Page 140: User Guide 1.1

07

Overviewof Python Scripting in RF4

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 :

Page 141: User Guide 1.1

07

Overviewof Python Scripting in RF4

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:

1

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)

Page 142: User Guide 1.1

07

Overviewof Python Scripting in RF4

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

Page 143: User Guide 1.1

07

Overviewof Python Scripting in RF4

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]

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 to create your 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:

07.6.Creating you

own functions

Page 144: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.

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, which are particularly useful to be aware of, and are worth a little extra explanation. In addition I focus mainly on the classes scene, emitter, particle and vector, since these 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 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:

07.7.A Selection of

ImportantBuilt-In RF4

Functions

Page 145: User Guide 1.1

07

Overviewof Python Scripting in RF4

> 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 scriptemres = 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”

Page 146: User Guide 1.1

07

Overviewof Python Scripting in RF4

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

Page 147: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.

Page 148: User Guide 1.1

07

Overviewof Python Scripting in RF4

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-

Page 149: User Guide 1.1

07

Overviewof Python Scripting in RF4

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-

Page 150: User Guide 1.1

07

Overviewof Python Scripting in RF4

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

Page 151: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.

Page 152: User Guide 1.1

07

Overviewof Python Scripting in RF4

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

Page 153: User Guide 1.1

07

Overviewof Python Scripting in RF4

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 particlemyparticle = 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.

Page 154: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.

Page 155: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.xvector.yvector.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:

Page 156: User Guide 1.1

07

Overviewof Python Scripting in RF4

>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 - particleposdist = 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()

Page 157: User Guide 1.1

07

Overviewof Python Scripting in RF4

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

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 also where certain things should definitely not be done. You’ll be pleased to know that 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

07.8.Where to do

scripting tasks

Page 158: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.

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 create scripts, try to make them so others could easily use them by imagining that you 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.0agelimit = 2.5gravitymag = 12.0

then we create equivalent global variables and assign these to them:

07.9.Making Scripts Artist-Friendly

Page 159: User Guide 1.1

07

Overviewof Python Scripting in RF4

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”)

Page 160: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.

When you download Python, it comes along with an array of “extra functions”, that come 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 of the functions within any of these modules. For example, say you want to calculate the cosine of an angle in your script. There’s no built-in function for this, to do it you need to 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:

07.10.Additional resources: importing modules

Page 161: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.

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 be given in production case studies.

bubbletrail

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.

07.11.Some

inspiration: examples of

scripting results

Page 162: User Guide 1.1

07

Overviewof Python Scripting in RF4

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-

Page 163: User Guide 1.1

07

Overviewof Python Scripting in RF4

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.

Page 164: User Guide 1.1

08

Scripting Taskexamples in RF4

Simulation Tasks: Scripted Daemons

One of the most useful things about scripting in RF4 is that you can create your own tailored and completely controllable daemons to apply forces to particles or rigid bodies. 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:

08.1.Simulation

Tasks: Scripted Daemons

Page 165: User Guide 1.1

08

Scripting Taskexamples in RF4

# get the attractor daemon positionattractdaem = 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 positionattractdaem = scene.getDaemon(“Scripted01”)attractpos = attractdaem.getParameter(“Position”)# for each particle in the emitter, get the distance between the particle and the attractor positionparticle = emitter.getFirstParticle()while particle:

ppos = particle.getPosition()diffvec = attractpos - pposapdist = 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 forceparticle = 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

Page 166: User Guide 1.1

08

Scripting Taskexamples in RF4

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 positionattractdaem = scene.getDaemon(“Scripted01”)attractpos = attractdaem.getParameter(“Position”)# for each particle in the emitter, get the distance between the particle and the attractor positionparticle = emitter.getFirstParticle()while particle:

ppos = particle.getPosition()diffvec = attractpos - pposapdist = diffvec.module()# calculate the attraction strength based on the distanceif apdist < distlimit: forcemagnitude = 0.0else: 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 forceparticle = 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 positionattractdaem = scene.getDaemon(“Scripted01”)attractpos = attractdaem.getParameter(“Position”)# for each particle in the emitter, get the distance between the particle and the attractor positionparticle = emitter.getFirstParticle()while particle:

ppos = particle.getPosition()diffvec = attractpos - pposapdist = diffvec.module()# calculate the attraction strength based on the distanceif apdist < distlimit: forcemagnitude = 0.0else:

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.

Page 167: User Guide 1.1

08

Scripting Taskexamples in RF4

y,forcemagnitude*diffvec.z)# apply the forceparticle = 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 positionattractdaem = scene.getDaemon(“Scripted01”)attractpos = attractdaem.getParameter(“Position”)# for each particle in the emitter, get the distance between the particle and the attractor positionparticle = emitter.getFirstParticle()while particle:

ppos = particle.getPosition()diffvec = attractpos - pposapdist = diffvec.module()# calculate the attraction strength based on the distanceif apdist < distlimit: forcemagnitude = 0.0else: 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 forceparticle.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.0maxmag = 10.0decayrate = 1.5# get the attractor daemon positionattractdaem = scene.getDaemon(“Scripted01”)attractpos = attractdaem.getParameter(“Position”)# for each particle in the emitter, get the distance between the particle and the attractor positionparticle = emitter.getFirstParticle()while particle:

ppos = particle.getPosition()diffvec = attractpos - pposapdist = diffvec.module()

Page 168: User Guide 1.1

08

Scripting Taskexamples in RF4

# calculate the attraction strength based on the distanceif apdist < distlimit: forcemagnitude = 0.0else: 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 forceparticle.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

Page 169: User Guide 1.1

08

Scripting Taskexamples in RF4

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 particleparticle = 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.

Page 170: User Guide 1.1

08

Scripting Taskexamples in RF4

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 negativefor 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 particleparticle = 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 = 0for 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 particleparticle = 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.

Page 171: User Guide 1.1

08

Scripting Taskexamples in RF4

flag = 1for 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.

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. Although you can create a wide variety of looks and some very nice water surfaces with these, you had to build the patterns through a combination that takes some time to de-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 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

08.2.Simulation

Tasks: Create A Customized Wave Pattern

Page 172: User Guide 1.1

08

Scripting Taskexamples in RF4

and that they have names like:

noiserender_perlin.1.tganoiserender_perlin.2.tganoiserender_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 imagesfilePath = “E:/rf_rd/test_scripted_displacement/perlin/noiserender_per-lin.”# open the image file for this frameim = Image.open( filePath + str(frame) + “.tga” )# get the image dimensions in pixelsimWidth = im.size[0]imHeight = im.size[1]# loop through the realwave surface’s vertices, map to the image size and

Page 173: User Guide 1.1

08

Scripting Taskexamples in RF4

get the corresponding# uvw-mapped pixelfor 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 imagesfilePath = “E:/rf_rd/test_scripted_displacement/perlin/noiserender_per-lin.”# open the image file for this frameim = Image.open( filePath + str(frame) + “.tga” )# get the image dimensions in pixelsimWidth = 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 pixelfor 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.

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, you can do very nice simulations of things like fireworks. Let’s do a basic version here.

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:

08.3.Simulation

Tasks: Particle Spawning

Page 174: User Guide 1.1

08

Scripting Taskexamples in RF4

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,randfacspeed)) 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.

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 an object. This is great when you want to keep blasting fluid onto something no matter what it does or how it’s keyframed animation might get changed.

Let’s do a simple version here.

08.4.Simulation

Tasks: Emitter Orientation

Page 175: User Guide 1.1

08

Scripting Taskexamples in RF4

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.

Page 176: User Guide 1.1

09Epilogue

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