UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

137 lines (134 loc) 4.19 kB
import { math } from '../../core/math/math.js'; import { Vec3 } from '../../core/math/vec3.js'; import { DISTANCE_INVERSE, DISTANCE_LINEAR, DISTANCE_EXPONENTIAL } from './constants.js'; import { hasAudioContext } from './capabilities.js'; import { Channel } from './channel.js'; var MAX_DISTANCE = 10000; class Channel3d extends Channel { getPosition() { return this.position; } setPosition(position) { this.position.copy(position); var panner = this.panner; if ('positionX' in panner) { panner.positionX.value = position.x; panner.positionY.value = position.y; panner.positionZ.value = position.z; } else if (panner.setPosition) { panner.setPosition(position.x, position.y, position.z); } } getVelocity() { return this.velocity; } setVelocity(velocity) { this.velocity.copy(velocity); } getMaxDistance() { return this.panner.maxDistance; } setMaxDistance(max) { this.panner.maxDistance = max; } getMinDistance() { return this.panner.refDistance; } setMinDistance(min) { this.panner.refDistance = min; } getRollOffFactor() { return this.panner.rolloffFactor; } setRollOffFactor(factor) { this.panner.rolloffFactor = factor; } getDistanceModel() { return this.panner.distanceModel; } setDistanceModel(distanceModel) { this.panner.distanceModel = distanceModel; } _createSource() { var context = this.manager.context; this.source = context.createBufferSource(); this.source.buffer = this.sound.buffer; this.source.connect(this.panner); this.panner.connect(this.gain); this.gain.connect(context.destination); if (!this.loop) { this.source.onended = this.pause.bind(this); } } constructor(manager, sound, options){ super(manager, sound, options); this.position = new Vec3(); this.velocity = new Vec3(); if (hasAudioContext()) { this.panner = manager.context.createPanner(); } else { this.maxDistance = MAX_DISTANCE; this.minDistance = 1; this.rollOffFactor = 1; this.distanceModel = DISTANCE_INVERSE; } } } if (!hasAudioContext()) { var offset = new Vec3(); var fallOff = function fallOff(posOne, posTwo, refDistance, maxDistance, rolloffFactor, distanceModel) { offset = offset.sub2(posOne, posTwo); var distance = offset.length(); if (distance < refDistance) { return 1; } else if (distance > maxDistance) { return 0; } var result = 0; if (distanceModel === DISTANCE_LINEAR) { result = 1 - rolloffFactor * (distance - refDistance) / (maxDistance - refDistance); } else if (distanceModel === DISTANCE_INVERSE) { result = refDistance / (refDistance + rolloffFactor * (distance - refDistance)); } else if (distanceModel === DISTANCE_EXPONENTIAL) { result = Math.pow(distance / refDistance, -rolloffFactor); } return math.clamp(result, 0, 1); }; Object.assign(Channel3d.prototype, { setPosition: function setPosition(position) { this.position.copy(position); if (this.source) { var listener = this.manager.listener; var lpos = listener.getPosition(); var factor = fallOff(lpos, this.position, this.minDistance, this.maxDistance, this.rollOffFactor, this.distanceModel); var v = this.getVolume(); this.source.volume = v * factor; } }, getMaxDistance: function getMaxDistance() { return this.maxDistance; }, setMaxDistance: function setMaxDistance(max) { this.maxDistance = max; }, getMinDistance: function getMinDistance() { return this.minDistance; }, setMinDistance: function setMinDistance(min) { this.minDistance = min; }, getRollOffFactor: function getRollOffFactor() { return this.rollOffFactor; }, setRollOffFactor: function setRollOffFactor(factor) { this.rollOffFactor = factor; }, getDistanceModel: function getDistanceModel() { return this.distanceModel; }, setDistanceModel: function setDistanceModel(distanceModel) { this.distanceModel = distanceModel; } }); } export { Channel3d };