7.5 根据相机位置从一个3D位置播放声音:3D声音
问题
要让你的3D游戏更真实,你想让每个声音都位于3D空间的某个位置。通过这种方式,在相机右侧发生的爆炸会主要通过右声道播放,这样用户就会感到爆炸是真的发生在他的右侧。即使爆炸不在相机的视野中,玩家也可以知道在他的右侧发生了什么事。
注意:Zune不支持Xact和下面的Apply3D()方法,只支持Cue对象,3D音效只被PC和Xbox 360支持。
解决方案
XNA可以让这些事变得简单。对每个声音,你必须设置相机的3D位置和使用声音Cue对象的Apply3D方法设置声源的位置。注意当相机或声源移动时,你需要调用这个方法更新Cue。工作原理如果你想设置声源的3D位置,首先必须为这个音源设置一个AudioEmitter对象和为相机设置一个AudioListener对象。当将这两者传递到Cue的Apply3D方法中时,XNA会计算音响(或耳机)左右声道声音的分配。
下面的方法创建了两个对象:
private void UpdateSoundPosition(Cue cue, Vector3 sourcePos, Vector3 camPos, Vector3 camForward, Vector3 camUp)
{
AudioEmitter emitter = new AudioEmitter();
emitter.Position = sourcePos;
![]()
AudioListener listener = new AudioListener();
listener.Position = camPos;
listener.Forward = camForward;
listener.Up = camUp;
![]()
cue.Apply3D(listener, emitter);
}
对emitter(音源)来说,你只需设置位置。对listener(相机)来说,你还要设置Forward和Up向量,因为当相机旋转了180度后,左右声道会互换。
当创建了这两个变量后,你可以将它们传递到Cue的Apply3D方法中,当音源或相机发生移动时都要进行这个操作。
你需要在第一次调用Play方法前调用Apply3D方法。所以,确保在Cue中还没有调用 Play方法:
protected override void Initialize()
{
fpsCam = new QuakeCamera(GraphicsDevice.Viewport, new Vector3(0,0,5) , 0, 0);
![]()
audioEngine = new AudioEngine("Content/Audio/MyXACTproject.xgs");
waveBank = new WaveBank(audioEngine, "Content/Audio/myWaveBank.xwb");
soundBank = new SoundBank(audioEngine, "Content/Audio/mySoundBank.xsb");
![]()
cue1 = soundBank.GetCue("audio1");
![]()
base.Initialize();
}
在Update方法中,如果你移动了相机位置或音源位置,就需要调用UpdateSoundPosition方法:
protected override void Update(GameTime gameTime)
{
GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);
if (gamePadState.Buttons.Back == ButtonState.Pressed)
this.Exit();
![]()
MouseState mouseState = Mouse.GetState();
KeyboardState keyState = Keyboard.GetState();
![]()
fpsCam.Update(mouseState, keyState, gamePadState);
![]()
float time = (float)gameTime.TotalGameTime.TotalMilliseconds/1000.0f;
Vector3 startingPos = new Vector3(0, 0, -10);
Matrix rotMatrix = Matrix.CreateRotationY(time);
modelPos = Vector3.Transform(startingPos, rotMatrix);
![]()
UpdateSoundPosition(cue1, modelPos, fpsCam.Position, fpsCam.Forward, fpsCam.UpVector);
![]()
if (cue1.IsPrepared)
cue1.Play();
audioEngine.Update();
![]()
base.Update(gameTime);
}
这个方法的前半部分检查用户输入并将输入传递到相机,解释请见教程2-3。当中的代码块更新音源位置。当相机和音源更新后,你需要调用UpdateSoundPosition方法告知cue1对象最后的位置。如果cue1还没有播放,则开始播放。
当心:因为3D effect是通过控制左右声道的音量实现的,所以声音中的任何立体声信息会丢失:首先将声音转换为单声道,然后对应物体的3D位置设置左右声道的音量。
代码
所有的Initialize,UpdateSoundPosition和Update方法前面已经写过了。
扩展阅读
Xact音频工具让你可以在cue中添加一些很棒的3D音效,诸如距离衰减和多普勒效应。因为是图形界面,在视频中介绍要比在书中好得多。在http://creators.xna.com 网站上有一些很好的视频介绍如何将3D音效添加到cue中。
译者注:在http://creators.xna.com/en-US/sample/3daudio网页上也有一个3D音效的例子,实现了距离衰减,多普勒效应,源代码Audio3DSample.rar下载。
发布时间:2009/10/21 上午9:51:30 阅读次数:5463