Obstruction core functionality

When an important audio source is completely occluded from a listener, it is often due to the emitter being located in a different room or being obstructed in some way. However, occlusion alone does not always produce convincing results when this is not the case.

To remedy this, an obstruction value must be calculated to determine the degree to which an audio source is obstructed. As outlined in my original proposal, I planned to utilize the native navigation inside UE5. However, this would restrict the obstruction pathfinding to walkable surfaces, leading to inconsistencies in areas with non-walkable openings such as windows and open ceilings.

Similar audio propagation systems such as Microsoft’s Project Acoustics (Microsoft, 2023) use a highly detailed voxel-based representation of an environment to calculate obstruction, among other aspects of propagation. Developing my own voxel-based pathfinding system is beyond the scope of this project, which is where Customizable Pathfinding (Trautman, 2022) comes in. Customizable Pathfinding generates a voxel grid within a user-defined volume at a much lower density than that of Project Acoustics, allowing it to be performant at runtime. This voxel grid is then used with an iteration of the A* pathfinding algorithm, returning an array of nodes for a path from emitter to listener.

Implementing Customizable Pathfinding was a relatively straightforward process (special thanks to the developer Dominik for the guidance), primarily requiring two things to function correctly: a volume that covers the playable area and ensuring both emitter and listener are within that defined volume. In addition to this, the volume must be configured in such a way that the size of voxels is only as small as required for the target environment, as a higher density of voxels creates additional overhead for pathfinding. The completed audio propagation system will provide an inherited Blueprint for the pathfinding volume, pre-configured with appropriate values for audio obstruction in most environments (guidance for optimization will be provided).

To calculate a path from emitter to listener, Customizable Pathfinding exposes a function named “Find Path Async,” requiring a start and end vector for the path, as well as a reference to the target pathfinding volume. It must be ensured that the volume is generated prior to a pathfinding call, as this will result in a failure. The function is performed asynchronously, significantly reducing the frame-time overhead at the cost of potentially delayed results; this is managed by limiting the number of times per second a path can be requested by the emitter, to a point where the chance of overlapping asynchronous requests is practically zero on any relatively modern machine. Despite this, error handling for this eventuality has been implemented.

After successfully receiving a path from Customizable Pathfinding, the function returns an array of nodes along the found path. This array is then iterated through to determine the overall length of the path, as well as other data such as the angles between each node in the array. This data will then be interpreted to produce an approximated obstruction value to be used in coordination with the occlusion sub-system.

The final component of the obstruction feature calculates the angles between nodes along the found path. “Find Path Async” returns an array of structs containing both the vector position of the node and the normalized direction vector pointing towards the next node. By storing the direction vector value of the previous node in the iteration, we can calculate the angle between each node pair by getting the inverse cosine of the dot product result from those two direction vectors. This resulting value is then added to an array to be returned for interpretation.