Optimization of Large-Scale , Real-Time Simulations by Spatial Hashing

As simulations grow in scale, optimization techniques become virtually required to provide real-time response. In this paper we will discuss how spatial hashing can be utilized to optimize many aspects of large-scale simulations. Spatial hashing is a technique in which objects in a 2D or 3D domain space are projected into a 1D hash table allowing for very fast queries on objects in the domain space. Previous research has shown spatial hashing to be an effective optimization technique for collision detection. We propose several extensions of the technique in order to simultaneously optimize nearly all aspects of simulations including: 1) mobile object collision, 2) object-terrain collision, 3) object and terrain rendering, 4) object interaction, decision, or AI routines, and 5) picking. The results of a simulation are presented where visibility determination, collision and response, and an AI routine is calculated in real-time for over 30,000 mobiles objects on a typical desktop PC. Introduction As the number objects in a simulation increases there becomes a growing need for optimization in order to provide real-time response. The main areas where performance becomes unacceptably low for large numbers of objects are rendering, collision, and decisions or AI routines. With regard to rendering, objects not in view of the camera must quickly be discarded from consideration to maintain an acceptable frame rate. With regard to collision, it is generally an N routine where all objects must be compared to all other objects in the scene. Due to the exponential nature of collision, application performance can quickly degrade as number of objects in the simulation increases. With regard to AI or autonomous agent decisions, they can often be exponential as well. For example, consider any application where objects must react to other objects in the vicinity. Clearly every object must be aware of the distance to every other object. In this paper we propose several methods to concurrently optimize collision, rendering, and AI routines in simulations based on the following established techniques: • Spatial Hashing: where objects in 2D or 3D space are projected into a 1D hash table allowing especially fast location and proximity detection queries • Bounding Volumes: where complex objects are encased in simple volumes for fast location and collision computation • Position Over Time: where the position of an object is not only considered each frame (discrete), but over the course of each frame (continuous) Specifically, using spatial hashing-based methods we will address the implementation and optimization of: • Object-object collision: collision between mobile objects • Object-terrain collision: traversal of terrain by the mobile objects • Rendering: use of the grid and hash table to quickly discard objects and terrain that are not in view of the camera and thus need not be rendered (visibility determination) • Picking and Object Selection: a type of collision detection where one or more objects in the scene are selected by users or AI entities • AI decisions: use of the fast location and proximity detection provided by hashing to speed up AI decisions All of the above can be simultaneously implemented or optimized with little additional memory overhead using the proposed techniques. Discussion will proceed in the following manner. First, we will examine related research, discuss any restrictions posed upon the application setup, and discuss the basics of spatial hashing and bounding volumes. Then, we will look at the details of implementing a spatial hashing based scheme to optimize collision, rendering, picking, and AI routines. Finally, we will conclude with the results of a C++/OpenGL simulation. Related Work Various forms of spatial hashing have been used for: real-time collision detection for simulations or games with large numbers of mobile objects [7], collision of flexible or deformable models [3] [4] [6], collision for dense mesh animations [9], penetration depth and deformable model collision response [5]. Spatial hashing methods have also been used outside the graphics and simulations area in several ways including: nearest-neighbor detection in spatial databases [12], spatial hash-joins in relational databases [10], and range-monitoring queries on mobile, real-world objects [8]. To the best of our knowledge there has been no widely published research on the application of spatial hashing to concurrently optimize collision, rendering, picking, and AI routines. Tree-based techniques do exist that may be used for both collision and rendering optimization (for example BSP trees [13]) however they may perform poorly for scenes with thousands of mobile objects since the tree must be rebuilt for every frame of animation. Rebuilding a tree every frame is at best O(NlogN) for N objects whereas rebuilding a hash table is O(N) by application of a simple hash function to each object. Tree-based solutions are further complicated by the need to insure a balanced tree. These deficiencies have been overcome by self-adjusting trees [11] where the tree is only partially updated any given frame and automatically kept balanced. Self-adjusting trees have shown to be sufficiently fast for collision detection in real-time applications with a substantial number of moving objects. However, we wish to simultaneously optimize collision, rendering, and AI routines with a single data structure. Assumptions and Restrictions We assume a typical real-time application setup with an update/draw loop. Every frame all objects are updated and then rendered. The only restriction posed on the simulation setup by our spatial hashing method is that most objects should be somewhat smaller than the grid cells that subdivide the scene. This not absolutely required but as we will see, it makes hashing more efficient. Spatial Hashing Overview Spatial hashing is a process by which a 3D or 2D domain space is projected into a 1D hash table. To implement spatial hashing at least three things are required. • a 2D or 3D grid • a hash function • a hash table First, the entire domain space is subdivided by a grid (uniform spatial subdivision) which may be 2D or 3D. The grid can be defined by three variables. • float cell size: the size of each cell • float min, max: two points that “anchor” the grid in the domain space The hash function takes any given 2D or 3D positional data and returns a unique grid cell that corresponds to a 1D bucket in the hash table. Objects are hashed periodically (every frame for real-time applications usually) and their locations can then be quickly queried in the hash table. Spatial hashing can be implemented in a number of ways, but the following method is presented as an example. Figure 1 shows a 2D grid over a domain space, 10 mobile objects, a 16 bucket hash table, and an object index (objects lettered AJ) where each object’s current bucket in the hash table is indexed. We define the following variables: • float min = 0 • float max = 100 • int cell size = 25 • int width = (max-min)/cell size = 4 • int number of buckets = width The spheres represent mobile objects wandering through the grid. Each cell is 25 units (cell size) and the entire grid is 100 units across (max min). Since the width is 4 ((max-min)/cell size), a 16 bucket hash table (width) is required. As mobile objects wander the grid space, they hash their position (x,y) every frame using the formula: int grid_cell = ( floor(x/cell size) ) + ( floor(y/cell size) )*width This formula translates a 2D object location into a single integer – the unique grid cell that the object occupies. The hash function can be made considerably faster by removing division with a new variable “conversion factor” which is set as 1/cell size. We can also remove the floor function by allowing type coercion to truncate our positional data (floating point) to a hash bucket (integer). So the modified hash function will look like this: int grid_cell = x*conversion factor + y*conversion factor*width There are two ways to update the hash table. If all objects are re-hashed every frame (usually the case in animated simulations or games) the contents of every bucket can simply be deleted before update. If objects are only updated infrequently, the old hash-data for the object must be deleted before the new hash-data is inserted. This can be easily determined using the object index. Figure 1 – An example of mobile objects in a grid, a hash table, and the object index. 0 1 2 15 14 13 Hash Table 16 buckets Grid – 16 cells, 10 mobile objects