Chapter 4. Octrees

Table of Contents

4.1. Collision detection
4.2. How octree works
4.2.1. Checking for collisions using the octree
4.2.2. Constructing octree
4.3. Octrees for dynamic worlds
4.3.1. Transforming between world and local coordinates
4.3.2. The future — dynamic irregular octrees
4.4. Similar data structures

Octree is a tree structure used to partition a 3D space. Each octree node has eight children (hence the name octree, oct + tree). Our engine uses octrees for a couple of tasks.

4.1. Collision detection

Generally speaking, octree is useful for various collision detection tasks:

  1. First of all, for a normal collision detection needed in games. That is for checking collisions between the player and the world geometry. The player may be represented by a sphere, and when the player moves we check that:

    • The line segment between the current player position and the new player position does not collide with the world.

    • The sphere surrounding new player position does not collide with the world.

    When we detect a collision, we can simply reject player move, or (much better) propose another, non-colliding new player position. This way the player can slide along the wall when he tries to move into it.

    This is done within MoveCollision method of the TTriangleOctree class.

    Also, when gravity works, we want the player to preserve some preferred height above the ground. This allows the player to climb up and down the hills, stairs etc. It is often called terrain-following. This requires calculating current player height above the ground. By comparing this height with a preferred height we know whether the player position should fall down or raise up. This is done by checking for a collision between a ray (that starts at player's position and is directed down) with the world.

    This is done by HeightCollision method of TTriangleOctree class.

  2. For ray-tracer, this is the most important data structure. Ray-tracer checks collisions of rays with the world to calculate it's image. Also when calculating shadows we check for collision between light point (or a random point on light's surface, in case of surface lights) and the possibly shadowed geometry point.

    This is done by RayCollision and SegmentCollision methods of TTriangleOctree class.

  3. When player picks (for example by clicking with mouse) given point on the screen showing 3D scene, we want to know which object from our 3D scene (for example, which VRML node) he actually picked. So again we want to do collision detection between a ray (starting at player's position and with direction calculated from player's looking direction, screen dimensions and picked point coordinates on the screen) and the world.

    Note that there are other methods to determine which object player picked. For example you could employ some OpenGL tricks: rendering in selection mode, or reading color buffer contents to get results of depth buffer tests. See The OpenGL Programming Guide - The Redbook for details. But once we have octree already implemented, it is usually easier and less cumbersome to use than these tricks.

  4. When rendering using OpenGL, we don't want to pass to OpenGL objects that are known to be invisible to the player. For example, we know that objects outside of the camera frustum are invisible. In certain cases (when e.g. dense fog is used) we also know that objects further from player than certain distance are not visible.

    This means that we want to check for collision between camera frustum and/or sphere with the world. This is done by EnumerateCollidingOctreeItems and SphereCollision methods.

    More information about how these algorithms are used will be given in Section 6.4, “VRML scene class for OpenGL”.