@babylonjs/viewer
Version:
The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.
892 lines (880 loc) • 31.4 kB
JavaScript
import { a as _AbstractAudioSubNode, _ as _WebAudioBaseSubGraph, b as _GetVolumeAudioSubNode } from './webAudioBaseSubGraph-BjGMAHX6.esm.js';
import { aD as Quaternion, V as Vector3, M as Matrix } from './index-MZPybX0H.esm.js';
import { e as _SpatialAudioAttacherComponent, d as _WebAudioParameterComponent, f as _SpatialWebAudioUpdaterComponent } from './spatialWebAudioUpdaterComponent-jS7MKp73.esm.js';
const _SpatialAudioDefaults = {
coneInnerAngle: 6.28318530718,
coneOuterAngle: 6.28318530718,
coneOuterVolume: 0,
distanceModel: "linear",
maxDistance: 10000,
minDistance: 1,
orientation: Vector3.Right(),
panningEnabled: true,
panningModel: "equalpower",
position: Vector3.Zero(),
rolloffFactor: 1,
rotation: Vector3.Zero(),
rotationQuaternion: new Quaternion(),
};
/**
* @param options The spatial audio options to check.
* @returns `true` if spatial audio options are defined, otherwise `false`.
*/
function _HasSpatialAudioOptions(options) {
return (options.spatialEnabled ||
options.spatialAutoUpdate !== undefined ||
options.spatialConeInnerAngle !== undefined ||
options.spatialConeOuterAngle !== undefined ||
options.spatialConeOuterVolume !== undefined ||
options.spatialDistanceModel !== undefined ||
options.spatialMaxDistance !== undefined ||
options.spatialMinDistance !== undefined ||
options.spatialMinUpdateTime !== undefined ||
options.spatialOrientation !== undefined ||
options.spatialPanningEnabled !== undefined ||
options.spatialPanningModel !== undefined ||
options.spatialPosition !== undefined ||
options.spatialRolloffFactor !== undefined ||
options.spatialRotation !== undefined ||
options.spatialRotationQuaternion !== undefined);
}
/**
* Abstract class representing the `spatial` audio property on a sound or audio bus.
*
* @see {@link AudioEngineV2.listener}
*/
class AbstractSpatialAudio {
}
const _StereoAudioDefaults = {
pan: 0,
};
/**
* @param options The stereo audio options to check.
* @returns `true` if stereo audio options are defined, otherwise `false`.
*/
function _HasStereoAudioOptions(options) {
return options.stereoEnabled || options.stereoPan !== undefined;
}
/**
* Abstract class representing the `stereo` audio property on a sound or audio bus.
*
* @see {@link AudioEngineV2.listener}
*/
class AbstractStereoAudio {
}
/** @internal */
class _StereoAudioSubNode extends _AbstractAudioSubNode {
constructor(engine) {
super("Stereo" /* AudioSubNode.STEREO */, engine);
}
/** @internal */
setOptions(options) {
this.pan = options.stereoPan ?? _StereoAudioDefaults.pan;
}
}
/** @internal */
function _GetStereoAudioSubNode(subGraph) {
return subGraph.getSubNode("Stereo" /* AudioSubNode.STEREO */);
}
/** @internal */
function _SetStereoAudioProperty(subGraph, property, value) {
subGraph.callOnSubNode("Stereo" /* AudioSubNode.STEREO */, (node) => {
node[property] = value;
});
}
/** @internal */
class _StereoAudio extends AbstractStereoAudio {
/** @internal */
constructor(subGraph) {
super();
this._pan = _StereoAudioDefaults.pan;
this._subGraph = subGraph;
}
/** @internal */
get pan() {
return this._pan;
}
set pan(value) {
this._pan = value;
_SetStereoAudioProperty(this._subGraph, "pan", value);
}
}
/** @internal */
class _SpatialAudioSubNode extends _AbstractAudioSubNode {
constructor(engine) {
super("Spatial" /* AudioSubNode.SPATIAL */, engine);
this._attacherComponent = null;
}
/** @internal */
get isAttached() {
return this._attacherComponent !== null && this._attacherComponent.isAttached;
}
/** @internal */
get attachedNode() {
return this._attacherComponent?.sceneNode ?? null;
}
/** @internal */
get useBoundingBox() {
return this._attacherComponent?.useBoundingBox ?? false;
}
/** @internal */
get attachmentType() {
return this._attacherComponent?.attachmentType ?? 3 /* SpatialAudioAttachmentType.PositionAndRotation */;
}
/** @internal */
attach(sceneNode, useBoundingBox, attachmentType) {
this.detach();
if (!this._attacherComponent) {
this._attacherComponent = new _SpatialAudioAttacherComponent(this);
}
this._attacherComponent.attach(sceneNode, useBoundingBox, attachmentType);
}
/** @internal */
detach() {
this._attacherComponent?.detach();
}
/** @internal */
dispose() {
super.dispose();
this._attacherComponent?.dispose();
this._attacherComponent = null;
}
/** @internal */
setOptions(options) {
this.coneInnerAngle = options.spatialConeInnerAngle ?? _SpatialAudioDefaults.coneInnerAngle;
this.coneOuterAngle = options.spatialConeOuterAngle ?? _SpatialAudioDefaults.coneOuterAngle;
this.coneOuterVolume = options.spatialConeOuterVolume ?? _SpatialAudioDefaults.coneOuterVolume;
this.distanceModel = options.spatialDistanceModel ?? _SpatialAudioDefaults.distanceModel;
this.maxDistance = options.spatialMaxDistance ?? _SpatialAudioDefaults.maxDistance;
this.minDistance = options.spatialMinDistance ?? _SpatialAudioDefaults.minDistance;
this.orientation = options.spatialOrientation ?? _SpatialAudioDefaults.orientation;
this.panningEnabled = options.spatialPanningEnabled ?? _SpatialAudioDefaults.panningEnabled;
this.panningModel = options.spatialPanningModel ?? _SpatialAudioDefaults.panningModel;
this.rolloffFactor = options.spatialRolloffFactor ?? _SpatialAudioDefaults.rolloffFactor;
if (options.spatialPosition) {
this.position = options.spatialPosition.clone();
}
if (options.spatialRotationQuaternion) {
this.rotationQuaternion = options.spatialRotationQuaternion.clone();
}
else if (options.spatialRotation) {
this.rotation = options.spatialRotation.clone();
}
else {
this.rotationQuaternion = _SpatialAudioDefaults.rotationQuaternion.clone();
}
this.update();
}
/** @internal */
update() {
if (this.isAttached) {
this._attacherComponent?.update();
}
else {
this._updatePosition();
this._updateRotation();
}
}
}
/** @internal */
function _GetSpatialAudioSubNode(subGraph) {
return subGraph.getSubNode("Spatial" /* AudioSubNode.SPATIAL */);
}
/** @internal */
function _SetSpatialAudioProperty(subGraph, property, value) {
subGraph.callOnSubNode("Spatial" /* AudioSubNode.SPATIAL */, (node) => {
node[property] = value;
});
}
const TmpMatrix = Matrix.Zero();
const TmpQuaternion = new Quaternion();
function D2r(degrees) {
return (degrees * Math.PI) / 180;
}
function R2d(radians) {
return (radians * 180) / Math.PI;
}
/** @internal */
// eslint-disable-next-line @typescript-eslint/require-await
async function _CreateSpatialAudioSubNodeAsync(engine) {
return new _SpatialWebAudioSubNode(engine);
}
/** @internal */
class _SpatialWebAudioSubNode extends _SpatialAudioSubNode {
/** @internal */
constructor(engine) {
super(engine);
this._lastOrientation = Vector3.Zero();
this._lastPosition = Vector3.Zero();
this._lastRotation = Vector3.Zero();
this._lastRotationQuaternion = new Quaternion();
this._panningEnabled = _SpatialAudioDefaults.panningEnabled;
/** @internal */
this.orientation = _SpatialAudioDefaults.orientation.clone();
/** @internal */
this.position = _SpatialAudioDefaults.position.clone();
/** @internal */
this.rotation = _SpatialAudioDefaults.rotation.clone();
/** @internal */
this.rotationQuaternion = _SpatialAudioDefaults.rotationQuaternion.clone();
this._inputNode = new GainNode(engine._audioContext);
this._attenuationNode = new GainNode(engine._audioContext);
this._attenuation = new _WebAudioParameterComponent(engine, this._attenuationNode.gain);
this.node = new PannerNode(engine._audioContext);
this._orientationX = new _WebAudioParameterComponent(engine, this.node.orientationX);
this._orientationY = new _WebAudioParameterComponent(engine, this.node.orientationY);
this._orientationZ = new _WebAudioParameterComponent(engine, this.node.orientationZ);
this._positionX = new _WebAudioParameterComponent(engine, this.node.positionX);
this._positionY = new _WebAudioParameterComponent(engine, this.node.positionY);
this._positionZ = new _WebAudioParameterComponent(engine, this.node.positionZ);
this._connectActiveInput();
}
/** @internal */
dispose() {
super.dispose();
this._attenuation.dispose();
this._orientationX.dispose();
this._orientationY.dispose();
this._orientationZ.dispose();
this._positionX.dispose();
this._positionY.dispose();
this._positionZ.dispose();
this._inputNode.disconnect();
this._attenuationNode.disconnect();
this.node.disconnect();
}
/** @internal */
get coneInnerAngle() {
return D2r(this.node.coneInnerAngle);
}
set coneInnerAngle(value) {
this.node.coneInnerAngle = R2d(value);
}
/** @internal */
get coneOuterAngle() {
return D2r(this.node.coneOuterAngle);
}
set coneOuterAngle(value) {
this.node.coneOuterAngle = R2d(value);
}
/** @internal */
get coneOuterVolume() {
return this.node.coneOuterGain;
}
set coneOuterVolume(value) {
this.node.coneOuterGain = value;
}
/** @internal */
get distanceModel() {
return this.node.distanceModel;
}
set distanceModel(value) {
this.node.distanceModel = value;
// Wiggle the max distance to make the change take effect.
const maxDistance = this.node.maxDistance;
this.node.maxDistance = maxDistance + 0.001;
this.node.maxDistance = maxDistance;
this._updateAttenuation();
}
/** @internal */
get minDistance() {
return this.node.refDistance;
}
set minDistance(value) {
this.node.refDistance = value;
this._updateAttenuation();
}
/** @internal */
get maxDistance() {
return this.node.maxDistance;
}
set maxDistance(value) {
this.node.maxDistance = value;
this._updateAttenuation();
}
/** @internal */
get panningEnabled() {
return this._panningEnabled;
}
set panningEnabled(value) {
if (this._panningEnabled === value) {
return;
}
this._panningEnabled = value;
this._connectActiveInput();
this._updateAttenuation();
}
/** @internal */
get panningModel() {
return this.node.panningModel;
}
set panningModel(value) {
this.node.panningModel = value;
}
/** @internal */
get rolloffFactor() {
return this.node.rolloffFactor;
}
set rolloffFactor(value) {
this.node.rolloffFactor = value;
this._updateAttenuation();
}
/** @internal */
get _inNode() {
return this._inputNode;
}
/** @internal */
get _outNode() {
return this._panningEnabled ? this.node : this._attenuationNode;
}
/** @internal */
_updatePosition() {
if (this._lastPosition.equalsWithEpsilon(this.position)) {
this._updateAttenuation();
return;
}
this._positionX.targetValue = this.position.x;
this._positionY.targetValue = this.position.y;
this._positionZ.targetValue = this.position.z;
this._lastPosition.copyFrom(this.position);
this._updateAttenuation();
}
/** @internal */
_updateRotation() {
let rotated = false;
if (!this._lastRotationQuaternion.equalsWithEpsilon(this.rotationQuaternion)) {
TmpQuaternion.copyFrom(this.rotationQuaternion);
this._lastRotationQuaternion.copyFrom(this.rotationQuaternion);
rotated = true;
}
else if (!this._lastRotation.equalsWithEpsilon(this.rotation)) {
Quaternion.FromEulerAnglesToRef(this.rotation.x, this.rotation.y, this.rotation.z, TmpQuaternion);
this._lastRotation.copyFrom(this.rotation);
rotated = true;
}
else if (this._lastOrientation.equalsWithEpsilon(this.orientation)) {
return;
}
if (rotated) {
Matrix.FromQuaternionToRef(TmpQuaternion, TmpMatrix);
Vector3.TransformNormalToRef(Vector3.RightReadOnly, TmpMatrix, this.orientation);
}
this._orientationX.targetValue = this.orientation.x;
this._orientationY.targetValue = this.orientation.y;
this._orientationZ.targetValue = this.orientation.z;
}
_connect(node) {
const connected = super._connect(node);
if (!connected) {
return false;
}
// If the wrapped node is not available now, it will be connected later by the subgraph.
if (node._inNode) {
this.node.connect(node._inNode);
this._attenuationNode.connect(node._inNode);
}
return true;
}
_disconnect(node) {
const disconnected = super._disconnect(node);
if (!disconnected) {
return false;
}
if (node._inNode) {
this.node.disconnect(node._inNode);
this._attenuationNode.disconnect(node._inNode);
}
return true;
}
/** @internal */
getClassName() {
return "_SpatialWebAudioSubNode";
}
_connectActiveInput() {
this._inputNode.disconnect();
if (this._panningEnabled) {
this._inputNode.connect(this.node);
}
else {
this._inputNode.connect(this._attenuationNode);
}
}
_updateAttenuation() {
if (this._panningEnabled) {
this._attenuation.targetValue = 1;
return;
}
const listenerPosition = this.engine.listener.position;
const deltaX = this.position.x - listenerPosition.x;
const deltaY = this.position.y - listenerPosition.y;
const deltaZ = this.position.z - listenerPosition.z;
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);
const minDistance = Math.max(this.minDistance, 0);
let attenuation = 1;
switch (this.distanceModel) {
case "linear":
{
const maxDistance = Math.max(this.maxDistance, minDistance);
const clampedDistance = Math.min(Math.max(distance, minDistance), maxDistance);
attenuation =
maxDistance === minDistance ? (distance <= minDistance ? 1 : 0) : 1 - (this.rolloffFactor * (clampedDistance - minDistance)) / (maxDistance - minDistance);
}
break;
case "inverse":
if (minDistance === 0) {
attenuation = 0;
break;
}
attenuation = minDistance / (minDistance + this.rolloffFactor * (Math.max(distance, minDistance) - minDistance));
break;
case "exponential":
if (minDistance === 0) {
attenuation = 0;
break;
}
attenuation = Math.pow(Math.max(distance, minDistance) / minDistance, -this.rolloffFactor);
break;
}
this._attenuation.targetValue = Math.min(Math.max(attenuation, 0), 1);
}
}
/** @internal */
// eslint-disable-next-line @typescript-eslint/require-await
async function _CreateStereoAudioSubNodeAsync(engine) {
return new _StereoWebAudioSubNode(engine);
}
/** @internal */
class _StereoWebAudioSubNode extends _StereoAudioSubNode {
/** @internal */
constructor(engine) {
super(engine);
this.node = new StereoPannerNode(engine._audioContext);
this._pan = new _WebAudioParameterComponent(engine, this.node.pan);
}
/** @internal */
dispose() {
super.dispose();
this._pan.dispose();
}
/** @internal */
get pan() {
return this._pan.targetValue;
}
/** @internal */
set pan(value) {
this._pan.targetValue = value;
}
/** @internal */
get _inNode() {
return this.node;
}
/** @internal */
get _outNode() {
return this.node;
}
/** @internal */
getClassName() {
return "_StereoWebAudioSubNode";
}
_connect(node) {
const connected = super._connect(node);
if (!connected) {
return false;
}
// If the wrapped node is not available now, it will be connected later by the subgraph.
if (node._inNode) {
this.node.connect(node._inNode);
}
return true;
}
_disconnect(node) {
const disconnected = super._disconnect(node);
if (!disconnected) {
return false;
}
if (node._inNode) {
this.node.disconnect(node._inNode);
}
return true;
}
}
/** @internal */
class _WebAudioBusAndSoundSubGraph extends _WebAudioBaseSubGraph {
constructor() {
super(...arguments);
this._rootNode = null;
this._inputNode = null;
}
/** @internal */
async initAsync(options) {
await super.initAsync(options);
let hasSpatialOptions;
let hasStereoOptions;
if ((hasSpatialOptions = _HasSpatialAudioOptions(options))) {
await this.createAndAddSubNodeAsync("Spatial" /* AudioSubNode.SPATIAL */);
}
if ((hasStereoOptions = _HasStereoAudioOptions(options))) {
await this.createAndAddSubNodeAsync("Stereo" /* AudioSubNode.STEREO */);
}
await this._createSubNodePromisesResolvedAsync();
if (hasSpatialOptions) {
_GetSpatialAudioSubNode(this)?.setOptions(options);
}
if (hasStereoOptions) {
_GetStereoAudioSubNode(this)?.setOptions(options);
}
}
/** @internal */
get _inNode() {
return this._inputNode;
}
// eslint-disable-next-line @typescript-eslint/promise-function-async
_createSubNode(name) {
try {
const node = super._createSubNode(name);
return node;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
}
catch (e) { }
switch (name) {
case "Spatial" /* AudioSubNode.SPATIAL */:
return _CreateSpatialAudioSubNodeAsync(this._owner.engine);
case "Stereo" /* AudioSubNode.STEREO */:
return _CreateStereoAudioSubNodeAsync(this._owner.engine);
default:
throw new Error(`Unknown subnode name: ${name}`);
}
}
_onSubNodesChanged() {
super._onSubNodesChanged();
const spatialNode = _GetSpatialAudioSubNode(this);
const stereoNode = _GetStereoAudioSubNode(this);
const volumeNode = _GetVolumeAudioSubNode(this);
if (spatialNode && spatialNode.getClassName() !== "_SpatialWebAudioSubNode") {
throw new Error("Not a WebAudio subnode.");
}
if (stereoNode && stereoNode.getClassName() !== "_StereoWebAudioSubNode") {
throw new Error("Not a WebAudio subnode.");
}
if (volumeNode && volumeNode.getClassName() !== "_VolumeWebAudioSubNode") {
throw new Error("Not a WebAudio subnode.");
}
if (spatialNode) {
spatialNode.disconnectAll();
if (volumeNode) {
spatialNode.connect(volumeNode);
}
}
if (stereoNode) {
stereoNode.disconnectAll();
if (volumeNode) {
stereoNode.connect(volumeNode);
}
}
if (spatialNode && stereoNode) {
this._rootNode = new GainNode(this._owner.engine._audioContext);
this._rootNode.connect(spatialNode._inNode);
this._rootNode.connect(stereoNode._inNode);
}
else {
this._rootNode?.disconnect();
this._rootNode = null;
}
let inSubNode = null;
let inNode;
if (this._rootNode) {
inNode = this._rootNode;
}
else {
if (spatialNode) {
inSubNode = spatialNode;
}
else if (stereoNode) {
inSubNode = stereoNode;
}
else if (volumeNode) {
inSubNode = volumeNode;
}
inNode = inSubNode?._inNode ?? null;
}
if (this._inputNode !== inNode) {
// Disconnect the wrapped upstream WebAudio nodes from the old wrapped WebAudio node.
// The wrapper nodes are unaware of this change.
if (this._inputNode && this._upstreamNodes) {
const it = this._upstreamNodes.values();
for (let next = it.next(); !next.done; next = it.next()) {
next.value._outNode?.disconnect(this._inputNode);
}
}
this._inputNode = inNode;
// Connect the wrapped upstream WebAudio nodes to the new wrapped WebAudio node.
// The wrapper nodes are unaware of this change.
if (inNode && this._upstreamNodes) {
const it = this._upstreamNodes.values();
for (let next = it.next(); !next.done; next = it.next()) {
next.value._outNode?.connect(inNode);
}
}
}
}
}
/** @internal */
class _SpatialAudio extends AbstractSpatialAudio {
/** @internal */
constructor(subGraph) {
super();
this._coneInnerAngle = _SpatialAudioDefaults.coneInnerAngle;
this._coneOuterAngle = _SpatialAudioDefaults.coneOuterAngle;
this._coneOuterVolume = _SpatialAudioDefaults.coneOuterVolume;
this._distanceModel = _SpatialAudioDefaults.distanceModel;
this._maxDistance = _SpatialAudioDefaults.maxDistance;
this._minDistance = _SpatialAudioDefaults.minDistance;
this._panningEnabled = _SpatialAudioDefaults.panningEnabled;
this._panningModel = _SpatialAudioDefaults.panningModel;
this._rolloffFactor = _SpatialAudioDefaults.rolloffFactor;
const subNode = _GetSpatialAudioSubNode(subGraph);
if (subNode) {
this._orientation = subNode.orientation.clone();
this._panningEnabled = subNode.panningEnabled;
this._position = subNode.position.clone();
this._rotation = subNode.rotation.clone();
this._rotationQuaternion = subNode.rotationQuaternion.clone();
}
else {
this._orientation = _SpatialAudioDefaults.orientation.clone();
this._position = _SpatialAudioDefaults.position.clone();
this._rotation = _SpatialAudioDefaults.rotation.clone();
this._rotationQuaternion = _SpatialAudioDefaults.rotationQuaternion.clone();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
subGraph.createAndAddSubNodeAsync("Spatial" /* AudioSubNode.SPATIAL */);
}
this._subGraph = subGraph;
}
/** @internal */
dispose() {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this._subGraph.removeSubNodeAsync(_GetSpatialAudioSubNode(this._subGraph));
}
/** @internal */
get coneInnerAngle() {
return this._coneInnerAngle;
}
set coneInnerAngle(value) {
this._coneInnerAngle = value;
_SetSpatialAudioProperty(this._subGraph, "coneInnerAngle", value);
}
/** @internal */
get coneOuterAngle() {
return this._coneOuterAngle;
}
set coneOuterAngle(value) {
this._coneOuterAngle = value;
_SetSpatialAudioProperty(this._subGraph, "coneOuterAngle", value);
}
/** @internal */
get coneOuterVolume() {
return this._coneOuterVolume;
}
set coneOuterVolume(value) {
this._coneOuterVolume = value;
_SetSpatialAudioProperty(this._subGraph, "coneOuterVolume", value);
}
/** @internal */
get distanceModel() {
return this._distanceModel;
}
set distanceModel(value) {
this._distanceModel = value;
_SetSpatialAudioProperty(this._subGraph, "distanceModel", value);
}
/** @internal */
get isAttached() {
return this._subGraph.getSubNode("Spatial" /* AudioSubNode.SPATIAL */)?.isAttached ?? false;
}
/** @internal */
get attachedNode() {
return this._subGraph.getSubNode("Spatial" /* AudioSubNode.SPATIAL */)?.attachedNode ?? null;
}
/** @internal */
get useBoundingBox() {
return this._subGraph.getSubNode("Spatial" /* AudioSubNode.SPATIAL */)?.useBoundingBox ?? false;
}
/** @internal */
get attachmentType() {
return this._subGraph.getSubNode("Spatial" /* AudioSubNode.SPATIAL */)?.attachmentType ?? 3 /* SpatialAudioAttachmentType.PositionAndRotation */;
}
/** @internal */
get maxDistance() {
return this._maxDistance;
}
set maxDistance(value) {
if (value <= 0) {
value = 0.000001;
}
this._maxDistance = value;
_SetSpatialAudioProperty(this._subGraph, "maxDistance", value);
}
/** @internal */
get minDistance() {
return this._minDistance;
}
set minDistance(value) {
this._minDistance = value;
_SetSpatialAudioProperty(this._subGraph, "minDistance", value);
}
/** @internal */
get orientation() {
return this._orientation;
}
set orientation(value) {
this._orientation = value;
this._updateRotation();
}
/** @internal */
get panningEnabled() {
return this._panningEnabled;
}
set panningEnabled(value) {
this._panningEnabled = value;
_SetSpatialAudioProperty(this._subGraph, "panningEnabled", value);
}
/** @internal */
get panningModel() {
return this._panningModel;
}
set panningModel(value) {
this._panningModel = value;
_SetSpatialAudioProperty(this._subGraph, "panningModel", value);
}
/** @internal */
get position() {
return this._position;
}
set position(value) {
this._position = value;
this._updatePosition();
}
/** @internal */
get rolloffFactor() {
return this._rolloffFactor;
}
set rolloffFactor(value) {
this._rolloffFactor = value;
_SetSpatialAudioProperty(this._subGraph, "rolloffFactor", value);
}
/** @internal */
get rotation() {
return this._rotation;
}
set rotation(value) {
this._rotation = value;
this._updateRotation();
}
/** @internal */
get rotationQuaternion() {
return this._rotationQuaternion;
}
set rotationQuaternion(value) {
this._rotationQuaternion = value;
this._updateRotation();
}
/**
* Attaches to a scene node.
*
* Detaches automatically before attaching to the given scene node.
* If `sceneNode` is `null` it is the same as calling `detach()`.
*
* @param sceneNode The scene node to attach to, or `null` to detach.
* @param useBoundingBox Whether to use the bounding box of the node for positioning. Defaults to `false`.
* @param attachmentType Whether to attach to the node's position and/or rotation. Defaults to `PositionAndRotation`.
*/
attach(sceneNode, useBoundingBox = false, attachmentType = 3 /* SpatialAudioAttachmentType.PositionAndRotation */) {
_GetSpatialAudioSubNode(this._subGraph)?.attach(sceneNode, useBoundingBox, attachmentType);
}
/**
* Detaches from the scene node if attached.
*/
detach() {
_GetSpatialAudioSubNode(this._subGraph)?.detach();
}
/** @internal */
update() {
const subNode = _GetSpatialAudioSubNode(this._subGraph);
if (!subNode) {
return;
}
if (subNode.isAttached) {
subNode.update();
}
else {
this._updatePosition(subNode);
this._updateRotation(subNode);
}
}
_updatePosition(subNode = null) {
if (!subNode) {
subNode = _GetSpatialAudioSubNode(this._subGraph);
if (!subNode) {
return;
}
}
const position = subNode.position;
if (!position.equalsWithEpsilon(this._position)) {
subNode.position.copyFrom(this._position);
subNode._updatePosition();
}
else if (!subNode.panningEnabled) {
subNode._updatePosition();
}
}
_updateRotation(subNode = null) {
if (!subNode) {
subNode = _GetSpatialAudioSubNode(this._subGraph);
if (!subNode) {
return;
}
}
if (!subNode.rotationQuaternion.equalsWithEpsilon(this._rotationQuaternion)) {
subNode.rotationQuaternion.copyFrom(this._rotationQuaternion);
subNode._updateRotation();
this._orientation.copyFrom(subNode.orientation);
this._rotation.copyFrom(subNode.rotation);
}
else if (!subNode.rotation.equalsWithEpsilon(this._rotation)) {
subNode.rotation.copyFrom(this._rotation);
subNode._updateRotation();
this._orientation.copyFrom(subNode.orientation);
this._rotationQuaternion.copyFrom(subNode.rotationQuaternion);
}
else if (!subNode.orientation.equalsWithEpsilon(this._orientation)) {
subNode.orientation.copyFrom(this._orientation);
subNode._updateRotation();
this._rotation.copyFrom(subNode.rotation);
this._rotationQuaternion.copyFrom(subNode.rotationQuaternion);
}
}
}
/** @internal */
class _SpatialWebAudio extends _SpatialAudio {
/** @internal */
constructor(subGraph, autoUpdate, minUpdateTime) {
super(subGraph);
this._updaterComponent = new _SpatialWebAudioUpdaterComponent(this, autoUpdate, minUpdateTime);
}
/** @internal */
get minUpdateTime() {
return this._updaterComponent.minUpdateTime;
}
/** @internal */
set minUpdateTime(value) {
this._updaterComponent.minUpdateTime = value;
}
/** @internal */
dispose() {
super.dispose();
this._updaterComponent.dispose();
this._updaterComponent = null;
}
}
export { _HasSpatialAudioOptions as _, _StereoAudio as a, _SpatialWebAudio as b, _WebAudioBusAndSoundSubGraph as c, _SpatialAudioDefaults as d };
//# sourceMappingURL=spatialWebAudio-BHkDY-w9.esm.js.map