Efficient Simulation of Fluid Dynamics in a 3D Game Engine
Transcription
Efficient Simulation of Fluid Dynamics in a 3D Game Engine
Efficient Simulation of Fluid Dynamics in a 3D Game Engine ROBERT BONGART Master of Science Thesis Stockholm, Sweden 2007 Efficient Simulation of Fluid Dynamics in a 3D Game Engine ROBERT BONGART Master’s Thesis in Computer Science (20 credits) at the School of Engineering and Business Management Royal Institute of Technology year 2007 Supervisor at CSC was Olle Bälter Examiner was Lars Kjelldahl TRITA-CSC-E 2007:018 ISRN-KTH/CSC/E--07/018--SE ISSN-1653-5715 Royal Institute of Technology School of Computer Science and Communication KTH CSC SE-100 44 Stockholm, Sweden URL: www.csc.kth.se Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Efficient Simulation of Fluid Dynamics in a 3D Game Engine Abstract This thesis deals with the efficient simulation of Computational Fluid Dynamics (CFD) into a realtime 3D graphics engine by discussing the development of the C’Nedra virtual reality game engine project carried out at Ecole Centrale Paris. The thesis tries to somewhat bridge the gap of theoretical papers of CFD algorithms by implementing Jos Stam’s stable method for fluid effects in 3D with the C’Nedra plug-in framework and simulates fire and smoke. I find that my CFD implementation in the C’Nedra game engine gives decent results in terms of realism however mediocre results in terms of performance. Hence, I conclude that the engine is in many ways not mature for the implementation of CFD. Effektiv simulering av flödesdynamik i en 3D spelmotor Sammanfattning Examensarbetet behandlar effektiv simulering av datorbehandlad flödesdynamik i en 3D grafikmotor genom att diskutera utvecklingen av spelmotorn C’Nedra på Ecole Centrale Paris. Uppsatsen försker genombrygga klyftan mellan teoritiska uppsatser om datorbehandlad flödesdynamik genom att implementera Jos Stam’s stabila algorithm för flödes dynamik i 3D med hjälp av C’Nedra plug-in klasser och simulera eld och rök. Jag finner att min implementaion av datorbehandlad flödes-dynamik i C’Nedra ger godkända resutlat i termer av realism, men dåliga resutlat i termer av effektivitet. Jag drar därför slutsatsen att C’Nedra inte är en mogen plattform för att implementera flödesdynamik. Simulation efficace de mécaniques fluides dans un moteur de jeux 3D Résumé Cette thèse traite l'exécution et simulation efficace de la mécanique de fluides dans le moteur en temps réel des graphiques 3D en discutant le développement du projet virtuel de moteur de jeu de C'Nedra mis à exécution à Ecole Centrale Paris. Je constate que le moteur de jeu C'Nedra est de beaucoup de manière pas suffisamment robuste pour l’utilisation de mécaniques de fluides. Je mis en forme la méthode stable de Jos Stam pour les mécaniques de fluides en 3D avec le système de plug-in en C’Nedra et simule la dissipation de gaz et feu. Je trouve que m’implémentation de simulation de mécanique de fluides numerique en C’Nedra donne de résultats suffisantes en termes de réalisme, mais mauvais en termes de efficacité. Alors, je fais la conclusion que C’Nedra n’est pas un logiciel bien construit pour implémenter les mécaniques de fluides. Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Acknowledgement I would like to dedicate this thesis to my beloved family: my late mother Urszula and my dear father Krzysztof. They have supported me, not only during the writing of this thesis, but also through my entire educational path in life. Without their inspirational and loving support, I would not have accomplished any of it. Secondly, I would like to thank my advisors Olle Bälter at The Royal Institute of Technology and Patric Callet at Ecole Centrale Paris for their support and guidance. I would also like to thank Sébastien Candel for his excellent course in Fluid Dynamics at Ecole Centrale Paris. Third, I want to thank my fellow students Francois Foucart, Patrice Laidet and Fabrice Larcher who all contributed to the project at ECP as well the VIA Centrale Réseaux association. Finally, I would like to thank my girlfriend Karin in Stockholm who stood up with me the last months during the writing of this thesis. I want to dedicate this thesis to my mother who always wanted me to be successful and who introduced me to computers in general. Below is a poem about life in memory of her: Life is but a stopping place, A pause in what's to be, A resting place along the road, to sweet eternity. We all have different journeys, Different paths along the way, We all were meant to learn some things, but never meant to stay... Our destination is a place, Far greater than we know. For some the journey's quicker, For some the journey's slow. And when the journey finally ends, We'll claim a great reward, And find an everlasting peace. Table of Contents 1 Introduction........................................................................................................................................... 1 1.1 General Introduction................................................................................................................................... 1 1.2 Background and Purpose............................................................................................................................ 2 1.3 Work Performed .......................................................................................................................................... 2 1.4 Problem statement....................................................................................................................................... 2 1.5 Outline........................................................................................................................................................... 3 1.6 Target Audience ........................................................................................................................................... 3 1.7 Delimitations ................................................................................................................................................ 3 2 Game Engines.......................................................................................................................................4 2.1 What is a Game Engine?............................................................................................................................. 4 2.2 Background of Game Engines................................................................................................................... 4 2.3 Game Engine Functionality and Design................................................................................................... 5 3 C’Nedra Game Engine..........................................................................................................................6 3.1 Background................................................................................................................................................... 6 3.2 History and Evolution................................................................................................................................. 6 3.3 Functionality and Design ............................................................................................................................ 6 3.4 Kernel ............................................................................................................................................................ 7 3.5 C’Nedra Plug-ins.......................................................................................................................................... 8 3.6 Graphics Engine (3D plug-in).................................................................................................................... 8 3.6.1 Scene Management ............................................................................................................................................ 9 3.6.2 Rendering pipeline ........................................................................................................................................... 10 3.6.3 Lighting.......................................................................................................................................................... 11 3.6.4 Texturing ....................................................................................................................................................... 12 3.6.5 Shadowing ...................................................................................................................................................... 14 3.6.6 Shaders........................................................................................................................................................... 14 3.7 Physics Engine (World plug-in) ............................................................................................................... 14 3.7.1 Mesh Loading................................................................................................................................................. 14 3.8 Terrain Engine (Terrain plug-in).............................................................................................................. 17 3.8.1 Height Field Approach ................................................................................................................................... 17 3.8.2 Importing Pre-Generated Terrain Meshes......................................................................................................... 17 3.8.3 Artificial Terrain Generation .......................................................................................................................... 17 3.9 Artificial Intelligence Engine (AI plug-in) .............................................................................................. 18 3.10 Multimedia Engine (Sound plug-in) ........................................................................................................ 20 3.11 Interface management (Interface plug-in) .............................................................................................. 20 3.12 Scripting (xml plug-in)............................................................................................................................... 20 3.13 User Driven Data....................................................................................................................................... 20 3.14 Editors ......................................................................................................................................................... 21 3.15 Special Effects (special-effects plug-in)................................................................................................... 21 3.16 Summary of Features implemented in C’Nedra during thesis work ................................................... 22 4 Theory of Fluid Substances ................................................................................................................ 23 4.1 Definition of Fluid Substances................................................................................................................. 23 4.2 Perception of Fluid Substances................................................................................................................ 23 4.3 Simulation Approaches for Fluids ........................................................................................................... 24 4.4 Choice of Method for Simulation............................................................................................................ 24 4.5 The Navier-Stokes Equations .................................................................................................................. 24 4.5.1 External Forces .............................................................................................................................................. 25 4.5.2 Advection ....................................................................................................................................................... 25 4.5.3 Diffusion ........................................................................................................................................................ 25 4.5.4 Pressure .......................................................................................................................................................... 26 4.5.5 Incompressibility.............................................................................................................................................. 26 5 Previous research ................................................................................................................................ 28 5.1 Particle systems and Noise ....................................................................................................................... 28 5.2 CFD approaches ........................................................................................................................................ 28 5.3 Large Scale Fluid Motion .......................................................................................................................... 30 5.4 Summary ..................................................................................................................................................... 30 6 Methodology ....................................................................................................................................... 31 6.1 Outline of Methodology ........................................................................................................................... 31 6.2 Solving the Navier-Stokes Equations...................................................................................................... 31 6.2.1 Helmholtz-Hodge Decomposition..................................................................................................................... 31 6.2.2 Advection ....................................................................................................................................................... 33 6.2.3 Viscous Diffusion ........................................................................................................................................... 33 6.2.4 Initial and Boundary Conditions ..................................................................................................................... 34 6.3 Implementation .......................................................................................................................................... 35 6.3.1 Discretization ................................................................................................................................................. 35 6.3.2 Solver Implementation ..................................................................................................................................... 37 6.3.3 Texture implementation................................................................................................................................... 37 6.4 Scenario testing........................................................................................................................................... 37 6.4.1 Equipment ..................................................................................................................................................... 37 7 Results ................................................................................................................................................. 38 7.1 Test Criteria....................................................................................................................................................... 38 7.2 Test Scenarios ................................................................................................................................................... 38 7.2.1 Test 1: Advection of the Velocity Field ............................................................................................................ 38 7.2.2 Test 2: Advection of the Density Field ............................................................................................................. 40 7.2.3 Test 3: Thermal Buoyancy............................................................................................................................... 41 7.2.6 Test 6: Boundaries .......................................................................................................................................... 47 7.2.7 Test 7: Exploding Object ................................................................................................................................ 49 7.2.8 Test 8: Time & Gridsize................................................................................................................................ 50 7.2.9 Test 9: Number of Iterations in the Pressure Solver.......................................................................................... 51 7.2.10 Test 10: Time and Stability .......................................................................................................................... 52 7.2.11 Test 11: Texture Precision ............................................................................................................................ 52 7.2.12 Test 12: Multiple Instances ........................................................................................................................... 53 7.3 Summary of Results ......................................................................................................................................... 57 8 Conclusions ......................................................................................................................................... 58 8.1 Possible improvements in C’Nedra ............................................................................................................... 58 8.2 Possible improvement of fluid dynamics in C’Nedra ................................................................................. 59 9 Critique................................................................................................................................................ 60 9.1 Problems Experienced..................................................................................................................................... 60 9.2 Field Developing Fast...................................................................................................................................... 60 10 Literature ........................................................................................................................................... 61 10.1 CFD literature................................................................................................................................................. 61 10.2 Textbooks ....................................................................................................................................................... 62 10.3 Internet sources.............................................................................................................................................. 62 Appendix 1: Notation............................................................................................................................. 64 Vectors and Vector Fields ........................................................................................................................................ 64 The Gradient Operator............................................................................................................................................. 64 Appendix 2: C’Nedra XML file.............................................................................................................. 66 Appendix 3: CFD Solver Code............................................................................................................... 67 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Table of Figures Figure 1: The pictures are taken from the movie Shrek and display simulations of fluid. Figure 2: A simplified model of the game engine building blocks. Figure 3: A schema displaying the various parts in the C’Nedra virtual reality toolkit. Figure 4: A simplified model of a real-time air-traffic control system. Figure 5: Plug-in class structure. Figure 6: Scene graph holding a sphere build up by triangles defined by vertices. Figure 7: Uniform grids, BSP Trees and Octrees. Figure 8: A simplified model of the rendering process. Figure 9: Lighting equation. Figure 10: The three fundamental components of lighting in 3D graphics engines: diffuse, ambient, and specular. Figure 11: The image displays texturing implemented in C’Nedra. Figure 12: Per-vertex and per-pixel normals. Figure 13: Pictures showing a model created with a 3D scanner at the ECP research facility. Figure 14: Skeletal Animation. Figure 15: Oriented bounded box decomposition in C’Nedra. Figure 16: Collision with the tank that rolls over with the help of the laws of physics. Figure 17: Height field terrain engine implementation. Figure 18: Height field terrain engine implementation visualized in C’Nedra. Figure 19: Pictures showing simulations created in C’Nedra virtual reality toolkit with a simple xml file. Figure 20: Pictures showing the new editor implemented to help designers creating worlds by not writing XML directly. Figure 21: Special effects implemented into C’Nedra. Figure 22: Summary of generic game engine features. Figure 23: Summary of fluid effects. Figure 24: Steps followed in implementing fluids in 3D graphics. Figure 25: Newton’s second law of motion. Figure 26: Navier-Stokes equations. Figure 27: Helmholtz-Hodge Decomposition Theorem. Figure 28: The simulation algorithm. Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Figure 29: Euler’s method. Figure 30: Stam’s method. Figure 31: Discretization of the simulation volume. Figure 32: Hot smoke rising with all steps in the algorithm enabled. Figure 33: Hot smoke rising with all steps in the algorithm enabled. Figure 34: Hot smoke rising with all steps in the algorithm enabled. Figure 35: Cold smoke falling and ring up the sides of the simulation box. Figure 36: Smoke rising with Vorticity Confinement Disabled. Figure 37: Smoke rising with Vorticity Confinement Enabled. Figure 38: Red hot smoke rising. Figure 39: Red smoke with object boundary. Figure 40: Single burning object. Figure 41: Exploding object. Figure 42: Showing how frame rate changes with grid size. Figure 43: Displays how frame rate changes with the number of iterations. Figure 44: Showing how the frame rate changes with time steps. Figure 45: Frame rate as a function of texture precision. Figure 46: Simultaneously burning fires. Figure 47: Simultaneously igniting and burning objects. Figure 48: Simultaneous black hot smoke rising. Figure 49: A summary of possible improvements in C’Nedra. Figure 50: A summary of possible improvements to C’Nedra pertaining to fluid dynamics. Figure 51: A summary of open source graphics engines. Figure 52: A summary of commercial source graphics engines. Figure 53: A summary of open source graphics engines. Figure 54: A summary of 3D modelling software. Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 1 Introduction Chapter 1 is the introductory chapter giving a general introduction to 3D graphics and the Computational Fluid Dynamics field. This is followed by a presentation of the background, purpose and problem statement of this thesis. A detailed outline is also presented as well as the target audience introduced. As we have entered the 3rd millennia, it is clear that computer and communications technologies have become a dominant force in people’s lives. Activities as wide-ranging as filmmaking, publishing, banking and education continue to undergo revolutionary changes as these technologies alter how we conduct our daily activities. 3D graphics in particular have during the last 10-15 years become an increasingly essential part of the engineering and entertainment community, and as computers have become more and more powerful, so has the exigency for realism increased. Figure 1: The pictures are taken from the movie Shrek and display simulations of fluid In order to tackle this demand for higher performance, we are to a greater extent turning to the natural laws of physics. One of the most difficult areas pertaining to implementing physics into computer graphics is called Computational Fluid Dynamics (CFD) and refers to the creation of realistic fluids often in 3D environments. This field involves methods for solving mathematical equations modelling real world behavior such as for example the Navier-Stokes Equations. This thesis aims at shedding some light on the implementation of such modelling methods into real-time 3D graphics engines. An example of this is the answer to the question by Jeffrey Katzenberg, the director at DreamWorks SKG, of which scene was the most difficult to produce in Shrek stated in Enright et al. (2003): “It’s the pouring of milk into a glass…” 1.1 General Introduction The implementation of theoretical algorithms in the CFD area is not always straight forward, especially when it comes to the specific needs of game engines. In these graphics systems there is a myriad of components interacting and one has to try various approaches, often ad-hoc and experimental, in order to get a satisfactory result. Many papers give theoretical advice about these various algorithms, however they do not give the reader any practical help about how it actually is to implement these into real game engines. Therefore this thesis tries to somewhat bridge this gap by implementing such an algorithms and testing its efficiency in terms of execution performance. 1 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 1.2 Background and Purpose The purpose of the Master Thesis project was to develop a real time graphics engine supporting the academic needs of Ecole Centrale Paris (ECP) and was later extended into implementing CFD into this system. ECP aimed at using the application in order for students to simulate various physical phenomena as part of their curricula. Most of the work for this Master Thesis was carried out at the ECP research facility for Applied Mathematics on Systems (Laboratoire de Mathématiques Appliquées aux Systèmes) (www.mas.ecp.fr/) in conjunction with the C’Nedra Open Source Virtual Reality Framework (www.cnedra.org/) and the VIA Centrale Reseaux association at ECP (www.via.ecp.fr/via/). Other stake holders that attended the presentation in Paris were the French Ministry of Education. The purpose of the project was initially to create a game engine from scratch and was later evolved into implementing CFD techniques into this specific graphics engine. The reason for not using an existing and established system such as Ogre (ogre3d.org) or Torque (www.garagegames.com) was that the school wanted to possess its own platform. This decision was to a high degree based on the success that the school has had with VideoLan (www.videolan.org) and VLC player which has allowed for the creation of the company Anevia (www.anevia.com). 1.3 Work Performed A comprehensive literature study was conducted throughout the whole project. The game engine kernel was further developed in order to allow xml scripting language to define objects. The C’Nedra Plug-ins were further developed to properly support sound, network, interface, physics and better 3D capabilities. A collision detection system was created and implemented partially based on the Tokamak physics engine. 3D models were created both by using 3D Max Studio 5.0 and Maya 6.0 and a 3D scanner in the research facility and implemented into scenarios. A webpage for the 3D scanner was conceived (catia.etudes.ecp.fr/optocat/index.html). Website for the project was launched (www.cnedra.org). A report in French pertaining to the needs of ECP was composed and the project was presented to the school as well as the French Ministry of Education. Fluid dynamics based on the Stam Navier-Stokes solver were implemented into fire and gas simulations and tested. This report in English pertaining to the KTH requirements was composed and presented. 1.4 Problem statement With the introduction and the background of the work carried out in mind, I formulate my main research question representing the main theme of this thesis: Can realistic fluid dynamics be run efficiently in the C’Nedra game engine? 2 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 1.5 Outline Chapter 1 introduces the rationale behind this thesis and discusses the implementation of fluid dynamics into 3D game engines. The chapter lays out the problem statement of the thesis and discusses the target audience as well as its delimitations. Chapter 2 discusses 3D game engines in more detail by going through the background of game engines and their functionality. Chapter 3 goes through the C’Nedra game engine step by step. The chapter gives the background to the specific game engine used, the history and evolution as well as a thorough outline of its functionality. Chapter 4 lays down the theory of fluids. The chapter defines fluids and examines various approaches to simulating them. The chapter explains the framework for the Navier-Stokes Equations. Chapter 5 gives an outline of the previous research made in the Computational Fluid Dynamics field. Chapter 6 is the methodology chapter and describes how CFD has been implemented into C’Nedra. Chapter 7 presents the results of the thesis and discusses them briefly. Chapter 8 concludes the thesis and suggests points for improvement. Chapter 9 criticises the work done and suggests points for improvement. 1.6 Target Audience The target audience is mainly researchers and industry entrepreneurs, developing products and architectures based on 3D game engines. Students and other readers that are interested in gaining a broad picture of game engines will also find it valuable reading this thesis. Stakeholders interested in creating open source graphics engines will find interesting information here as well. 1.7 Delimitations The area of game engines and CFD is a tremendously vast area, which could not possibly be covered in a single master thesis; hence this thesis aims at specifically focusing on the implementation of computational fluid dynamics into 3D game engines. Further, I also focus on the implementation of fire and gas effects seeing as it would be out of the scope for this thesis to cover all the various forms of fluid in depth such as oceans, clouds, smoke etc. The reader should keep in mind that the progress in the area is very fast and some topics covered may already have been outdated during the writing of this thesis. 3 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 2 Game Engines Chapter 2 defines game engines and goes through what a game engine is. The chapter also deals with the background and functionality of real-time graphics engines in order to give the reader a foundation for the work performed in the thesis project. Readers with a thorough understanding of computer graphics and game engines may pass to the next chapter. 2.1 What is a Game Engine? A game engine is the core software component of a video game. It usually handles graphical rendering and other necessary technology, but might also handle additional tasks such as artificial intelligence and collision detection between game objects, among other things. The most common element that a game engine provides is graphics rendering facilities. Another common attribute of game engines is platform abstraction, so the game can run in various platforms with little, if any, changes in the game source code. Game engines are often coupled with various stand alone packages that ease development such as for example physics engines that add realistic motion and explosions just to mention a few capabilities. 2.2 Background of Game Engines The term "game engine" arose in the mid-1990s, especially in connection with 3D games such as first-person shooters (FPS) with the popularity of Id Software's Doom and Quake games. These software packages were created in such a way that would allow developers to licence the core portion of the software and design their own graphics, characters, weapons and other so called “game content” (Stang 2003). Further on, games such as Quake III Arean and Epic Game’s 1998 Unreal were designed specifically with this approach in mind, which enabled the licensing of such technology. This has proved to be a very useful auxiliary revenue stream for some game developers seeing as a single license for a high-end commercial game engine can range from US$10,000 to $3,750,000. Moreover, reusable engines make developing game sequels much easier and faster, a valuable advantage in the competitive computer game industry (Stang 2003). The continued refinement of game engines has allowed a strong separation between rendering, scripting, artwork, and level design. This has increased the emphasis on the artist’s rather than programmer’s work. First-person shooter games remain the predominant users of third-party game engines, but they are now also being used in other genres. For example, the role playing game Morrowind and the Massively Multiplayer Online Role-Playing Game (MMORPG) Dark Age of Camelot are based on the NetImmerse engine, the MMORPG Lineage II is based on the Unreal engine. On game consoles game engines are used as well, for example the RenderWare engine is used in Grand Theft Auto III and Burnout 2 & 3. Modern game engines are some of the most complex applications written, frequently featuring dozens of finely tuned systems interacting to ensure a finely controlled user experience. 4 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 2.3 Game Engine Functionality and Design When discussing the game engine I try to cover the areas that are pertinent to the areas covered during the project. A game engine consists of many parts that interact with each other in order for a game to work. What makes or breaks a game engine is how well the various parts interact with each other in a functioning package. A complex game engine with gaming capabilities is constructed with object oriented programming and design patterns seeing as the complexity between everything from simple window handling to keeping track of objects in the scenes grows exponentially during the development process. The following figure is a simplified model for a generic game engine: Figure 2: A simplified model of the game engine building blocks Plug-ins Terrain Engine Data Physics Engine AI Engine (World) Graphics Engine Special Effects (Renderer) Kernel Multimedia Engine Sound files Textures (avi, mp3, wav) (bmp, jpg, png...) 3D models Multimedia (3ds,obj...) (avi, mpg...) Scripting The finished 3D application The model displays hypothetical parts in a simplified game engine and the interaction between plugins, kernel, scripting and data. The purpose of the game engine is to simplify and accelerate the speed in which new productions as well as sequels can be released. Of course, in theory all the parts could be intertwined on code level; however this would make it extremely difficult to add new functions and create an evolving programming vehicle. Hence these plug-ins are often implemented with the aid of design patterns i.e. high level data structures that simplify programming. In the following chapter, I go through the parts of the game engine one by one in order to give the reader a global picture of game engine functionality and in particular the C’Nedra game engine functionality. This is however only an overview seeing as one could write several books for every single part and algorithm available. I therefore direct the reader to one good introductory text for more in dept reading such as Angel (2001). 5 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 3 C’Nedra Game Engine Chapter 3 gives the lay down of the C’Nedra game engine which was developed by students at Ecole Centrale Paris and used in this master thesis project. The chapter explains the background and the development behind the engine, the history and evolution of the engine and finally in broad terms how the engine works. 3.1 Background C’Nedra (pronounced [snedra]) is a fully functioning 3D real-time virtual reality graphics engine with networking capabilities. Its cross-platform software programmed in C++ runs on both Linux and Windows and is available with a GPL license developed by students at Ecole Centrale Paris. The system allows the user to generate a virtual world containing objects, sounds and events thanks to a script file defined in the XML language. The software is composed of a core and several plugins meaning that the various parts of the engine can be developed decoupled of each other. The C’Nedra toolkit and additional information on the project is available on: www.cnedra.org 3.2 History and Evolution C’Nedra was launched in 2000 by students within the master thesis project framework of the second year at Ecole Centrale Paris. The aim of these students was at the time to create real time 3D and network application in line with that of Massively Multiplayer Online Role-Playing Games. The first elements that were set up were basic interface management such as 3D, sound and window management. The continuation of the research project was assured by new teams taking up where the old left in 2001, 2002 and 2003 as well as creating an on campus club affiliated with VIA Centrale Réseaux (the creator of Videolan and Vlc player). Thereafter in 2003, the project was directed towards a more structured programming approach seeing as the development of a 3D graphics engine is complex. Thus during 2003, the development principle of the project was restudied and the objective of the project was more broadly defined than that initially envisaged – namely to design a real time user defined virtual reality generator. In order for efficient development of the engine, a kernel-plug-in structure was set up in 2003-2004. The plug-ins are independent of each other with thread management making it possible creating powerful applications with dissociated functionalities. 3.3 Functionality and Design Explaining the entire structure and functionality of C’Nedra is out of the scope for this thesis. I will here focus on the main functionality in order to give the reader an understanding of the work carried out and how fluid mechanics were implemented into the system. The development platform was mainly Windows XP with Microsoft Visual C++ and Debian Linux. 6 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Figure 3: A schema displaying the various parts in the C’Nedra virtual reality toolkit The image displays the main structure in the C’Nedra 3D game engine. The game engine has a kernel-plug-in structure with a xml-file used for scripting capabilities. 3.4 Kernel A kernel is the core of the game engine as well as the core of real-time software applications. In C’Nedra it supplies real-time management of threads making interacting parts autonomous and hence the illusion of a real-time system is achieved. It also takes care of tasks such as memory management and it allows for a client-server structure. In a formal definition, real-time software pertains to computer applications that have a time-critical nature or, more generally, applications in which data acquisition and response must be performed under time-constrained conditions. Consider, for example, a computer program that displays information about arrivals on a large screen in an airport terminal; several lines of text display information about flight numbers, status, and time of landing, and so on. Clearly, the software responds to timely events – an airplane lands, delays are announced, and so on. The arrival of these bits of information is highly unpredictable, and the application must process and respond to them accordingly. Moreover, this time-dependent information must then be displayed on a screen to provide a visual presentation of the timedependent data. Figure 4: A simplified model of a real-time air-traffic control system Games are not very different from this architecture. Imagine that we eliminate the radar, generate virtual air traffic using a software simulator, and tell the user he must make planes land safely. Add a scoreboard to that and a game over screen and it begins to sound familiar. All games are indeed interactive, real-time applications. The operator (henceforth called the player) can communicate with the game world, which itself simulates real-time activity using software components. An enemy chasing us, elevators going up and down, and returning fire are all examples of the kind of virtual real-time found in games. But there is more to games than you might think. Games are also time constrained; they must display information at a set pace (usually above 25 frames per second) 7 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart to allow interaction to become seamless. This certainly limits the scope of both the real-time simulators and the presentation layer found in games – we cannot do more than what the hardware allows in the given time slice. 3.5 C’Nedra Plug-ins The C’Nedra game engine is constructed so that independent plug-ins can be developed and used in various scenarios. In C’Nedra there are three layers of implementation and there is one global and one non-global class for each layer. The kernel layer represents the classes for the kernel implementation of the plug-in which defines how a plug-in should communicate with the rest of the application. The Interface layer contains classes used to make the features in a specific plug-in available to other plug-ins. The messages sent between the plug-ins are based on these classes. The Plug-in layer contains classes at the programmer’s disposal to implement the plug-ins methods and classes. This layer defines the plug-in. Figure 5: Plug-in class structure The rest of this chapter will explain and elaborate upon some of the plug-ins implemented in C’Nedra and conclude with the special effects plug-in being the integral part of this thesis. 3.6 Graphics Engine (3D plug-in) In the following section, I describe the core of game engines i.e. the graphics engine. I use a top down approach instead of bottom-up as often described in the literature. In C’Nedra graphics scenes are built up by scene graphs of objects that are represented by vertices r r r defined by {x , y , z }∈ ℜ3 . Two vertices are grouped together to create a facet that grouped together creates primitives often in the form of triangles. These primitives are then used to build various geometric objects defined by matrices or quarternions. The objects are grouped into scene graphs representing a higher level of abstraction defined as scene management. The reason for using triangles is that they are minimal and are determined by 3 points or 3 edges. We can define a triangle by ( x1 , y1 , z1 ), ( x 2 , y 2 , z 2 ), ( x3 , y 3 , z 3 ) or we can define it in terms of three edges on the following equation and matrix form: 8 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Ax1 + By1 + Cz1 + D = 0 ⎡ x1 Ax 2 + By 2 + Cz 2 + D = 0 Æ ⎢ x 2 ⎢ Ax3 + By 3 + Cz3 + D = 0 ⎢⎣ x3 y1 y2 y3 z1 ⎤ ⎡ A⎤ ⎡1⎤ z 2 ⎥ ⎢ B ⎥ = − D ⎢1⎥ ⎥⎢ ⎥ ⎢⎥ z 3 ⎥⎦ ⎢⎣C ⎥⎦ ⎢⎣1⎥⎦ 3D Graphics Engines are often divided into several layers where the scene management layer deals primarily with objects and the rendering layer deals with triangles and graphics state. Figure 6: Scene graph holding a sphere build up by triangles defined by vertices Scenegraph Triangles with vertices Object 3.6.1 Scene Management The scene management system in C’Nedra is responsible for efficiently rendering complex scenes. The system maintains a world full of objects and determines what gets drawn and in what order. Scene graphs are conceptual tools used to represent virtual three-dimensional (3D) worlds in computer graphics applications. A scene graph is a hierarchical structure containing nodes connected by edges. The nodes of the scene graph manage the data describing a virtual scene and the edges that connect the nodes describe the relationships that exist between them in a meaningful way. The nodes are ideally arranged in a hierarchical manner that corresponds spatially and semantically to the modelled object/world. There exist several ways of partitioning objects and the shapes used is often referred to Oriented Bounded Box (OBB). Uniform grids mean dividing space uniformly instead of hierarchically and can be very fast or very slow depending on distribution of size and variations in location. Binary Space Partitioning (BSP) tree starts with all of the space. If there are too many objects we split into two subspaces and choose a plane to divide the space in two. This plane can be placed anywhere and oriented in any direction. Heuristics are used to choose a good plane. In order the access objects in the nodes recursion is used. BSP trees of various environments can easily be created by third party software from for example Id such as q3Radiant. Octrees starts by placing a cube around the entire scene. If the cube contains “too may” primitives (say 10) we split into 8 equally nested cubes. We then recursively test and possibly subdivide each of those cubes. We hence get a more regular structure than a sphere tree, which provides a clear rule for subdivision and no overlap between cells. 9 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Figure 7: Uniform grids, BSP Trees and Octrees The picture displays the 2D division in a uniform grid to the left, a BSP tree in the middle and an octree to the right. In C’Nedra the Scene Management system is based on evenly divided bounded boxes that are held in a recursive tree in the form of BSP. 3.6.2 Rendering pipeline C’Nedra allows for both OpenGL and DirectX implementations of handling graphics. Although, the two graphics packages impose different API’s their implementation is similar in broad terms. C’Nedra is mainly based on OpenGL and in this thesis I will focus on the OpenGL API although the fundamentals are equivalent. When rendering 3D graphics, the user application passes geometric primitives to the graphics adapter as streams of vertices. E.g., a triangle is passed to the graphics adapter as three vertices, defining the corners of the triangle. Normally, an object in a scene is passed down for tessellation (subdivision into triangles) and passed as triangles in the form of vertices to the render system. Each vertex can have a range of attributes attached to it, such as a normal vector, a color, and other properties, which affect the processing of the vertex and the primitive it defines. Upon receiving the vertex streams, the graphics adapter applies the appropriate geometric transformations of the vertex coordinates and normal vectors, to reflect the desired view of the 3D objects. A color is computed for each vertex, taking account for the attributes of the vertices and the light in the scene. Transformations, which are represented by matrix multiplication, include modelling, viewing, and projection operations. Such operations include rotation, translation, scaling, reflection, orthographic projection, and perspective projection. Generally, one uses a combination of several transformations to draw a scene. Since the scene is rendered on a rectangular window, objects (or parts of objects) that lie outside the window must be clipped. In three-dimensional computer graphics, clipping occurs by throwing out objects on one side of a clipping plane. Culling is similar to clipping but means to determine which objects in the scene are not visible. Backface culling is normally handled in lower rendering layer such as OpenGL or DirectX presented in the next section. However, when we have large groups of objects we would like to cull groups of objects quickly. Finally, a correspondence must be established between the transformed coordinates and screen pixels. This is known as a viewport transformation. The primitives are clipped, so only the viewable parts remain, and the primitives are rasterized, producing streams of fragments, which are pixels with color values, texture coordinates, and depth values. Different operations, such as texture mapping, blending, and depth-testing, can then be 10 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart performed for each fragment, before the fragments are finally drawn onto a frame buffer as pixels, thereby creating the rendered image. Figure 8: A simplified model of the rendering process 3.6.3 Lighting Light is the most important idea behind visual representation of anything that a human being can visually perceive. The idea of perception of light lies in the fact that what we can see is not based on the objects that you are viewing but on the rays of light cast from a light source and reflected from those objects. It is important to note that eyes do not directly see objects as there is no physical correlation between your eyes and those objects. Light rays commonly originate from an energy source such as the sun or a lamp in your room. It is important to note that theoretically a ray of light travels in a straight line and by the time you visually perceive an object, it is the rays of light reflected or scattered off that object that your eyes absorb. When considering lighting in a game engine such as C’Nedra many various components have to be taken into account such as the property of the surfaces i.e. their material properties, the location and direction of the light sources, the properties of the lights shining on the object as well as the location of the viewer. The following terms describe different types of light that are essential to 3D game engines such as C’Nedra: Figure 9: Lighting equation clit = cspecular + cdiffuse + cambient It is important to understand what effect each of these types of light creates on the surface of rendered 3D objects. These terms were created because certain effects that light produces on the objects needed to be described in order to derive the complex mathematical calculations of light. However, this does not mean that these exact types of light actually exist in nature, we just think of them as an abstraction of the effects that light can produce when cast on different materials. It would be very time consuming to calculate the real mechanics of light and the way it works in nature so, this common set of light types was generally adopted by OpenGL: specular, diffuse and ambient. These components can be implemented in a game engine with various techniques often depending on the capabilities of the hardware as well as the light implementation algorithms at hand. 11 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Diffuse component represents a directional light cast by a light source. Diffuse light can be described as the light that has a position in space and comes from a single direction. A flashlight can be though of as emitting diffuse light. When diffuse light touches the surface of an object, it scatters and reflects evenly across that surface. Ambient component is the average volume of light that is created by emission of light from all of the light sources surrounding the lit area. When sun rays pass through the window of a room they hit the walls and are reflected and scattered into all different directions which averagely brightens up the whole room. This visual quality is described by ambient light. Ambient light alone cannot communicate the complete representation of an object set in 3D space because all vertices are evenly lit by the same color and the object appears to be 2-dimensional. Specular component is what gives a surface its shiny appearance i.e. the component of light that a surface reflects to the environment. Specular reflection (or specular highlight) is displayed bellow in addition to the ambient and diffuse layers of light. You can observe how the object's 3D representation is greatly augmented by specular light properties. Just like diffuse light, Specular light is a directional type of light. It comes from one particular direction. The difference between the two is that specular light reflects off the surface in a sharp and uniform way. The rendering of specular light relies on the angle between the viewer and the light source. From the viewer’s standpoint specular light creates a highlighted area on the surface of the viewed object known as specular highlight or specular reflection. The intensity of the specular reflection is dependent on the material the object is made of and the strength of the light source which contains the specular light component. Figure 10: The three fundamental components of lighting in 3D graphics engines: ambient, diffuse and specular ambient diffuse specular Lightmapping is basically just a texture that contains luminance information rather than an image. The elements of the lightmap are referred to as lumels as they represent elements of luminosity. After the lightmap has been generated, the texture to be lit and the lightmap are blended together when applied to the polygon to produce the final effect. The blending can be pre-calculated before runtime to speed up the program, though the trend now is to use hardware multi-texturing. 3.6.4 Texturing Texturing is achieved by storing texture coordinates as vertex data for all vertices and then wrapping an image file over the object. This is called planar mapping. The coordinates are interpolated to each pixel during scan conversion. The color is looked up in the texture map file per pixel. There are various ways of coming up with the coordinate assignments as well as generating the texture which can be used in creating various effects. The methods implemented in C’Nedra are as presented bellow: 12 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Figure 11: The image displays texturing implemented in C’Nedra Environment Mapping is a texture technique that fakes mirror-like reflections of an environment. This is done by precomputing an image and storing it in an environment map and reflecting distant environment. The technique is a relatively simple technique that can be used to simulate the look of reflective surfaces such as water or metals. Instead of computing the true reflection, which is a costly process, it uses a texture map and some texture coordinate trickery to create a quite convincing reflective effect. Notice, however, that environment mapping does not simulate true reflections. It is just a clever mathematical trick that fools the eye almost completely. Sphere Mapping is a type of environment mapping in which the irradiance image is equivalent to that which would be seen in a perfectly reflective hemisphere when viewed using an orthographic projection. It is used to add a reflection to a metallic or reflective object in your scene. Although it is not as accurate as real life or as a cube environment map, it is a whole lot faster. Cube mapping uses a cube as coordinates for the texturing process. Bump Mapping is a method for making a smooth surface bumpy by using a texture to represent the variation in surface height. Then with Phong interpolation we have a normal for each pixel and use the texture value to perturb the normal. Finally, we use the perturbed normal for the per-pixel lighting. Procedural Texturing is a way of numerically computing the texture and is useful for pseudo-random “noise” functions. Examples of such algorithms are the Perlin noise function, which is a smoothly varying pattern which useful for swirly turbulent effects and the Worley Cellular Noise is a pattern with edges that is useful for rocky scaly effects. Per-pixel vs. per-vertex lighting Depending on the rendering technique used the lighting equation can also be calculated per-pixel or per-vertex. Per-pixel lighting looks better than per-vertex lighting and is usually hardware accelerated. When displaying light a normal is used on the surface of the object. However, before per-pixel lighting was introduced with newer graphics cards you had to tesstle an object to a very fine mesh in order to receive the same results and this was highly computationally expensive. Figure 12: Per-vertex and per-pixel normals 13 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 3.6.5 Shadowing When another object is between the surface and a light source that light source should not contribute to the surface’s illumination. Shadow Mapping is a way of implementing shadows by rendering an image from the light’s point of view and aiming the camera to look at objects in the scene. Then only the z-buffer depth values (holds depth of closes object to the camera) are rendered (no colors are needed) and the results are stored in a shadowmap. Then when lighting a point on a surface, for each light that has a shadowmap transform the point to the shadowmap’s image space. We get the the X,Y and Z values. The Z value to the depth value at X, Y in the shadowmap. If the shadowmap depth is less than Z then some other object is closer to the light than this point. Hence, this light is blocked and should not be included in the illumination. However, if the shadowmap is the same as Z, then this point is the one that’s closes to the light and we should illuminate it with this light. 3.6.6 Shaders The software or hardware render calls an arbitrary routine at every pixel which is known as shader. It implements various type of lightning models and is often written in special-purpose languages such as RenderMan Shading Languauge, Cg, and HLSL (Direct X). Normally, there are two types of shaders namely Vertex and Pixel where the prior runs once for each vertex while the second runs for each pixel as explained in the lighting section. Vertex shaders and fragment shaders are constructed using API specific languages. In OpenGl, these languages are supplied in the GL_ ARB_vertex_program and GL_ARB_fragment_progam extensions, defining two different assembly languages. High-level languages for creating vertex shaders and fragment shaders are also becoming widely used. The most well known is Cg (C for graphics), which is a C-like language designed by NVDIA. The Microsoft DirectX 9.0 API supports a similar high level language called High-Level Shading Language (HLSL) and in OpenGl the extensions GL_ARB_shading_languauge_100 gives support for the similar OpenGL Shading Languauge. As of today C’Nedra does not have support for vertex shaders hence this is not utilized when implementing fluid dynamics into the system. 3.7 Physics Engine (World plug-in) In order to make an object or the user move in a game engine various projections of matrices have to be performed such as scaling, translation or rotation. The motion techniques are often coupled with a physics engine with the aim of implementing the laws of physics such as for example gravity. A physics engine allows for real world constraints to be simulated in the game engine. This could be everything from motion and inertia to for example gravity. A very important issue in the creation of game engines is collision detection. We implemented this in C’Nedra with the Tokamak physics package (www.tokamakphysics.com). 3.7.1 Mesh Loading In high quality games of today all characters and objects in a game are modelled and textured in modelling software such as 3D Max Studio or Maya. These objects are then loaded by means of mesh loading, which means parsing objects from files created in modelling software. Depending on the file type various sorts of parsers have to been written to incorporate the data in the modelling file to be transferred into the graphics engine API. The C’Nedra engine supports 3D objects implemented in both 3D Max Studio (3ds) format with texturing; however does not support animated objects with skeletal structures. During the project various models were implemented with Maya and 3D Max Studio into C’Nedra. 14 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Figure 13: Pictures showing a model created with a 3D scanner at the ECP research facility The images display a tank that we scanned by a 3D scanner, textured in 3D Max Studio and finally inserted into C’Nedra graphics engine. 3.7.2 Skeletal Animation This is a technique used to pose character models. A skeleton is embedded in, and attached to, a character model. Once the skeleton is attached, the character model becomes the skin. Posing the skeleton causes the skin to be deformed to match the position of the underlying bones. Skeletal animation has a major advantage over jointed models in that a one piece mesh is used, so there are no seams. The model be created and animated in a modelling program such as Maya or 3D Max studio and then inserted and controlled from within the game engine. Figure 14: Skeletal Animation 3.7.3 Collision We based the collisions detection system in C’Nedra on an OBB (oriented bounded boxings), tree approach. C’Nedra enables collision of two objects in translation meaning that spinning collision effects can be implemented as explained in Eberly (2001). 15 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Figure 15: Oriented bounded box decomposition in C’Nedra The collision system coupled with Tokamak takes advantage of forward and inverse kinematics but does not use skeletal bodies. The next part discusses this functionality. Figure 16: Collision with the tank that rolls over with the help of the laws of physics 3.7.4 Kinematics This is a concept that involves explicitly setting the position and orientation of objects at specific frame times. For skeletons this means directly setting the rotations at selected joints and possibly the global translation applied to the root joint creating a pose. To avoid doing this for each frame of an animation, a series of keyframe poses can be specified at different frames with intermediate poses calculated by interpolating the joint parameters between the keyframe. The object can then be animated by displaying each intermediate pose. Inverse Kinematics allows for the position of any object within a skeleton only to be indirectly controlled by specifying rotations at the joints between the root and the object itself. In contrast forward kinematic techniques provide direct control over the placement of an end-effect or object at the end of a kinematic chain of joints solving for the joint rotations which place the object at the desired location. An animator can instead directly specify the position of an end-effector while the system automatically computes the joint angles needed to place the part. 3.7.5 Dynamics Forward Dynamics involves explicit application of time varying forces and torques to objects. Some forces such as those due to gravity and collisions between objects may be handled automatically. An equation relates angular acceleration to apply torques by the animation system and other forces are applied directly by the animator to objects in the scene. The motion is approximated by taking a 16 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart series of discrete steps in time and at each step solving the equations of motion for the acceleration an object undergoes in response to the applied force. Given the position and velocity of an object from the previous time step, the acceleration can be twice integrated to determine a new velocity and position respectively for the current time step. Inverse Dynamics automatically determines the force and torque functions needed to accomplish a stated goal. In the degenerate case the stated goal is a complete description of the motion and the aim is to determine the forces and torques which reproduce the motion under forward dynamic simulation. While this case is of interest in robotics, its application is of little use in an animation system after all if the motion trajectories and timing are known beforehand the expense of the physical simulation is unnecessary. 3.8 Terrain Engine (Terrain plug-in) The terrain engine is the part of the system that interacts with the renderer in order to build seamless creator defined terrain. This is most commonly done by creating large meshes with varying height. The mesh is textured with various techniques such as for example splatting. 3.8.1 Height Field Approach C’Nedra used the simplest form of terrain representation: a regular height field which is a grid in the XZ-plane, with evenly spaced points with a height attributed to each point. This representation saves a lot of space when storing the terrain because one will only need the heights, and a reference point in the terrain, for instance the centre point in the XZ-plane. Since the grid is evenly spaced one does not need to store both x and z values for each point. Starting from this premise, one can easily conceive a height map as a greyscale image, where the intensity of each pixel corresponds to a height. This method is simple and gives the game creator control over the area created; however it is not very useful for certain games were random worlds are created. Figure 17: Height field terrain engine implementation 3.8.2 Importing Pre-Generated Terrain Meshes Another common technique is to generate meshes of terrain in special terrain generating software or in modelling languages such as Maya or 3D Max Studio and importing these into the game engine, which also is possible in C’Nedra by loading the terrain as an object defined in the XMLfile. 3.8.3 Artificial Terrain Generation Other more sophisticated methods for implementing terrain consist of artificially generating terrain. This means using some sort of algorithm that divides the space and creates either highs or lows. 17 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Examples of common such algorithms are the Fault Algorithm, the Circles Algorithm and Mid Point Displacement. Even though artificial terrain generation was not implemented into C’Nedra, I give a brief explanation of parts of its functionality: The Fault Algorithm starts with a planar height field, where all points have zero height. Then it selects a random line which divides the terrain in two parts (in general these parts will be different in size). The points to one side of the line will have their height displaced upwards, whereas the points on the other side will have their heights displaced downwards. So now we have a terrain with two distinct heights. If one keeps dividing the terrain like this then one gets something that has valleys, mountains and so on. Circles Algorithm works similarly to the fault algorithm; however, instead of a line dividing the space, the circle algorithm uses a circle with random centre. The radius is user defined. Points inside the circle are displaced upwards, whereas the remaining points will keep their height. This leaves us with valleys and mountains. Figure 18: Height field terrain engine implementation visualized in C’Nedra Mipmapping is a level-of-detail method used in C’Nedra with reasonable compromise between performance and quality which is used in most graphics hardware and software renderers. Level of Detail (LOD) refers to the various techniques of reducing detail for objects as they get further away. There are various techniques that are implemented throughout the game engine’s various building blocks. By using this several mipmaps are stored as scaled down-versions of the original image usually half the resolution. These are then tiled as a function of distance to conserve memory. 3.9 Artificial Intelligence Engine (AI plug-in) Artificial Intelligence, as used by commercial game developers is simplistic in comparison to the techniques being used in mainstream academic research and industrial applications. Some of the more important reasons for this lack of sophistication include a lack of CPU resources and development time, as well as lack of control of the result achieved. This has led to the emergence of a number of very well established, well understood and robust techniques that are in wide use by game developers. These include Finite State Machines, and their close relation Fuzzy State Machines, the A* path finding algorithm, and a number of techniques including flocking algorithms. These are often referred to as deterministic approaches. More advanced types of techniques are statistical including for example neural networks, genetic algorithms and case-based reasoning. In the beginning of the project we intended to implement AI; however due to lack of time this was never pursued seriously. 18 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Nevertheless, I present some of the most common topics in the area according to Millington (2001). Finite State Machines (FMS) are used to create deterministic behavior in game engines such as for example triggering opponents to charge when the user enters a certain area or performs an action. It is mostly only a design concept – that is, the game has no general FSM interpreter, but the FSMs are realized by scripts and simple if-then statements. Fuzzy logic enables a computer to reason about linguistic terms and rules in a way similar to humans thereby making it easy to extract domain specific knowledge from an expert and to present it in a form a game playing agent can utilize. Monitoring and adapting to the opponent's style of play. A number of rules which can be adapted, graded, modified and measured which is an excellent way of computer learning. Fuzzy logic represents facts as a matter of degree rather than true/false statements. Humans often assign facts to categories with some flexibility about the boundary conditions. For example, in a football match, a player might have to decide whether to try to outrun a defender or pass the ball to a teammate, e.g. decisions will be based on assessments of speed and agility like “the defender is fast but can't turn very quickly” rather than “the defender can cover 20m in 2.8s from standing, but requires 0.95s to turn 180 degrees” Path finding algorithms are used to find the best (shortest) solution of a problem where the outcomes and paths to the solution are represented by for example a tree. Every problem in AI is a “virtual” tree of all possible (successful or unsuccessful) solutions. And there are various approaches of finding an efficient search strategy. The leaves in the trees are the solutions. For example the computer decides the best path to move a vehicle without crashing into a wall. The widely used A* algorithm is an improved version of Dijkstra’s shortest-path algorithm. Classic Flocking means that virtual agents are steered to follow another object under certain constraints. For example, it may be used when the computer has characters helping the player or enemies searching for the player. Neural Networks can be fed with information that could be interpreted as vision or auditory information. This information can then be used to select an output response or teach the net. These responses can be learned in real-time and updated to optimize the response. A neural net can be used by game creatures as a form of memory. The neural net can learn through experience a set of responses, and then when a new experience occurs, the net can respond with something that is the best guess at what should be done. The output of a neural net can be used to control the actions of a game creature. The inputs can be various variables in the game engine. The net can then control the behavior of the creature. Genetic algorithms are good when searching very large problem spaces, and also for evolutionary development. For example, using characters with a large structure of possible traits (aggressiveness, probability of running away when low on health etc.) then a genetic algorithm can be used to find the best combination of theses structures to beat the player. For example, the player would go through a level, and at the end of that level, the program would pick the monsters that had done the best against the player. Case-based reasoning broadly construed, is the process of solving new problems based on the solutions of similar past problems. This is a way of the computer to learn from past experiences. For example in a strategy game the computer could use a genetic algorithm when optimally allocating resources and then use case-based reasoning to bias this behavior towards previously human created behaviour by having stored prior human decisions. 19 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 3.10 Multimedia Engine (Sound plug-in) No game engine worth the name can be without sound. This component may seem easy to implement; however there are a lot of issues to achieving realistic sound effects with moving objects such as for example Doppler effects. C’Nedra use a package called OpenAl, which supplements a great open source API for sound development. OpenAl is basically an audio library that contains functions for playing back sounds and music in a game environment. It allows a programmer to load whatever sounds they like and control certain characteristics such as position, velocity, direction and angles for cones that determine how the sound is travelling. All sounds are positioned relative to the listener which represents the current place in the game universe where the user is. 3.11 Interface management (Interface plug-in) A game engine normally has various types of interfaces that the user can utilise in order to interact with the system. This can be everything from simple mouse and keyboard input to more elaborate menu systems orthogonally projected onto the screen. C’Nedra supports mouse and keyboard interaction as well as the creation of orthogonal and projected interfaces. 3.12 Scripting (xml plug-in) Many commercial game engines include simplified scripting languages that allow the game creator to create applications without having extensive programming skills. The scripting language is often an XML or C like language that interacts with the game engine API. Other languages commonly used are LUA and JavaScript. The C’Nedra game engine supports scripting by using a XMLconfiguration file. In order to create a scenario you only have to modify the XML configuration file and there is no need to rebuild the entire software package each time a new object is added or changed in a scenario. Please refer to Appendix for an example of XML-scripting from the C’Nedra 3D game engine. By defining a specific object the necessary collision coordinates are automatically generated and placed in a .mtrdat file and the object can be used in the world. Figure 19: Pictures showing simulations created in C’Nedra virtual reality toolkit with a simple xml file 3.13 User Driven Data The structure of game engines is to allow for user driven data to easily be implemented into the system from other applications such as for example Maya and 3D Max Studio. Models implemented into the engine are first created, textured and animated in these modelling environments and then inserted into the game engine by using the XML-script file. 20 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 3.14 Editors Most commercial game engines include GUI-, World- and Scenario Editors intertwining the scripting languages making it possible for “What You See Is What You Get” development and almost no programming skills are needed to create interesting games. During my year of the project there was no editor available for constructing world through the xml file. Today there is a very simple editor available for creating worlds. Figure 20: Pictures showing the new editor implemented to help designers creating worlds by not writing XML directly 3.15 Special Effects (special-effects plug-in) Even though there were many algorithms implemented into C’Nedra which would have been interesting to discuss more in depth in this thesis, I choose to focus on the implementation of CFD in the form of special effects of fire and gas. Hence the special effect plug-in implemented in C’Nedra is the base for the rest of this thesis. The plug-in developed allows for placing a fluid substance in the form of gas or fire defined by a rectangular grid. Figure 21: Special effects implemented into C’Nedra 21 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart The fluid can then be animated thanks to the Navier-Stokes equations. The animation can be controlled by setting various parameters such as the ambient temperature or the boundaries of an object submerged in smoke or fire. The rest of this paper will deal with the implementation of fluid dynamics in the form of fire and smoke. 3.16 Summary of Features implemented in C’Nedra during thesis work In this last section, I summarize the work carried out in enhancing the C’Nedra game engine. The integral part of this thesis deals with implementing special effects in the form of fire and gas; however, many other enhancements to the C’Nedra toolkit were carried out in due course of the project. These areas have mainly been dealt with in the previous chapters and are summarized in the table bellow: Figure 22: Summary of C’Nedra game engine features Kernel Graphics Engine Terrain Engine Physics Engine Special Effects Real-time thread management Scene Management Height Field Mesh loading Client-server Rendering Imported Meshes Camera Movement Lighting Texturing Collision detection Shadowing LOD AI Engine Multimedia Engine Other Gas 2D Sound Interface management Fire 3D Sound Scripting User driven data Editors Texturing Cross Platform 22 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 4 Theory of Fluid Substances From having given the reader a general introduction to game engines and the particular software in question I move on to introducing the theory behind this thesis. I start by defining what fluids are and what types of simulation approaches are the most common. The chapter also defines the Navier-Stokes equations, which often are used to model fluids substances in Computational Fluids Dynamics. 4.1 Definition of Fluid Substances As the aim of this thesis is to simulate fluid substances such as liquids or gases, it is important that we understand what fluid really is. In this chapter, I will try to define fluids by describing how we perceive fluid, and introduce the mathematical model of fluid motion. Please refer to Appendix I for an outline of the mathematical notation used in the thesis. To describe all physical properties of fluids would be out of the scope of this thesis. I therefore limit the introduction to the necessities of this report. For a more thorough description of fluid dynamics, I refer the reader to physics textbooks, such as Candel (1995). 4.2 Perception of Fluid Substances Fluid substance effects range from small scale effects, such as water poured into a glass and smoke rising from a cigarette, to large scale effects, such as oceans. To give an idea of the wide range of fluid effects, I give a list of examples: Figure 23: Summary of fluid substance effects Large scale liquids: rivers, oceans, waterfalls, etc. Small scale liquids: coffee in a cup, water in a bath tub, etc. Explosions: from local explosions, such as from a grenade, to big explosions, creating blast waves. Evolution of weather systems: cloud formations, hurricanes, etc. Global wind: wind blowing in treetops, wind that makes fallen leafs “dance” in corners of buildings, etc. Local wind: a blowing fan, warm air rising from a heater, etc. Fire: from candles to burning buildings. Smoke: for instance rising from a candle. Mist: drifting fog. Clouds: moving clouds in the sky, flying into clouds in flight simulators. 23 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 4.3 Simulation Approaches for Fluids Currently there are many different approaches to simulating fluids in real time graphics engines ranging from particle systems and ad-hoc methods to more advanced approaches such as computational fluid dynamics (CFD) often involving solving the Navier-Stokes equations with various algorithms. The implemented approach all depends on the specific application. For example when simulating a fountain or a waterfall then perhaps some sort of particle system would be the most efficient implementation, while when displaying a flame with more realism we would like to use CFD approaches. The implementation of a fluid would normally consist of the following steps: Figure 24: Steps followed in implementing fluids in 3D graphics 1. Choice of method based on the needs of the simulation in question 2. Creation of a motion by particles systems, CFD approaches or ad-hoc methods 3. Rendering of the fluid using texturing and for example shading 4. Application or handling of constraints such as collision i.e. floating in the fluid or waves 4.4 Choice of Method for Simulation Which method to use in practice depends largely on the problem at hand and on the computing power available. Most engineering tasks require that the simulation provide accurate bounds on the physical quantities involved to answer questions related to safety, performance, etc. The visual appearance (shape) of the flow is of secondary importance in these applications. In computer graphics, on the other hand, the shape and the behaviour of the fluid are of primary interest, while physical accuracy is secondary or in some cases irrelevant. Fluid solvers, for computer graphics, should ideally provide a user with a tool that enables us to achieve fluid-like effects in real-time. 4.5 The Navier-Stokes Equations The Navier-Stokes differential equations are a set of partial differential equations (PDEs), which describe the motion of viscous incompressible fluids. This means that all properties of the fluid are described exclusively by its viscosity and density. Although air is not actually incompressible, most gas effects observed in everyday life uphold this property. Thus, I will assume gas to be incompressible in the context of this report. The Navier-Stokes equations are based on the assumption that fluids can be described as a collection of particles. The terms describe the forces acting on a particle, derived by observing the behavior in a unit cube around the particle. This is done under the assumption that the fluid inside this unit cube behave uniformly. The Navier-Stokes equations were derived from Newton’s second law of motion, which states that: Figure 25: Newton’s second law of motion r r f = m⋅a 24 (4.1) Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart r r where m is mass, a is acceleration, and f is force. They describe the changes in a velocity field, i.e. the acceleration of the fluid, as a sum of the forces acting on the fluid – including forces introduced by the fluids own movement. In a compact vector notation the Navier-Stokes equations are presented as: Figure 26: Navier-Stokes equations r ∂u 1 r r r r 1 = f − (u ⋅ ∇ )u + v∇ 2 u − ∇p, ∂t ρ ρ (4.2) r ∇ ⋅ u = 0. (4.3) 4.5.1 External Forces The first term in the Navier-Stokes equations represents external forces and is given by the following expression: 1 r 1 x y f = (f , f , f ρ r ( where the force field f = f x , f y , f z ) T ρ ) z T (4.4) is the sum of all external forces working on the fluid, and r ρ is the density of the fluid, which describes the mass of a unit cube of fluid. Because u is a vector quantity, there are four equations and four unknowns: u, v, w, p . The four terms on the right-hand side of Equation (4.2) represent accelerations. I will examine each of them in turn. 4.5.2 Advection The second term in the Navier-Stokes equations represents advection and represents the force of the fluid motion working on itself. This can be thought of as the molecules in a fluid bouncing into each other. If one molecule bumps into another molecule, the other molecule is affected and will start moving. The contribution of advection is described by: ⎛ x ⎜u ⎜ ⎜ r r − (u ⋅ ∇ )u = −⎜ u x ⎜ ⎜ux ⎜ ⎝ r ∂u x ∂x ∂u y ∂x ∂u z ∂x ( ∂u x ∂y ∂u y uy ∂y ∂u z uy ∂y uy where ∇ is the gradient operator, and u = u x , u y , u z ) T ∂u x ⎞ ⎟ ∂z ⎟ ∂u y ⎟ uz ⎟ ∂z ⎟ ∂u z ⎟ uz ∂z ⎟⎠ uz (4.5) is the velocity. 4.5.3 Diffusion Diffusion occurs when part of the fluid passes by an obstacle, or another part of the fluid with a different velocity. The fluid is slowed down and vortices appear. The contribution of diffusion is described by the term: 25 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart ⎛ ∂ 2u x ⎜ 2 ⎜ ∂x ⎜ ∂ 2u y r v∇ 2 u = v ⎜ 2 ⎜ ∂2x z ⎜∂ u ⎜ ∂x 2 ⎝ ∂ 2u x ∂y 2 ∂ 2u y + ∂y 2 ∂ 2u z + ∂y 2 + ∂ 2u x ∂z 2 ∂ 2u y + ∂z 2 ∂ 2u z + ∂z 2 + ⎞ ⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ⎠ (4.6) where v is the kinematic viscosity of the fluid, which describes the “thickness” of the fluid. Hence, diffusion is also referred to as the effect of viscosity. Some fluids are “thicker” than others. For example, molasses and maple syrup flow slowly, but alcohol flows quickly. We say that thick fluids have a high viscosity. Viscosity is a measure of how resistive a fluid is to flow. This resistance results in diffusion of the momentum (and therefore velocity), so the third term is called the diffusion term. 4.5.4 Pressure Fluid moving in and out of the observed unit cube causes the pressure to change. Differences in pressure between the unit cube and its surroundings affect the velocity as described given by T r 1 ⎛ ∂p ∂p ∂p ⎞ − ∇p = − ⎜⎜ , , ⎟⎟ , ρ ρ ⎝ ∂x ∂y ∂z ⎠ 1 (4.7) r where ρ is still the density of the fluid and p is the pressure. Because the molecules of a fluid can move around each other, they tend to “squish” and “slosh”. When force is applied to a fluid, it does not instantly propagate through the entire volume. Instead, the molecules close to the force push on those farther away, and pressure builds up. Because pressure is force per unit area, any r r pressure in the fluid naturally leads to acceleration. (Think of Newton’s second law, F = m ⋅ a ) The second term, called the pressure term, represents this acceleration. 4.5.5 Incompressibility To ensure that the volume of the fluid is kept constant, the net flow of the unit cube should be zero, indicating that the amounts of fluid entering and leaving the cube should be equal. This is described by the incompressibility constraint: r ∂u x ∂u y ∂u z ∇⋅u = 0 ⇔ + + = 0. ∂x ∂y ∂z (4.8) By adding all these terms, the equations (4.2) and (4.8) can thus be written component wise, without the use of the gradient operator, as: 26 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart ∂u x ∂u x ∂u x ⎞ ⎛ ∂ 2 u x ∂ 2 u x ∂ 2 u x ⎞ 1 ∂p f x ⎛ x ∂u x ⎟ + v⎜ ⎟− = − ⎜⎜ u + uy + uz + + ∂t ∂x ∂y ∂z ⎟⎠ ⎜⎝ ∂x 2 ∂y 2 ∂z 2 ⎟⎠ ρ ∂x ρ ⎝ y y ⎛ ∂ 2 u y ∂ 2 u y ∂ 2 u y ⎞ 1 ∂p ∂u y f y ⎛ x ∂u y y ∂u z ∂u ⎞ ⎟ + v⎜ ⎟− = − ⎜u +u +u + + ∂t ∂x ∂y ∂z ⎟⎠ ⎜⎝ ∂x 2 ∂y 2 ∂z 2 ⎟⎠ ρ ∂y ρ ⎜⎝ ∂u z ∂u z ∂u z ⎞ ⎛ ∂ 2 u z ∂ 2 u z ∂ 2 u z ⎞ 1 ∂p f z ⎛ x ∂u z ⎟ + v⎜ ⎟− = − ⎜⎜ u + uy + uz + + ∂t ∂y ∂z ⎟⎠ ⎜⎝ ∂x 2 ∂y 2 ∂z 2 ⎟⎠ ρ ∂z ρ ⎝ ∂x (4.9) ∂u x ∂u y ∂u z + + = 0. ∂x ∂y ∂z The most important quantity to represent in a fluid simulation is the velocity of the fluid, because velocity determines how the fluid moves itself and the things that are in it. In the context of this report, I define the velocity vector field of a fluid on a Cartesian grid such that for every discrete r r r r r r position x = ( x, y , z ) , there is an associated velocity at time t , u ( x , t ) = (u ( x , t ), v ( x , t ), w( x , t ) ) The key to fluid simulation is to take steps in time, and at each time step, correctly determine the current velocity field. This is done by solving the Navier-Stokes equations for incompressible flow. Once velocity field is acquired, one can use it to move objects, smoke, cloud water concentrations, and other quantities that can be displayed in applications. 27 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 5 Previous research Chapter 5 introduces previous research on implementing computational fluid dynamics into 3D graphics and gives some background for the fluid dynamics solver implemented and tested in this thesis. 5.1 Particle systems and Noise Particle Systems were introduced in the early 1980s by Pixar (then part of the Lucasfilm special effects group) for the movie Star Trek II: The Wrath of Kahn. Specifically, particle systems were used to represent a chain-reaction explosion on the surface of a planet, so the planet changed from a dead, barren look to a full living ecosystem (Eberly 2001). Particle systems are essentially a mathematical formalism used to describe phenomena that are complex, dynamic and highly parallel with small individual components. Examples of such behavior include smoke from a chimney, fire, birds flying in a flock, snowflakes, and hundreds of other phenomena. Particle systems are context insensitive, meaning they can be used to model very different situations. The particle system is a tool, but does not imply a specific use-case in itself. By changing some of its inner components, it can be suited to many problems. Noise is a method of mimicking CFD and was first described by Perlin (1985), who modelled ocean waves by stochastically perturbing surface normals (bump mapping) according to a superposition of randomly distributed spherical wavefront sources. A random spatial frequency f is assigned to each spherical wavefront source. The amplitude of the wavefronts are f=1 and the phase of the sources is modulated by a function of pf. 5.2 CFD approaches The Navier-Stokes differential equations are a set of partial differential equations (PDEs) that describe the motion of viscous incompressible fluids. This means that all properties of the fluid are described exclusively by its viscosity and density. The solution of these equations has long been impossible. However, thanks to advances in numerical computation these equations have entered computer graphics and are one of the hottest topics today and can be used to simulate everything from water and gas to clouds and fire. Foster and Metaxas (1996) describe one of the first methods for simulating the full 3D Navier-Stokes equations for computer graphics. The method is based on explicit methods and only stable for small time steps. In fact, the time step must uphold the Courant-FriedrichLevy (CFL) condition: ⎛ ∂t ∂t z ∂t ⎞ 1 > max⎜⎜ u x , u y ,u ⎟⎟, ∀u x , u y , u z x y z ∂ ∂ ∂ ⎝ ⎠ (5.1) where u x , u y , and u z are the velocity components in x, y and z directions. Foster and Metaxas (1997) give an extended version of the 1996 algorithm including the forces of thermal buoyancy. This means that temperature is represented in the centre of each grid cell, defining a discrete temperature field equivalently to pressure. The temperature field is advected and diffused using the same method as with velocity. When updating the velocity field, the temperatures are used for calculating external forces given by: 28 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart r r Fbv = − βg y (T0 − Tk ), (5.2) r where β is the coefficient of thermal expansion, g y is the gravity vector, T0 , is the initial reference temperature, and Tk is the simulated temperature. Stam (1999) extends Foster and Metaxas (1996) with the aim of making the solver unconditionally stable. Thus, the different contributions of the Navier-Stokes equations are added in the following steps: 1. External forces are added simply by adding the force field to the velocity field. 2. The effect of advection is added by using a semi-Lagrangian method. With this method, grid points are advected backwards (as opposed to forward in Lagrangian methods) to find the new velocities values. 3. The effect of diffusion is added by solving the diffusion term using an implicit method, yielding: ∂u~ r u~ − =u ∂t (5.3) r ∂u~ is given where u is the current velocity, u~ is the yet unknown, updated velocity, and ∂t by the diffusion term of the Navier-Stokes equations. This yields a velocity field that is not mass-conserving. But instead of using a Sucessiver Over Relaxation (SOR) method, a mathematical result called Helmholtz-Hodge decomposition is used. This states that any vector field can be decomposed into a scalar gradient field and a mass-conserving vector field, yielding: r r u~ = u + ∇q, ∇ ⋅ u = 0 (5.4) ⇒ ∇ ⋅ u~ = ∇2 q. The last equation is a Poisson equation for the unknown scalar field q . When spatially discretezed this equation yields a sparse linear system, which can be solved in a number of ways. When solved, the pressure field is used to calculate the mass-conserving velocity field according to the last equation. Fedkiw et al (2001) give a method for simulating smoke based on Stam’s method. Under the assumption that the effects of viscosity are negligible in gases, when simulated on a coarse grid, the diffusion term of the Navier-Stokes equations are left out, leaving the incompressible Euler equations: r r r r ∂u = −(u ⋅ ∇ )u − ∇ρ + f , ∂t r ∇ ⋅ u = 0, 29 (5.5) Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart r r where u is the velocity, ρ is the pressure, and f is the external forces. In order to make up for the coarse grid representations, vorticity confinement is used to add the small scale detail that has been damped out by numerical dissipation back into the velocity field. Stam (2003) presents a simple and rapid implementation of the Stam (1999) fluid dynamics solver for game engines with the Navier-Stokes equations. The algorithm presented in Stam’s papers presents a 2D implementation and needs to be extended into 3D. Losasso et al. (2004) present a method for simulating water and smoke on an unrestricted octree data structure exploiting mesh refinement techniques to capture the small scale visual detail. The paper proposes a new technique for discretizing the Poisson equation on this octree grid with fast solution methods such as preconditioned conjugate gradients. Harris et al. (2003) present a physically-based, visually-realistic cloud simulation suitable for interactive applications such as flight simulators. Clouds in the system are modelled using partial differential equations describing fluid motion, thermodynamic processes, buoyant forces, and water phase transitions. Guendelman et al. (2005) present a novel method for solid/fluid coupling that can treat infinitesimally thin solids modelled by a lower dimensional triangulated surface. Since classical solid/fluid coupling algorithms rasterizing the solid body onto the fluid grid, an entirely new approach is required to treat thin objects that do not contain an interior region. Selle et al. (2005) introduce a new hybrid technique that makes synergistic use of Lagrangian vortex particle methods and Eulerian grid based methods to overcome the weaknesses of both. The approach uses vorticity confinement itself to couple these two methods together and generates highly turbulent effects unachievable by standard grid based methods, and show applications to smoke, water and explosion simulations. 5.3 Large Scale Fluid Motion Oceans among other phenomena are often large scale phenomena that need a different approach than the local both with regards to quality as well as performance. For example, simulating an entire ocean in a flight simulator with Navier-Stokes is very computationally expensive and not very practical. These algorithms are often based on various combinations of trigometric functions. These approaches are however not the focus of this thesis as I am focusing on local fluid such as fire and gas. 5.4 Summary When rendering fluids, such as water and liquids in general, where the surface is, in fact, defining the substance, particle system come short. Using particle systems for rendering liquid effects tends to make the surface of the liquid seem diffuse, which ruins the visual effect. Thus, particle systems are more appropriate for rendering low quality gases. More advanced methods, based on the physics of fluids, achieve much more realistic effects, and can be used for the generation a wider range of effects (Johanson 2004). Unfortunately, they do take a lot of processing power in real-time; 30 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart nevertheless I choose to implement Stam’s algorithm in 3D seeing as the approach, gives astonishing results and is quite straight forward to implement. 31 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 6 Methodology Chapter 6 discusses the methodology used in the project. Further, the methodology used in creating fluid effects and testing scenarios for the specific game engine is discussed. 6.1 Outline of Methodology 1. Gaining understanding of C’Nedra through implementing new functionality 2. Solving the Navier-Stokes Equations 3. Implementing the algorithm in a C’Nedra plug-in 4. Scenario testing of the special effects plug-in 6.2 Solving the Navier-Stokes Equations Analytical solutions of the Navier-Stokes equations can only be found for a few simple physical problems. Nevertheless, it is possible to use numerical integration techniques to solve them incrementally. The aim of this project is to display the evolution of the flow over time, so an incremental numerical solution is sufficient. The algorithm I used to solve the Navier- Stokes equations is based on the “stable fluids” technique described in Stam, (1999), Stam (2003) and Fedkiw et al. (2001). In this section I describe the mathematics of each step in the algorithm. The first step in the algorithm is to transform the Navier-Stokes equations into a form that one can use in numerical solution. Recall that the two-dimensional Navier-Stokes equations are three equations that we can solve for the quantities u , v , and p (velocity, viscosity and pressure). The following section describes a transformation that leads to a straightforward algorithm. 6.2.1 Helmholtz-Hodge Decomposition r From vector calculus we know that any vector v can be decomposed into a set of basis vector r components whose sum is defined by v . For example, we commonly represent vectors on a r Cartesian grid as a pair of distances along the grid axes v = ( x, y ) . This can be written as r v = xi + yj where i and j are unit basis vectors aligned to the axes of the grid. Hence we can decompose a vector into a sum of vectors; and we can also decompose a vector field into a sum of vector fields. If we allow D to represent the region in space on which a fluid is defined to have a r smooth boundary, ∂D , and a normal direction n one can use that any vector field can be decomposed into the sum of two other vector fields: a divergence-free vector field and the gradient of a scalar field. 32 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Figure 27: Helmholtz-Hodge Decomposition Theorem r A vector field w on D and be uniquely decomposed in the form: r r w = u + ∇p , (6.1) r r r where u has zero divergence and is parallel to ∂D i.e. u ⋅ n = 0 on ∂D . Step 1 In order to solve the Navier-Stokes equations we need to perform several calculations to update the velocity field at each time step. We need to apply advection, diffusion and force. This gives us a r new velocity field, w , with nonzero divergence; however the continuity equation requires that each time step ends with a divergence-free velocity. The Helmholtz-Hodge Decompostion Theorem states that the divergence of the velocity can be corrected by subtracting the gradient of the pressure field: r r u = w − ∇p (6.2) Step 2 If we apply the divergence operator to both sides of Equation (6.4.1), we obtain r r r ∇ ⋅ w = ∇ ⋅ (u + ∇p ) = ∇ ⋅ u + ∇ 2 p (6.3) r And we have that ∇ ⋅ u = 0 , which gives us r ∇2 p = ∇ ⋅ w (6.4) This is a Poisson equation for pressure of the fluids. It means that when we arrive at our divergent r r velocity, w , we can solve Equation (6.4) for p , and then use w and p to compute the divergence r free field, u , using Equations (6.3). r The next step is to find a way to compute w . Seeing as we know that the definition of the dot r r product, we can find the projection of a vector r onto a unit vector s by computing the dot r r product of r and s . The dot product is a projection operator for vectors that maps a vector r r r onto its component in the direction of s . We define a projection operator, P , that projects a r vector field w onto its divergence free component, u . If we apply P to Equation (6.1) r r Pw = Pu + P (∇p ) P (6.5) r r r Pw = Pu = u (6.6) P(∇p ) = 0 (6.7) r ⎛ r r 1 r r⎞ ∂u = P⎜⎜ − (u ⋅ ∇ )u − ∇p + v∇ 2 u + F ⎟⎟ ∂t ρ ⎝ ⎠ r r r r r ∂u = P − (u ⋅ ∇ )u + v∇ 2 u + F ∂t ( ) 33 (6.8) (6.9) Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Figure 28: The simulation algorithm S = P o D o Ao F (6.10) Add force Æ Advect Æ Diffuse Æ Project V 6.2.2 Advection Advection is a process by which a fluid’s velocity transports itself and other quantities in the fluid. To compute the advection of a quantity, we must update the quantity at each grid point. Seeing as we are computing how a quantity moves along the velocity field, it helps to imagine that each grid r cell is represented by a particle. If we move the position r of each particle forward along the velocity field the distance it would travel in time δt : Figure 29: Euler’s method r r r r (t + δt ) = r (t ) + u (t )δt (6.11) This is a simple method for forward integration of ordinary differential equations. However, there are problems with this approach. The first is that simulations that use explicit methods for advection are unstable for large time r steps, and can “blow up” if the magnitude of u (t )δt is greater than the size of a single grid cell. The solution is to invert the problem and use an implicit method (Stam, 1999). Rather than advecting quantities by computing where a particle moves over the current time step, trace the trajectory of the particle from each grid cell back in time to its former position, and copy the quantities at that position to the starting grid cell. To update a quantity q (this could be velocity, density, temperature, or any quantity carried by the fluid), use the following equation: Figure 30: Stam’s method r r r r q ( x , t + δ t ) = q ( x − u ( x , t )δ t , t ) (6.12) Not only is this method easily implemented on the Graphics Processing Unit (GPU), but as Stam showed, it is stable for arbitrary time steps and velocities. 6.2.3 Viscous Diffusion Viscous fluids have a certain amount of resistance to flow, which results in diffusion (or dissipation) of velocity. A partial differential equation for viscous diffusion is: r r ∂u = v∇ 2u ∂t (6.13) r r r r r r u ( x , t + δ t ) = u ( x , t ) + v δ t∇ 2 u ( x , t ) (6.14) (I − v δ t∇ )ur ( xr , t + δ t ) = ur ( xr , t ) (6.15) 2 34 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Here, I is the identity matrix. This formulation is stable for arbitrary time steps and viscosities. Equation (6.15) is a Poisson equation for velocity. Remember that the use of the Helmholtz-Hodge decomposition results in a Poisson equation for pressure. These equations can be solved using an iterative relaxation technique. Solution of Poisson Equations We need to solve two Poisson equations: The Poisson-pressure equation Viscous diffusions equation These are solved through an iterative approach that starts an approximate solution and improves it r r r every iteration. The poison equation is a matrix equation on the form A x = b , where x is the vector of unknown values. The iterative technique starts with an initial “guess” for the r r solution x ( 0 ) , and each step k produces an improved solution x ( k ) . One of the simplest of these approaches is called Jacobi iteration Both Equation (6.4) and (6.15) can be discretized (See Appenix) and written on the form: x i(−k1), j + x i(+k1), j + x i(,kj )−1 + x i(,kj )+1 + α bi , j r x i(,kj +1 ) = , β (6.16) where α and β are constants. This expression becomes different for the two different Poisson equations. r In the Poisson-pressure equation x represents p δ t , and b represents ∇ ⋅ w , α = (δ x )2 , and β = 4. 2 r For the viscous diffusion equation, x and b represents u , α = (δ x ) , and β = 4 + α . vδt To solve the equations, I simply run a number of iterations in which I apply Equation (6.16). 6.2.4 Initial and Boundary Conditions Any differential equation problem defined on a finite domain requires boundary conditions in order to be well-posed. Also, to compute the evolution of the flow over time, we must know how it started—in other words, its initial conditions. For my fluid simulation, I assume the fluid initially has zero velocity and zero pressure. Because my fluid is simulated on a rectangular grid, I assume that it is a fluid in a box and cannot flow through the sides of the box. For velocity, I use the no-slip condition, which specifies that velocity goes to zero at the boundaries. The correct solution of the Poisson-pressure equation requires pure Neumann boundary conditions: ∂ pr = 0 . This means that at a boundary, the rate of change of pressure in the direction ∂n normal to the boundary is zero. 35 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 6.3 Implementation The implementation provides the simulation code for smoke and fire. The simulation code is based on a simple one-phase-flow. The code is intended for smoke animated seeing as a fire animation model is better approximated by a two-phase-flow (one for the fuel and one for the hot gaseous products) rather than a one-phase flow. However, due to time constraints, I use a one-phase-flow model. The one-phase-flow simulation used the incompressible, invicid Navier-Stokes-equations including a convection and pressure term and external forces for buoyancy and vorticity confinement to update the flow. The stable fluids method from Stam (2003), that provides a semi-lagrange approach for better handling of numerical instabilities, is used to update the fluid state. The stability inherently comes from particle tracing along the streamline backward in time while computing the convection flow. This approach is stable, but pretty much damps out curls and turbulence. In order to ameliorate this problem, a vorticity confinement term is added to the equation to get the turbulence back. In order to animate smoke, density values are placed at the inflow region and are convected through the flow. For displaying fire or a flame, temperature values are convected along steamlines as is done in the smoke animation with the density values. But here, an additional temperature falloff, that simulates the energy exchange with the cooler, surrounding air, is computed. 6.3.1 Discretization To solve the Navier-Stokes equations using a computer, the equations have to be discretized, so numerical methods can be applied. To apply the numerical methods efficiently, the values of the fields representing velocity, pressure, temperature, etc. Should be easy obtainable in the points needed by the numerical methods. This indicates that the discretization of the equations and the discretization of the vector fields are tightly connected, and should thus be considred together, in this chapter, some of the most commonly used discretization methods will be described. Uniform Cartesian Grinds are the most commonly used for computer graphics applications. The grid used in this project is of this type. A Cartesian grid means that cells are axis-aligned boxes. Together, all the boxes form a larger box; hence it can be thought of as a volume. One should think of a uniform Cartesian grid as volume, placed in allpositive octant of a three-dimensional left-handed coordinate system, divided into smaller cells. The lower left cell is placed with one corner in origo. Collocated Grids are a special type of uniform Cartesian grid. In a collocated grid, all fields in the simulation are represented at the centre of cells. I.e., if r p = , C ( c i , j ,k ), c i , j ,k ∈ Φ then r r r u ( p ) = u ( C ( c i , j ,k )) r is represented explicitly in the discretization of the field u with the grid Φ . Values at other positions must be interpolated from the nearest values. To shorten the notation, we will simply use r the u i , j ,k to specify 36 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart r r u i , j ,k = u ( C ( c i , j ,k )), c i , j ,k ∈ Φ . Although this representation is attractive because of its simplicity it has some numerical disadvantages. For instance, when using central differencing, on a collocated grid, the divergence r r ∇ ⋅ u of the velocity field u is computed discretely as: ∂ u ix, j ,k ∂ u iy, j ,k ∂ u iz, j ,k r ∇ ⋅ u i , j ,k = + + = ∂x ∂y ∂z uix+1, j ,k − uix−1, j ,k + u1y, j +1,k − u1y, j −1,k + u1z,1,k +1 − u1z,1,k −1 2h r r I.e., the divergence in point p = C ( c i , j ,k ) is computed without regards to the value u ( p ) of the velocity field in that position. This is a general problem, since a stepwise linear function is not differentiable in the end points of the linear intervals. In this case it actually corresponds to taking the average of the divergences computed in the centre of the neighbouring intervals, since e.g. x x x x x x x 1 ⎛ ∂ui +1 / 2, j ,k ∂ui −1 / 2, j ,k ⎞ 1 ⎛ ui +1, j ,k − ui , j ,k ui , j ,k − ui −1, j ,k ⎞ 1 (u x ⎜ ⎟= ⎜ ⎟ = 2 h i + 1 , j , k − u i −1 , j , k ) . + + ⎟ ∂x ⎟⎠ 2 ⎜⎝ 2 ⎜⎝ ∂x h h ⎠ . This introduces numerical dissipation of the fluid motion, making the fluid appear thicker than it should. Figure 31: Discretization of simulation volume Staggered Grids is another type of uniform Cartesian grid. With this type of grid, the pressure field is still represented at the centre of cells, but velocities are represented on the faces between cells, and could thus be thought of as indicating flow between cells. Many other types of fields are also used in the field of CFD for discretizing the simulation volume. Many of the grids are outside the scope of this thesis. Nevertheless, this is an interesting subject that the reader could do more research into, for example structured grids and adaptive grids. 37 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 6.3.2 Solver Implementation The simulation code is found in Appendix and can be summarized in update per frame as follows: 1. Update temporary velocity field (stable convection) 2. Compute pressure field (solving Poisson’s equation) 3. Project pressure gradients onto temperature velocity field 4. Compute vorticity confinement force 5. Advect temperature values (including falloff) 6. Compute buoyancy-force, dependent on temperature 7. Add integrated forces to the velocity field 6.3.3 Texture implementation Since we are dealing with 3D simulation and thus 3D vector fields, an obvious choice for field representation is to use 3D texture maps. In 3D texture maps, pixels are indexes using 3D coordinates (R,S,T), so no abstraction between grid coordinates and texture coordinates is needed. The colors can then be set for the various RGB components to fit the needs of the simulation. 6.4 Scenario testing 6.4.1 Equipment The computer system Microsoft Windows XP was mainly used. The hardware was a lap top DELL Inspiron with an Intel Pentium Centrino 1.5 GHz with 1 Gb Ram. For the display system, a 17-inch wide WUXGA TFT screen on ATI Mobility Radeon 9600 PRO TURBO 128 MB was applied. The screen ran at a 60 Hz refresh frequency, with a 1920x1200 pixels resolution, and with 32-bit color. The monitor’s contrast and brightness settings were both set to maximum. 38 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 7 Results Chapter 7 presents the test criteria for implementing CFD, explains what was tested and goes through the test scenarios giving the results achieved. 7.1 Test Criteria Solver efficiency: In order for a special effect to work in a 3D graphics engine the algorithm have to run fast. Can the solver actually run in real-time, and what frame rates are actually possible? Fire- and smoke like behaviour: The main purpose of the thesis is to simulate smoke in a 3D game engine. Hence one criterion should be whether the simulation appears to be realistic or not. Interaction with objects: In order for a special effects simulation to be useful in a 3D graphics engine it has to be able to interact with other objects. Hence, does the simulated fluid behave convincingly around inserted objects? The overall performance of the solver depends of many basic operations such as the handling of 3D textures, and the handling and execution of the various steps in the solver as well as the overall C’Nedra game engine. To test all operations explicitly would be an enormous task, and unnecessary. It should be noted that all images displayed are given after a certain timeframe with one second being the most frequent time slice. 7.2 Test Scenarios 7.2.1 Test 1: Advection of the Velocity Field Advection is one of the most important features of fluid motion. Thus, it should be clear, that when put in motion, e.g. by a vent force, the fluid advects accordingly. To test the effect of the fluid advection it self, a scene is set up as shown in the images bellow. Tests are run by only enabling velocity source, velocity advection and mass-conservation steps. To get a clearer view of the advection, the velocity vector field is displayed. Only vectors with a magnitude greater than some minimum are displayed to avoid a lot of small vectors disturbing the picture. Vectors are colored with the color white. When running the test scenario, velocities should advect from the centre of the simulation box towards the facets of the simulation box and arrive simultaneously in all directions and be forced in diagonal stream due to mass-conservation. 39 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart In the pictures bellow we see that the velocities do in fact advect towards the facets of the simulation box and arrive simultaneously. When facets touch each other, the incompressibility forces the fluid outwards in diagonal streams as expected. The streams are not perfectly symmetric however, which may be due to some type of calculation error. Figure 32: Advection of the velocity field t=0 t=1s t=2s t=3s t=4s t=5s t=6s t=7s t=8s 40 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 7.2.2 Test 2: Advection of the Density Field This test investigates the ability of another field to advect freely along the velocity field. For this test the setup shown in the figures presented bellow. This test is run with the following steps enabled: velocity source, velocity advection, density source, and density advection. The result should be velocity vectors (white) moving through the density field (yellow) in the simulation box. The velocity force is applied in one end of a rectangular box and the results shows the velocity vectors propagating causing the density field to advect. Figure 33: Advection of the density field t=0 t=1s t=2s t=3s t=4s t=5s t=6s t=7s t=8s 41 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 7.2.3 Test 3: Thermal Buoyancy Differences in temperature should give rise to according forces: Heat should cause smoke to rise, and cold should cause smoke to fall down. Test 3a. Heat Source Here the velocity source step is disabled in order to disable the vent force and enable the temperature source and thermal buoyancy steps. Herby a hot temperature source is inserted that should cause the density to rise. Figure 34: Hot smoke rising with all steps in the algorithm enabled t=0 t=1s t=2s t=3s t=4s t=5s t=6 t=7s t=8s 42 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart t=9 t=10s t=11s As can be inferred from the pictures the smoke does in fact rise in a realistic smoke like behavior. Test 3b. Cold Source In this test the smoke is turned upside down. Density and a cold source are inserted in the top of the simulation box. The enabled steps are: velocity advection, density source, density advection temperature source, and thermal buoyancy. When running this test, the density should stream downward, hit the ground and stream outward and up the sides of the simulation box. Figure 35: Cold smoke falling and ring up the sides of the simulation box t=0 t=1s t=2s t=3s t=4s t=5s 43 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart t=6 t=9 t=7s t=8s t=10s t=11s As can be seen in the pictures the smoke does in fact fall down and stream upward the sides of the simulation box implying smoke like behavior that follows the properties of buoyancy. 7.2.4 Test 4: Vorticity Confinement These tests aim to investigate the effect of adding vorticity confinement to the simulation. As was described in previous chapters vorticity confinement improves the numerical solution of the Navier-Stokes equations by adding turbulence back. Test 4a. Vorticity Confinement Disabled This simulation is run without vorticity confinement showing smoke rising without turbulence decreasing the realism of the simulation. The smoke more looks like a beam than realistic smoke. Figure 36: Smoke rising with vorticity confinement disabled t=0 t=1s 44 t=2s Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart t=3s t=4s t=5s t=6 t=7s t=8s t=10s t=11s t=9 Test 4b. Vorticity Confinement Enabled Now the same simulation as 4a is run but with vortcity confinement enabled, which should cause the rising smoke to be more disturbed, and thus, more smoke-like than the smooth streams of previous tests. 45 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Figure 37: Smoke rising with vorticity confinement enabled t=0 t=1s t=2s t=3s t=4s t=5s t=6 t=7s t=8s t=9 t=10s t=11s The pictures show that swirls are added to the smoke stream, and the stream is widened on its way to the top of the box. Hence the simulation looks much more realistic with turbulence. One can conclude that vorticity confinement does add the effect expected and creates realistic smoke like behavior. 46 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 7.2.5 Test 5: Colored Density By changing the RGB values of the smoke we can achieve smoke with various colors and alpha components. Bellow I present red smoke: Figure 38: Red hot smoke rising t=0 t=1s t=2s t=3s t=4s t=5s t=6 t=9 t=7s t=10s 47 t=8s t=11s Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Hence by showing that one can change the color of the smoke as well as the alpha component one can achieve various results suitable for various simulated environments. This increases the flexibility in creating realistic simulations. 7.2.6 Test 6: Boundaries Seeing as the handling of internal boundaries in the solver is very straight forward, these tests should be seen as a clarification of its capabilities. I introduce a simple, solid object into the fluid. The setup is shown in the starting image of the simulation. All the solver steps are enabled. Test 6a. Object submerged in smoke In this simulation a simple, solid object is introduced into the fluid. The setup is show in the pictures bellow. The smoke should advect upwards until reaching the object. It should then curl around the object, and form a wider, less dense stream above the object. Figure 39: Red smoke with object boundary t=0s t=1s t=2s t=3s t=4s t=5s t=6s t=7s t=8s 48 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart t=9 t=10s t=11s From the results of the test shown in the figure, we see that the simple method actually works very well with a simple object. The smoke rises with the object, it is forced around the object, and continues upwards with a curling behaviour. Test 6b. Burning object We now turn to setting an object on fire. The approach is analogue to simulating smoke; however here a temperature gradient is added and advected in the form of texture. This feature creates a fire like behavior with the same properties as the smoke with regards to objects. Hence the following simulation is possible: Figure 40: Single burning object t=0 t=1s t=2s t=3 t=4s t=5s 49 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart t=6s t=9 t=7s t=8s t=10s t=11s The images show how the object slowly turns on fire by overheating and then bursting into fire. Seeing as an object that is burning actually is turned into a gas the simulation becomes quite realistic. In terms of efficiency it runs on the same level as the smoke simulation. One drawback of the simulation is that the grid size implemented only allows for a certain size of the object. Hence in order to create large scale fires one would need a large grid which is not feasible due to the need of high performance in 3D game engines. 7.2.7 Test 7: Exploding Object This simulation intends to display the capabilities of the fluid solver in creating other effect by interacting with the fluid with the aim of displaying explosions. A burning object is thus expanded and then eliminated creating the illusion of an explosion. Figure 41: Exploding object t=0 t=1s 50 t=2s Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart t=3s t=4s t=5s t=6 t=7s t=8s t=9 t=10s t=11s This efficiency of the simulation is similar to that of the other simulations. By turning an object on fire, expanding and then rapidly disabling it, a mushroom like cloud is created. This shows the versatility of the algorithm making it useful for in more applications. 7.2.8 Test 8: Time & Gridsize By having shown that the implementation can in fact produce quite realistic effect we turn to performance. The first test to measure performance is to measure the frame rate on varying grid sizes. The obtainable frame rate is very dependent of the size of the grid – a larger grid yields a lower frame rate. These tests are meant to clarify the relation between the size of a grid and the fame rate of the simulation with that grid. The graph bellow summarized the results yielded: 51 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Figure 42: Showing how frame rate changes with grid size 70 60 Frames/second 50 40 30 20 10 0 4x4x4 8x8x8 16x16x16 32x32x32 64x64x64 60,121 50,349 11,976 1,449 0 Grid size The simulation clearly shows that the solver is dependent on the size of the grid; the smaller the grid volume the better frame rate for the simulation. For a simulation to be minimal useful the quality of a 16x16x16 grid size is need with gives us only 12-14 frames per second. Increasing the grid size gives catastrophic results. These results prove that the implementation is not efficient in the plug-in setting of the C’Nedra game engine. In the following tests I check for parameters that might improve the performances of the implementation. 7.2.9 Test 9: Number of Iterations in the Pressure Solver Figure 43: Displays how frame rate changes with the number of iterations 16 14 Frames/second 12 10 8 6 4 2 200 190 180 170 160 150 140 130 120 110 90 100 80 70 60 50 40 30 20 10 1 0 Number of Iterations By increasing the number of iterations in the pressure solver we see that the frame rate falls. What is interesting is that the quality of the fluid animation does not seem to be affected with the number of iterations in the pressure solver. 52 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 7.2.10 Test 10: Time and Stability In all previous tests the time step has been fixed to 0.01 corresponding to 13-14 frames per second. In this section experiments are made with different time steps to explore the stability of the solver when using the time steps as a variable. The results are presented in the graph bellow: Figure 44: Showing how the frame rate changes with time steps 14 13,5 Frames/second 13 12,5 12 11,5 11 10,5 0,00001 0,0001 0,001 0,01 0,1 1 10 100 1000 10000 100000 dt From the graph one can infer that there does not seem to be any clear correlation between frame rates and time steps. The graphics quality of the simulation was negligibly affected. Hence we conclude that decreasing the number of iterations does only marginally increase frame rate. 7.2.11 Test 11: Texture Precision In this test we will run the same simulation as before but with different texture map precision to get a feeling of how much influence the frame rate and graphics quality. From the results summarized in the graph bellow we see that when increasing the bit quality of the textures the frame rate falls heavily. Hence one can conclude that lowering the texture precision does only marginally improve the frame rate. Figure 45: Frame rate as a function of texture precision 16 14 Frames/second 12 10 8 6 4 2 0 8-bit 16-bit 32-bit 14,392 10,121 8,432 Texture precision 53 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 7.2.12 Test 12: Multiple Instances These tests are designed to test the efficiency of running multiple instances of fires, burning objects and smoke on the same time. Test 12a. Simultaneously burning fires We first simulate two burning fires. When running the simulation it becomes clear that on average it runs with half the speed of only running one instance. The realism is quite good and the reader can observe burning fires, burning objects as well as simulteanous smoke in the following images. Figure 46: Simultaneously burning fires t=0 t=2s t=4s t=6 t=8s t=10s t=12 t=14s t=16s 54 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart t=18 t=20s t=22s t=2s t=4s Test 12b. Simultaneously burning objects Figure 47: Simultaneously igniting and burning objects t=0 t=6 t=8s t=10s t=12 t=14s t=16s 55 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart t=18 t=20s t=22s t=0 t=2s t=4s t=6 t=8s t=10s Test 12c. Simultaneous black smoke Figure 48: Simultaneous black hot smoke rising 56 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart t=12 t=14s t=16s t=18 t=20s t=22s Hence we conclude that due to the poor performance of the simulation it is difficult to run this implementation of fluid dynamics in a computer game. A computer game would need the possibility of many multiple fires and smoke in order to for example simulate a battle field. In terms of realism the implementation has positive results but in terms of performance the implementation has unfavorable results. 57 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 7.3 Summary of Results The table bellow summarizes the main results found when conducting the simulations showing that the C’Nedra game engine is not a good platform to implement the Stam fluid algorithm. Figure 49: A summary of the results Realism Advection works. Vorticity confinement works. Thermal buoyancy works. Temperature gradient works making it possible to simulate fire. Pigmentation and translucency is possible. Boundaries work (object submerged in smoke and objects burning). Performance On a 16x16x16 grid the simulation has only 12 frames/second showing that only very small grid sizes are possible. Decreasing the number of iterations in the pressure solver only marginally improves frame rate. Frame rate only increases marginally with lower texture precision. Multiple instances run extremely slowly. With regards to the quality of the simulation one can without performing any in depth tests infer that the smoke and fire like behavior is satisfactory. The reason for the mediocre performances may be that the algorithm is difficult to implement correctly in general. Seeing as the algorithm has been used in real-time games this should not be the case. Instead, I infer that the experimental structure of C’Nedra makes the interaction of the algorithm in the form of a plug-in extremely slow. Another reason for low performance may be due to having chosen to solve the algorithm on a rectangular grid. Today, there are newer implementations that have tried to solve the algorithm on other data structures such as octrees. This might give better performance. With regards to the quality of the simulation one can without performing any in depth tests infer that the smoke and fire behavior is satisfactory. One way of testing which of the above causes have the largest impact on the simulation would be to make a simple implementation of the algorithm in a lean-and-mean standalone graphics application on various grids and measure the performance. Due to time constraints this was deemed to be out of the scope for this thesis. 58 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 8 Conclusions Chapter 8 discusses the results and draws conclusions from the work carried out on the game engine, the CFD solver implemented and the scenarios tested. I will start this chapter by returning to the first chapter and my posed problem statement: Can realistic fluid dynamics be run efficiently in the C’Nedra game engine? Well, after having acquired substantial knowledge of how to develop software with the C’Nedra toolkit and its overall performance as well as run the various simulations, I conclude that it is not advised to use C’Nedra as a platform for CFD development. I conclude this on the overall difficulty in implementing plug-ins in the engine and the performance yielded from the simulations. The game engine in its current form is highly unstable and lacks pertinent documentation. The temptation of creating a game engine from scratch is time consuming and hence it would be more beneficial to use one of the more robust and established ones either open source or commercial. Having tried some existing established game engines during due course of the project in educational purpose such as Ogre and Torque as explained in the first chapter, I would recommend any of these engines both in a commercial and educational objective, seeing as they contain a tremendous amount of advanced functionalities already. It is therefore straightforward to extend these as they come with documentation and well documented source code. Both engines are highly robust and are being used in commercial applications. 8.1 Possible improvements in C’Nedra Figure 50: A summary of possible improvements in C’Nedra Skeletal body support. Artificial Intelligence support. Improved terrain engine with artificially generated terrain. Additional special effects such as water effects, lens flares, etc. Improved performance and error handling. Vertex shader support 59 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 8.2 Possible improvement of fluid dynamics in C’Nedra In many aspects the C’Nedra engine is outdated as to regards to performance seeing as there or more competitive open source engines out there such as Ogre or price worthy commercial ones such as Torque it would be of interest to move to these platform for Ecole Centrale Paris and continue development to continue development and testing of CFD. For static effects we could animate the fluid effect in Maya and then import it into the game engine making the costly real-time calculations of solving the Navier-Stokes eliminated to the cost of running the animation. This takes away the ability for the user to interact with the fluid in real-time. In this last section I summarize some of the possible improvements to the implemented special effects plug-in. Figure 51: A summary of possible improvements to C’Nedra pertaining to fluid dynamics Implementing and solving the fluid algorithm of Navier-Stokes on various other grids such as for example octrees. Implementing other fluid effects with Navier-Stokes such as water effects. Trying other approaches of simulating fluid effects such as for example particle systems. Implementing a lean-and-mean version of the algorithm in a standalone graphics application. 60 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 9 Critique In this last chapter I criticise the work performed as well as the results achieved. I also talk about the fast development in the field of Computational Fluid Dynamics and game engine design. 9.1 Problems Experienced The project work was carried out in a timely fashion; however due to personal high set goals on further developing the 3D game engine upon returning from France and pursuing studies at Stockholm School of Economics delayed this written report. Finally, due to the passing of my mother I had to take time in order to sort out personal issues. Hence, the finalization of this project could have been carried out faster and more in line with the project planning. 9.2 Field Developing Fast Seeing as the field computer graphics is very fast moving, the current standards have changed a lot, even in the rather short duration of this project. Thus, elements of this report may already be outdated at the time it is turned in. When reading, it should be kept in mind that this report only reflects a snapshot of the available methods and features, at the time of writing. During my work with this project, others have published material on the same subject, some too late for me to take their work into account and appreciation. As a result of this, related or even duplicate work may exist, which have not been considered in the analysis. It is my conviction, however, that this report is still legitimate as an introductory text on the subject, and show legitimate results. 61 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 10 Literature 10.1 CFD literature [1] Chen, J. and Lobo, N., “Toward Interactive-Rate Simulation of Fluids with Moving Obstacles Using Navier-Stokes Equations”. Graphical Models and Image Processing, 57(2), 1995, pp. 107-116. [2] Ebert, D. S. and Parent, R. E. “Rendering and Animation of Gaseous Phenomena by Combining Fast Volume and Scanline A-buffer Techniques”. Computer Graphics (SIGGRAPH 90 Conference Proceedings), 24(4):357366, August 1990. [3] Fedkiw, R., Stam, J. and Wann Jensen, H., "Visual Simulation of Smoke", In SIGGRAPH 2001 Conference Proceedings, Annual Conference Series, August 2001, 1-8. [4] Foster N. and Fedkiw, R., “Practical Animation of Liquids”, SIGGRAPH 2001 (in press). [5] Foster, N. and Metaxas, D., “Modeling the Motion of Hot, Turbulent Gas”, Proceedings of SIGGRAPH '97. [6] Foster, N. and Metaxas, D., “Controlling Fluid Animation”, Proceedings CGI '97, pp. 178-188. [7] Foster, N. and Metaxas, D., “Realistic Animation of Liquids”, Proceedings GI '96, pp. 204-212. [8] Gardner, “Visual Simulation of Clouds”. Computer Graphics (SIGGRAPH 85 Conference Proceedings), 19(3):297384, July 1985. [9] Guendelman et al. “Coupling Water and Smoke to Thin Deformable and Rigid Shell”, ACM SIGGRAPH 2005, ACM TOG 24, Pages 973-981. [10] Johanson, C. “Real-time water rendering – Introducing the projected grid concept”, Lund University 2004. [11] Kass, M. and Miller, G., “Rapid, Stable Fluid Dynamics for Computer Graphics”. ACM Computer Graphics (SIGGRAPH '90), 24(4):4957, August 1990. [12] Losasso et al., "Simulating Water and Smoke With an Octree Data Struture ", In SIGGRAPH 2004 Conference Proceedings, Annual Conference Series, August 2001, 1-8. ACM TOG 23, pages 457462. [13] O'Brien, J. F. and Hodgins, J. K., “Dynamic Simulation of Splashing Fluids.” Proceedings of 62 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Computer Animation `95, Geneva Switzerland, April 19-21, pp. 198-205. [14] Reeves, W. T., “Particle Systems. A Technique for Modelling a Class of Fuzzy Objects”. ACM Computer Graphics (SIGGRAPH '83), 17(3):359376, July 1983. [15] Stam, J., “Stable Fluids”, In SIGGRAPH 99 Conference Proceedings, Annual Conference Series, August 1999, 121-128. [16] Stam, J., “A General Animation Framework for Gaseous Phenomena”. ERCIM Research Report, R047, January 1997. [17] Stam, J. and Fiume, E., “Turbulent Wind Fields for Gaseous Phenomena”, In SIGGRAPH 93 Conference Proceedings, Annual Conference Series, August 1993, 369-376. [18] Stam, J. and Fiume, E., "Depicting Fire and Other Gaseous Phenomena Using Diffusion Processes". In Proceedings of SIGGRAPH ’95, pages 129136. Addison-Wesley Publishing Company, August 1995. [19] Selle et al. “A Vortex Particel Method for Smoke, Water and Explosions”, ACM SIGGRAPH 2005, ACM TOG 24, Pages 973-981. [20] Stang, B. “Game Engines Features and possibilities”, IMM DTU 2003. [21] Y. Dobashi, K. Kaneda, T. Okita, and T. Nishita. ”A Simple, Efficient Method for Realistic Animation of Clouds”. In SIGGRAPH 2000 Conference Proceedings, Annual Conference Series, pages 1928, July 2000. 10.2 Textbooks [22] Angel E. 2001.Computer graphics, a top down approach. Prentice Hall. ISBN 123456789. [23] Candel, S., 1995. Mécanique des fluides, DUNOD, ISBN 2-10-001136-7. [24] Dalmau S. 2003. Core Techniques and Algorithms. New Riders Publishing. ISBN 0-1310-2009 9. [25] Eberly, D. “3D Game Engine Design”. Academic Press, 2001. ISBN 1558605932. [26] Millington, I. “Artificial Intelligence for Games”. Morgan Kaufman. ISBN 0129977820. 63 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart 10.3 Internet sources [27] Microsoft Direct X (www.microsoft.com/windows/directx/default.aspx) [28] OpenAl (www.openal.org) [29] OpenGl (www.opengl.org) [30] Tokamak (www.tokamakphysics.com/) 64 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Appendix 1: Notation Mathematics plays an important role in the simulation of fluid dynamics. In the following section, I introduce the notation used in this report. Also, I introduce some mathematical concepts, which are used extensively throughout the report. Vectors and Vector Fields r I denote vectors with small caps with an arrow above, e.g. v . Similarly, vector fields will be written r in small caps with an arrow above, e.g. v (x ) . When nothing else is mentioned, vectors are assumed r three-dimensional, i.e. v ∈ ℜ3 , and vector fields are assumed to functions r v ( x ) : ℜ3 → ℜ3 . Vectors and vector fields will sometimes be written component wise. In this case we will use the notations: being T r v = (v x , v y , v z ) , v x , v y , v z ∈ ℜ, T r v ( x ) = (v x ( x ), v y ( x ), v y ( x ) ) , v x ( x ), v y ( x ), v y ( x ) ∈ ℜ x ∈ ℜ3 . The Gradient Operator The equations of fluid motion are highly dependent on the gradient operator, ∇ (nabla), defined by T ⎛ ∂ ∂ ∂⎞ ∇ = ⎜⎜ , , ⎟⎟ . ⎝ ∂x ∂ y ∂ z ⎠ For a scalar field s ( x ) I define the gradient of the scalar field: T ⎛ ∂( x ) ∂( x ) ∂( x ) ⎞ , , ∇s ( x ) = ⎜⎜ ⎟ , ∂y ∂z ⎟⎠ ⎝ ∂x x ∈ ℜ3 , r For the vector field v ( x ) I define the divergence of the vector field: r ∂v x ( x ) ∂v y ( x ) ∂v z ( x ) ∇ ⋅ v ( x) = + + , ∂x ∂y ∂z x ∈ ℜ3 , And the curl of the vector field ⎛ ∂v x ( x ) ⎜ ⎜ ∂y ⎜ ∂v x ( x ) ∇ × v( x ) = ⎜ ⎜ ∂y z ⎜ ∂v ( x ) ⎜ ∂x ⎝ − − − r For a vector field v ( x ) I use the notation: 65 ∂v y ( x ) ⎞ ⎟ ∂z ⎟ ∂v x ( x ) ⎟ ⎟, ∂x ⎟ ∂v x ( x ) ⎟ ∂y ⎟⎠ x ∈ ℜ3 . Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart ⎛ ∂ 2v x ( x) ⎜ 2 ⎜ ∂x ⎜ ∂ 2 v y ( x) r ∇ ⋅ (∇v ( x ) ) = ⎜ 2 ⎜ 2∂xz ⎜ ∂ v ( x) ⎜ ∂x 2 ⎝ r ∂ 2 v x ( x) + ∂y 2 ∂ 2 v y ( x) + + ∂y 2 ∂ 2v z ( x) + + ∂y 2 + ∂ 2 v x ( x) ⎞ ⎟ ∂z 2 ⎟ ∂ 2v y ( x) ⎟ ⎟, ∂z 2 ⎟ ∂ 2v z ( x) ⎟ ∂z 2 ⎟⎠ x ∈ ℜ3 , r And for vector fields v (x ) and w(x ) I use the notation: ⎛ x ∂w x ( x ) ⎜ v ( x) ∂x ⎜ y ⎜ (vr ( x ) ⋅ ∇ )wr = ⎜ v x ( x ) ∂w ( x ) ∂x ⎜ z ⎜ v x ( x ) ∂w ( x ) ⎜ ∂x ⎝ ∂w x ( x ) ⎞ ∂w x ( x ) ⎟ + v z ( x) ∂z 2 ⎟ ∂y ∂w y ( x ) ⎟ ∂w y ( x ) + v z ( x) + v y ( x) ⎟, ∂z 2 ⎟ ∂y ∂w z ( x ) ⎟ ∂w z ( x ) + v z ( x) + v y ( x) ∂z 2 ⎟⎠ ∂y + v y ( x) Which finally gives us the laplacian: ∇ ⋅ ∇ = ∇2 . 66 x ∈ ℜ3 , Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Appendix 2: C’Nedra XML file <?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?> - <Configuration> - <I_MsgHandler> <speed movement="6" rotation="5" jump="15" /> <movement_type name="fly" /> <mouse enabled="1" sensitivity="0.3" /> </I_MsgHandler> <Timer name="GlobalTimer" /> - <I_3D> <I_Window ref="CNedraWindow" /> <landscape texture="dat/terrain.png" texture_details="dat/terrain.png" step="64" detail_tex_paramX="0.01" detail_tex_paramZ="0.01" /> <sky top="dat/sky.png" bottom="dat/sky.png" face1="dat/sky.png" face2="dat/sky.png" face3="dat/sky.png" face4="dat/sky.png" distance="4000" /> <light id="0" positional="0" x="0" y="0.8" z="1" shininess="1" specular_r="0" specular_g="0" specular_b="0" specular_a="1" diffuse_r="1" diffuse_g="1" diffuse_b="1" diffuse_a="1" ambient_r="0" ambient_g="0" ambient_b="0" ambient_a="1" /> <light id="1" positional="1" x="0" y="100" z="0" shininess="1" specular_r="0" specular_g="0" specular_b="0" specular_a="1" diffuse_r="1" diffuse_g="1" diffuse_b="1" diffuse_a="1" ambient_r="1" ambient_g="0" ambient_b="0" ambient_a="1" /> - <object_description> <eglise type="3ds" /> <player type="3ds" /> <balle type="3ds" /> <tank type="3ds" /> </object_description> </I_3D> - <descent load="true" type="singleplayer" frame_time="20"> <Timer ref="GlobalTimer" /> <I_Window ref="CNedraWindow" /> - <I_Fps> <I_Window ref="CNedraWindow" /> <Timer ref="GlobalTimer" /> </I_Fps> - <I_Sound NbBuffers="3" BufferSizeMilliSec="100000"> <Timer ref="GlobalTimer" /> </I_Sound> - <Sounds> <Cathedrale sound="dat/sounds/collision-cathedrale-1.wav" /> <Cathedrale sound="dat/sounds/collision-cathedrale-2.wav" /> <ShootBall sound="dat/sounds/rocket.wav" /> <OnQ sound="dat/sounds/touche-q-1.wav" /> <OnQ sound="dat/sounds/touche-q-2.wav" /> </Sounds> </descent> - <I_World viscosity="0.3" airviscosity="0.005" gravity="0.4" gravitation_constant="0" maxspeed="2000"> <landscape heightmap="dat/hmap.bmp" sizeX="2000" sizeZ="2000" /> <player x="0" y="100" z="400" theta="0" mass="100" HP="100" /> <balle mass="5" timer="50" damage="20" /> <object type="tank" x="0" y="500" z="0" mass="100" /> 67 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart <object type="tank" x="1500" y="500" z="0" mass="100" /> <object type="eglise" x="0" y="20" z="-1500" theta="-90" static="1" /> </I_World> </Configuration> 68 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart Appendix 3: CFD Solver Code /* This codes extends Stam’s algorithm which is copyright and patented by Alias. Hence this extension should only be used for academic research and not for commercial applications. */ #include "CFD_Cnedra.h" #include "CFD_Cnedra_utils.h" #include "perlin.h" #include <stdlib.h> #include <math.h> #include #include #include #include #include <windows.h> <GL/gl.h> <GL/glu.h> "glext.h" <math.h> #define I(i,j,k) ((i) + ((NX)+2)*(j) + ((NX)+2)*((NY)+2)*(k)) #define FOR_EACH_CELL for(i=1; i<=NX; ++i) { for(j=1; j<=NY; ++j) { for(k=1; k<=NZ; ++k) { #define END_FOR }}} #define MAX_ITER 5 #define INFLOW_PAUSE 100 extern int CFD_showFieldId; extern bool CFD_useObstacles; extern float CFD_obstX, CFD_obstY, CFD_obstZ, CFD_obstR; static float dt = 0.001; static const float INFLOW_VEL =1.0f; static float CFD_vortConf=3.0f, CFD_buoy=0.3f; float CFD_airT=1.0f, CFD_smokeT=300.0f, CFD_coolConst=1000.0f; //1000 int i,j,k; float x,y,z; CFD_Cnedra::CFD_Cnedra() : NX(CELLS_IN_X), NY(CELLS_IN_Y), NZ(CELLS_IN_Z), eR(2.5f), h(1.0f) { p1x=(NX+2)/2; p0x=-p1x; p1y=(NY+2)/2; p0y=-p1y; p1z=(NZ+2)/2; p0z=-p1z; size=(NX+2)*(NY+2)*(NZ+2); fDens=1.0f; fVsc=0.0f; fU0 = new float[size]; fV0 = new float[size]; fW0 = new float[size]; fU1 = new float[size]; fV1 = new float[size]; fW1 = new float[size]; fDiv = new float[size]; fP = new float[size]; CU = new float[size]; CV = new float[size]; CW = new float[size]; D0 = new float[size]; D1 = new float[size]; T0 = new float[size]; T1 = new float[size]; BU = new float[size]; M = new int[size]; N2D_B = new float[NX*NZ*3]; memset(fU0,0,size*sizeof(float)); memset(fV0,0,size*sizeof(float)); memset(fW0,0,size*sizeof(float)); memset(fU1,0,size*sizeof(float)); memset(fV1,0,size*sizeof(float)); memset(fW1,0,size*sizeof(float)); memset(fDiv,0,size*sizeof(float)); memset(fP,0,size*sizeof(float)); memset(CU,0,size*sizeof(float)); memset(CV,0,size*sizeof(float)); memset(CW,0,size*sizeof(float)); memset(D0,0,size*sizeof(float)); memset(D1,0,size*sizeof(float)); memset(T0,0,size*sizeof(float)); memset(T1,0,size*sizeof(float)); memset(BU,0,size*sizeof(float)); memset(M,0,size*sizeof(int)); 69 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart if (CFD_useObstacles==true) { FOR_EACH_CELL x=(float)(i-p1x)-CFD_obstX; y=(float)(j-p1y)-CFD_obstY; z=(float)(k-p1z)-CFD_obstZ; if((x-1)*(x-1) + (y+(CELLS_IN_Y/4))*(y+(CELLS_IN_Y/4)) + z*z < CFD_obstR*CFD_obstR) { M[I(i,j,k)]=1; } END_FOR } } CFD_Cnedra::~CFD_Cnedra() { delete [] fU0; delete [] fV0; delete [] fW0; delete [] fU1; delete [] fV1; delete [] fW1; delete [] fDiv; delete [] fP; delete [] CU; delete [] CV; delete [] CW; delete [] D0; delete [] D1; delete [] T0; delete [] T1; delete [] BU; delete [] M; delete [] N2D_B; } void CFD_Cnedra::addForce(float* u0, float* v0, float* w0, float* su, float* sv, float* sw) { for(int i=0; i<size; ++i) { u0[i]+=dt*su[i]; v0[i]+=dt*sv[i]; w0[i]+=dt*sw[i]; } } void CFD_Cnedra::diffuse(float vsc, float* a0, float* a1) { float _sum,_invA=1.0f/(dt*6.0f+1); setBnd(a1); FOR_EACH_CELL _sum=a1[I(i-1,j,k)]+a1[I(i+1,j,k)]+a1[I(i,j1,k)]+a1[I(i,j+1,k)]+a1[I(i,j,k-1)]+a1[I(i,j,k+1)]; a0[I(i,j,k)] = a1[I(i,j,k)] + dt*vsc * (_sum - a1[I(i,j,k)]*6); END_FOR setBnd(a0); } void CFD_Cnedra::advect(float* a0, float* a1, float* u, float* v, float* w) { int x0,x1, y0,y1, z0,z1; FOR_EACH_CELL x=i-(dt*u[I(i,j,k)]); y=j-(dt*v[I(i,j,k)]); z=k(dt*w[I(i,j,k)]); // 3 if(x<0.5f) {x=0.5f;} if(x>NX+0.5f) {x=NX+0.5f;} x0=(int)x; x1=x0+1; // 4 if(y<0.5f) {y=0.5f;} if(y>NY+0.5f) {y=NY+0.5f;} y0=(int)y; y1=y0+1; // 4 if(z<0.5f) {z=0.5f;} if(z>NZ+0.5f) {z=NZ+0.5f;} z0=(int)z; z1=z0+1; // 4 a0[I(i,j,k)]=trilerp(a1[I(x0,y0,z0)],a1[I(x1,y0,z0)],a1[I(x0,y1,z0)],a 1[I(x1,y1,z0)], a1[I(x0,y0,z1)],a1[I(x1,y0,z1)],a1[I(x0,y1,z1)],a1[I(x1,y1,z1)], x-x0, y-y0, z-z0); END_FOR } void CFD_Cnedra::project(float* u0, float* u1, float* v0, float* v1, float* w0, float* w1, float* div, float* p, float matDens) { FOR_EACH_CELL 70 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart div[I(i,j,k)] = ((u1[I(i+1,j,k)]-u1[I(i-1,j,k)]) + (v1[I(i,j+1,k)]-v1[I(i,j-1,k)]) + (w1[I(i,j,k+1)]-w1[I(i,j,k-1)])) * 0.5f; p[I(i,j,k)] = 0.0f; END_FOR setBnd(div); setBnd(p); int _cf=6; float lhs; for (int l=0; l<MAX_ITER; ++l) { FOR_EACH_CELL if(CFD_useObstacles) { int _L=1-M[I(i-1,j,k)]; int _R=1-M[I(i+1,j,k)]; int _B=1M[I(i,j-1,k)]; int _T=1-M[I(i,j+1,k)]; int _N=1-M[I(i,j,k-1)]; int _F=1-M[I(i,j,k+1)]; _cf=(_L+_R)+(_B+_T)+(_N+_F); lhs=_L*p[I(i-1,j,k)]+_R*p[I(i+1,j,k)]+_B*p[I(i,j1,k)]+_T*p[I(i,j+1,k)]+_N*p[I(i,j,k-1)]+_F*p[I(i,j,k+1)]; } else { lhs=p[I(i-1,j,k)]+p[I(i+1,j,k)]+p[I(i,j1,k)]+p[I(i,j+1,k)]+p[I(i,j,k-1)]+p[I(i,j,k+1)];} if(_cf!=0) {p[I(i,j,k)]=(lhs-(div[I(i,j,k)]/dt))/_cf;} END_FOR setBnd(p); } FOR_EACH_CELL u0[I(i,j,k)] = u1[I(i,j,k)] dt*(((p[I(i+1,j,k)]-p[I(i-1,j,k)])*0.5f)); v0[I(i,j,k)] = v1[I(i,j,k)] dt*(((p[I(i,j+1,k)]-p[I(i,j-1,k)])*0.5f)); w0[I(i,j,k)] = w1[I(i,j,k)] - dt*(((p[I(i,j,k+1)]-p[I(i,j,k1)])*0.5f)); END_FOR setBnd(u0); setBnd(v0); setBnd(w0); } void CFD_Cnedra::setBnd(float *f) { for(i=1; i<=NX; ++i) for(j=1; j<=NY; ++j) { f[I(i,j,0)] = f[I(i,j,1)]; f[I(i,j,NZ+1)] = f[I(i,j,NZ)]; } for(j=1; j<=NY; ++j) for(k=1; k<=NZ; ++k) { f[I(0,j,k)] = f[I(1,j,k)]; f[I(NX+1,j,k)] = f[I(NX,j,k)]; } for(i=1; i<=NX; ++i) for(k=1; k<=NZ; ++k) { f[I(i,0,k)] = f[I(i,1,k)]; f[I(i,NY+1,k)] = f[I(i,NY,k)]; } for (i=1; i<=NX; ++i) { f[I(i,0,0)] = (f[I(i,1,0)] + f[I(i,0,1)]) * 0.5f; f[I(i,NY+1,0)] = (f[I(i,NY,0)] + f[I(i,NY+1,1)]) * 0.5f; f[I(i,0,NZ+1)] = (f[I(i,0,NZ)] + f[I(i,1,NZ+1)]) * 0.5f; f[I(i,NY+1,NZ+1)] = (f[I(i,NY,NZ+1)] + f[I(i,NY+1,NZ)]) * 0.5f; } for (j=1; j<=NY; ++j) { f[I(0,j,0)] = (f[I(1,j,0)] + f[I(0,j,1)]) * 0.5f; f[I(NX+1,j,0)] = (f[I(NX,j,0)] + f[I(NX+1,j,1)]) * 0.5f; f[I(0,j,NZ+1)] = (f[I(0,j,NZ)] + f[I(1,j,NZ+1)]) * 0.5f; f[I(NX+1,j,NZ+1)] = (f[I(NX,j,NZ+1)] + f[I(NX+1,j,NZ)]) * 0.5f; } for (k=1; k<=NZ; ++k) { f[I(0,0,k)] = (f[I(0,1,k)] + f[I(1,0,k)]) * 0.5f; f[I(0,NY+1,k)] = (f[I(0,NY,k)] + f[I(1,NY+1,k)]) * 0.5f; f[I(NX+1,0,k)] = (f[I(NX,0,k)] + f[I(NX+1,1,k)]) * 0.5f; 71 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart f[I(NX+1,NY+1,k)] = (f[I(NX+1,NY,k)] + f[I(NX,NY+1,k)]) * 0.5f; } f[I(0,0,0)] = (f[I(1,0,0)] + f[I(0,1,0)] + f[I(0,0,1)]) * 0.3333333f; f[I(NX+1,0,0)] = (f[I(NX,0,0)] + f[I(NX+1,1,0)] + f[I(NX+1,0,1)]) * 0.3333333f; f[I(0,NY+1,0)] = (f[I(1,NY+1,0)] + f[I(0,NY,0)] + f[I(0,NY+1,1)]) * 0.3333333f; f[I(0,0,NZ+1)] = (f[I(1,0,NZ+1)] + f[I(0,1,NZ+1)] + f[I(0,0,NZ)]) * 0.3333333f; f[I(NX+1,NY+1,0)] = (f[I(NX,NY+1,0)] + f[I(NX+1,NY,0)] + f[I(NX+1,NY+1,1)]) * 0.3333333f; f[I(0,NY+1,NZ+1)] = (f[I(0,NY,NZ+1)] + f[I(0,NY+1,NZ)] + f[I(1,NY+1,NZ+1)]) * 0.3333333f; f[I(NX+1,0,NZ+1)] = (f[I(NX,0,NZ+1)] + f[I(NX+1,0,NZ)] + f[I(NX+1,1,NZ+1)]) * 0.3333333f; f[I(NX+1,NY+1,NZ+1)] = (f[I(NX,NY+1,NZ+1)]+f[I(NX+1,NY,NZ+1)]+f[I(NX+1,NY+1,NZ)]) * 0.3333333f; } void CFD_Cnedra::setInflow(float* fu0, float* fv0, float* fw0) { this->genN2DMap(N2D_B,NX,NZ, 0.05f); for(i=1;i<=NX;++i) for(k=1;k<=NZ;++k) { x=(float)(i-p1x); z=(float)(k-p1z); if((x*x + z*z)<eR*eR) { fu0[I(i,1,k)] = (N2D_B[k*NX*3+i*3]) * INFLOW_VEL * 0.5f; fv0[I(i,1,k)] = ((N2D_B[k*NX*3+i*3+1]+1.0f)*5.0f + INFLOW_VEL); fw0[I(i,1,k)] = (N2D_B[k*NX*3+i*3+2]) * INFLOW_VEL * 0.5f; } } memset(M,0,size*sizeof(int)); if (CFD_useObstacles==true) { FOR_EACH_CELL x=(float)(i-p1x)-CFD_obstX; y=(float)(j-p1y)-CFD_obstY; z=(float)(k-p1z)-CFD_obstZ; if((x-1)*(x-1) + (y+(CELLS_IN_Y/4))*(y+(CELLS_IN_Y/4)) + z*z < CFD_obstR*CFD_obstR) { M[I(i,j,k)]=1; } END_FOR } } vec3 CFD_Cnedra::getVorticity(int i, int j, int k) { float DwDy,DvDz,DuDz,DwDx,DvDx,DuDy; DwDy=DvDz=DuDz=DwDx=DvDx=DuDy=0.0f; DwDy = (fW0[I(i,j+1,k)]-fW0[I(i,j-1,k)])*0.5f; DvDz = (fV0[I(i,j,k+1)]-fV0[I(i,j,k-1)])*0.5f; DuDz = (fU0[I(i,j,k+1)]-fU0[I(i,j,k-1)])*0.5f; DwDx = (fW0[I(i+1,j,k)]-fW0[I(i-1,j,k)])*0.5f; DvDx = (fV0[I(i+1,j,k)]-fV0[I(i-1,j,k)])*0.5f; DuDy = (fU0[I(i,j+1,k)]-fU0[I(i,j-1,k)])*0.5f; return vec3(DwDy-DvDz, DuDz-DwDx, DvDx-DuDy); } inline float nrm1(const vec3 &v) fabs(v.z));} inline float nrm2(const vec3 &v) v.z*v.z);} {return (fabs(v.x) + fabs(v.y) + {return sqrt(v.x*v.x + v.y*v.y + void CFD_Cnedra::updateCurls(float *cu, float *cv, float *cw) { 72 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart memset(cu,0,size*sizeof(float)); memset(cv,0,size*sizeof(float)); memset(cw,0,size*sizeof(float)); float DoDx=0.0f,DoDy=0.0f,DoDz=0.0f,len,invL; vec3 _v; FOR_EACH_CELL if(i>=2 && i<=NX-2) DoDx=(nrm2(getVorticity(i+1,j,k))nrm2(getVorticity(i-1,j,k)))*0.5f; if(j>=2 && j<=NY-2) DoDy=(nrm2(getVorticity(i,j+1,k))nrm2(getVorticity(i,j-1,k)))*0.5f; if(k>=2 && k<=NZ-2) DoDz=(nrm2(getVorticity(i,j,k+1))nrm2(getVorticity(i,j,k-1)))*0.5f; len = sqrt(DoDx*DoDx + DoDy*DoDy + DoDz*DoDz); if(len>=C_EPS) {invL=1.0f/len;DoDx*=invL;DoDy*=invL;DoDz*=invL;} else {DoDx=DoDy=DoDz=0.0f;} _v=getVorticity(i,j,k); cu[I(i,j,k)] = (DoDy*_v.z - _v.y*DoDz) * CFD_vortConf; cv[I(i,j,k)] = (DoDz*_v.x - _v.z*DoDx) * CFD_vortConf; cw[I(i,j,k)] = (DoDx*_v.y - _v.x*DoDy) * CFD_vortConf; END_FOR } void CFD_Cnedra::updateDensity() { for(i=1;i<=NX;++i) for(k=1;k<=NZ;++k) { x=(float)(i-p1x); z=(float)(k-p1z); if((x*x + z*z)<eR*eR) {D0[I(i,1,k)]=1.0f;} } FOR_EACH_CELL if(CFD_useObstacles) { x=(i-p1x)-CFD_obstX; y=(j-p1y)-CFD_obstY; z=(k-p1z)-CFD_obstZ; if((x-1)*(x1)+(y+(CELLS_IN_Y/4))*(y+(CELLS_IN_Y/4))+z*z<CFD_obstR*CFD_obstR) {D0[I(i,j,k)]=1.0f;} } END_FOR setBnd(D0); swp(D0,D1); advect(D0,D1,fU0,fV0,fW0); } void CFD_Cnedra::updateVelocity() { this->addExtForces(); if(CFD_useObstacles) { FOR_EACH_CELL x=(i-p1x)-CFD_obstX; y=(j-p1y)-CFD_obstY; z=(k-p1z)-CFD_obstZ; if((x-1)*(x1)+(y+(CELLS_IN_Y/4))*(y+(CELLS_IN_Y/4))+z*z<CFD_obstR*CFD_obstR) { float _x=x-1; float _y=y+(CELLS_IN_Y/4); float _z=z; float _l=sqrt(_x*_x + _y*_y + _z*_z); if(fabs(_l)<=C_EPS) {_l=C_EPS*sgn(_l);} float _invL=5.0f/_l; fU0[I(i,j,k)]=_x*_invL; fV0[I(i,j,k)]=_y*_invL; fW0[I(i,j,k)]=_z*_invL; } END_FOR } if(fVsc >= C_EPS) { swp(fU0,fU1); swp(fV0,fV1); swp(fW0,fW1); diffuse(fVsc,fU0,fU1); diffuse(fVsc,fV0,fV1); diffuse(fVsc,fW0,fW1); swp(fU0,fU1);swp(fV0,fV1);swp(fW0,fW1); project(fU0,fU1,fV0,fV1,fW0,fW1,fDiv,fP,fDens); setObstacleBnd(); } swp(fU0,fU1); swp(fV0,fV1); swp(fW0,fW1); advect(fU0,fU1,fU1,fV1,fW1); advect(fV0,fV1,fU1,fV1,fW1); advect(fW0,fW1,fU1,fV1,fW1); 73 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart setObstacleBnd(); swp(fU0,fU1);swp(fV0,fV1);swp(fW0,fW1); project(fU0,fU1,fV0,fV1,fW0,fW1,fDiv,fP,fDens); setObstacleBnd(); } void CFD_Cnedra::updateTemperature() { static float offset=0.0f; offset+=0.0025f; for(i=1;i<=NX;++i) for(k=1;k<=NZ;++k) { x=(float)(i-p1x); z=(float)(k-p1z); float xSqr = x*x; float zSqr = z*z; float radiusSqr = eR*eR; if(xSqr + zSqr < radiusSqr) { if(xSqr + zSqr < radiusSqr*0.6f) { int _x=(i+1)*(1.0f/NX)*2.0f; int _y=(k+1)*(1.0f/NZ)*2.0f; float val = PerlinNoise2D(_x+offset,_y+offset,1.5f,1.0f,4); T0[I(i,1,k)] = (fabs(val)+0.95f) * CFD_smokeT*0.45f; } else { T0[I(i,1,k)] = CFD_smokeT*0.45f; } } } FOR_EACH_CELL if(CFD_useObstacles) { x=(i-p1x)-CFD_obstX; y=(j-p1y)-CFD_obstY; z=(k-p1z)-CFD_obstZ; if((x-1)*(x1)+(y+(CELLS_IN_Y/4))*(y+(CELLS_IN_Y/4))+z*z<CFD_obstR*CFD_obstR) {T0[I(i,j,k)]=CFD_smokeT;} } END_FOR setBnd(T0); swp(T0,T1); advect(T0,T1,fU0,fV0,fW0); FOR_EACH_CELL if(T0[I(i,j,k)]>CFD_airT) T0[I(i,j,k)]-=CFD_coolConst*0.2f*pow((T0[I(i,j,k)]CFD_airT)/(CFD_smokeT-CFD_airT),5); if(T0[I(i,j,k)]<(CFD_smokeT-CFD_airT)*0.1f) T0[I(i,j,k)]*=0.75f; END_FOR setBnd(T0); } void CFD_Cnedra::addExtForces() { this->updateCurls(CU, CV, CW); addForce(fU0,fV0,fW0,CU,CV,CW); FOR_EACH_CELL float _t=T0[I(i,j,k)]; BU[I(i,j,k)]=CFD_buoy*(T0[I(i,j,k)]); fV0[I(i,j,k)]+=dt*BU[I(i,j,k)]; END_FOR } void CFD_Cnedra::update() { this->setInflow(fU0,fV0,fW0); float _maxFVel=0.0f; FOR_EACH_CELL float _FVel = fabs(fU0[I(i,j,k)]) + fabs(fV0[I(i,j,k)]) + fabs(fW0[I(i,j,k)]); if(_maxFVel<_FVel) _maxFVel=_FVel; END_FOR dt = 1.0f/(_maxFVel+(0.5f+0.5f+0.5f)); this->updateVelocity(); this->updateDensity(); this>updateTemperature(); } void CFD_Cnedra::render(bool doVolRend) { 74 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_3D); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (!doVolRend) { float *_fU,*_fV,*_fW; switch(CFD_showFieldId) { case CM_SHOW_VEL_FIELD: _fU=fU0;_fV=fV0;_fW=fW0; break; case CM_SHOW_VORT_FIELD: _fU=CU;_fV=CV;_fW=CW; break; } float dx,dy,dz; glLineWidth(2); glBegin(GL_LINES); FOR_EACH_CELL x=(float)(i-p1x); y=(float)(j-p1y); z=(float)(k-p1z); dx=_fU[I(i,j,k)]; dy=_fV[I(i,j,k)]; dz=_fW[I(i,j,k)]; float len=(float)sqrt(dx*dx + dy*dy + dz*dz); if(len>1.0f) {dx/=len;dy/=len;dz/=len;} glColor3f(0,0,0);glVertex3f(x,y,z);glColor3f(0.5f,0.0f,len/INFLOW_VEL) ;glVertex3f(x+dx,y+dy,z+dz); END_FOR glEnd(); glPointSize(4); glColor3f(0,1,1); glBegin(GL_POINTS); FOR_EACH_CELL if(M[I(i,j,k)]==1) glVertex3i(ip1x,j-p1y,k-p1z); END_FOR glEnd(); } glPopAttrib(); } void CFD_Cnedra::setObstacleBnd() { if (CFD_useObstacles) { FOR_EACH_CELL if (M[I(i,j,k)] == 1) { int _emptyNeighbors=0; if (M[I(i-1,j,k)] == 0) { ++_emptyNeighbors; fU0[I(i,j,k)]=-fU0[I(i-1,j,k)]; fV0[I(i,j,k)]=-fV0[I(i1,j,k)]; fW0[I(i,j,k)]=-fW0[I(i-1,j,k)]; } else if (M[I(i+1,j,k)] == 0) { ++_emptyNeighbors; fU0[I(i,j,k)]=-fU0[I(i+1,j,k)]; fV0[I(i,j,k)]=fV0[I(i+1,j,k)]; fW0[I(i,j,k)]=-fW0[I(i+1,j,k)]; } if (M[I(i,j-1,k)] == 0) { ++_emptyNeighbors; fU0[I(i,j,k)]=-fU0[I(i,j-1,k)]; fV0[I(i,j,k)]=-fV0[I(i,j1,k)]; fW0[I(i,j,k)]=-fW0[I(i,j-1,k)]; } else if (M[I(i,j+1,k)] == 0) { ++_emptyNeighbors; fU0[I(i,j,k)]=-fU0[I(i,j+1,k)]; fV0[I(i,j,k)]=fV0[I(i,j+1,k)]; fW0[I(i,j,k)]=-fW0[I(i,j+1,k)]; } if (M[I(i,j,k-1)] == 0) { ++_emptyNeighbors; fU0[I(i,j,k)]=-fU0[I(i,j,k-1)]; fV0[I(i,j,k)]=-fV0[I(i,j,k1)]; fW0[I(i,j,k)]=-fW0[I(i,j,k-1)]; } else if (M[I(i,j,k+1)] == 0) { ++_emptyNeighbors; fU0[I(i,j,k)]=-fU0[I(i,j,k+1)]; fV0[I(i,j,k)]=fV0[I(i,j,k+1)]; fW0[I(i,j,k)]=-fW0[I(i,j,k+1)]; } if (_emptyNeighbors == 0 || _emptyNeighbors > 1) { fU0[I(i,j,k)]=0.0f; fV0[I(i,j,k)]=0.0f; fW0[I(i,j,k)]=0.0f; } } END_FOR } } 75 Efficient Simulation of Fluid Dynamics in a 3D Game Engine – Robert Bongart void CFD_Cnedra::genN2DMap(float* n2D, int nW, int nH, float offset) { static float _o=0.0f; _o+=offset; for(j=0;j<nH;++j) for(i=0;i<nW;++i) { x=i*(1.0f/nW)*2.0f; y=j*(1.0f/nH)*2.0f; n2D[j*3*nW+i*3] = PerlinNoise2D(x+_o,y,1.5f,1.0f,4); n2D[j*3*nW+i*3+1] = PerlinNoise2D(x,y+_o,1.5f,1.0f,0.4); n2D[j*3*nW+i*3+2] = PerlinNoise2D(x-_o,y,1.5f,1.0f,40); } } 76 TRITA-CSC-E 2007: 018 ISRN-KTH/CSC/E--07/018--SE ISSN-1653-5715 www.kth.se