Room Bushes - How do they actually work? (from a technical standpoint) - by Mr. Bighead
Mr. Bighead on 25/4/2021 at 12:55
Alright. I'll try to figure something out about how to achieve this :)
vfig on 26/4/2021 at 01:04
The code is pretty straightforward to follow. You should start looking in sound/psndinst.cpp, at cPropSndInst::FindSoundPath()
But the dark engine's manually-placed room brushes is not a great setup to emulate these days. A much better appraoch these days would be to voxelise the empty space in your levels, and trace sound paths through that.
Mr. Bighead on 26/4/2021 at 17:28
Quote Posted by vfig
A much better appraoch these days would be to voxelise the empty space in your levels, and trace sound paths through that.
That's an interesting approach! I have to see how this would be possible with ue4. There is a Free Voxel Plugin now.
Do you have experience with setting up sound propagation in games?
vfig on 4/5/2021 at 13:36
I don't, but the basic principles for Thief-style single-path propagation are pretty straightforward (although not actually physically correct, it works pretty well in practice).
You make a volumetric representation of the space. On any given frame, for each sound emitter, you find the shortest path from the emitter to the receiver (the player). The length of this path governs the apparent volume of the sound, and the direction of the last segment of the path (that is, the direction from which the path reaches the receiver) governs the apparent direction of the sound.
Assuming the engine you're using already does basic positional audio (stereo separation and volume falloff by straight-line direction/distance) you could get Thief-like results by, at the start of the frame, moving the sound entity to the location of the second-last point of the path, and adjusting its volume based on the length of the path up to that point, like this:
Inline Image:
https://i.imgur.com/vFiVkbs.pngThe hard part of this (i.e. expensive) is the pathfinding. But it is a simple pathfinding problem, so you want to choose a volumetric representation and a pathfinding algorithm that is easy to create and maintain (unlike room brushes!) and gives you suitable performance. And all the usual pathfinding optimisations apply: for example, you ideally don't want to recalculate the entire path every frame, but only when the guard or the player has moved such that the path would have changed (in Thief, this is when either of them moves into a different room brush).
Once you have a system like this in place, supporting doors the way Thief does is straightforward: if the shortest path passes through a closed door, you simply multiply the sound entity's volume by an additional factor (according to how much the door should block the sound). To handle cases such as when a sound's path through a closed door is the shortest, but there is a slightly longer path through an open window beside the door—then you need to take the closed door's blocking factor into account in your pathfinding algorithm's cost function so that it prefers the window path. This is because what you really want is not the
shortest path overall, but the path with
least volume reduction.
Addendum: You might wonder why Thief bothers with the room brush representation, when it already has a complete, precise, accurate, volumetric representation of the entire level, in the form of its bsp tree. Like, when deciding which polygons need to be rendered on any given frame, the game is essentially pathfinding through the bsp nodes and portals to find all the nodes that are visible from the camera position. So couldn't the sound propagation do the same? So, it could, but the level geo is a lot more complex than room brush geo, so there are way more nodes and portals to trace through, making pathfinding much more expensive. For rendering, the game only needs to consider portals directly in view of the camera, so it doesn't have to search very far or very deep; but the sound pathfinding needs to go in all directions and around corners to an arbitrary distance (limited only by the maximum radius of the sound emitter). So the simpler geometry of room brushes makes the sound pathfinding a whole lot cheaper. But i speculate that even back in 1998 it might have been possible to use the bsp tree. In the quake engine and its descendants, the straight-line paths between
all bsp nodes that can see each other are precalculated when compiling the map (the 'vis' step), and stored in the pvs, the "potentially viewable set". This makes the renderer faster, because it doesn't have to walk from the node with the camera in through portal after portal after portal to build a list of all the nodes that might need to be drawn; it just looks up the pvs and immediately gets the entire list. If the sound pathfinding algorithm could use the pvs, it would be able to 'jump' much longer distances when searching, and find paths much more quickly. But the dark engine's renderer doesn't use a pvs, and without that using the bsp tree for sound pathfinding is
definitely too expensive for real time on 1998 era cpus that are already very busy doing lots of rendering.
Mr. Bighead on 5/5/2021 at 17:15
This is absolutely gorgeous! :D
Thanks a lot for this really gold, in-depth explanation.
Especially this one is very interesting:
Quote Posted by vfig
you ideally don't want to recalculate the entire path every frame, but only when the guard or the player has moved such that the path would have changed
and:
Quote Posted by vfig
This is because what you really want is not the
shortest path overall, but the path with
least volume reduction.
I actually already experimented with sound propagation in ue4 by using function's like GetPathLength or GetPathCost. But this is (like you mentioned) a really cpu heavy calculation.
Using a custom hard coded function would be the right solution. But this is for later^^
...at the moment I'm stuck with the challenge of creating a pathfinding function which is not based on floor pathfinding. To picture an example:
If a space would be divided by a wall there would be no way to propagate the sound entity to the other half of the space if there would be no connection on the floor. But realistically the sound would of course be propagated over the wall. The same situation applies for your window example.
So this is all related to more engine research. Again, I'm very grateful for your effort.
vfig on 7/5/2021 at 04:21
Well, that specific situation you describe might be resolvable if you set up a NavAgent with a very big step height (so that it can essentially step over any wall). But of course you still will likely have problems with propagation through floor/ceiling holes.
So using a floor-based navmesh is less than ideal, as you say. But still probably good enough for putting together a rough working prototype. Then if the prototype seems viable, you can swap in or build a different pathfinding system. Or you might find that even the floor nav is good enough if augmented with author-placed links for floor/ceiling holes, who knows?
Remember, it doesnt have to be right, it only has to work and sound convincing. :)
Mr. Bighead on 7/5/2021 at 19:43
Quote Posted by vfig
Remember, it doesnt have to be right, it only has to work and sound convincing. :)
So true! I'll keep that in mind!
zappenduster on 17/5/2021 at 11:58
BTW ... the property Add>Room>Ambient seems to have no effect? :confused:
vfig on 20/5/2021 at 12:29
Quote Posted by zappenduster
BTW ... the property Add>Room>Ambient seems to have no effect? :confused:
yes, the property exists in thief, but neither the game code nor the stock scripts use it. (so in making a profit i made use of it to drive my custom ambience scripts on a room by room basis)