170人参与 • 2024-08-04 • 手游
最近在用 cocos creator 3.8 制作一个 3d 联机坦克大战游戏。因为项目需要,在 cocos creator 中实现了 3d 空间音效的方案,在此分享给大家,希望能对大家有所帮助。
在 3d 游戏中,合理搭配音效元素,可以显著提升游戏沉浸感。利用双通道管线和自定义音频混合创建具有 3d 空间效果的音频,已经被用于大部分的 3d 游戏场景,尤其是 fps 类游戏。
在场景中添加具有 3d 效果的脚步声、枪声,玩家即可借助专业的耳机设备,通过 3d 空间音效做到“听声辨位”,从而丰富游戏的玩法。
本篇教程用于引导大家如何在 cocos 中使用浏览器自带 audiocontext api
实现 3d 音效。
详情请参考 mdn 文档:
音频上下文,是一张节点图,将音频模块节点连接在一起,构成音频处理流程图。类似于 shader graph,动画图,如下图所示:
这里并没有提供可视化工具,但在代码中,我们可以通过anode.connect(bnode)
的方式来连接所有的音效节点,来达成类似于混合和编排的效果。
想要处理音频,我们首先需要创建一个 audiocontext 实例,代码如下:
this.ac = new audiocontext();
在 cocos 中,我们推荐以 buffer 的形式获取音频源,这样可以避免创建 html 元素。我们可以利用 cocos 的 audioclip 属性,快速拿到资产库中音频源的 audiobuffer 数据。
代码:
@property({
type: audioclip,
displayname: "音频源",
})
audioclip: audioclip;
//...略
this.source = this.ac.createbuffersource();
this.source.buffer = this.audioclip._player._player._audiobuffer;
this.source.start();
在游戏开发中,摄像机是眼睛,那么 listener 就类似于耳朵。大部分情况下我们的场景中仅有一个激活的 listener。
this.listener = this.ac.listener;
和摄像机一样,我们可以设置 listener
的位置和方向。(请注意,这里传给 setorientation
的是 cocos 中节点的 forward
和 up
向量)。
一般情况下,这里的 listenernode
可以传摄像机的节点(因为眼睛和耳朵的位置很接近)。
对应的就是以摄像机的位置为 listener
的坐标计算空间音频的声道和衰减模型。
代码如下:
@property({
type: node,
displayname: "收听者",
})
listenernode: node;
//...
this.listener.setorientation(
this.listenernode.forward.x || 0,
this.listenernode.forward.y || 0,
this.listenernode.forward.z || 0,
this.listenernode.up.x || 0,
this.listenernode.up.y || 1,
this.listenernode.up.z || 0
);
this.listener.setposition(
this.listenernode.worldposition.x || 0,
this.listenernode.worldposition.y || 0,
this.listenernode.worldposition.z || 0
);
与 listener
对应,panner
对应的是 3d 空间中的 “发声者”(比如喇叭声、枪声、脚步声)。
常用的参数我们可以设置 panner
的位置(position
)、最大距离( maxdistance
)等等,代码如下:
@property({
type: node,
displayname: "发声者",
})
pannernode: node;
//...略
this.panner = this.ac.createpanner();
this.panner.panningmodel = "equalpower"; // 音频空间化算法模型
this.panner.distancemodel = "linear"; // 远离时的音量衰减算法
this.panner.maxdistance = this.maxdistance; // 最大距离
this.panner.refdistance = 5; // 开始衰减的参考距离
this.panner.rollofffactor = 3; // 衰减速度
this.panner.coneinnerangle = 360; // 声音360度扩散
this.panner.orientationx.value = 1; // 声源朝向x分量
this.panner.orientationy.value = 0;
this.panner.orientationz.value = 0;
this.panner.setposition(
this.pannernode.worldposition.x,
this.pannernode.worldposition.y,
this.pannernode.worldposition.z
);
文章的开头我们说过,audiocontext
是一张“节点图”,那这里我们就增加一个gainnode
(增益节点),增益是一个无单位的值,会对所有输入声道的音频进行相应的增加(相乘)。
此处我们用于修改整体音频的音量大小。gain
修改的效果会影响到 panner
的结果。
举个例子:收音机的音量如果音量很小,那么离太远就听不清了,反之音量很大,那离得很远也能听到。
代码如下:
this.gainnode = this.ac.creategain();
//修改音量
this.gainnode.gain.value = 0.2;
把我们创建的节点连接起来,用 connect
方法。
this.gainnode.connect(this.ac.destination);
this.gainnode.connect(this.panner);
this.source.connect(this.panner);
this.panner.connect(this.gainnode);
由于我们是手动创建的音频上下文节点,所以 cocos 并不会在销毁组件的时候自动释放这些音频实例,这可能导致我们已经切换场景了,但上一个场景的音频还在继续播放。
要解决这个问题,我们只需要在组件销毁的生命周期钩子函数 ondestroy 中手动释放我们创建的音频实例即可。
代码如下:
ondestroy() {
try {
this.gainnode.disconnect(this.ac.destination);
this.gainnode.disconnect(this.panner);
this.source.disconnect(this.panner);
this.panner.disconnect(this.gainnode);
this.source.stop();
this.ac.close();
} catch (e) {
console.log(e);
}
}
点击【阅读原文】或者前往:https://forum.cocos.org/t/topic/156994,可在文中找到本文源码。
以上就是在 cocos 中应用 3d 音效的全部内容,欢迎各位大佬查漏补缺,评论区探讨交流。希望这篇教程能对您的工作提供帮助。
蔬菜土豆泥,前端工程师,来自古城西安,热爱游戏开发,喜欢钻研各种 web 3d 效果,擅长电商互动小游戏和交互式广告的开发与设计。
目前在用 cocos creator 开发 3d 网络游戏,也会不定期分享一些自己的经验心得,希望能够和大家多多交流,共同进步。
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论