@needle-tools/engine 5.0.3 → 5.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -4
- package/README.md +6 -7
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-BXk8jYW3.js → needle-engine.bundle-BGyKqxBH.js} +12394 -11786
- package/dist/needle-engine.bundle-CiYtOO2O.min.js +1732 -0
- package/dist/needle-engine.bundle-DzVx9Z8D.umd.cjs +1732 -0
- package/dist/needle-engine.d.ts +660 -63
- package/dist/needle-engine.js +579 -566
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{vendor-vHLk8sXu.js → vendor-CAcsI0eU.js} +116 -115
- package/dist/{vendor-CntUvmJu.umd.cjs → vendor-CEM38hLE.umd.cjs} +2 -2
- package/dist/{vendor-DPbfJJ4d.min.js → vendor-HRlxIBga.min.js} +2 -2
- package/lib/engine/api.d.ts +2 -0
- package/lib/engine/api.js +2 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/engine_addressables.js +5 -1
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_animation.d.ts +14 -7
- package/lib/engine/engine_animation.js +49 -9
- package/lib/engine/engine_animation.js.map +1 -1
- package/lib/engine/engine_components.js +33 -4
- package/lib/engine/engine_components.js.map +1 -1
- package/lib/engine/engine_context.d.ts +7 -2
- package/lib/engine/engine_context.js +10 -2
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_gameobject.d.ts +4 -0
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_init.js +4 -0
- package/lib/engine/engine_init.js.map +1 -1
- package/lib/engine/engine_input.js +4 -1
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_materialpropertyblock.js +0 -19
- package/lib/engine/engine_materialpropertyblock.js.map +1 -1
- package/lib/engine/engine_networking.d.ts +11 -8
- package/lib/engine/engine_networking.js +43 -26
- package/lib/engine/engine_networking.js.map +1 -1
- package/lib/engine/engine_networking_instantiate.d.ts +100 -5
- package/lib/engine/engine_networking_instantiate.js +150 -16
- package/lib/engine/engine_networking_instantiate.js.map +1 -1
- package/lib/engine/engine_networking_prefabs.d.ts +59 -0
- package/lib/engine/engine_networking_prefabs.js +67 -0
- package/lib/engine/engine_networking_prefabs.js.map +1 -0
- package/lib/engine/engine_physics_rapier.d.ts +3 -0
- package/lib/engine/engine_physics_rapier.js +13 -9
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_utils.js +2 -2
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/postprocessing/api.d.ts +2 -0
- package/lib/engine/postprocessing/api.js +2 -0
- package/lib/engine/postprocessing/api.js.map +1 -0
- package/lib/engine/postprocessing/index.d.ts +2 -0
- package/lib/engine/postprocessing/index.js +2 -0
- package/lib/engine/postprocessing/index.js.map +1 -0
- package/lib/engine/postprocessing/postprocessing.d.ts +83 -0
- package/lib/engine/postprocessing/postprocessing.js +280 -0
- package/lib/engine/postprocessing/postprocessing.js.map +1 -0
- package/lib/engine/postprocessing/types.d.ts +39 -0
- package/lib/engine/postprocessing/types.js +2 -0
- package/lib/engine/postprocessing/types.js.map +1 -0
- package/lib/engine/webcomponents/WebXRButtons.js +17 -3
- package/lib/engine/webcomponents/WebXRButtons.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.d.ts +2 -0
- package/lib/engine/xr/NeedleXRSession.js +47 -14
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine/xr/events.d.ts +30 -3
- package/lib/engine/xr/events.js +38 -0
- package/lib/engine/xr/events.js.map +1 -1
- package/lib/engine/xr/init.d.ts +4 -0
- package/lib/engine/xr/init.js +43 -0
- package/lib/engine/xr/init.js.map +1 -0
- package/lib/engine-components/AnimationUtils.d.ts +4 -1
- package/lib/engine-components/AnimationUtils.js +7 -19
- package/lib/engine-components/AnimationUtils.js.map +1 -1
- package/lib/engine-components/AnimatorController.d.ts +135 -2
- package/lib/engine-components/AnimatorController.js +216 -13
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/SeeThrough.d.ts +0 -2
- package/lib/engine-components/SeeThrough.js +0 -89
- package/lib/engine-components/SeeThrough.js.map +1 -1
- package/lib/engine-components/SyncedRoom.d.ts +4 -0
- package/lib/engine-components/SyncedRoom.js +23 -8
- package/lib/engine-components/SyncedRoom.js.map +1 -1
- package/lib/engine-components/SyncedTransform.js +5 -5
- package/lib/engine-components/SyncedTransform.js.map +1 -1
- package/lib/engine-components/Voip.d.ts +46 -0
- package/lib/engine-components/Voip.js +126 -2
- package/lib/engine-components/Voip.js.map +1 -1
- package/lib/engine-components/api.d.ts +1 -0
- package/lib/engine-components/api.js +1 -0
- package/lib/engine-components/api.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +1 -0
- package/lib/engine-components/codegen/components.js +1 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/Tonemapping.d.ts +5 -2
- package/lib/engine-components/postprocessing/Effects/Tonemapping.js +11 -18
- package/lib/engine-components/postprocessing/Effects/Tonemapping.js.map +1 -1
- package/lib/engine-components/postprocessing/PostProcessingEffect.d.ts +3 -4
- package/lib/engine-components/postprocessing/PostProcessingEffect.js +6 -15
- package/lib/engine-components/postprocessing/PostProcessingEffect.js.map +1 -1
- package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +2 -1
- package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
- package/lib/engine-components/postprocessing/Volume.d.ts +18 -11
- package/lib/engine-components/postprocessing/Volume.js +61 -140
- package/lib/engine-components/postprocessing/Volume.js.map +1 -1
- package/lib/engine-components/postprocessing/index.d.ts +1 -0
- package/lib/engine-components/postprocessing/index.js +1 -0
- package/lib/engine-components/postprocessing/index.js.map +1 -1
- package/lib/engine-components/postprocessing/utils.d.ts +2 -0
- package/lib/engine-components/postprocessing/utils.js +2 -0
- package/lib/engine-components/postprocessing/utils.js.map +1 -1
- package/lib/engine-components/ui/Canvas.js +2 -2
- package/lib/engine-components/ui/Canvas.js.map +1 -1
- package/lib/engine-components/ui/Graphic.d.ts +3 -3
- package/lib/engine-components/ui/Graphic.js +6 -2
- package/lib/engine-components/ui/Graphic.js.map +1 -1
- package/lib/engine-components/ui/Text.d.ts +64 -11
- package/lib/engine-components/ui/Text.js +154 -45
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/engine-components/ui/index.d.ts +1 -0
- package/lib/engine-components/ui/index.js +1 -0
- package/lib/engine-components/ui/index.js.map +1 -1
- package/lib/engine-components-experimental/networking/PlayerSync.d.ts +25 -3
- package/lib/engine-components-experimental/networking/PlayerSync.js +60 -11
- package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
- package/package.json +5 -4
- package/plugins/common/logger.js +42 -19
- package/plugins/vite/ai.d.ts +11 -10
- package/plugins/vite/ai.js +305 -31
- package/plugins/vite/logger.client.js +4 -3
- package/src/engine/api.ts +3 -0
- package/src/engine/engine_addressables.ts +4 -1
- package/src/engine/engine_animation.ts +47 -9
- package/src/engine/engine_components.ts +36 -7
- package/src/engine/engine_context.ts +11 -2
- package/src/engine/engine_gameobject.ts +5 -0
- package/src/engine/engine_init.ts +4 -0
- package/src/engine/engine_input.ts +2 -1
- package/src/engine/engine_materialpropertyblock.ts +0 -19
- package/src/engine/engine_networking.ts +46 -23
- package/src/engine/engine_networking_instantiate.ts +160 -18
- package/src/engine/engine_networking_prefabs.ts +80 -0
- package/src/engine/engine_physics_rapier.ts +14 -9
- package/src/engine/engine_utils.ts +2 -2
- package/src/engine/postprocessing/api.ts +2 -0
- package/src/engine/postprocessing/index.ts +2 -0
- package/src/engine/postprocessing/postprocessing.ts +322 -0
- package/src/engine/postprocessing/types.ts +43 -0
- package/src/engine/webcomponents/WebXRButtons.ts +21 -4
- package/src/engine/xr/NeedleXRSession.ts +55 -20
- package/src/engine/xr/events.ts +44 -1
- package/src/engine/xr/init.ts +49 -0
- package/src/engine-components/AnimationUtils.ts +7 -17
- package/src/engine-components/AnimatorController.ts +288 -18
- package/src/engine-components/SeeThrough.ts +0 -116
- package/src/engine-components/SyncedRoom.ts +28 -9
- package/src/engine-components/SyncedTransform.ts +5 -5
- package/src/engine-components/Voip.ts +129 -2
- package/src/engine-components/api.ts +1 -0
- package/src/engine-components/codegen/components.ts +1 -0
- package/src/engine-components/postprocessing/Effects/Tonemapping.ts +16 -24
- package/src/engine-components/postprocessing/PostProcessingEffect.ts +9 -16
- package/src/engine-components/postprocessing/PostProcessingHandler.ts +2 -1
- package/src/engine-components/postprocessing/Volume.ts +72 -163
- package/src/engine-components/postprocessing/index.ts +1 -0
- package/src/engine-components/postprocessing/utils.ts +2 -0
- package/src/engine-components/ui/Canvas.ts +2 -2
- package/src/engine-components/ui/Graphic.ts +7 -3
- package/src/engine-components/ui/Text.ts +170 -52
- package/src/engine-components/ui/index.ts +2 -1
- package/src/engine-components-experimental/networking/PlayerSync.ts +64 -11
- package/dist/needle-engine.bundle-CNH61kLA.umd.cjs +0 -1730
- package/dist/needle-engine.bundle-Dvh1jROn.min.js +0 -1730
|
@@ -3,10 +3,10 @@ import { Application } from "../engine/engine_application.js";
|
|
|
3
3
|
import { RoomEvents } from "../engine/engine_networking.js";
|
|
4
4
|
import { disposeStream, NetworkedStreamEvents, NetworkedStreams, StreamEndedEvent, StreamReceivedEvent } from "../engine/engine_networking_streams.js"
|
|
5
5
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
6
|
-
import { DeviceUtilities, getParam } from "../engine/engine_utils.js";
|
|
7
|
-
import { delay } from "../engine/engine_utils.js";
|
|
6
|
+
import { delay, DeviceUtilities, getParam } from "../engine/engine_utils.js";
|
|
8
7
|
import { getIconElement } from "../engine/webcomponents/icons.js";
|
|
9
8
|
import { Behaviour } from "./Component.js";
|
|
9
|
+
import { EventList } from "./EventList.js";
|
|
10
10
|
|
|
11
11
|
export const noVoip = "noVoip";
|
|
12
12
|
const debugParam = getParam("debugvoip");
|
|
@@ -75,6 +75,66 @@ export class Voip extends Behaviour {
|
|
|
75
75
|
*/
|
|
76
76
|
debug: boolean = false;
|
|
77
77
|
|
|
78
|
+
private _volume: number = 1;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Volume for incoming audio streams (0 = silent, 1 = full volume).
|
|
82
|
+
* Changes apply immediately to all active incoming streams.
|
|
83
|
+
*/
|
|
84
|
+
@serializable()
|
|
85
|
+
get volume(): number { return this._volume; }
|
|
86
|
+
set volume(val: number) {
|
|
87
|
+
this._volume = val;
|
|
88
|
+
for (const audio of this._incomingStreams.values()) {
|
|
89
|
+
audio.volume = val;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get the incoming audio element for a specific user.
|
|
95
|
+
* Use this to route audio through the Web Audio API for spatial audio, effects, or analysis.
|
|
96
|
+
* @param userId The connection ID of the remote user
|
|
97
|
+
* @returns The HTMLAudioElement for this user's stream, or undefined if not connected
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* const audioEl = voip.getAudioElement(userId);
|
|
101
|
+
* if (audioEl) {
|
|
102
|
+
* const audioCtx = new AudioContext();
|
|
103
|
+
* const source = audioCtx.createMediaElementSource(audioEl);
|
|
104
|
+
* const panner = audioCtx.createPanner();
|
|
105
|
+
* source.connect(panner).connect(audioCtx.destination);
|
|
106
|
+
* }
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
getAudioElement(userId: string): HTMLAudioElement | undefined {
|
|
110
|
+
return this._incomingStreams.get(userId);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get all active incoming audio streams as a Map of userId → HTMLAudioElement.
|
|
115
|
+
* Useful for iterating over all connected voice users.
|
|
116
|
+
*/
|
|
117
|
+
get incomingStreams(): ReadonlyMap<string, HTMLAudioElement> {
|
|
118
|
+
return this._incomingStreams;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Threshold for speaking detection (0–255). When a user's audio amplitude exceeds this,
|
|
123
|
+
* they are considered "speaking". Default is 30.
|
|
124
|
+
*/
|
|
125
|
+
@serializable()
|
|
126
|
+
speakingThreshold: number = 30;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Event fired when a user's speaking state changes.
|
|
130
|
+
* Passes `{ userId: string, isSpeaking: boolean, volume: number }`.
|
|
131
|
+
*/
|
|
132
|
+
@serializable(EventList)
|
|
133
|
+
onSpeakingChanged: EventList = new EventList();
|
|
134
|
+
|
|
135
|
+
private _speakingStates = new Map<string, boolean>();
|
|
136
|
+
private _analysers = new Map<string, { analyser: AnalyserNode, data: Uint8Array, context: AudioContext }>();
|
|
137
|
+
|
|
78
138
|
private _net?: NetworkedStreams;
|
|
79
139
|
private _menubutton?: HTMLElement;
|
|
80
140
|
|
|
@@ -141,12 +201,25 @@ export class Voip extends Behaviour {
|
|
|
141
201
|
this.onEnabledChanged();
|
|
142
202
|
this.updateButton();
|
|
143
203
|
window.removeEventListener("visibilitychange", this.onVisibilityChanged);
|
|
204
|
+
// Clean up analysers
|
|
205
|
+
for (const userId of [...this._analysers.keys()]) {
|
|
206
|
+
this.cleanupAnalyser(userId);
|
|
207
|
+
}
|
|
144
208
|
}
|
|
145
209
|
|
|
146
210
|
/** @internal */
|
|
147
211
|
onDestroy(): void {
|
|
148
212
|
this._menubutton?.remove();
|
|
149
213
|
this._menubutton = undefined;
|
|
214
|
+
// Clean up all streams and analysers
|
|
215
|
+
for (const userId of [...this._analysers.keys()]) {
|
|
216
|
+
this.cleanupAnalyser(userId);
|
|
217
|
+
}
|
|
218
|
+
for (const incoming of this._incomingStreams.values()) {
|
|
219
|
+
disposeStream(incoming.srcObject as MediaStream);
|
|
220
|
+
}
|
|
221
|
+
this._incomingStreams.clear();
|
|
222
|
+
this._speakingStates.clear();
|
|
150
223
|
}
|
|
151
224
|
|
|
152
225
|
/** Set via the mic button (e.g. when the websocket connection closes and rejoins but the user was muted before we don't want to enable VOIP again automatically) */
|
|
@@ -347,10 +420,61 @@ export class Voip extends Behaviour {
|
|
|
347
420
|
disposeStream(incoming.srcObject as MediaStream);
|
|
348
421
|
}
|
|
349
422
|
this._incomingStreams.clear();
|
|
423
|
+
for (const userId of this._analysers.keys()) {
|
|
424
|
+
this.cleanupAnalyser(userId);
|
|
425
|
+
}
|
|
350
426
|
}
|
|
351
427
|
|
|
352
428
|
private _incomingStreams: Map<string, HTMLAudioElement> = new Map();
|
|
353
429
|
|
|
430
|
+
/** @internal */
|
|
431
|
+
update() {
|
|
432
|
+
// Only run speaking detection if someone is listening
|
|
433
|
+
if (!this.onSpeakingChanged || this.onSpeakingChanged.listenerCount <= 0) return;
|
|
434
|
+
|
|
435
|
+
for (const [userId, info] of this._analysers) {
|
|
436
|
+
info.analyser.getByteFrequencyData(info.data as Uint8Array<ArrayBuffer>);
|
|
437
|
+
// Average amplitude
|
|
438
|
+
let sum = 0;
|
|
439
|
+
for (let i = 0; i < info.data.length; i++) sum += info.data[i];
|
|
440
|
+
const avg = sum / info.data.length;
|
|
441
|
+
|
|
442
|
+
const wasSpeaking = this._speakingStates.get(userId) ?? false;
|
|
443
|
+
const isSpeaking = avg > this.speakingThreshold;
|
|
444
|
+
|
|
445
|
+
if (isSpeaking !== wasSpeaking) {
|
|
446
|
+
this._speakingStates.set(userId, isSpeaking);
|
|
447
|
+
this.onSpeakingChanged.invoke({ userId, isSpeaking, volume: avg / 255 });
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
private setupAnalyser(userId: string, _audioElement: HTMLAudioElement, stream: MediaStream) {
|
|
453
|
+
// Only set up if someone is listening or might listen
|
|
454
|
+
if (this._analysers.has(userId)) return;
|
|
455
|
+
try {
|
|
456
|
+
const audioCtx = new AudioContext();
|
|
457
|
+
const source = audioCtx.createMediaStreamSource(stream);
|
|
458
|
+
const analyser = audioCtx.createAnalyser();
|
|
459
|
+
analyser.fftSize = 256;
|
|
460
|
+
source.connect(analyser);
|
|
461
|
+
const data = new Uint8Array(analyser.frequencyBinCount);
|
|
462
|
+
this._analysers.set(userId, { analyser, data, context: audioCtx });
|
|
463
|
+
}
|
|
464
|
+
catch (err) {
|
|
465
|
+
if (this.debug) console.warn("VOIP: Failed to create analyser for", userId, err);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
private cleanupAnalyser(userId: string) {
|
|
470
|
+
const info = this._analysers.get(userId);
|
|
471
|
+
if (info) {
|
|
472
|
+
info.context.close();
|
|
473
|
+
this._analysers.delete(userId);
|
|
474
|
+
}
|
|
475
|
+
this._speakingStates.delete(userId);
|
|
476
|
+
}
|
|
477
|
+
|
|
354
478
|
private onReceiveStream = (evt: StreamReceivedEvent) => {
|
|
355
479
|
const userId = evt.target.userId;
|
|
356
480
|
const stream = evt.stream;
|
|
@@ -361,7 +485,9 @@ export class Voip extends Behaviour {
|
|
|
361
485
|
this._incomingStreams.set(userId, audioElement);
|
|
362
486
|
}
|
|
363
487
|
audioElement.srcObject = stream;
|
|
488
|
+
audioElement.volume = this._volume;
|
|
364
489
|
audioElement.setAttribute("autoplay", "true");
|
|
490
|
+
this.setupAnalyser(userId, audioElement, stream);
|
|
365
491
|
// for mobile we need to wait for user interaction to play audio. Auto play doesnt work on android when the page is refreshed
|
|
366
492
|
Application.registerWaitForInteraction(() => {
|
|
367
493
|
audioElement?.play().catch((err) => {
|
|
@@ -374,6 +500,7 @@ export class Voip extends Behaviour {
|
|
|
374
500
|
const existing = this._incomingStreams.get(evt.userId);
|
|
375
501
|
disposeStream(existing?.srcObject as MediaStream);
|
|
376
502
|
this._incomingStreams.delete(evt.userId);
|
|
503
|
+
this.cleanupAnalyser(evt.userId);
|
|
377
504
|
}
|
|
378
505
|
|
|
379
506
|
private onEnabledChanged = () => {
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
37
|
export * from "./codegen/components.js";
|
|
38
|
+
export { AnimatorControllerBuilder, type ConditionMode, type StateOptions, type TransitionOptions } from "./AnimatorController.js";
|
|
38
39
|
export { Collider } from "./Collider.js"; // export abstract type
|
|
39
40
|
export { Behaviour, Component, GameObject } from "./Component.js";
|
|
40
41
|
|
|
@@ -6,6 +6,7 @@ export { Animation } from "../Animation.js";
|
|
|
6
6
|
export { Keyframe } from "../AnimationCurve.js";
|
|
7
7
|
export { AnimationCurve } from "../AnimationCurve.js";
|
|
8
8
|
export { Animator } from "../Animator.js";
|
|
9
|
+
export { AnimatorControllerBuilder } from "../AnimatorController.js";
|
|
9
10
|
export { AnimatorController } from "../AnimatorController.js";
|
|
10
11
|
export { AudioListener } from "../AudioListener.js";
|
|
11
12
|
export { AudioSource } from "../AudioSource.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ToneMappingEffect as _TonemappingEffect, ToneMappingMode } from "postprocessing";
|
|
2
|
+
import type { ToneMapping } from "three";
|
|
2
3
|
|
|
3
4
|
import { MODULES } from "../../../engine/engine_modules.js";
|
|
4
5
|
import { serializable } from "../../../engine/engine_serialization.js";
|
|
5
6
|
import { nameToThreeTonemapping } from "../../../engine/engine_tonemapping.js";
|
|
6
7
|
import { getParam } from "../../../engine/engine_utils.js";
|
|
7
8
|
import { EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
|
|
8
|
-
import { findPostProcessingManager } from "../utils.js";
|
|
9
9
|
import { VolumeParameter } from "../VolumeParameter.js";
|
|
10
10
|
import { registerCustomEffectType } from "../VolumeProfile.js";
|
|
11
11
|
import { NEToneMappingMode, NEToneMappingModeNames, threeToNeedleToneMapping, threeToneMappingToEffectMode, toThreeToneMapping } from "./Tonemapping.utils.js";
|
|
@@ -14,8 +14,8 @@ const debug = getParam("debugpost");
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* [ToneMappingEffect](https://engine.needle.tools/docs/api/ToneMappingEffect) adjusts the brightness and contrast of the rendered scene to map high dynamic range (HDR) colors to a displayable range.
|
|
18
|
-
* This effect is essential for achieving realistic lighting and color representation in 3D scenes, as it helps to preserve details in both bright and dark areas.
|
|
17
|
+
* [ToneMappingEffect](https://engine.needle.tools/docs/api/ToneMappingEffect) adjusts the brightness and contrast of the rendered scene to map high dynamic range (HDR) colors to a displayable range.
|
|
18
|
+
* This effect is essential for achieving realistic lighting and color representation in 3D scenes, as it helps to preserve details in both bright and dark areas.
|
|
19
19
|
* Various tonemapping algorithms can be applied to achieve different visual styles and effects.
|
|
20
20
|
* @summary Tonemapping Post-Processing Effect
|
|
21
21
|
* @category Effects
|
|
@@ -46,18 +46,23 @@ export class ToneMappingEffect extends PostProcessingEffect {
|
|
|
46
46
|
|
|
47
47
|
get isToneMapping() { return true; }
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
/** The three.js ToneMapping enum value resolved from the current mode */
|
|
50
|
+
get threeToneMapping(): ToneMapping {
|
|
51
|
+
if (this.mode.isInitialized && this.mode.overrideState)
|
|
52
|
+
return toThreeToneMapping(this.mode.value);
|
|
53
|
+
return this.context.renderer.toneMapping as ToneMapping;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The exposure value to apply */
|
|
57
|
+
get toneMappingExposure(): number {
|
|
58
|
+
if (this.exposure.overrideState && this.exposure.value !== undefined)
|
|
59
|
+
return Math.max(0.0, this.exposure.value);
|
|
60
|
+
return this.context.renderer.toneMappingExposure;
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
private _tonemappingEffect: _TonemappingEffect | null = null;
|
|
58
64
|
onCreateEffect(): EffectProviderResult | undefined {
|
|
59
65
|
|
|
60
|
-
|
|
61
66
|
// ensure the effect tonemapping value is initialized
|
|
62
67
|
if (this.mode.isInitialized == false) {
|
|
63
68
|
const mode = threeToNeedleToneMapping(this.context.renderer.toneMapping);
|
|
@@ -90,19 +95,6 @@ export class ToneMappingEffect extends PostProcessingEffect {
|
|
|
90
95
|
return tonemapping;
|
|
91
96
|
}
|
|
92
97
|
|
|
93
|
-
|
|
94
|
-
onBeforeRender(): void {
|
|
95
|
-
if (this._tonemappingEffect && this.postprocessingContext?.handler.getEffectIsActive(this._tonemappingEffect)) {
|
|
96
|
-
if (this.mode.overrideState)
|
|
97
|
-
this.context.renderer.toneMapping = toThreeToneMapping(this.mode.value);
|
|
98
|
-
if (this.exposure.overrideState && this.exposure.value !== undefined) {
|
|
99
|
-
const newValue = Math.max(0.0, this.exposure.value);
|
|
100
|
-
this.context.renderer.toneMappingExposure = newValue;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
98
|
}
|
|
107
99
|
|
|
108
|
-
registerCustomEffectType("Tonemapping", ToneMappingEffect);
|
|
100
|
+
registerCustomEffectType("Tonemapping", ToneMappingEffect);
|
|
@@ -3,9 +3,10 @@ import type { Effect, Pass } from "postprocessing";
|
|
|
3
3
|
import type { EditorModification, IEditorModification } from "../../engine/engine_editor-sync.js";
|
|
4
4
|
import { serializable } from "../../engine/engine_serialization.js";
|
|
5
5
|
import { getParam } from "../../engine/engine_utils.js";
|
|
6
|
+
import type { PostProcessing } from "../../engine/postprocessing/index.js";
|
|
7
|
+
import type { IPostProcessingEffect } from "../../engine/postprocessing/types.js";
|
|
6
8
|
import { Component } from "../Component.js";
|
|
7
9
|
import type { PostProcessingHandler } from "./PostProcessingHandler.js";
|
|
8
|
-
import { getPostProcessingManager, IPostProcessingManager } from "./utils.js";
|
|
9
10
|
import { VolumeParameter } from "./VolumeParameter.js";
|
|
10
11
|
|
|
11
12
|
const debug = getParam("debugpost");
|
|
@@ -50,8 +51,9 @@ export interface IEffectProvider {
|
|
|
50
51
|
*
|
|
51
52
|
* @category Effects
|
|
52
53
|
* @group Components
|
|
54
|
+
* @see {@link PostProcessing} for core Needle Engine postprocessing control, also accessible via `context.postprocessing`
|
|
53
55
|
*/
|
|
54
|
-
export abstract class PostProcessingEffect extends Component implements IEffectProvider, IEditorModification {
|
|
56
|
+
export abstract class PostProcessingEffect extends Component implements IPostProcessingEffect, IEffectProvider, IEditorModification {
|
|
55
57
|
|
|
56
58
|
get isPostProcessingEffect() { return true; }
|
|
57
59
|
|
|
@@ -101,31 +103,22 @@ export abstract class PostProcessingEffect extends Component implements IEffectP
|
|
|
101
103
|
@serializable()
|
|
102
104
|
active: boolean = true;
|
|
103
105
|
|
|
104
|
-
private _manager: IPostProcessingManager | null = null;
|
|
105
|
-
|
|
106
106
|
onEnable(): void {
|
|
107
107
|
super.onEnable();
|
|
108
108
|
if (debug) console.warn("Enable", this.constructor.name + (!this.__internalDidAwakeAndStart ? " (awake)" : ""));
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
this.
|
|
109
|
+
// Ensure active is synced with the component's enabled state
|
|
110
|
+
this.active = true;
|
|
111
|
+
// Register directly with the core postprocessing stack
|
|
112
|
+
this.context.postprocessing.addEffect(this);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
onDisable(): void {
|
|
116
116
|
super.onDisable();
|
|
117
117
|
if (debug) console.warn("Disable", this.constructor.name);
|
|
118
|
-
this.
|
|
118
|
+
this.context.postprocessing.removeEffect(this);
|
|
119
119
|
this.active = false;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
protected onEffectEnabled(manager?: IPostProcessingManager) {
|
|
123
|
-
if (manager && manager.isPostProcessingManager === true) this._manager = manager;
|
|
124
|
-
else if (!this._manager) this._manager = getPostProcessingManager(this);
|
|
125
|
-
this._manager!.addEffect(this);
|
|
126
|
-
this._manager!.dirty = true;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
122
|
/** override to initialize bindings on parameters */
|
|
130
123
|
init() { }
|
|
131
124
|
|
|
@@ -8,6 +8,7 @@ import { Context } from "../../engine/engine_setup.js";
|
|
|
8
8
|
import { Graphics } from "../../engine/engine_three_utils.js";
|
|
9
9
|
import { Constructor } from "../../engine/engine_types.js";
|
|
10
10
|
import { getParam } from "../../engine/engine_utils.js";
|
|
11
|
+
import type { IPostProcessingHandler } from "../../engine/postprocessing/types.js";
|
|
11
12
|
import { Camera } from "../Camera.js";
|
|
12
13
|
import { threeToneMappingToEffectMode } from "./Effects/Tonemapping.utils.js";
|
|
13
14
|
import { PostProcessingEffect, PostProcessingEffectContext } from "./PostProcessingEffect.js";
|
|
@@ -26,7 +27,7 @@ const previousToneMapping = Symbol("needle:previous-tone-mapping");
|
|
|
26
27
|
/**
|
|
27
28
|
* [PostProcessingHandler](https://engine.needle.tools/docs/api/PostProcessingHandler) Is responsible for applying post processing effects to the scene. It is internally used by the {@link Volume} component
|
|
28
29
|
*/
|
|
29
|
-
export class PostProcessingHandler {
|
|
30
|
+
export class PostProcessingHandler implements IPostProcessingHandler {
|
|
30
31
|
|
|
31
32
|
private _composer: EffectComposer | null = null;
|
|
32
33
|
private _lastVolumeComponents?: PostProcessingEffect[];
|