手头上的项目,现在需要增加3D音效支持。选择使用OpenAL,因为它的语法和OpenGL很像,并且免费、开源。
在使用的时候遇到了一个问题,即如何设置OpenAL中的声音衰减。刚开始只是简单的设置Source和Listener的位置,然并卵。。。
然后只能去查看OpenAL的编程指南,发现了一个有趣的函数,即本文要介绍的alDistanceModel。
AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel);
OpenAL使用该函数来设置自己的距离模型,即根据Listener距离Source的距离对声音进行衰减处理。
有如下可选参数:
AL_INVERSE_DISTANCE
AL_INVERSE_DISTANCE_CLAMPED
AL_LINEAR_DISTANCE
AL_LINEAR_DISTANCE_CLAMPED
AL_EXPONENT_DISTANCE
AL_EXPONENT_DISTANCE_CLAMPED
AL_NONE
针对每种参数,OpenAL会使用不同的公式计算最终获得的音量大小,下面将逐一介绍这些公式。
要获得正确的效果,除了使用alDistanceModel,还要通过alSourcef函数设置AL_ROLLOFF_FACTOR、AL_MAX_DISTANCE、AL_REFERENCE_DISTANCE的值。
AL_ROLLOFF_FACTOR即多普勒系数,控制声音衰减的幅度
AL_MAX_DISTANCE 能听到声音的最大距离 超过这个距离就听不到了
AL_REFERENCE_DISTANCE 这是一个声音变化的中间值,即超过这个值之后 声音开始衰减
以下公式中,gain为最终获得的音量大小 范围为0~1 distance为实际的Listener距离声源的距离
AL_INVERSE_DISTANCE 倒数级的衰减
gain = AL_REFERENCE_DISTANCE / (AL_REFERENCE_DISTANCE + AL_ROLLOFF_FACTOR * (distance – AL_REFERENCE_DISTANCE));
AL_INVERSE_DISTANCE_CLAMPED
distance = max(distance,AL_REFERENCE_DISTANCE);
distance = min(distance,AL_MAX_DISTANCE);
gain = AL_REFERENCE_DISTANCE / (AL_REFERENCE_DISTANCE + AL_ROLLOFF_FACTOR * (distance – AL_REFERENCE_DISTANCE));
声音变化图:
由图可知,使用AL_INVERSE_DISTANCE时,声音随着distance的增加从无限大逐渐衰减
若使用AL_INVERSE_DISTANCE_CLAMPED,当distance小于设置的AL_REFERENCE_DISTANCE的值时,gain保持在1,大于AL_INVERSE_DISTANCE_CLAMPED时声音开始衰减。
下面的几个图同理(线性衰减的不同之处是可以设置AL_MAX_DISTANCE)
AL_LINEAR_DISTANCE 线性衰减
distance = min(distance, AL_MAX_DISTANCE) // avoid negative gain
gain = (1 – AL_ROLLOFF_FACTOR * (distance – AL_REFERENCE_DISTANCE) / (AL_MAX_DISTANCE – AL_REFERENCE_DISTANCE));
AL_LINEAR_DISTANCE_CLAMPED
distance = max(distance, AL_REFERENCE_DISTANCE)
distance = min(distance, AL_MAX_DISTANCE)
gain = (1 – AL_ROLLOFF_FACTOR * (distance – AL_REFERENCE_DISTANCE) / (AL_MAX_DISTANCE – AL_REFERENCE_DISTANCE));
声音变化图:
AL_EXPONENT_DISTANCE 指数级衰减
gain = (distance / AL_REFERENCE_DISTANCE) ^ (- AL_ROLLOFF_FACTOR);
AL_EXPONENT_DISTANCE_CLAMPED
distance = max(distance, AL_REFERENCE_DISTANCE)
distance = min(distance, AL_MAX_DISTANCE)
gain = (distance / AL_REFERENCE_DISTANCE) ^ (- AL_ROLLOFF_FACTOR);
声音变化图:
AL_NONE
gain = 1;即声音一直保持在最大音量
最终我选择了AL_INVERSE_DISTANCE_CLAMPED,AL_REFERENCE_DISTANCE设置50,AL_FOLLOFF_FACTOR设置2.0,感觉效果还不错~~