- Mastering openFrameworks:Creative Coding Demystified
- Denis Perevalov
- 2225字
- 2021-08-06 16:54:18
The basics of particle systems
Objects such as clouds and fire have no distinct shape, so it is hard to draw them using polygons. The novel method for drawing such objects was proposed by William T. Reeves in his article, Particle Systems—a Technique for Modeling a Class of Fuzzy Objects (ACM Transactions on Graphics, April 1983). The idea is in using particle systems, which are controllable sets of particles—small independently moving objects, considered as elementary components of the rendered object.
Today, particle systems play an important role in 2D and 3D computer graphics as a tool for photorealistic rendering of real-world fuzzy objects. Also, they are widely used for experimental and creative coding graphics.
Particles are independent objects that move according to some rules such as gravity, force, and friction. Each particle has a number of attributes such as position, velocity, lifetime, size, and color that changes with time.
The most important property of each particle system is an interaction type between the particles. It determines the kinds of objects and behaviors, which can be represented by the particle system, and designates methods of its physical modeling.
Interaction types
The frequently used interaction types are as follows:
- No interaction between particles: In this case, each particle can have a limited or an infinite lifetime. New particles can be generated from some point or region called emitter. Also, points can attract to or repel from some points or regions. This interaction type is appropriate for modeling sparse objects such as clouds, fire, traits, and also fireworks. Actually, this type was considered by William Reeves in his article and is considered later in this chapter.
You can play with a particle system consisting of a fixed number of particles with infinite lifetime in the openFrameworks example,
examples/math/particlesExample
. Use keys 1, 2, 3, and 4 for switching between several modes of the project; in these modes, particles will attract or repel from the mouse position, get attracted to some random points on the screen, or just fall like snowflakes. - Particles attract to and repel from other particles: In this case, the attraction and repulsion forces between two particles usually depend on the distance between them. For example, particles that are far attract, and particles that are closer repel. Such particle systems are used for modeling micro or macro physical systems such as molecules or galaxies and also for modeling the flocks.
Tip
Number of particles' pairs grow in a square law of particles' number. For example, if we have a particle system with 10,000 particles, there are 10,000 × 9,999 / 2 ~ 50 millions of particles' pairs. So performing direct calculations of all possible pairs' interactions is very inefficient, and methods such as geometric hashing are always used for computations' speedup.
- Particles interact in a complex way, indirectly, through some underlying nonstationary field. In this case, the field affects the particles' velocity, and (in some models) particles can affect the field itself. The most widely known example of such an interaction is fluid mechanics, modeled by the Navier–Stokes equations. Fluid mechanics is quite complex to implement and consumes a lot of computational resources, but it exhibits behaviors (that are impossible in simpler interaction types), such as vortices and turbulence. Particle systems using this interaction are widely used in 2D and 3D graphics for photorealistic modeling of smoke, water, and many other objects, and, of course, for experimental graphics.
Note
In openFrameworks, there exists an excellent implementation of fluid mechanics in an addon,
ofxMSAFluid
, by Memo Akten. You can download it from ofxaddons.com. See Appendix A, Working with Addons, for details on addons.
Particle systems are quite huge objects, so computing and rendering them can be a challenging task. In the next two subsections, we will consider various methods for doing it.
Computing particles' physics
Usually, each particle in a particle system is constantly moving. Hence, before each rendering step, we need to recompute the position, velocity, size, color, and other attributes using the chosen physical modeling method. The algorithmic complexity of such recomputing linearly depends on the number of particles.
For achieving high-quality graphics, particle systems should consist of thousands and even millions of particles. So computing particles' physics is often a resource-consuming task that affects the structure of the whole project. There are several schemas of organizing such computing. They are as follows:
- Single core computing: This performs all the computing in the
testApp::update()
function. This is the simplest method, which uses a single CPU's core. It lets us operate in openFrameworks with 10,000 to 40,000 particles at 60 FPS. This method is used in projects where the number of particles is in the specified range. Also, it is often used for prototyping a project. - Multiple core computing: This divides a particle system into several smaller subsystems and processes each of them in a separate thread. The operating system automatically distributes the threads' execution among all the available CPU's cores. This is the simplest way for revealing the power of all your CPUs' cores and to speedup the calculations. For doing this in openFrameworks, use the
ofThread
class (see its usage in openFrameworks' example,examples/utils/threadExample
).The speedup in this case highly depends on a number of available cores and the speed of a separate core. A typical PC has 4 to 16 cores working at 2 to 3 GHz, and the Intel Xeon Phi coprocessor has 60 cores working at 1 GHz. So, in principle, it is possible to compute a million particles in real time.
Until now we have considered CPU-based methods. All other methods are GPU-based and let us operate easily with 100,000 to 1,000,000 particles (depending on the video card). Let us see these methods:
- Using vertex shaders: We use this to set the initial positions of particles in the
ofMesh
object and then apply the vertex shader for changing its position in time. This method is simple and works fast but is limited. It creates non-interactive particles that fly just by predefined trajectories (specified by the vertex shader). See Chapter 7, Drawing in 3D, and Chapter 8, Using Shaders, for details on theofMesh
class and shaders.Note
It is possible to create interactive particles that change trajectories depending on the changing control parameters (such as the attractor position). To do it, you need to use a vertex shader with OpenGL's Transform Feedback feature.
- Using fragment shaders: This is used to represent each particle by a pixel in texture. For example, four color components (red, green, blue, and alpha) can hold the x and y coordinates of position and velocity of a particle. We then use a fragment shader for the corresponding processing pixels of the texture using the Ping-Pong FBO method. This method is quite simple, works fast, and can be used for computing particles without interaction and for moving particles in the fluid mechanics model (without computing the field). If you need to use more parameters for representing a particular particle, just use several textures. Each texture gives four additional float parameters.
Such a method is implemented in the openFrameworks' example,
examples/gl/gpuParticleSystemExample
. - Using compute shaders: Compute shaders are used for universal computations, and they let you perform advanced particles' modeling. See a demonstration of this technology at Stan Epp's video at youtube.com/watch?v=jwCAsyiYimY. The description of this video contains a link to the project's source codes.
- Using other GPU technologies: Most advanced GPU-based technologies are OpenCL and NVIDIA CUDA. You can use them for performing the most complicated computations. Note, if you are a novice in these technologies, adopting them in the openFrameworks project can require some effort from you.
Rendering particles
Visually, a particle system is a large number of small homogeneous objects called particles, which are drawn using different color and size but have quite a simple shape. There are several ways to render a particle system on the screen:
- Drawing each particle as a primitive (circle, triangle, or star): We do this by using functions such as
ofCircle()
orofTriangle()
. This way is the simplest, but works slowly, because each drawing command is sent separately in the video card. This method performs well only when the number of particles is small (from 1,000 to 10,000, depends on a video card). - Drawing each particle as a sprite: Here we use one image or array of images having the type
ofImage
orofTexture
(see Chapter 4, Images and Textures). They represent all possible particles' shapes. We draw each particle using theimage.draw( x, y, w, h )
function. This method is as slow as the previous one, but the resulting picture can be more expressive because it lets you create complex and blurred shapes. Also it is possible to use image sequences for creating animated particles such as flying moths (see the Using image sequence section in Chapter 5, Working with Videos). - Drawing each particle as a sprite: We do this using
ofMesh
orofVboMesh
(See details on usingofMesh
andofVboMesh
in the Using ofMesh section in Chapter 7, Drawing in 3D). Compared to the previous methods, this method works much faster because all the drawing commands are stored in a single array and are sent to the video card at once. Using this method, you can draw 10,000 to 1,000,000 particles (depends on the video card).In this method, you need to tile all the desired particles' images in one "big" image, and then use the
mesh
object for representing all the particles as quads with specified texture coordinates. Note, in this method, you need to specify four quad corners for each particle, which is a CPU-consuming task.
All the preceding methods can be used with CPU-based computing methods (single-core computing and multiple-core computing). Now we will consider the two most powerful methods that can be used successfully used with all the described methods of computing:
- Using point sprites: Point sprites is a method of drawing images by specifying only their center. Compared with using quads (described in previous item), it is a simple and also an efficient method but is limited by its expressive capabilities, for example, you cannot use different images for particles and rotate them. Though, you can change the size and color of the particles, which is enough in many projects.
See openFrameworks' example,
examples/gl/pointsAsTextures
, where this method is used for drawing particles with different sizes. (For changing sizes, it uses a vertex shader; see details about shaders in Chapter 8, Using Shaders). - Using a geometry shader: This method is as fast as point sprites but is free of its limitations—you can draw particles using different sprites and rotate them. In this method, you represent each particle as a vertex and specify its needed attributes such as the drawing position, index of using sprite, color, angle and size and then pass it in the geometry shader. (You can pass a particle's velocity too for affecting the shape of the particle on the screen.)
The shader translates each particle in a quad that is rendered on the screen.
Note that a geometry shader can also draw particles not as sprites but as shapes consisting of a number of lines (for example, stars) and constantly change their shape for obtaining vivid particles. See an example of using the geometry shader in the The furry carpet example section in Chapter 8, Using Shaders.
Creating a particle system – summary
Let's sum up all the described categories of interaction, modeling, and drawing. To make a project which draws a particle system, you need to specify its properties:
- Particles interaction type: This property checks whether the particles are independent (fire and clouds), interact with each other (flocks), or interact via some underlying field (liquid).
- Visualization: This property lets you define how a particle will be drawn—as a geometrical shape or a sprite—and how the particle's view should change during its lifetime (shape, color, size, and so on).
- A desired order of the particles' number: This property lets you set a desired order of the particles' number as 1,000 to 10,000, 10,000 to 100,000, 100,000 to 1,000,000, or more.
Having prepared this list, you should choose appropriate methods for physics computing and visualization:
- 1,000 to 10,000 particles with simple physics can be calculated using a single CPU core and rendered with simple methods (using
ofCircle()
,ofTriangle()
, orimage.draw()
) - 10,000 to 100,000 can be calculated with CPU too (using single or several cores) and rendered using
ofMesh
- For 100,000 to 1,000,000 particles and (or) complex physics, you definitely should use the GPU methods for computing and rendering
Tip
If your particle system is big and complex, before implementing it, we strongly suggest creating its prototype with several thousands of particles for debugging basic physics by using a single CPU and simple drawing.
In the rest of the chapter, we will implement a simple but fully-featured particle system consisting of several thousands of particles. These particles will be independent, and we will compute them using a single CPU's core and draw them as circles.
The aim of this project is in exploring the beauty of patterns, generated by a particle system, having a circular symmetry. The style of particles' behavior and a set of control parameters is taken from our Kuflex's project, Abstract Wall (see kuflex.com for details about this project).
Let's begin with modeling and drawing just one particle.
- Fundamentals of Linux
- Big Data Analytics
- Python數據可視化之Matplotlib與Pyecharts實戰
- 名師講壇:Spring實戰開發(Redis+SpringDataJPA+SpringMVC+SpringSecurity)
- Unity Game Development Scripting
- 深入淺出Go語言編程
- Spring技術內幕:深入解析Spring架構與設計原理(第2版)
- Kotlin極簡教程
- Kotlin進階實戰
- Android高級開發實戰:UI、NDK與安全
- H5頁面設計與制作(全彩慕課版·第2版)
- C#網絡編程高級篇之網頁游戲輔助程序設計
- Python程序設計現代方法
- HTML 5與CSS 3權威指南(第4版·下冊)
- Test-Driven Java Development(Second Edition)