зеркало из https://github.com/mozilla/Spoke.git
Allow independent audio parameter overrides
This commit is contained in:
Родитель
ff546df26e
Коммит
75585134ff
|
@ -1,14 +1,14 @@
|
|||
import EditorNodeMixin from "./EditorNodeMixin";
|
||||
import { PlaneBufferGeometry, MeshBasicMaterial, Mesh, DoubleSide } from "three";
|
||||
import audioIconUrl from "../../assets/audio-icon.png";
|
||||
import AudioParamsNode from "./AudioParamsNode";
|
||||
import AudioSource from "../objects/AudioSource";
|
||||
import loadTexture from "../utils/loadTexture";
|
||||
import { RethrownError } from "../utils/errors";
|
||||
import { AudioType, DistanceModelType } from "../objects/AudioParams";
|
||||
import { AudioElementType } from "../objects/AudioParams";
|
||||
|
||||
let audioHelperTexture = null;
|
||||
|
||||
export default class AudioNode extends EditorNodeMixin(AudioSource) {
|
||||
export default class AudioNode extends AudioParamsNode(AudioSource) {
|
||||
static componentName = "audio";
|
||||
|
||||
static nodeName = "Audio";
|
||||
|
@ -22,18 +22,6 @@ export default class AudioNode extends EditorNodeMixin(AudioSource) {
|
|||
|
||||
const audioComp = json.components.find(c => c.name === "audio");
|
||||
const { src, controls, autoPlay, loop } = audioComp.props;
|
||||
const audioParamsComp = json.components.find(c => c.name === "audio-params");
|
||||
const {
|
||||
audioType,
|
||||
gain,
|
||||
distanceModel,
|
||||
rolloffFactor,
|
||||
refDistance,
|
||||
maxDistance,
|
||||
coneInnerAngle,
|
||||
coneOuterAngle,
|
||||
coneOuterGain
|
||||
} = audioParamsComp.props;
|
||||
|
||||
loadAsync(
|
||||
(async () => {
|
||||
|
@ -41,15 +29,6 @@ export default class AudioNode extends EditorNodeMixin(AudioSource) {
|
|||
node.controls = controls || false;
|
||||
node.autoPlay = autoPlay;
|
||||
node.loop = loop;
|
||||
node.audioType = audioType;
|
||||
node.gain = gain;
|
||||
node.distanceModel = distanceModel;
|
||||
node.rolloffFactor = rolloffFactor;
|
||||
node.refDistance = refDistance;
|
||||
node.maxDistance = maxDistance;
|
||||
node.coneInnerAngle = coneInnerAngle;
|
||||
node.coneOuterAngle = coneOuterAngle;
|
||||
node.coneOuterGain = coneOuterGain;
|
||||
})()
|
||||
);
|
||||
|
||||
|
@ -57,7 +36,7 @@ export default class AudioNode extends EditorNodeMixin(AudioSource) {
|
|||
}
|
||||
|
||||
constructor(editor) {
|
||||
super(editor, editor.audioListener);
|
||||
super(editor, editor.audioListener, AudioElementType.AUDIO);
|
||||
|
||||
this._canonicalUrl = "";
|
||||
this._autoPlay = true;
|
||||
|
@ -178,17 +157,6 @@ export default class AudioNode extends EditorNodeMixin(AudioSource) {
|
|||
controls: this.controls,
|
||||
autoPlay: this.autoPlay,
|
||||
loop: this.loop
|
||||
},
|
||||
"audio-params": {
|
||||
audioType: this.audioType,
|
||||
gain: this.gain,
|
||||
distanceModel: this.distanceModel,
|
||||
rolloffFactor: this.rolloffFactor,
|
||||
refDistance: this.refDistance,
|
||||
maxDistance: this.maxDistance,
|
||||
coneInnerAngle: this.coneInnerAngle,
|
||||
coneOuterAngle: this.coneOuterAngle,
|
||||
coneOuterGain: this.coneOuterGain
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -202,20 +170,6 @@ export default class AudioNode extends EditorNodeMixin(AudioSource) {
|
|||
autoPlay: this.autoPlay,
|
||||
loop: this.loop
|
||||
});
|
||||
|
||||
// We don't want artificial distance based attenuation to be applied to stereo audios
|
||||
// so we set the distanceModel and rolloffFactor so the attenuation is always 1.
|
||||
this.addGLTFComponent("audio-params", {
|
||||
audioType: this.audioType,
|
||||
gain: this.gain,
|
||||
distanceModel: this.audioType === AudioType.Stereo ? DistanceModelType.Linear : this.distanceModel,
|
||||
rolloffFactor: this.audioType === AudioType.Stereo ? 0 : this.rolloffFactor,
|
||||
refDistance: this.refDistance,
|
||||
maxDistance: this.maxDistance,
|
||||
coneInnerAngle: this.coneInnerAngle,
|
||||
coneOuterAngle: this.coneOuterAngle,
|
||||
coneOuterGain: this.coneOuterGain
|
||||
});
|
||||
this.addGLTFComponent("networked", {
|
||||
id: this.uuid
|
||||
});
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
import { AudioType, DistanceModelType, SourceType } from "../objects/AudioParams";
|
||||
import EditorNodeMixin from "./EditorNodeMixin";
|
||||
|
||||
export default function AudioParamsNode(Type) {
|
||||
return class extends EditorNodeMixin(Type) {
|
||||
static async deserialize(editor, json) {
|
||||
const node = await super.deserialize(editor, json);
|
||||
|
||||
const audioParamsProps = json.components.find(c => c.name === "audio-params").props;
|
||||
|
||||
node.overrideAudioSettings =
|
||||
audioParamsProps.overrideAudioSettings === undefined ? true : audioParamsProps.overrideAudioSettings;
|
||||
node.audioType = audioParamsProps.audioType;
|
||||
node.gain = audioParamsProps.gain;
|
||||
node.distanceModel = audioParamsProps.distanceModel;
|
||||
node.rolloffFactor = audioParamsProps.rolloffFactor;
|
||||
node.refDistance = audioParamsProps.refDistance;
|
||||
node.maxDistance = audioParamsProps.maxDistance;
|
||||
node.coneInnerAngle = audioParamsProps.coneInnerAngle;
|
||||
node.coneOuterAngle = audioParamsProps.coneOuterAngle;
|
||||
node.coneOuterGain = audioParamsProps.coneOuterGain;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
constructor(editor, listener, type) {
|
||||
super(editor, listener, type);
|
||||
|
||||
this._overrideAudioSettings = false;
|
||||
}
|
||||
|
||||
get overrideAudioSettings() {
|
||||
return this._overrideAudioSettings;
|
||||
}
|
||||
|
||||
set overrideAudioSettings(overriden) {
|
||||
this._overrideAudioSettings = overriden;
|
||||
if (!overriden) {
|
||||
this.enabledProperties = {};
|
||||
}
|
||||
}
|
||||
|
||||
copy(source, recursive = true) {
|
||||
super.copy(source, recursive);
|
||||
|
||||
this._overrideAudioSettings = source._overrideAudioSettings;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
serialize(components) {
|
||||
return super.serialize({
|
||||
...components,
|
||||
...{
|
||||
"audio-params": {
|
||||
overrideAudioSettings: this.overrideAudioSettings,
|
||||
audioType: this.audioType,
|
||||
gain: this.gain,
|
||||
distanceModel: this.distanceModel,
|
||||
rolloffFactor: this.rolloffFactor,
|
||||
refDistance: this.refDistance,
|
||||
maxDistance: this.maxDistance,
|
||||
coneInnerAngle: this.coneInnerAngle,
|
||||
coneOuterAngle: this.coneOuterAngle,
|
||||
coneOuterGain: this.coneOuterGain
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prepareForExport() {
|
||||
if (this.overrideAudioSettings) {
|
||||
let distanceModel = this.optionalPropertyExportValue("distanceModel");
|
||||
let rolloffFactor = this.optionalPropertyExportValue("rolloffFactor");
|
||||
if (this.sourcetype === SourceType.MEDIA_VIDEO) {
|
||||
// We don't want artificial distance based attenuation to be applied to media stereo audios
|
||||
// so we set the distanceModel and rolloffFactor so the attenuation is always 1.
|
||||
distanceModel = this.optionalPropertyExportValue["distanceModel"]
|
||||
? this.audioType === AudioType.Stereo
|
||||
? DistanceModelType.Linear
|
||||
: this.optionalPropertyExportValue("distanceModel")
|
||||
: undefined;
|
||||
rolloffFactor = this.optionalPropertyExportValue["rolloffFactor"]
|
||||
? this.audioType === AudioType.Stereo
|
||||
? 0
|
||||
: this.optionalPropertyExportValue("rolloffFactor")
|
||||
: undefined;
|
||||
}
|
||||
|
||||
this.addGLTFComponent("audio-params", {
|
||||
audioType: this.optionalPropertyExportValue("audioType"),
|
||||
gain: this.optionalPropertyExportValue("gain"),
|
||||
distanceModel,
|
||||
rolloffFactor,
|
||||
refDistance: this.optionalPropertyExportValue("refDistance"),
|
||||
maxDistance: this.optionalPropertyExportValue("maxDistance"),
|
||||
coneInnerAngle: this.optionalPropertyExportValue("coneInnerAngle"),
|
||||
coneOuterAngle: this.optionalPropertyExportValue("coneOuterAngle"),
|
||||
coneOuterGain: this.optionalPropertyExportValue("coneOuterGain")
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
import { Material, BoxBufferGeometry, Mesh, BoxHelper } from "three";
|
||||
import AudioParams from "../objects/AudioParams";
|
||||
import EditorNodeMixin from "./EditorNodeMixin";
|
||||
import AudioParams, { AudioElementType } from "../objects/AudioParams";
|
||||
import AudioParamsNode from "./AudioParamsNode";
|
||||
|
||||
const requiredProperties = ["enabled", "inOut", "outIn"];
|
||||
|
||||
export default class AudioZoneNode extends EditorNodeMixin(AudioParams) {
|
||||
export default class AudioZoneNode extends AudioParamsNode(AudioParams) {
|
||||
static componentName = "audio-zone";
|
||||
|
||||
static nodeName = "Audio Zone";
|
||||
|
@ -13,8 +13,8 @@ export default class AudioZoneNode extends EditorNodeMixin(AudioParams) {
|
|||
|
||||
static _material = new Material();
|
||||
|
||||
static async deserialize(editor, json) {
|
||||
const node = await super.deserialize(editor, json);
|
||||
static async deserialize(editor, json, loadAsync, onError) {
|
||||
const node = await super.deserialize(editor, json, loadAsync, onError);
|
||||
|
||||
const zoneProps = json.components.find(c => c.name === "audio-zone").props;
|
||||
|
||||
|
@ -22,23 +22,11 @@ export default class AudioZoneNode extends EditorNodeMixin(AudioParams) {
|
|||
node.inOut = zoneProps.inOut;
|
||||
node.outIn = zoneProps.outIn;
|
||||
|
||||
const audioParamsProps = json.components.find(c => c.name === "audio-params").props;
|
||||
|
||||
node.audioType = audioParamsProps.audioType;
|
||||
node.gain = audioParamsProps.gain;
|
||||
node.distanceModel = audioParamsProps.distanceModel;
|
||||
node.rolloffFactor = audioParamsProps.rolloffFactor;
|
||||
node.refDistance = audioParamsProps.refDistance;
|
||||
node.maxDistance = audioParamsProps.maxDistance;
|
||||
node.coneInnerAngle = audioParamsProps.coneInnerAngle;
|
||||
node.coneOuterAngle = audioParamsProps.coneOuterAngle;
|
||||
node.coneOuterGain = audioParamsProps.coneOuterGain;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
constructor(editor) {
|
||||
super(editor, editor.audioListener);
|
||||
super(editor, AudioElementType.AUDIO_ZONE);
|
||||
|
||||
const boxMesh = new Mesh(AudioZoneNode._geometry, AudioZoneNode._material);
|
||||
const box = new BoxHelper(boxMesh, 0x00ff00);
|
||||
|
@ -78,17 +66,6 @@ export default class AudioZoneNode extends EditorNodeMixin(AudioParams) {
|
|||
enabled: this.enabled,
|
||||
inOut: this.inOut,
|
||||
outIn: this.outIn
|
||||
},
|
||||
"audio-params": {
|
||||
audioType: this.audioType,
|
||||
gain: this.gain,
|
||||
distanceModel: this.distanceModel,
|
||||
rolloffFactor: this.rolloffFactor,
|
||||
refDistance: this.refDistance,
|
||||
maxDistance: this.maxDistance,
|
||||
coneInnerAngle: this.coneInnerAngle,
|
||||
coneOuterAngle: this.coneOuterAngle,
|
||||
coneOuterGain: this.coneOuterGain
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -110,16 +87,5 @@ export default class AudioZoneNode extends EditorNodeMixin(AudioParams) {
|
|||
inOut: this.inOut,
|
||||
outIn: this.outIn
|
||||
});
|
||||
this.addGLTFComponent("audio-params", {
|
||||
audioType: this.audioType,
|
||||
gain: this.gain,
|
||||
distanceModel: this.distanceModel,
|
||||
rolloffFactor: this.rolloffFactor,
|
||||
refDistance: this.refDistance,
|
||||
maxDistance: this.maxDistance,
|
||||
coneInnerAngle: this.coneInnerAngle,
|
||||
coneOuterAngle: this.coneOuterAngle,
|
||||
coneOuterGain: this.coneOuterGain
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,12 @@ export default function EditorNodeMixin(Object3DClass) {
|
|||
if (editorSettingsComponent) {
|
||||
node.enabled = editorSettingsComponent.props.enabled;
|
||||
}
|
||||
|
||||
const enabledProperties = json.components.find(c => c.name === "enabled-properties");
|
||||
|
||||
if (enabledProperties) {
|
||||
node.enabledProperties = enabledProperties.props.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
|
@ -89,6 +95,7 @@ export default function EditorNodeMixin(Object3DClass) {
|
|||
this.loadingCube = null;
|
||||
this.errorIcon = null;
|
||||
this.issues = [];
|
||||
this._enabledProperties = {};
|
||||
}
|
||||
|
||||
clone(recursive) {
|
||||
|
@ -120,6 +127,7 @@ export default function EditorNodeMixin(Object3DClass) {
|
|||
this.issues = source.issues.slice();
|
||||
this._visible = source._visible;
|
||||
this.enabled = source.enabled;
|
||||
this._enabledProperties = source.enabledProperties;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -189,6 +197,12 @@ export default function EditorNodeMixin(Object3DClass) {
|
|||
props: {
|
||||
enabled: this.enabled
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "enabled-properties",
|
||||
props: {
|
||||
enabled: this.enabledProperties
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@ -457,5 +471,17 @@ export default function EditorNodeMixin(Object3DClass) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
optionalPropertyExportValue(propName) {
|
||||
return this.enabledProperties[propName] ? this[propName] : undefined;
|
||||
}
|
||||
|
||||
set enabledProperties(object) {
|
||||
this._enabledProperties = { ...this._enabledProperties, ...object };
|
||||
}
|
||||
|
||||
get enabledProperties() {
|
||||
return this._enabledProperties;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -566,6 +566,12 @@ export default class SceneNode extends EditorNodeMixin(Scene) {
|
|||
mediaConeOuterAngle: this.mediaConeOuterAngle,
|
||||
mediaConeOuterGain: this.mediaConeOuterGain
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "enabled-properties",
|
||||
props: {
|
||||
enabled: this.enabledProperties
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -637,18 +643,18 @@ export default class SceneNode extends EditorNodeMixin(Scene) {
|
|||
|
||||
if (this.overrideAudioSettings) {
|
||||
this.addGLTFComponent("audio-settings", {
|
||||
avatarDistanceModel: this.avatarDistanceModel,
|
||||
avatarRolloffFactor: this.avatarRolloffFactor,
|
||||
avatarRefDistance: this.avatarRefDistance,
|
||||
avatarMaxDistance: this.avatarMaxDistance,
|
||||
mediaVolume: this.mediaVolume,
|
||||
mediaDistanceModel: this.mediaDistanceModel,
|
||||
mediaRolloffFactor: this.mediaRolloffFactor,
|
||||
mediaRefDistance: this.mediaRefDistance,
|
||||
mediaMaxDistance: this.mediaMaxDistance,
|
||||
mediaConeInnerAngle: this.mediaConeInnerAngle,
|
||||
mediaConeOuterAngle: this.mediaConeOuterAngle,
|
||||
mediaConeOuterGain: this.mediaConeOuterGain
|
||||
avatarDistanceModel: this.optionalPropertyExportValue("avatarDistanceModel"),
|
||||
avatarRolloffFactor: this.optionalPropertyExportValue("avatarRolloffFactor"),
|
||||
avatarRefDistance: this.optionalPropertyExportValue("avatarRefDistance"),
|
||||
avatarMaxDistance: this.optionalPropertyExportValue("avatarMaxDistance"),
|
||||
mediaVolume: this.optionalPropertyExportValue("mediaVolume"),
|
||||
mediaDistanceModel: this.optionalPropertyExportValue("mediaDistanceModel"),
|
||||
mediaRolloffFactor: this.optionalPropertyExportValue("mediaRolloffFactor"),
|
||||
mediaRefDistance: this.optionalPropertyExportValue("mediaRefDistance"),
|
||||
mediaMaxDistance: this.optionalPropertyExportValue("mediaMaxDistance"),
|
||||
mediaConeInnerAngle: this.optionalPropertyExportValue("mediaConeInnerAngle"),
|
||||
mediaConeOuterAngle: this.optionalPropertyExportValue("mediaConeOuterAngle"),
|
||||
mediaConeOuterGain: this.optionalPropertyExportValue("mediaConeOuterGain")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import EditorNodeMixin from "./EditorNodeMixin";
|
||||
import Video from "../objects/Video";
|
||||
import AudioParamsNode from "./AudioParamsNode";
|
||||
import Hls from "hls.js/dist/hls.light";
|
||||
import isHLS from "../utils/isHLS";
|
||||
import spokeLandingVideo from "../../assets/video/SpokePromo.mp4";
|
||||
import { RethrownError } from "../utils/errors";
|
||||
import { getObjectPerfIssues } from "../utils/performance";
|
||||
import { AudioType, DistanceModelType } from "../objects/AudioParams";
|
||||
import { AudioElementType } from "../objects/AudioParams";
|
||||
|
||||
export default class VideoNode extends EditorNodeMixin(Video) {
|
||||
export default class VideoNode extends AudioParamsNode(Video) {
|
||||
static componentName = "video";
|
||||
|
||||
static nodeName = "Video";
|
||||
|
@ -21,18 +21,6 @@ export default class VideoNode extends EditorNodeMixin(Video) {
|
|||
|
||||
const videoComp = json.components.find(c => c.name === "video");
|
||||
const { src, controls, autoPlay, loop, projection } = videoComp.props;
|
||||
const audioParamsComp = json.components.find(c => c.name === "audio-params");
|
||||
const {
|
||||
audioType,
|
||||
gain,
|
||||
distanceModel,
|
||||
rolloffFactor,
|
||||
refDistance,
|
||||
maxDistance,
|
||||
coneInnerAngle,
|
||||
coneOuterAngle,
|
||||
coneOuterGain
|
||||
} = audioParamsComp.props;
|
||||
|
||||
loadAsync(
|
||||
(async () => {
|
||||
|
@ -41,15 +29,6 @@ export default class VideoNode extends EditorNodeMixin(Video) {
|
|||
node.autoPlay = autoPlay;
|
||||
node.loop = loop;
|
||||
node.projection = projection;
|
||||
node.audioType = audioType;
|
||||
node.gain = gain;
|
||||
node.distanceModel = distanceModel;
|
||||
node.rolloffFactor = rolloffFactor;
|
||||
node.refDistance = refDistance;
|
||||
node.maxDistance = maxDistance;
|
||||
node.coneInnerAngle = coneInnerAngle;
|
||||
node.coneOuterAngle = coneOuterAngle;
|
||||
node.coneOuterGain = coneOuterGain;
|
||||
})()
|
||||
);
|
||||
|
||||
|
@ -69,15 +48,6 @@ export default class VideoNode extends EditorNodeMixin(Video) {
|
|||
node.controls = controls || false;
|
||||
node.autoPlay = autoPlay;
|
||||
node.loop = loop;
|
||||
node.audioType = audioType;
|
||||
node.gain = gain;
|
||||
node.distanceModel = distanceModel;
|
||||
node.rolloffFactor = rolloffFactor;
|
||||
node.refDistance = refDistance;
|
||||
node.maxDistance = maxDistance;
|
||||
node.coneInnerAngle = coneInnerAngle;
|
||||
node.coneOuterAngle = coneOuterAngle;
|
||||
node.coneOuterGain = coneOuterGain;
|
||||
node.projection = projection;
|
||||
})()
|
||||
);
|
||||
|
@ -86,7 +56,7 @@ export default class VideoNode extends EditorNodeMixin(Video) {
|
|||
}
|
||||
|
||||
constructor(editor) {
|
||||
super(editor, editor.audioListener);
|
||||
super(editor, editor.audioListener, AudioElementType.VIDEO);
|
||||
|
||||
this._canonicalUrl = "";
|
||||
this._autoPlay = true;
|
||||
|
@ -219,17 +189,6 @@ export default class VideoNode extends EditorNodeMixin(Video) {
|
|||
autoPlay: this.autoPlay,
|
||||
loop: this.loop,
|
||||
projection: this.projection
|
||||
},
|
||||
"audio-params": {
|
||||
audioType: this.audioType,
|
||||
gain: this.gain,
|
||||
distanceModel: this.distanceModel,
|
||||
rolloffFactor: this.rolloffFactor,
|
||||
refDistance: this.refDistance,
|
||||
maxDistance: this.maxDistance,
|
||||
coneInnerAngle: this.coneInnerAngle,
|
||||
coneOuterAngle: this.coneOuterAngle,
|
||||
coneOuterGain: this.coneOuterGain
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -267,20 +226,6 @@ export default class VideoNode extends EditorNodeMixin(Video) {
|
|||
this.addGLTFComponent("link", { href: this.href });
|
||||
}
|
||||
|
||||
// We don't want artificial distance based attenuation to be applied to stereo audios
|
||||
// so we set the distanceModel and rolloffFactor so the attenuation is always 1.
|
||||
this.addGLTFComponent("audio-params", {
|
||||
audioType: this.audioType,
|
||||
gain: this.gain,
|
||||
distanceModel: this.audioType === AudioType.Stereo ? DistanceModelType.Linear : this.distanceModel,
|
||||
rolloffFactor: this.audioType === AudioType.Stereo ? 0 : this.rolloffFactor,
|
||||
refDistance: this.refDistance,
|
||||
maxDistance: this.maxDistance,
|
||||
coneInnerAngle: this.coneInnerAngle,
|
||||
coneOuterAngle: this.coneOuterAngle,
|
||||
coneOuterGain: this.coneOuterGain
|
||||
});
|
||||
|
||||
this.replaceObject();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,74 +1,86 @@
|
|||
// These enums need to be kept in sync with the ones in the Hubs client for consistency
|
||||
|
||||
import { Object3D } from "three";
|
||||
|
||||
export const SourceType = Object.freeze({
|
||||
MEDIA_VIDEO: 0,
|
||||
AVATAR_AUDIO_SOURCE: 1,
|
||||
AVATAR_RIG: 2,
|
||||
// TODO: Fill in missing value (2)
|
||||
AUDIO_TARGET: 3,
|
||||
AUDIO_ZONE: 4
|
||||
});
|
||||
|
||||
export const AudioType = Object.freeze({
|
||||
export const AudioType = {
|
||||
Stereo: "stereo",
|
||||
PannerNode: "pannernode"
|
||||
});
|
||||
};
|
||||
|
||||
export const DistanceModelType = Object.freeze({
|
||||
export const DistanceModelType = {
|
||||
Linear: "linear",
|
||||
Inverse: "inverse",
|
||||
Exponential: "exponential"
|
||||
};
|
||||
|
||||
export const MediaAudioDefaults = Object.freeze({
|
||||
audioType: AudioType.PannerNode,
|
||||
distanceModel: DistanceModelType.Inverse,
|
||||
rolloffFactor: 1,
|
||||
refDistance: 1,
|
||||
maxDistance: 10000,
|
||||
coneInnerAngle: 360,
|
||||
coneOuterAngle: 0,
|
||||
coneOuterGain: 0,
|
||||
gain: 0.5
|
||||
});
|
||||
|
||||
export const AudioParamsDefaults = Object.freeze({
|
||||
DISTANCE_MODEL: DistanceModelType.Inverse,
|
||||
ROLLOFF_FACTOR: 1,
|
||||
REF_DISTANCE: 1,
|
||||
MAX_DISTANCE: 10000,
|
||||
INNER_ANGLE: 360,
|
||||
OUTER_ANGLE: 0,
|
||||
OUTER_GAIN: 0,
|
||||
GAIN: 0.5
|
||||
export const AudioZoneDefaults = Object.freeze({
|
||||
audioType: AudioType.PannerNode,
|
||||
distanceModel: DistanceModelType.Inverse,
|
||||
rolloffFactor: 1,
|
||||
refDistance: 1,
|
||||
maxDistance: 10000,
|
||||
coneInnerAngle: 360,
|
||||
coneOuterAngle: 0,
|
||||
coneOuterGain: 0,
|
||||
gain: 0.5
|
||||
});
|
||||
|
||||
export const AvatarAudioParamsDefaults = Object.freeze({
|
||||
DISTANCE_MODEL: DistanceModelType.Inverse,
|
||||
ROLLOFF_FACTOR: 2,
|
||||
REF_DISTANCE: 1,
|
||||
MAX_DISTANCE: 10000,
|
||||
INNER_ANGLE: 180,
|
||||
OUTER_ANGLE: 360,
|
||||
OUTER_GAIN: 0,
|
||||
VOLUME: 1.0
|
||||
export const Defaults = {
|
||||
[SourceType.MEDIA_VIDEO]: MediaAudioDefaults,
|
||||
[SourceType.AUDIO_ZONE]: AudioZoneDefaults
|
||||
};
|
||||
|
||||
export const AudioElementType = Object.freeze({
|
||||
AUDIO: "audio",
|
||||
VIDEO: "video",
|
||||
AUDIO_ZONE: "audio-zone"
|
||||
});
|
||||
|
||||
export const MediaAudioParamsDefaults = Object.freeze({
|
||||
DISTANCE_MODEL: DistanceModelType.Inverse,
|
||||
ROLLOFF_FACTOR: 1,
|
||||
REF_DISTANCE: 1,
|
||||
MAX_DISTANCE: 10000,
|
||||
INNER_ANGLE: 360,
|
||||
OUTER_ANGLE: 0,
|
||||
OUTER_GAIN: 0,
|
||||
VOLUME: 0.5
|
||||
});
|
||||
export const sourceTypeForElementType = {
|
||||
[AudioElementType.AUDIO]: SourceType.MEDIA_VIDEO,
|
||||
[AudioElementType.VIDEO]: SourceType.MEDIA_VIDEO,
|
||||
[AudioElementType.AUDIO_ZONE]: SourceType.AUDIO_ZONE
|
||||
};
|
||||
|
||||
export const AudioTypeOptions = Object.values(AudioType).map(v => ({ label: v, value: v }));
|
||||
|
||||
export const DistanceModelOptions = Object.values(DistanceModelType).map(v => ({ label: v, value: v }));
|
||||
|
||||
export default class AudioParams extends Object3D {
|
||||
constructor() {
|
||||
super();
|
||||
constructor(type, ...args) {
|
||||
super(...args);
|
||||
|
||||
this.audioType = AudioType.PannerNode;
|
||||
this.gain = AudioParamsDefaults.GAIN;
|
||||
this.distanceModel = AudioParamsDefaults.DISTANCE_MODEL;
|
||||
this.rolloffFactor = AudioParamsDefaults.ROLLOFF_FACTOR;
|
||||
this.refDistance = AudioParamsDefaults.REF_DISTANCE;
|
||||
this.maxDistance = AudioParamsDefaults.MAX_DISTANCE;
|
||||
this.coneInnerAngle = AudioParamsDefaults.INNER_ANGLE;
|
||||
this.coneOuterAngle = AudioParamsDefaults.OUTER_ANGLE;
|
||||
this.coneOuterGain = AudioParamsDefaults.OUTER_GAIN;
|
||||
this.sourceType = sourceTypeForElementType[type];
|
||||
|
||||
this.audioType = Defaults[this.sourceType].audioType;
|
||||
this.gain = Defaults[this.sourceType].gain;
|
||||
this.distanceModel = Defaults[this.sourceType].distanceModel;
|
||||
this.rolloffFactor = Defaults[this.sourceType].rolloffFactor;
|
||||
this.refDistance = Defaults[this.sourceType].refDistance;
|
||||
this.maxDistance = Defaults[this.sourceType].maxDistance;
|
||||
this.coneInnerAngle = Defaults[this.sourceType].coneInnerAngle;
|
||||
this.coneOuterAngle = Defaults[this.sourceType].coneOuterAngle;
|
||||
this.coneOuterGain = Defaults[this.sourceType].coneOuterGain;
|
||||
}
|
||||
|
||||
get audioType() {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { Audio, PositionalAudio } from "three";
|
||||
import { RethrownError } from "../utils/errors";
|
||||
import { default as AudioParamsClass, AudioType } from "./AudioParams";
|
||||
import AudioParams, { AudioType } from "./AudioParams";
|
||||
|
||||
export default class AudioSource extends AudioParamsClass {
|
||||
constructor(audioListener, elTag = "audio") {
|
||||
super();
|
||||
export default class AudioSource extends AudioParams {
|
||||
constructor(audioListener, type, ...args) {
|
||||
super(type, ...args);
|
||||
|
||||
const el = document.createElement(elTag);
|
||||
const el = document.createElement(type);
|
||||
el.setAttribute("playsinline", "");
|
||||
el.setAttribute("webkit-playsinline", "");
|
||||
el.crossOrigin = "anonymous";
|
||||
|
|
|
@ -20,8 +20,8 @@ export const VideoProjection = {
|
|||
};
|
||||
|
||||
export default class Video extends AudioSource {
|
||||
constructor(audioListener) {
|
||||
super(audioListener, "video");
|
||||
constructor(audioListener, sourceType) {
|
||||
super(audioListener, sourceType);
|
||||
|
||||
this._videoTexture = new VideoTexture(this.el);
|
||||
this._videoTexture.minFilter = LinearFilter;
|
||||
|
|
|
@ -3,6 +3,7 @@ import PropTypes from "prop-types";
|
|||
import styled from "styled-components";
|
||||
import { QuestionCircle } from "styled-icons/fa-regular/QuestionCircle";
|
||||
import { InfoTooltip } from "../layout/Tooltip";
|
||||
import BooleanInput from "./BooleanInput";
|
||||
|
||||
export const InputGroupContainer = styled.div`
|
||||
display: flex;
|
||||
|
@ -10,6 +11,7 @@ export const InputGroupContainer = styled.div`
|
|||
padding: 4px 8px;
|
||||
flex: 1;
|
||||
min-height: 24px;
|
||||
align-items: center;
|
||||
|
||||
${props =>
|
||||
props.disabled &&
|
||||
|
@ -20,7 +22,6 @@ export const InputGroupContainer = styled.div`
|
|||
|
||||
& > label {
|
||||
display: block;
|
||||
width: 25%;
|
||||
color: ${props => props.theme.text2};
|
||||
padding-bottom: 2px;
|
||||
padding-top: 4px;
|
||||
|
@ -28,10 +29,17 @@ export const InputGroupContainer = styled.div`
|
|||
`;
|
||||
|
||||
export const InputGroupContent = styled.div`
|
||||
${props =>
|
||||
props.disabled &&
|
||||
`
|
||||
pointer-events: none;
|
||||
opacity: 0.3;
|
||||
`}
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
flex: 3;
|
||||
padding-left: 8px;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
export const InputGroupInfoIcon = styled(QuestionCircle)`
|
||||
|
@ -43,6 +51,38 @@ export const InputGroupInfoIcon = styled(QuestionCircle)`
|
|||
align-self: center;
|
||||
`;
|
||||
|
||||
export const InputGroupHeader = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
|
||||
${props =>
|
||||
props.disabled &&
|
||||
`
|
||||
pointer-events: none;
|
||||
opacity: 0.3;
|
||||
`}
|
||||
|
||||
& > :first-child {
|
||||
padding-right: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const OptionalGroup = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
|
||||
${props =>
|
||||
props.disabled &&
|
||||
`
|
||||
pointer-events: none;
|
||||
opacity: 0.3;
|
||||
`}
|
||||
`;
|
||||
|
||||
export function InputGroupInfo({ info }) {
|
||||
return (
|
||||
<InfoTooltip info={info}>
|
||||
|
@ -55,11 +95,14 @@ InputGroupInfo.propTypes = {
|
|||
info: PropTypes.string
|
||||
};
|
||||
|
||||
export default function InputGroup({ name, children, disabled, info, ...rest }) {
|
||||
export default function InputGroup({ name, children, disabled, info, optional, enabled, onEnable, ...rest }) {
|
||||
return (
|
||||
<InputGroupContainer disabled={disabled} {...rest}>
|
||||
<label>{name}:</label>
|
||||
<InputGroupContent>
|
||||
<InputGroupHeader>
|
||||
{optional && <BooleanInput value={enabled} onChange={onEnable} />}
|
||||
<OptionalGroup disabled={optional && !enabled}>{name && <label>{name}:</label>}</OptionalGroup>
|
||||
</InputGroupHeader>
|
||||
<InputGroupContent disabled={optional && !enabled}>
|
||||
{children}
|
||||
{info && <InputGroupInfo info={info} />}
|
||||
</InputGroupContent>
|
||||
|
@ -72,5 +115,8 @@ InputGroup.propTypes = {
|
|||
children: PropTypes.any,
|
||||
disabled: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
info: PropTypes.string
|
||||
info: PropTypes.string,
|
||||
optional: PropTypes.bool,
|
||||
enabled: PropTypes.bool,
|
||||
onEnable: PropTypes.func
|
||||
};
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { InputGroupContainer, InputGroupContent, InputGroupInfo } from "./InputGroup";
|
||||
import { InputGroupHeader, InputGroupContainer, InputGroupContent, InputGroupInfo, OptionalGroup } from "./InputGroup";
|
||||
import Scrubber from "./Scrubber";
|
||||
import NumericInput from "./NumericInput";
|
||||
import BooleanInput from "./BooleanInput";
|
||||
|
||||
export default function NumericInputGroup({ name, className, info, ...rest }) {
|
||||
export default function NumericInputGroup({ name, className, info, optional, enabled, onEnable, ...rest }) {
|
||||
const { displayPrecision, ...scrubberProps } = rest;
|
||||
return (
|
||||
<InputGroupContainer>
|
||||
<Scrubber {...scrubberProps}>{name}:</Scrubber>
|
||||
<InputGroupContent>
|
||||
<InputGroupHeader>
|
||||
{optional && <BooleanInput value={enabled} onChange={onEnable} />}
|
||||
<OptionalGroup disabled={optional && !enabled}>
|
||||
<Scrubber {...scrubberProps}>{name}:</Scrubber>
|
||||
</OptionalGroup>
|
||||
</InputGroupHeader>
|
||||
<InputGroupContent disabled={optional && !enabled}>
|
||||
<NumericInput {...rest} />
|
||||
{info && <InputGroupInfo info={info} />}
|
||||
</InputGroupContent>
|
||||
|
@ -20,5 +26,8 @@ export default function NumericInputGroup({ name, className, info, ...rest }) {
|
|||
NumericInputGroup.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
className: PropTypes.string,
|
||||
info: PropTypes.string
|
||||
info: PropTypes.string,
|
||||
optional: PropTypes.bool,
|
||||
enabled: PropTypes.bool,
|
||||
onEnable: PropTypes.func
|
||||
};
|
||||
|
|
|
@ -5,122 +5,168 @@ import SelectInput from "../inputs/SelectInput";
|
|||
import NumericInputGroup from "../inputs/NumericInputGroup";
|
||||
import CompoundNumericInput from "../inputs/CompoundNumericInput";
|
||||
import { AudioType, AudioTypeOptions, DistanceModelOptions, DistanceModelType } from "../../editor/objects/AudioParams";
|
||||
import useEnablePropertySelected from "./useEnablePropertySelected";
|
||||
import useSetPropertySelected from "./useSetPropertySelected";
|
||||
import BooleanInput from "../inputs/BooleanInput";
|
||||
|
||||
export default function AudioParamsProperties({ node, editor, multiEdit }) {
|
||||
const onChangeAudioType = useSetPropertySelected(editor, "audioType");
|
||||
const onChangeGain = useSetPropertySelected(editor, "gain");
|
||||
const onChangeDistanceModel = useSetPropertySelected(editor, "distanceModel");
|
||||
const onChangeRolloffFactor = useSetPropertySelected(editor, "rolloffFactor");
|
||||
const onChangeRefDistance = useSetPropertySelected(editor, "refDistance");
|
||||
const onChangeMaxDistance = useSetPropertySelected(editor, "maxDistance");
|
||||
const onChangeConeInnerAngle = useSetPropertySelected(editor, "coneInnerAngle");
|
||||
const onChangeConeOuterAngle = useSetPropertySelected(editor, "coneOuterAngle");
|
||||
const onChangeConeOuterGain = useSetPropertySelected(editor, "coneOuterGain");
|
||||
const onChangeOverrideAudioSettings = useSetPropertySelected(editor, "overrideAudioSettings");
|
||||
const [onChangeAudioType, onEnableAudioType] = useEnablePropertySelected(editor, "audioType");
|
||||
const [onChangeGain, onEnableGain] = useEnablePropertySelected(editor, "gain");
|
||||
const [onChangeDistanceModel, onEnableDistanceModel] = useEnablePropertySelected(editor, "distanceModel");
|
||||
const [onChangeRolloffFactor, onEnableRolloffFactor] = useEnablePropertySelected(editor, "rolloffFactor");
|
||||
const [onChangeRefDistance, onEnableRefDistance] = useEnablePropertySelected(editor, "refDistance");
|
||||
const [onChangeMaxDistance, onEnableMaxDistance] = useEnablePropertySelected(editor, "maxDistance");
|
||||
const [onChangeConeInnerAngle, onEnableConeInnerAngle] = useEnablePropertySelected(editor, "coneInnerAngle");
|
||||
const [onChangeConeOuterAngle, onEnableConeOuterAngle] = useEnablePropertySelected(editor, "coneOuterAngle");
|
||||
const [onChangeConeOuterGain, onEnableConeOuterGain] = useEnablePropertySelected(editor, "coneOuterGain");
|
||||
|
||||
// TODO: Make node audio settings work with multi-edit
|
||||
|
||||
return (
|
||||
<>
|
||||
<InputGroup name="Audio Type">
|
||||
<SelectInput options={AudioTypeOptions} value={node.audioType} onChange={onChangeAudioType} />
|
||||
<InputGroup name="Override Audio Settings">
|
||||
<BooleanInput value={node.overrideAudioSettings} onChange={onChangeOverrideAudioSettings} />
|
||||
</InputGroup>
|
||||
<InputGroup name="Volume">
|
||||
<CompoundNumericInput value={node.gain} onChange={onChangeGain} />
|
||||
</InputGroup>
|
||||
{!multiEdit && node.audioType === AudioType.PannerNode && (
|
||||
{node.overrideAudioSettings && (
|
||||
<>
|
||||
<InputGroup name="Distance Model" info="The algorithim used to calculate audio rolloff.">
|
||||
<SelectInput options={DistanceModelOptions} value={node.distanceModel} onChange={onChangeDistanceModel} />
|
||||
</InputGroup>
|
||||
|
||||
{node.distanceModel === DistanceModelType.linear ? (
|
||||
<InputGroup
|
||||
name="Rolloff Factor"
|
||||
info="A double value describing how quickly the volume is reduced as the source moves away from the listener. 0 to 1"
|
||||
>
|
||||
<CompoundNumericInput
|
||||
min={0}
|
||||
max={1}
|
||||
smallStep={0.001}
|
||||
mediumStep={0.01}
|
||||
largeStep={0.1}
|
||||
value={node.rolloffFactor}
|
||||
onChange={onChangeRolloffFactor}
|
||||
/>
|
||||
</InputGroup>
|
||||
) : (
|
||||
<NumericInputGroup
|
||||
name="Rolloff Factor"
|
||||
info="A double value describing how quickly the volume is reduced as the source moves away from the listener. 0 to Infinity"
|
||||
min={0}
|
||||
smallStep={0.1}
|
||||
mediumStep={1}
|
||||
largeStep={10}
|
||||
value={node.rolloffFactor}
|
||||
onChange={onChangeRolloffFactor}
|
||||
/>
|
||||
)}
|
||||
<NumericInputGroup
|
||||
name="Ref Distance"
|
||||
info="A double value representing the reference distance for reducing volume as the audio source moves further from the listener."
|
||||
min={0}
|
||||
smallStep={0.1}
|
||||
mediumStep={1}
|
||||
largeStep={10}
|
||||
value={node.refDistance}
|
||||
onChange={onChangeRefDistance}
|
||||
unit="m"
|
||||
/>
|
||||
<NumericInputGroup
|
||||
name="Max Distance"
|
||||
info="A double value representing the maximum distance between the audio source and the listener, after which the volume is not reduced any further."
|
||||
min={0.00001}
|
||||
smallStep={0.1}
|
||||
mediumStep={1}
|
||||
largeStep={10}
|
||||
value={node.maxDistance}
|
||||
onChange={onChangeMaxDistance}
|
||||
unit="m"
|
||||
/>
|
||||
<NumericInputGroup
|
||||
name="Cone Inner Angle"
|
||||
info="A double value describing the angle, in degrees, of a cone inside of which there will be no volume reduction."
|
||||
min={0}
|
||||
max={360}
|
||||
smallStep={0.1}
|
||||
mediumStep={1}
|
||||
largeStep={10}
|
||||
value={node.coneInnerAngle}
|
||||
onChange={onChangeConeInnerAngle}
|
||||
unit="°"
|
||||
disabled={multiEdit}
|
||||
/>
|
||||
<NumericInputGroup
|
||||
name="Cone Outer Angle"
|
||||
info="A double value describing the angle, in degrees, of a cone outside of which the volume will be reduced by a constant value, defined by the coneOuterGain attribute."
|
||||
min={0}
|
||||
max={360}
|
||||
smallStep={0.1}
|
||||
mediumStep={1}
|
||||
largeStep={10}
|
||||
value={node.coneOuterAngle}
|
||||
onChange={onChangeConeOuterAngle}
|
||||
unit="°"
|
||||
disabled={multiEdit}
|
||||
/>
|
||||
<InputGroup
|
||||
name="Cone Outer Gain"
|
||||
info="A double value describing the amount of volume reduction outside the cone defined by the coneOuterAngle attribute. Its default value is 0, meaning that no sound can be heard."
|
||||
name="Audio Type"
|
||||
optional
|
||||
enabled={node.enabledProperties["audioType"]}
|
||||
onEnable={onEnableAudioType}
|
||||
>
|
||||
<CompoundNumericInput
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
value={node.coneOuterGain}
|
||||
onChange={onChangeConeOuterGain}
|
||||
/>
|
||||
<SelectInput options={AudioTypeOptions} value={node.audioType} onChange={onChangeAudioType} />
|
||||
</InputGroup>
|
||||
<InputGroup name="Volume" optional enabled={node.enabledProperties["gain"]} onEnable={onEnableGain}>
|
||||
<CompoundNumericInput value={node.gain} onChange={onChangeGain} />
|
||||
</InputGroup>
|
||||
{!multiEdit && node.audioType === AudioType.PannerNode && (
|
||||
<>
|
||||
<InputGroup
|
||||
name="Distance Model"
|
||||
info="The algorithim used to calculate audio rolloff."
|
||||
optional
|
||||
enabled={node.enabledProperties["distanceModel"]}
|
||||
onEnable={onEnableDistanceModel}
|
||||
>
|
||||
<SelectInput
|
||||
options={DistanceModelOptions}
|
||||
value={node.distanceModel}
|
||||
onChange={onChangeDistanceModel}
|
||||
/>
|
||||
</InputGroup>
|
||||
|
||||
{node.distanceModel === DistanceModelType.linear ? (
|
||||
<InputGroup
|
||||
name="Rolloff Factor"
|
||||
info="A double value describing how quickly the volume is reduced as the source moves away from the listener. 0 to 1"
|
||||
optional
|
||||
enabled={node.enabledProperties["rolloffFactor"]}
|
||||
onEnable={onEnableRolloffFactor}
|
||||
>
|
||||
<CompoundNumericInput
|
||||
min={0}
|
||||
max={1}
|
||||
smallStep={0.001}
|
||||
mediumStep={0.01}
|
||||
largeStep={0.1}
|
||||
value={node.rolloffFactor}
|
||||
onChange={onChangeRolloffFactor}
|
||||
/>
|
||||
</InputGroup>
|
||||
) : (
|
||||
<NumericInputGroup
|
||||
name="Rolloff Factor"
|
||||
info="A double value describing how quickly the volume is reduced as the source moves away from the listener. 0 to 1"
|
||||
min={0}
|
||||
smallStep={0.1}
|
||||
mediumStep={1}
|
||||
largeStep={10}
|
||||
value={node.rolloffFactor}
|
||||
onChange={onChangeRolloffFactor}
|
||||
optional
|
||||
enabled={node.enabledProperties["rolloffFactor"]}
|
||||
onEnable={onEnableRolloffFactor}
|
||||
/>
|
||||
)}
|
||||
<NumericInputGroup
|
||||
name="Ref Distance"
|
||||
info="A double value representing the reference distance for reducing volume as the audio source moves further from the listener."
|
||||
min={0}
|
||||
smallStep={0.1}
|
||||
mediumStep={1}
|
||||
largeStep={10}
|
||||
value={node.refDistance}
|
||||
onChange={onChangeRefDistance}
|
||||
unit="m"
|
||||
optional
|
||||
enabled={node.enabledProperties["refDistance"]}
|
||||
onEnable={onEnableRefDistance}
|
||||
/>
|
||||
<NumericInputGroup
|
||||
name="Max Distance"
|
||||
info="A double value representing the maximum distance between the audio source and the listener, after which the volume is not reduced any further."
|
||||
min={0.00001}
|
||||
smallStep={0.1}
|
||||
mediumStep={1}
|
||||
largeStep={10}
|
||||
value={node.maxDistance}
|
||||
onChange={onChangeMaxDistance}
|
||||
unit="m"
|
||||
optional
|
||||
enabled={node.enabledProperties["maxDistance"]}
|
||||
onEnable={onEnableMaxDistance}
|
||||
/>
|
||||
<NumericInputGroup
|
||||
name="Cone Inner Angle"
|
||||
info="A double value describing the angle, in degrees, of a cone inside of which there will be no volume reduction."
|
||||
min={0}
|
||||
max={360}
|
||||
smallStep={0.1}
|
||||
mediumStep={1}
|
||||
largeStep={10}
|
||||
value={node.coneInnerAngle}
|
||||
onChange={onChangeConeInnerAngle}
|
||||
unit="°"
|
||||
disabled={multiEdit}
|
||||
optional
|
||||
enabled={node.enabledProperties["coneInnerAngle"]}
|
||||
onEnable={onEnableConeInnerAngle}
|
||||
/>
|
||||
<NumericInputGroup
|
||||
name="Cone Outer Angle"
|
||||
info="A double value describing the angle, in degrees, of a cone outside of which the volume will be reduced by a constant value, defined by the coneOuterGain attribute."
|
||||
min={0}
|
||||
max={360}
|
||||
smallStep={0.1}
|
||||
mediumStep={1}
|
||||
largeStep={10}
|
||||
value={node.coneOuterAngle}
|
||||
onChange={onChangeConeOuterAngle}
|
||||
unit="°"
|
||||
disabled={multiEdit}
|
||||
optional
|
||||
enabled={node.enabledProperties["coneOuterAngle"]}
|
||||
onEnable={onEnableConeOuterAngle}
|
||||
/>
|
||||
<InputGroup
|
||||
name="Cone Outer Gain"
|
||||
info="A double value describing the amount of volume reduction outside the cone defined by the coneOuterAngle attribute. Its default value is 0, meaning that no sound can be heard."
|
||||
optional
|
||||
enabled={node.enabledProperties["coneOuterGain"]}
|
||||
onEnable={onEnableConeOuterGain}
|
||||
>
|
||||
<CompoundNumericInput
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
value={node.coneOuterGain}
|
||||
onChange={onChangeConeOuterGain}
|
||||
/>
|
||||
</InputGroup>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -11,6 +11,7 @@ import SelectInput from "../inputs/SelectInput";
|
|||
import useSetPropertySelected from "./useSetPropertySelected";
|
||||
import BooleanInput from "../inputs/BooleanInput";
|
||||
import { DistanceModelOptions, DistanceModelType } from "../../editor/objects/AudioParams";
|
||||
import useEnablePropertySelected from "./useEnablePropertySelected";
|
||||
|
||||
const FogTypeOptions = [
|
||||
{
|
||||
|
@ -38,18 +39,39 @@ export default function SceneNodeEditor(props) {
|
|||
const onChangeFogDensity = useSetPropertySelected(editor, "fogDensity");
|
||||
|
||||
const onChangeOverrideAudioSettings = useSetPropertySelected(editor, "overrideAudioSettings");
|
||||
const onChangeMediaVolume = useSetPropertySelected(editor, "mediaVolume");
|
||||
const onChangeMediaDistanceModel = useSetPropertySelected(editor, "mediaDistanceModel");
|
||||
const onChangeMediaRolloffFactor = useSetPropertySelected(editor, "mediaRolloffFactor");
|
||||
const onChangeMediaRefDistance = useSetPropertySelected(editor, "mediaRefDistance");
|
||||
const onChangeMediaMaxDistance = useSetPropertySelected(editor, "mediaMaxDistance");
|
||||
const onChangeMediaConeInnerAngle = useSetPropertySelected(editor, "mediaConeInnerAngle");
|
||||
const onChangeMediaConeOuterAngle = useSetPropertySelected(editor, "mediaConeOuterAngle");
|
||||
const onChangeMediaConeOuterGain = useSetPropertySelected(editor, "mediaConeOuterGain");
|
||||
const onChangeAvatarDistanceModel = useSetPropertySelected(editor, "avatarDistanceModel");
|
||||
const onChangeAvatarRolloffFactor = useSetPropertySelected(editor, "avatarRolloffFactor");
|
||||
const onChangeAvatarRefDistance = useSetPropertySelected(editor, "avatarRefDistance");
|
||||
const onChangeAvatarMaxDistance = useSetPropertySelected(editor, "avatarMaxDistance");
|
||||
const [onChangeMediaVolume, onEnableMediaVolume] = useEnablePropertySelected(editor, "mediaVolume");
|
||||
const [onChangeMediaDistanceModel, onEnableMediaDistanceModel] = useEnablePropertySelected(
|
||||
editor,
|
||||
"mediaDistanceModel"
|
||||
);
|
||||
const [onChangeMediaRolloffFactor, onEnableMediaRolloffFactor] = useEnablePropertySelected(
|
||||
editor,
|
||||
"mediaRolloffFactor"
|
||||
);
|
||||
const [onChangeMediaRefDistance, onEnableMediaRefDistance] = useEnablePropertySelected(editor, "mediaRefDistance");
|
||||
const [onChangeMediaMaxDistance, onEnableMediaMaxDistance] = useEnablePropertySelected(editor, "mediaMaxDistance");
|
||||
const [onChangeMediaConeInnerAngle, onEnableMediaConeInnerAngle] = useEnablePropertySelected(
|
||||
editor,
|
||||
"mediaConeInnerAngle"
|
||||
);
|
||||
const [onChangeMediaConeOuterAngle, onEnableMediaConeOuterAngle] = useEnablePropertySelected(
|
||||
editor,
|
||||
"mediaConeOuterAngle"
|
||||
);
|
||||
const [onChangeMediaConeOuterGain, onEnableMediaConeOuterGain] = useEnablePropertySelected(
|
||||
editor,
|
||||
"mediaConeOuterGain"
|
||||
);
|
||||
const [onChangeAvatarDistanceModel, onEnableAvatarDistanceModel] = useEnablePropertySelected(
|
||||
editor,
|
||||
"avatarDistanceModel"
|
||||
);
|
||||
const [onChangeAvatarRolloffFactor, onEnableAvatarRolloffFactor] = useEnablePropertySelected(
|
||||
editor,
|
||||
"avatarRolloffFactor"
|
||||
);
|
||||
const [onChangeAvatarRefDistance, onEnableAvatarRefDistance] = useEnablePropertySelected(editor, "avatarRefDistance");
|
||||
const [onChangeAvatarMaxDistance, onEnableAvatarMaxDistance] = useEnablePropertySelected(editor, "avatarMaxDistance");
|
||||
|
||||
return (
|
||||
<NodeEditor {...props} description={SceneNodeEditor.description}>
|
||||
|
@ -102,7 +124,13 @@ export default function SceneNodeEditor(props) {
|
|||
</InputGroup>
|
||||
{node.overrideAudioSettings && (
|
||||
<>
|
||||
<InputGroup name="Avatar Distance Model" info="The algorithim used to calculate audio rolloff.">
|
||||
<InputGroup
|
||||
name="Avatar Distance Model"
|
||||
info="The algorithim used to calculate audio rolloff."
|
||||
optional
|
||||
enabled={node.enabledProperties["avatarDistanceModel"]}
|
||||
onEnable={onEnableAvatarDistanceModel}
|
||||
>
|
||||
<SelectInput
|
||||
options={DistanceModelOptions}
|
||||
value={node.avatarDistanceModel}
|
||||
|
@ -114,6 +142,9 @@ export default function SceneNodeEditor(props) {
|
|||
<InputGroup
|
||||
name="Avatar Rolloff Factor"
|
||||
info="A double value describing how quickly the volume is reduced as the source moves away from the listener. 0 to 1"
|
||||
optional
|
||||
enabled={node.enabledProperties["avatarRolloffFactor"]}
|
||||
onEnable={onEnableAvatarRolloffFactor}
|
||||
>
|
||||
<CompoundNumericInput
|
||||
min={0}
|
||||
|
@ -135,6 +166,9 @@ export default function SceneNodeEditor(props) {
|
|||
largeStep={10}
|
||||
value={node.avatarRolloffFactor}
|
||||
onChange={onChangeAvatarRolloffFactor}
|
||||
optional
|
||||
enabled={node.enabledProperties["avatarRolloffFactor"]}
|
||||
onEnable={onEnableAvatarRolloffFactor}
|
||||
/>
|
||||
)}
|
||||
<NumericInputGroup
|
||||
|
@ -147,6 +181,9 @@ export default function SceneNodeEditor(props) {
|
|||
value={node.avatarRefDistance}
|
||||
onChange={onChangeAvatarRefDistance}
|
||||
unit="m"
|
||||
optional
|
||||
enabled={node.enabledProperties["avatarRefDistance"]}
|
||||
onEnable={onEnableAvatarRefDistance}
|
||||
/>
|
||||
<NumericInputGroup
|
||||
name="Avatar Max Distance"
|
||||
|
@ -158,11 +195,25 @@ export default function SceneNodeEditor(props) {
|
|||
value={node.avatarMaxDistance}
|
||||
onChange={onChangeAvatarMaxDistance}
|
||||
unit="m"
|
||||
optional
|
||||
enabled={node.enabledProperties["avatarMaxDistance"]}
|
||||
onEnable={onEnableAvatarMaxDistance}
|
||||
/>
|
||||
<InputGroup name="Media Volume">
|
||||
<InputGroup
|
||||
name="Media Volume"
|
||||
optional
|
||||
enabled={node.enabledProperties["mediaVolume"]}
|
||||
onEnable={onEnableMediaVolume}
|
||||
>
|
||||
<CompoundNumericInput value={node.mediaVolume} onChange={onChangeMediaVolume} />
|
||||
</InputGroup>
|
||||
<InputGroup name="Media Distance Model" info="The algorithim used to calculate audio rolloff.">
|
||||
<InputGroup
|
||||
name="Media Distance Model"
|
||||
info="The algorithim used to calculate audio rolloff."
|
||||
optional
|
||||
enabled={node.enabledProperties["mediaDistanceModel"]}
|
||||
onEnable={onEnableMediaDistanceModel}
|
||||
>
|
||||
<SelectInput
|
||||
options={DistanceModelOptions}
|
||||
value={node.mediaDistanceModel}
|
||||
|
@ -174,6 +225,9 @@ export default function SceneNodeEditor(props) {
|
|||
<InputGroup
|
||||
name="Media Rolloff Factor"
|
||||
info="A double value describing how quickly the volume is reduced as the source moves away from the listener. 0 to 1"
|
||||
optional
|
||||
enabled={node.enabledProperties["mediaRolloffFactor"]}
|
||||
onEnable={onEnableMediaRolloffFactor}
|
||||
>
|
||||
<CompoundNumericInput
|
||||
min={0}
|
||||
|
@ -195,6 +249,9 @@ export default function SceneNodeEditor(props) {
|
|||
largeStep={10}
|
||||
value={node.mediaRolloffFactor}
|
||||
onChange={onChangeMediaRolloffFactor}
|
||||
optional
|
||||
enabled={node.enabledProperties["mediaRolloffFactor"]}
|
||||
onEnable={onEnableMediaRolloffFactor}
|
||||
/>
|
||||
)}
|
||||
<NumericInputGroup
|
||||
|
@ -207,6 +264,9 @@ export default function SceneNodeEditor(props) {
|
|||
value={node.mediaRefDistance}
|
||||
onChange={onChangeMediaRefDistance}
|
||||
unit="m"
|
||||
optional
|
||||
enabled={node.enabledProperties["mediaRefDistance"]}
|
||||
onEnable={onEnableMediaRefDistance}
|
||||
/>
|
||||
<NumericInputGroup
|
||||
name="Media Max Distance"
|
||||
|
@ -218,6 +278,9 @@ export default function SceneNodeEditor(props) {
|
|||
value={node.mediaMaxDistance}
|
||||
onChange={onChangeMediaMaxDistance}
|
||||
unit="m"
|
||||
optional
|
||||
enabled={node.enabledProperties["mediaMaxDistance"]}
|
||||
onEnable={onEnableMediaMaxDistance}
|
||||
/>
|
||||
<NumericInputGroup
|
||||
name="Media Cone Inner Angle"
|
||||
|
@ -230,6 +293,9 @@ export default function SceneNodeEditor(props) {
|
|||
value={node.mediaConeInnerAngle}
|
||||
onChange={onChangeMediaConeInnerAngle}
|
||||
unit="°"
|
||||
optional
|
||||
enabled={node.enabledProperties["mediaConeInnerAngle"]}
|
||||
onEnable={onEnableMediaConeInnerAngle}
|
||||
/>
|
||||
<NumericInputGroup
|
||||
name="Media Cone Outer Angle"
|
||||
|
@ -242,10 +308,16 @@ export default function SceneNodeEditor(props) {
|
|||
value={node.mediaConeOuterAngle}
|
||||
onChange={onChangeMediaConeOuterAngle}
|
||||
unit="°"
|
||||
optional
|
||||
enabled={node.enabledProperties["mediaConeOuterAngle"]}
|
||||
onEnable={onEnableMediaConeOuterAngle}
|
||||
/>
|
||||
<InputGroup
|
||||
name="Media Cone Outer Gain"
|
||||
info="A double value describing the amount of volume reduction outside the cone defined by the coneOuterAngle attribute. Its default value is 0, meaning that no sound can be heard."
|
||||
optional
|
||||
enabled={node.enabledProperties["mediaConeOuterGain"]}
|
||||
onEnable={onEnableMediaConeOuterGain}
|
||||
>
|
||||
<CompoundNumericInput
|
||||
min={0}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import { useCallback } from "react";
|
||||
|
||||
export default function useEnablePropertySelected(editor, propName) {
|
||||
return [
|
||||
useCallback(value => editor.setPropertySelected(propName, value), [editor, propName]),
|
||||
useCallback(value => editor.setPropertySelected("enabledProperties", { [propName]: value }), [editor, propName])
|
||||
];
|
||||
}
|
Загрузка…
Ссылка в новой задаче