forked from 0ad/0ad
85 lines
3.9 KiB
Plaintext
85 lines
3.9 KiB
Plaintext
PLAYING AMBIENT SOUND WHEN CAMERA IS OVER BUILDING
|
|
==================================================
|
|
|
|
data flow:
|
|
C++ JS
|
|
> list of visible entities (1)
|
|
< list of sound requests and their weights
|
|
list of changed sounds
|
|
|
|
C++ code generates list of entities on screen
|
|
rationale: done in C++ for performance and to avoid having to expose the "patch" subdivision scheme to JS.
|
|
UPDATE: this is much thornier than expected.
|
|
1) we only want stuff that is visible to be played. hearing things off screen would be distressing and weird
|
|
2) don't play sound for buildings in FoW, to prevent "audio spying"
|
|
most straightforward way is simply scan all entities; if building, check against visible frustum.
|
|
if inside AND within 3d distance cutoff of viewer pos, add to visible_building
|
|
optimization for later: get all patches within 3d distance cutoff; discard all not within frustum; only test
|
|
entities within those remaining patches.
|
|
pass that to JS decideWhatToPlay
|
|
it returns list of sounds it wants playing
|
|
format: see AmbientSoundReq below
|
|
C++ sound engine compares its list of currently sounds;
|
|
fades out those no longer wanted and starts new ones immediately
|
|
|
|
|
|
new entity properties needed:
|
|
-----------------------------
|
|
- ambientGroup: a soundGroup of several sounds; one is picked at random to be played (see below)
|
|
- priority: to determine which entity should trump the others in a crowded city.
|
|
|
|
|
|
// weight is so that we can play several ambient sounds at a time, but ones for buildings at edge of screen are quieter
|
|
// values: 0..1; probably calculated from distance to camera
|
|
type AmbientSoundReq = (SoundGroupString, weight)
|
|
|
|
// (suggestion only; may be revised if too much cacophony/constant sound results)
|
|
JS_decideWhatToPlay(in HEntity visible_ents[], out AmbientSoundReq desired_ambient_sounds[])
|
|
{
|
|
// * "important" means the building is at center of attention and should mostly override the other sounds.
|
|
// this is complicated as well. the camera may have any orientation, especially in cinematic mode;
|
|
// that means we can't just rely on casting a ray from viewer through middle screen pixel to terrain.
|
|
// our building list already covers only the visible ones, so we can use 3d distance from viewer
|
|
// (without worrying about including buildings behind us i.e. out of sight).
|
|
// important := fairly small distance (covers the case where users zoom really close to a building) OR
|
|
// building is close to center of screen (as determined via ray cast method; skip this if the camera
|
|
// is weird, i.e. looking above the horizon, in which case the ray cast would fail).
|
|
// note: not playing sounds when looking down vertically at the town but zoomed out very far is ok (desirable even).
|
|
if an entity is important(*)
|
|
desired_ambient_sounds[i++] = ent.ambientGroup
|
|
|
|
forall ambient types (farm, dock etc.) in decreasing order of priority
|
|
stop if >= 3 sounds in list
|
|
if enough buildings on screen
|
|
desired_ambient_sounds[i++] = ent.ambientGroup
|
|
|
|
maybe add some random variation to spice things up? (i.e. also play some other building sounds;
|
|
don't always have one building override the others)
|
|
}
|
|
|
|
|
|
C++ code keeps a list of all active sounds:
|
|
type ActiveSound = (Handle, SoundGroupString)
|
|
ActiveSound active_sound_list[]
|
|
|
|
Handle startPlayingAmbient(soundGroup, weight)
|
|
{
|
|
filename = soundGroup.pickRandom()
|
|
return snd_play(filename, globalAmbientVolume*soundGroup.volume*weight)
|
|
}
|
|
|
|
updateAmbientSounds(desired_ambient_sounds)
|
|
{
|
|
for all in desired_ambient_sounds but not active_sound_list:
|
|
handle = startPlayingAmbient(amb.group, amb.weight)
|
|
active_sound_list[i++] = (handle, amb.group)
|
|
|
|
for all in active_sound_list but not desired_ambient_sounds:
|
|
snd_fade(OUT, active.handle)
|
|
}
|
|
|
|
|
|
|
|
RANDOMIZED SOUNDS
|
|
==================================================
|
|
(needed for ambient and normal battle sounds) |