@babylonjs/loaders
Version:
The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.
217 lines • 11.1 kB
JavaScript
import { Vector3 } from "@babylonjs/core/Maths/math";
import { Tools } from "@babylonjs/core/Misc/tools";
import { AnimationEvent } from "@babylonjs/core/Animations/animationEvent";
import { Sound } from "@babylonjs/core/Audio/sound";
import { WeightedSound } from "@babylonjs/core/Audio/weightedsound";
import { GLTFLoader, ArrayItem } from "../glTFLoader";
var NAME = "MSFT_audio_emitter";
/**
* [Specification](https://github.com/najadojo/glTF/tree/MSFT_audio_emitter/extensions/2.0/Vendor/MSFT_audio_emitter)
*/
var MSFT_audio_emitter = /** @class */ (function () {
/** @hidden */
function MSFT_audio_emitter(loader) {
/** The name of this extension. */
this.name = NAME;
/** Defines whether this extension is enabled. */
this.enabled = true;
this._loader = loader;
}
/** @hidden */
MSFT_audio_emitter.prototype.dispose = function () {
delete this._loader;
delete this._clips;
delete this._emitters;
};
/** @hidden */
MSFT_audio_emitter.prototype.onLoading = function () {
var extensions = this._loader.gltf.extensions;
if (extensions && extensions[this.name]) {
var extension = extensions[this.name];
this._clips = extension.clips;
this._emitters = extension.emitters;
ArrayItem.Assign(this._clips);
ArrayItem.Assign(this._emitters);
}
};
/** @hidden */
MSFT_audio_emitter.prototype.loadSceneAsync = function (context, scene) {
var _this = this;
return GLTFLoader.LoadExtensionAsync(context, scene, this.name, function (extensionContext, extension) {
var promises = new Array();
promises.push(_this._loader.loadSceneAsync(context, scene));
for (var _i = 0, _a = extension.emitters; _i < _a.length; _i++) {
var emitterIndex = _a[_i];
var emitter = ArrayItem.Get(extensionContext + "/emitters", _this._emitters, emitterIndex);
if (emitter.refDistance != undefined || emitter.maxDistance != undefined || emitter.rolloffFactor != undefined ||
emitter.distanceModel != undefined || emitter.innerAngle != undefined || emitter.outerAngle != undefined) {
throw new Error(extensionContext + ": Direction or Distance properties are not allowed on emitters attached to a scene");
}
promises.push(_this._loadEmitterAsync(extensionContext + "/emitters/" + emitter.index, emitter));
}
return Promise.all(promises).then(function () { });
});
};
/** @hidden */
MSFT_audio_emitter.prototype.loadNodeAsync = function (context, node, assign) {
var _this = this;
return GLTFLoader.LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
var promises = new Array();
return _this._loader.loadNodeAsync(extensionContext, node, function (babylonMesh) {
var _loop_1 = function (emitterIndex) {
var emitter = ArrayItem.Get(extensionContext + "/emitters", _this._emitters, emitterIndex);
promises.push(_this._loadEmitterAsync(extensionContext + "/emitters/" + emitter.index, emitter).then(function () {
for (var _i = 0, _a = emitter._babylonSounds; _i < _a.length; _i++) {
var sound = _a[_i];
sound.attachToMesh(babylonMesh);
if (emitter.innerAngle != undefined || emitter.outerAngle != undefined) {
sound.setLocalDirectionToMesh(Vector3.Forward());
sound.setDirectionalCone(2 * Tools.ToDegrees(emitter.innerAngle == undefined ? Math.PI : emitter.innerAngle), 2 * Tools.ToDegrees(emitter.outerAngle == undefined ? Math.PI : emitter.outerAngle), 0);
}
}
}));
};
for (var _i = 0, _a = extension.emitters; _i < _a.length; _i++) {
var emitterIndex = _a[_i];
_loop_1(emitterIndex);
}
assign(babylonMesh);
}).then(function (babylonMesh) {
return Promise.all(promises).then(function () {
return babylonMesh;
});
});
});
};
/** @hidden */
MSFT_audio_emitter.prototype.loadAnimationAsync = function (context, animation) {
var _this = this;
return GLTFLoader.LoadExtensionAsync(context, animation, this.name, function (extensionContext, extension) {
return _this._loader.loadAnimationAsync(context, animation).then(function (babylonAnimationGroup) {
var promises = new Array();
ArrayItem.Assign(extension.events);
for (var _i = 0, _a = extension.events; _i < _a.length; _i++) {
var event_1 = _a[_i];
promises.push(_this._loadAnimationEventAsync(extensionContext + "/events/" + event_1.index, context, animation, event_1, babylonAnimationGroup));
}
return Promise.all(promises).then(function () {
return babylonAnimationGroup;
});
});
});
};
MSFT_audio_emitter.prototype._loadClipAsync = function (context, clip) {
if (clip._objectURL) {
return clip._objectURL;
}
var promise;
if (clip.uri) {
promise = this._loader.loadUriAsync(context, clip, clip.uri);
}
else {
var bufferView = ArrayItem.Get(context + "/bufferView", this._loader.gltf.bufferViews, clip.bufferView);
promise = this._loader.loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView);
}
clip._objectURL = promise.then(function (data) {
return URL.createObjectURL(new Blob([data], { type: clip.mimeType }));
});
return clip._objectURL;
};
MSFT_audio_emitter.prototype._loadEmitterAsync = function (context, emitter) {
var _this = this;
emitter._babylonSounds = emitter._babylonSounds || [];
if (!emitter._babylonData) {
var clipPromises = new Array();
var name_1 = emitter.name || "emitter" + emitter.index;
var options_1 = {
loop: false,
autoplay: false,
volume: emitter.volume == undefined ? 1 : emitter.volume,
};
var _loop_2 = function (i) {
var clipContext = "#/extensions/" + this_1.name + "/clips";
var clip = ArrayItem.Get(clipContext, this_1._clips, emitter.clips[i].clip);
clipPromises.push(this_1._loadClipAsync(clipContext + "/" + emitter.clips[i].clip, clip).then(function (objectURL) {
var sound = emitter._babylonSounds[i] = new Sound(name_1, objectURL, _this._loader.babylonScene, null, options_1);
sound.refDistance = emitter.refDistance || 1;
sound.maxDistance = emitter.maxDistance || 256;
sound.rolloffFactor = emitter.rolloffFactor || 1;
sound.distanceModel = emitter.distanceModel || 'exponential';
sound._positionInEmitterSpace = true;
}));
};
var this_1 = this;
for (var i = 0; i < emitter.clips.length; i++) {
_loop_2(i);
}
var promise = Promise.all(clipPromises).then(function () {
var weights = emitter.clips.map(function (clip) { return clip.weight || 1; });
var weightedSound = new WeightedSound(emitter.loop || false, emitter._babylonSounds, weights);
if (emitter.innerAngle) {
weightedSound.directionalConeInnerAngle = 2 * Tools.ToDegrees(emitter.innerAngle);
}
if (emitter.outerAngle) {
weightedSound.directionalConeOuterAngle = 2 * Tools.ToDegrees(emitter.outerAngle);
}
if (emitter.volume) {
weightedSound.volume = emitter.volume;
}
emitter._babylonData.sound = weightedSound;
});
emitter._babylonData = {
loaded: promise
};
}
return emitter._babylonData.loaded;
};
MSFT_audio_emitter.prototype._getEventAction = function (context, sound, action, time, startOffset) {
switch (action) {
case "play" /* play */: {
return function (currentFrame) {
var frameOffset = (startOffset || 0) + (currentFrame - time);
sound.play(frameOffset);
};
}
case "stop" /* stop */: {
return function (currentFrame) {
sound.stop();
};
}
case "pause" /* pause */: {
return function (currentFrame) {
sound.pause();
};
}
default: {
throw new Error(context + ": Unsupported action " + action);
}
}
};
MSFT_audio_emitter.prototype._loadAnimationEventAsync = function (context, animationContext, animation, event, babylonAnimationGroup) {
var _this = this;
if (babylonAnimationGroup.targetedAnimations.length == 0) {
return Promise.resolve();
}
var babylonAnimation = babylonAnimationGroup.targetedAnimations[0];
var emitterIndex = event.emitter;
var emitter = ArrayItem.Get("#/extensions/" + this.name + "/emitters", this._emitters, emitterIndex);
return this._loadEmitterAsync(context, emitter).then(function () {
var sound = emitter._babylonData.sound;
if (sound) {
var babylonAnimationEvent = new AnimationEvent(event.time, _this._getEventAction(context, sound, event.action, event.time, event.startOffset));
babylonAnimation.animation.addEvent(babylonAnimationEvent);
// Make sure all started audio stops when this animation is terminated.
babylonAnimationGroup.onAnimationGroupEndObservable.add(function () {
sound.stop();
});
babylonAnimationGroup.onAnimationGroupPauseObservable.add(function () {
sound.pause();
});
}
});
};
return MSFT_audio_emitter;
}());
export { MSFT_audio_emitter };
GLTFLoader.RegisterExtension(NAME, function (loader) { return new MSFT_audio_emitter(loader); });
//# sourceMappingURL=MSFT_audio_emitter.js.map