0ad/source/sound/ambient_design.txt
2006-01-08 02:05:44 +00:00

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)