@@ -3,4 +3,5 @@
|
|
3
3
|
export { ButtonsFactory } from "./buttons.js"
|
4
4
|
export * from "./icons.js"
|
5
5
|
export { type NeedleMenuPostMessageModel } from "./needle menu/needle-menu.js"
|
6
|
-
export { NeedleButtonElement } from "./needle-button.js"
|
6
|
+
export { NeedleButtonElement } from "./needle-button.js"
|
7
|
+
export { WebXRButtonFactory } from "./WebXRButtons.js"
|
@@ -62,6 +62,7 @@
|
|
62
62
|
export { DragControls } from "../DragControls.js";
|
63
63
|
export { DropListener } from "../DropListener.js";
|
64
64
|
export { Duplicatable } from "../Duplicatable.js";
|
65
|
+
export { EffectWrapper } from "../postprocessing/Effects/EffectWrapper.js";
|
65
66
|
export { EmissionModule } from "../ParticleSystemModules.js";
|
66
67
|
export { EmphasizeOnClick } from "../export/usdz/extensions/behavior/BehaviourComponents.js";
|
67
68
|
export { EventList } from "../EventList.js";
|
@@ -147,6 +148,7 @@
|
|
147
148
|
export { SetActiveOnClick } from "../export/usdz/extensions/behavior/BehaviourComponents.js";
|
148
149
|
export { ShadowCatcher } from "../ShadowCatcher.js";
|
149
150
|
export { ShapeModule } from "../ParticleSystemModules.js";
|
151
|
+
export { SharpeningEffect } from "../postprocessing/Effects/Sharpening.js";
|
150
152
|
export { SignalAsset } from "../timeline/SignalAsset.js";
|
151
153
|
export { SignalReceiver } from "../timeline/SignalAsset.js";
|
152
154
|
export { SignalReceiverEvent } from "../timeline/SignalAsset.js";
|
@@ -204,7 +206,6 @@
|
|
204
206
|
export { WebARCameraBackground } from "../webxr/WebARCameraBackground.js";
|
205
207
|
export { WebARSessionRoot } from "../webxr/WebARSessionRoot.js";
|
206
208
|
export { WebXR } from "../webxr/WebXR.js";
|
207
|
-
export { WebXRButtonFactory } from "../../engine/webcomponents/WebXRButtons.js";
|
208
209
|
export { WebXRImageTracking } from "../webxr/WebXRImageTracking.js";
|
209
210
|
export { WebXRImageTrackingModel } from "../webxr/WebXRImageTracking.js";
|
210
211
|
export { WebXRPlaneTracking } from "../webxr/WebXRPlaneTracking.js";
|
@@ -1,11 +1,10 @@
|
|
1
1
|
import { EffectComposer, RenderPass } from "postprocessing";
|
2
2
|
import {
|
3
|
+
AgXToneMapping,
|
3
4
|
BufferGeometry, Cache, Camera, Clock, Color, DepthTexture, Group,
|
4
5
|
Material, NearestFilter, NoToneMapping, Object3D, PCFSoftShadowMap,
|
5
6
|
PerspectiveCamera, RGBAFormat, Scene, SRGBColorSpace,
|
6
|
-
Texture, WebGLRenderer, type WebGLRendererParameters, WebGLRenderTarget, type WebXRArrayCamera
|
7
|
-
AgXToneMapping
|
8
|
-
} from 'three';
|
7
|
+
Texture, WebGLRenderer, type WebGLRendererParameters, WebGLRenderTarget, type WebXRArrayCamera} from 'three';
|
9
8
|
import * as Stats from 'three/examples/jsm/libs/stats.module.js';
|
10
9
|
|
11
10
|
import { isDevEnvironment, LogType, showBalloonError, showBalloonMessage, showBalloonWarning } from './debug/index.js';
|
@@ -29,12 +28,12 @@
|
|
29
28
|
import { RendererData as SceneLighting } from './engine_scenelighting.js';
|
30
29
|
import { logHierarchy } from './engine_three_utils.js';
|
31
30
|
import { Time } from './engine_time.js';
|
31
|
+
import { patchTonemapping } from './engine_tonemapping.js';
|
32
32
|
import type { CoroutineData, GLTF, ICamera, IComponent, IContext, ILight, LoadedGLTF, Vec2 } from "./engine_types.js";
|
33
33
|
import * as utils from "./engine_utils.js";
|
34
34
|
import { delay, getParam } from './engine_utils.js';
|
35
35
|
import type { INeedleXRSessionEventReceiver, NeedleXRSession } from './engine_xr.js';
|
36
36
|
import { NeedleMenu } from './webcomponents/needle menu/needle-menu.js';
|
37
|
-
import { patchTonemapping } from './engine_tonemapping.js';
|
38
37
|
|
39
38
|
|
40
39
|
const debug = utils.getParam("debugcontext");
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { ShaderChunk } from "three";
|
2
|
+
|
2
3
|
import type { Context } from "./engine_setup";
|
3
4
|
|
4
5
|
let patchedTonemapping = false;
|
@@ -25,7 +25,7 @@
|
|
25
25
|
// We want to save on requests so we first check the file extension if there's any
|
26
26
|
// In some scenarios we might not have one (e.g. if we're dealing with blob: files or if the URL doesn't contain the filename)
|
27
27
|
// In that case we need to check the header
|
28
|
-
|
28
|
+
const _url = url;
|
29
29
|
// if (!_url.startsWith("http") && !url.startsWith("blob:")) {
|
30
30
|
// // _url = "file:" + url;
|
31
31
|
// }
|
@@ -1,4 +1,5 @@
|
|
1
1
|
export * from "./PostProcessingEffect.js";
|
2
2
|
export * from "./PostProcessingHandler.js"
|
3
|
+
export { PostProcessingManager } from "./Volume.js"
|
3
4
|
export * from "./VolumeParameter.js"
|
4
|
-
export * from "./VolumeProfile.js";
|
5
|
+
export * from "./VolumeProfile.js";
|
@@ -1,5 +1,5 @@
|
|
1
|
+
import { iconFontUrl, loadFont } from "./fonts.js";
|
1
2
|
import { WebXRButtonFactory } from "./WebXRButtons.js";
|
2
|
-
import { iconFontUrl, loadFont } from "./fonts.js";
|
3
3
|
|
4
4
|
const htmlTagName = "needle-button";
|
5
5
|
|
@@ -127,10 +127,16 @@
|
|
127
127
|
existing.add();
|
128
128
|
return;
|
129
129
|
}
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
130
|
+
if (node instanceof HTMLButtonElement) {
|
131
|
+
const spatialButton = this.createButton(menu, node);
|
132
|
+
this.htmlButtonsMap.set(node, spatialButton);
|
133
|
+
spatialButton.add();
|
134
|
+
}
|
135
|
+
else if (node instanceof HTMLSlotElement) {
|
136
|
+
node.assignedNodes().forEach((node) => {
|
137
|
+
this.createButtonFromHTMLNode(node);
|
138
|
+
});
|
139
|
+
}
|
134
140
|
}
|
135
141
|
|
136
142
|
private readonly _menuTarget: Object3D = new Object3D();
|
@@ -5,6 +5,7 @@
|
|
5
5
|
import type { ISerializable, SerializationContext } from "../../engine/engine_serialization_core.js";
|
6
6
|
import { getParam } from "../../engine/engine_utils.js";
|
7
7
|
import { Component } from "../Component.js";
|
8
|
+
import { getPostProcessingManager,IPostProcessingManager } from "./utils.js";
|
8
9
|
import { VolumeParameter } from "./VolumeParameter.js";
|
9
10
|
|
10
11
|
const debug = getParam("debugpost");
|
@@ -44,29 +45,41 @@
|
|
44
45
|
*/
|
45
46
|
export abstract class PostProcessingEffect extends Component implements IEffectProvider, ISerializable, IEditorModification {
|
46
47
|
|
48
|
+
get isPostProcessingEffect() { return true; }
|
49
|
+
|
47
50
|
constructor(params: any = undefined) {
|
48
51
|
super();
|
52
|
+
this.ensureVolumeParameters();
|
49
53
|
if (params) {
|
50
|
-
this.ensureVolumeParameters();
|
51
54
|
for (const key of Object.keys(params)) {
|
52
55
|
const value = params[key];
|
53
56
|
const param = this[key];
|
54
57
|
if (param instanceof VolumeParameter) {
|
55
58
|
param.value = value;
|
56
59
|
}
|
60
|
+
// allow assigning values to properties that are not VolumeParameters
|
61
|
+
// this is useful when effects are created in code
|
62
|
+
else if(param !== undefined){
|
63
|
+
this[key] = value;
|
64
|
+
}
|
57
65
|
}
|
58
66
|
}
|
59
67
|
}
|
60
68
|
|
61
69
|
abstract get typeName(): string;
|
62
70
|
|
71
|
+
private _manager: IPostProcessingManager | null = null;
|
72
|
+
|
63
73
|
onEnable(): void {
|
74
|
+
this._manager = getPostProcessingManager(this);
|
75
|
+
this._manager?.addEffect(this);
|
64
76
|
// Dont override the serialized value by enabling (we could also just disable this component / map enabled to active)
|
65
77
|
if (this.__internalDidAwakeAndStart)
|
66
78
|
this.active = true;
|
67
79
|
}
|
68
80
|
|
69
81
|
onDisable(): void {
|
82
|
+
this._manager?.removeEffect(this);
|
70
83
|
this.active = false;
|
71
84
|
}
|
72
85
|
|
@@ -7,7 +7,9 @@
|
|
7
7
|
import type { Constructor } from "../../engine/engine_types.js";
|
8
8
|
import { getParam, isMobileDevice } from "../../engine/engine_utils.js";
|
9
9
|
import { Camera } from "../Camera.js";
|
10
|
+
import { Antialiasing } from "./Effects/Antialiasing.js";
|
10
11
|
import { ColorAdjustments } from "./Effects/ColorAdjustments.js";
|
12
|
+
import { SharpeningEffect } from "./Effects/Sharpening.js";
|
11
13
|
import { ToneMapping } from "./Effects/Tonemapping.js";
|
12
14
|
import { PostProcessingEffect } from "./PostProcessingEffect.js";
|
13
15
|
|
@@ -270,4 +272,6 @@
|
|
270
272
|
HueSaturationEffect,
|
271
273
|
BrightnessContrastEffect,
|
272
274
|
PixelationEffect,
|
275
|
+
SharpeningEffect,
|
276
|
+
Antialiasing
|
273
277
|
];
|
@@ -64,6 +64,7 @@
|
|
64
64
|
import { DragControls } from "../../engine-components/DragControls.js";
|
65
65
|
import { DropListener } from "../../engine-components/DropListener.js";
|
66
66
|
import { Duplicatable } from "../../engine-components/Duplicatable.js";
|
67
|
+
import { EffectWrapper } from "../../engine-components/postprocessing/Effects/EffectWrapper.js";
|
67
68
|
import { EmissionModule } from "../../engine-components/ParticleSystemModules.js";
|
68
69
|
import { EmphasizeOnClick } from "../../engine-components/export/usdz/extensions/behavior/BehaviourComponents.js";
|
69
70
|
import { EventList } from "../../engine-components/EventList.js";
|
@@ -152,6 +153,7 @@
|
|
152
153
|
import { SetActiveOnClick } from "../../engine-components/export/usdz/extensions/behavior/BehaviourComponents.js";
|
153
154
|
import { ShadowCatcher } from "../../engine-components/ShadowCatcher.js";
|
154
155
|
import { ShapeModule } from "../../engine-components/ParticleSystemModules.js";
|
156
|
+
import { SharpeningEffect } from "../../engine-components/postprocessing/Effects/Sharpening.js";
|
155
157
|
import { SignalAsset } from "../../engine-components/timeline/SignalAsset.js";
|
156
158
|
import { SignalReceiver } from "../../engine-components/timeline/SignalAsset.js";
|
157
159
|
import { SignalReceiverEvent } from "../../engine-components/timeline/SignalAsset.js";
|
@@ -209,7 +211,6 @@
|
|
209
211
|
import { WebARCameraBackground } from "../../engine-components/webxr/WebARCameraBackground.js";
|
210
212
|
import { WebARSessionRoot } from "../../engine-components/webxr/WebARSessionRoot.js";
|
211
213
|
import { WebXR } from "../../engine-components/webxr/WebXR.js";
|
212
|
-
import { WebXRButtonFactory } from "../webcomponents/WebXRButtons.js";
|
213
214
|
import { WebXRImageTracking } from "../../engine-components/webxr/WebXRImageTracking.js";
|
214
215
|
import { WebXRImageTrackingModel } from "../../engine-components/webxr/WebXRImageTracking.js";
|
215
216
|
import { WebXRPlaneTracking } from "../../engine-components/webxr/WebXRPlaneTracking.js";
|
@@ -284,6 +285,7 @@
|
|
284
285
|
TypeStore.add("DragControls", DragControls);
|
285
286
|
TypeStore.add("DropListener", DropListener);
|
286
287
|
TypeStore.add("Duplicatable", Duplicatable);
|
288
|
+
TypeStore.add("EffectWrapper", EffectWrapper);
|
287
289
|
TypeStore.add("EmissionModule", EmissionModule);
|
288
290
|
TypeStore.add("EmphasizeOnClick", EmphasizeOnClick);
|
289
291
|
TypeStore.add("EventList", EventList);
|
@@ -372,6 +374,7 @@
|
|
372
374
|
TypeStore.add("SetActiveOnClick", SetActiveOnClick);
|
373
375
|
TypeStore.add("ShadowCatcher", ShadowCatcher);
|
374
376
|
TypeStore.add("ShapeModule", ShapeModule);
|
377
|
+
TypeStore.add("SharpeningEffect", SharpeningEffect);
|
375
378
|
TypeStore.add("SignalAsset", SignalAsset);
|
376
379
|
TypeStore.add("SignalReceiver", SignalReceiver);
|
377
380
|
TypeStore.add("SignalReceiverEvent", SignalReceiverEvent);
|
@@ -429,7 +432,6 @@
|
|
429
432
|
TypeStore.add("WebARCameraBackground", WebARCameraBackground);
|
430
433
|
TypeStore.add("WebARSessionRoot", WebARSessionRoot);
|
431
434
|
TypeStore.add("WebXR", WebXR);
|
432
|
-
TypeStore.add("WebXRButtonFactory", WebXRButtonFactory);
|
433
435
|
TypeStore.add("WebXRImageTracking", WebXRImageTracking);
|
434
436
|
TypeStore.add("WebXRImageTrackingModel", WebXRImageTrackingModel);
|
435
437
|
TypeStore.add("WebXRPlaneTracking", WebXRPlaneTracking);
|
@@ -8,10 +8,10 @@
|
|
8
8
|
|
9
9
|
export enum TonemappingMode {
|
10
10
|
None = 0,
|
11
|
-
Neutral = 1,
|
12
|
-
ACES = 2,
|
13
|
-
AgX = 3,
|
14
|
-
KhronosNeutral = 4,
|
11
|
+
Neutral = 1, // Neutral tonemapper, close to Reinhard
|
12
|
+
ACES = 2, // ACES Filmic reference tonemapper (custom approximation)
|
13
|
+
AgX = 3, // AgX Filmic tonemapper
|
14
|
+
KhronosNeutral = 4, // PBR Neural tonemapper
|
15
15
|
}
|
16
16
|
|
17
17
|
export class ToneMapping extends PostProcessingEffect {
|
@@ -6,12 +6,12 @@
|
|
6
6
|
import { serializable } from "../../../engine/engine_serialization.js";
|
7
7
|
import { getFormattedDate, Progress } from "../../../engine/engine_time_utils.js";
|
8
8
|
import { getParam, isiOS, isMobileDevice, isSafari } from "../../../engine/engine_utils.js";
|
9
|
+
import { WebXRButtonFactory } from "../../../engine/webcomponents/WebXRButtons.js";
|
9
10
|
import { Behaviour, GameObject } from "../../Component.js";
|
10
11
|
import { Renderer } from "../../Renderer.js"
|
11
12
|
import { SpriteRenderer } from "../../SpriteRenderer.js";
|
12
13
|
import { WebARSessionRoot } from "../../webxr/WebARSessionRoot.js";
|
13
14
|
import { WebXR } from "../../webxr/WebXR.js";
|
14
|
-
import { WebXRButtonFactory } from "../../../engine/webcomponents/WebXRButtons.js";
|
15
15
|
import { XRState, XRStateFlag } from "../../webxr/XRFlag.js";
|
16
16
|
import type { IUSDExporterExtension } from "./Extension.js";
|
17
17
|
import { AnimationExtension } from "./extensions/Animation.js"
|
@@ -1,30 +1,93 @@
|
|
1
|
-
import { EffectComposer } from "postprocessing";
|
1
|
+
import { Effect, EffectComposer } from "postprocessing";
|
2
2
|
|
3
3
|
import { isDevEnvironment, showBalloonMessage } from "../../engine/debug/index.js";
|
4
4
|
import type { EditorModification, IEditorModification as IEditorModificationReceiver } from "../../engine/engine_editor-sync.js";
|
5
5
|
import { serializeable } from "../../engine/engine_serialization_decorator.js";
|
6
6
|
import { getParam } from "../../engine/engine_utils.js";
|
7
7
|
import { Behaviour } from "../Component.js";
|
8
|
+
import { EffectWrapper } from "./Effects/EffectWrapper.js";
|
8
9
|
import { PostProcessingEffect } from "./PostProcessingEffect.js";
|
9
10
|
import { PostProcessingHandler } from "./PostProcessingHandler.js";
|
11
|
+
import { IPostProcessingManager, setPostprocessingManagerType } from "./utils.js";
|
10
12
|
import { VolumeParameter } from "./VolumeParameter.js";
|
11
13
|
import { VolumeProfile } from "./VolumeProfile.js";
|
12
14
|
|
13
15
|
const debug = getParam("debugpost");
|
14
16
|
|
15
|
-
/** Handles PostProcessing effects */
|
16
|
-
export class Volume extends Behaviour implements IEditorModificationReceiver {
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
/** The Volume/PostprocessingManager component is responsible for managing post processing effects.
|
19
|
+
* Add this component to any object in your scene to enable post processing effects.
|
20
|
+
*
|
21
|
+
* @example Add bloom
|
22
|
+
* ```ts
|
23
|
+
* const volume = new Volume();
|
24
|
+
* volume.addEffect(new BloomEffect({
|
25
|
+
* intensity: 3,
|
26
|
+
* luminanceThreshold: .2
|
27
|
+
* }));
|
28
|
+
* gameObject.addComponent(volume);
|
29
|
+
* ```
|
30
|
+
*
|
31
|
+
* @example Remove bloom
|
32
|
+
* ```ts
|
33
|
+
* volume.removeEffect(bloom);
|
34
|
+
* ```
|
35
|
+
*
|
36
|
+
* @example Add pixelation
|
37
|
+
* ```ts
|
38
|
+
* const pixelation = new PixelationEffect();
|
39
|
+
* pixelation.granularity.value = 10;
|
40
|
+
* volume.addEffect(pixelation);
|
41
|
+
* ```
|
42
|
+
*/
|
43
|
+
export class Volume extends Behaviour implements IEditorModificationReceiver, IPostProcessingManager {
|
20
44
|
|
45
|
+
get isPostProcessingManager() {
|
46
|
+
return true;
|
47
|
+
}
|
48
|
+
|
21
49
|
/** Currently active postprocessing effects */
|
22
50
|
get effects() {
|
23
|
-
return this.
|
51
|
+
return this._activeEffects;
|
24
52
|
}
|
25
53
|
|
54
|
+
@serializeable(VolumeProfile)
|
55
|
+
sharedProfile?: VolumeProfile;
|
56
|
+
|
57
|
+
/**
|
58
|
+
* Add a post processing effect to the stack and schedules the effect stack to be re-created.
|
59
|
+
*/
|
60
|
+
addEffect<T extends PostProcessingEffect | Effect>(effect: T): T {
|
61
|
+
|
62
|
+
let entry = effect as PostProcessingEffect;
|
63
|
+
if (entry instanceof Effect) {
|
64
|
+
entry = new EffectWrapper(entry);
|
65
|
+
}
|
66
|
+
if (this._effects.includes(entry)) return effect;
|
67
|
+
this._effects.push(entry);
|
68
|
+
this._isDirty = true;
|
69
|
+
return effect;
|
70
|
+
}
|
71
|
+
removeEffect<T extends PostProcessingEffect | Effect>(effect: T): T {
|
72
|
+
|
73
|
+
let index = -1;
|
74
|
+
if (effect instanceof Effect) {
|
75
|
+
index = this._effects.findIndex(e => e instanceof EffectWrapper && e.effect === effect);
|
76
|
+
}
|
77
|
+
else
|
78
|
+
index = this._effects.indexOf(effect);
|
79
|
+
|
80
|
+
if (index !== -1) {
|
81
|
+
this._effects.splice(index, 1);
|
82
|
+
this._isDirty = true;
|
83
|
+
return effect;
|
84
|
+
}
|
85
|
+
return effect;
|
86
|
+
}
|
87
|
+
|
26
88
|
private _postprocessing?: PostProcessingHandler;
|
27
|
-
private
|
89
|
+
private readonly _activeEffects: PostProcessingEffect[] = [];
|
90
|
+
private readonly _effects: PostProcessingEffect[] = [];
|
28
91
|
|
29
92
|
/**
|
30
93
|
* When dirty the post processing effects will be re-applied
|
@@ -67,12 +130,12 @@
|
|
67
130
|
|
68
131
|
// Wait for the first frame to be rendered before creating because then we know we have a camera (issue 135)
|
69
132
|
if (this.context.mainCamera) {
|
70
|
-
if (
|
133
|
+
if (this._isDirty) {
|
71
134
|
this.apply();
|
72
135
|
}
|
73
136
|
}
|
74
137
|
|
75
|
-
if (this.context.composer) {
|
138
|
+
if (this.context.composer && this._postprocessing?.composer === this.context.composer) {
|
76
139
|
this.context.composer.setRenderer(this.context.renderer);
|
77
140
|
this.context.composer.setMainScene(this.context.scene);
|
78
141
|
if (this.context.mainCamera)
|
@@ -105,25 +168,25 @@
|
|
105
168
|
this._isDirty = false;
|
106
169
|
this.unapply();
|
107
170
|
|
108
|
-
this.
|
171
|
+
this._activeEffects.length = 0;
|
109
172
|
// get from profile
|
110
173
|
if (this.sharedProfile?.components) {
|
111
|
-
this.
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
if (debug && additionalComponents?.length)
|
116
|
-
console.log("Additional", additionalComponents);
|
117
|
-
if (additionalComponents) {
|
118
|
-
for (const comp of additionalComponents) {
|
119
|
-
if (comp.active) this._effects.push(comp);
|
174
|
+
const comps = this.sharedProfile.components;
|
175
|
+
for (const effect of comps) {
|
176
|
+
if (effect.active && !this._activeEffects.includes(effect))
|
177
|
+
this._activeEffects.push(effect);
|
120
178
|
}
|
121
179
|
}
|
180
|
+
// add effects registered via code
|
181
|
+
for (const effect of this._effects) {
|
182
|
+
if (effect.active && !this._activeEffects.includes(effect))
|
183
|
+
this._activeEffects.push(effect);
|
184
|
+
}
|
122
185
|
|
123
|
-
if (this.
|
186
|
+
if (this._activeEffects.length > 0) {
|
124
187
|
if (!this._postprocessing)
|
125
188
|
this._postprocessing = new PostProcessingHandler(this.context);
|
126
|
-
this._postprocessing.apply(this.
|
189
|
+
this._postprocessing.apply(this._activeEffects);
|
127
190
|
this._applyPostQueue();
|
128
191
|
}
|
129
192
|
|
@@ -153,12 +216,12 @@
|
|
153
216
|
return true;
|
154
217
|
}
|
155
218
|
|
156
|
-
if (!this.
|
219
|
+
if (!this._activeEffects?.length) return;
|
157
220
|
const path = modification.propertyName.split(".");
|
158
221
|
if (path.length === 3 || path.length === 4) {
|
159
222
|
const componentName = path[1];
|
160
223
|
const propertyName = path[2];
|
161
|
-
for (const comp of this.
|
224
|
+
for (const comp of this._activeEffects) {
|
162
225
|
if (comp.typeName?.toLowerCase() === componentName.toLowerCase()) {
|
163
226
|
|
164
227
|
if (propertyName === "active") {
|
@@ -230,3 +293,8 @@
|
|
230
293
|
|
231
294
|
/** cached VolumeParameter keys per object */
|
232
295
|
const effectVolumeProperties: Map<string, string[]> = new Map<string, string[]>();
|
296
|
+
|
297
|
+
|
298
|
+
setPostprocessingManagerType(Volume);
|
299
|
+
|
300
|
+
export { Volume as PostProcessingManager };
|
@@ -30,12 +30,24 @@
|
|
30
30
|
/** @internal */
|
31
31
|
export class VolumeProfile {
|
32
32
|
|
33
|
+
/** effects added to the volume */
|
33
34
|
@serializeable([d => resolveComponentType(d), PostProcessingEffect])
|
34
35
|
components: PostProcessingEffect[] = [];
|
35
36
|
|
36
|
-
/**
|
37
|
+
/**
|
38
|
+
* call init on all components
|
39
|
+
* @hidden
|
40
|
+
**/
|
37
41
|
init() {
|
38
42
|
this.components?.forEach(c => c.init());
|
39
43
|
}
|
44
|
+
|
45
|
+
addEffect(effect: PostProcessingEffect) {
|
46
|
+
this.components.push(effect);
|
47
|
+
}
|
48
|
+
removeEffect(effect: PostProcessingEffect) {
|
49
|
+
const idx = this.components.indexOf(effect);
|
50
|
+
if (idx >= 0) this.components.splice(idx, 1);
|
51
|
+
}
|
40
52
|
}
|
41
53
|
|
@@ -8,6 +8,7 @@
|
|
8
8
|
import { type NeedleXREventArgs, NeedleXRSession } from "../../engine/engine_xr.js";
|
9
9
|
import { ButtonsFactory } from "../../engine/webcomponents/buttons.js";
|
10
10
|
import { getIconElement } from "../../engine/webcomponents/icons.js";
|
11
|
+
import { WebXRButtonFactory } from "../../engine/webcomponents/WebXRButtons.js";
|
11
12
|
import { PlayerSync } from "../../engine-components-experimental/networking/PlayerSync.js";
|
12
13
|
import { Behaviour, GameObject } from "../Component.js";
|
13
14
|
import { USDZExporter } from "../export/usdz/USDZExporter.js";
|
@@ -17,7 +18,6 @@
|
|
17
18
|
import { XRControllerModel } from "./controllers/XRControllerModel.js";
|
18
19
|
import { XRControllerMovement } from "./controllers/XRControllerMovement.js";
|
19
20
|
import { WebARSessionRoot } from "./WebARSessionRoot.js";
|
20
|
-
import { WebXRButtonFactory } from "../../engine/webcomponents/WebXRButtons.js";
|
21
21
|
import { XRState, XRStateFlag } from "./XRFlag.js";
|
22
22
|
|
23
23
|
const debug = getParam("debugwebxr");
|
@@ -1,12 +1,12 @@
|
|
1
|
+
import { USDZExporter } from "../../engine-components/export/usdz/USDZExporter.js";
|
1
2
|
import { isDevEnvironment, showBalloonMessage } from "../debug/index.js";
|
3
|
+
import { findObjectOfType } from "../engine_components.js";
|
4
|
+
import { Context } from "../engine_setup.js";
|
2
5
|
import { isMozillaXR } from "../engine_utils.js";
|
3
6
|
import { NeedleXRSession } from "../engine_xr.js";
|
7
|
+
import { onXRSessionEnd, onXRSessionStart } from "../xr/events.js";
|
4
8
|
import { ButtonsFactory } from "./buttons.js";
|
5
9
|
import { getIconElement } from "./icons.js";
|
6
|
-
import { onXRSessionEnd, onXRSessionStart } from "../xr/events.js";
|
7
|
-
import { findObjectOfType } from "../engine_components.js";
|
8
|
-
import { USDZExporter } from "../../engine-components/export/usdz/USDZExporter.js";
|
9
|
-
import { Context } from "../engine_setup.js";
|
10
10
|
|
11
11
|
// TODO: move these buttons into their own web components so their logic is encapsulated (e.g. the CSS animation when a xr session is requested)
|
12
12
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { Effect } from "postprocessing";
|
2
|
+
|
3
|
+
import { EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
|
4
|
+
|
5
|
+
export class EffectWrapper extends PostProcessingEffect {
|
6
|
+
|
7
|
+
readonly effect: Effect;
|
8
|
+
|
9
|
+
constructor(effect: Effect) {
|
10
|
+
super();
|
11
|
+
this.effect = effect;
|
12
|
+
}
|
13
|
+
|
14
|
+
get typeName(): string {
|
15
|
+
return this.effect.constructor.name;
|
16
|
+
}
|
17
|
+
|
18
|
+
onCreateEffect(): EffectProviderResult | undefined {
|
19
|
+
return this.effect;
|
20
|
+
}
|
21
|
+
|
22
|
+
}
|
@@ -0,0 +1,102 @@
|
|
1
|
+
import { BlendFunction, Effect } from "postprocessing";
|
2
|
+
import { Uniform } from "three";
|
3
|
+
|
4
|
+
import { serializable } from "../../../engine/engine_serialization.js";
|
5
|
+
import { PostProcessingEffect } from "../PostProcessingEffect.js";
|
6
|
+
|
7
|
+
export class SharpeningEffect extends PostProcessingEffect {
|
8
|
+
|
9
|
+
get typeName() {
|
10
|
+
return "Sharpening";
|
11
|
+
}
|
12
|
+
|
13
|
+
private _effect?: _SharpeningEffect;
|
14
|
+
|
15
|
+
onCreateEffect() {
|
16
|
+
return this.effect;
|
17
|
+
}
|
18
|
+
|
19
|
+
private get effect() {
|
20
|
+
this._effect ??= new _SharpeningEffect();
|
21
|
+
return this._effect;
|
22
|
+
}
|
23
|
+
|
24
|
+
@serializable()
|
25
|
+
set amount(value: number) {
|
26
|
+
this.effect.uniforms.get("amount")!.value = value;
|
27
|
+
}
|
28
|
+
get amount() {
|
29
|
+
return this.effect.uniforms.get("amount")!.value;
|
30
|
+
}
|
31
|
+
|
32
|
+
@serializable()
|
33
|
+
set radius(value: number) {
|
34
|
+
this.effect.uniforms.get("radius")!.value = value;
|
35
|
+
}
|
36
|
+
get radius() {
|
37
|
+
return this.effect.uniforms.get("radius")!.value;
|
38
|
+
}
|
39
|
+
|
40
|
+
// @serializable()
|
41
|
+
// set threshold(value: number) {
|
42
|
+
// this.effect.uniforms.get("threshold")!.value = value;
|
43
|
+
// }
|
44
|
+
// get threshold() {
|
45
|
+
// return this.effect.uniforms.get("threshold")!.value;
|
46
|
+
// }
|
47
|
+
|
48
|
+
}
|
49
|
+
|
50
|
+
|
51
|
+
const vert = `
|
52
|
+
void mainSupport() {
|
53
|
+
vUv = uv;
|
54
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
55
|
+
}
|
56
|
+
`
|
57
|
+
|
58
|
+
const frag = `
|
59
|
+
uniform sampler2D tDiffuse;
|
60
|
+
uniform float amount;
|
61
|
+
uniform float threshold;
|
62
|
+
uniform float radius;
|
63
|
+
|
64
|
+
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
|
65
|
+
float tx = 1.0 / resolution.x;
|
66
|
+
float ty = 1.0 / resolution.y;
|
67
|
+
vec2 texelSize = vec2(tx, ty);
|
68
|
+
|
69
|
+
vec4 color = texture2D(tDiffuse, uv);
|
70
|
+
vec4 blurred = vec4(0.0);
|
71
|
+
float total = 0.0;
|
72
|
+
for (float x = -radius; x <= radius; x++) {
|
73
|
+
for (float y = -radius; y <= radius; y++) {
|
74
|
+
vec2 offset = vec2(x, y) * texelSize;
|
75
|
+
vec4 diffuse = texture2D(tDiffuse, uv + offset);
|
76
|
+
float weight = exp(-length(offset) * amount);
|
77
|
+
blurred += diffuse * weight;
|
78
|
+
total += weight;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
blurred /= total;
|
82
|
+
vec4 sharp = inputColor + (inputColor - blurred) * amount;
|
83
|
+
// float luma = dot(inputColor.rgb, vec3(0.299, 0.587, 0.114));
|
84
|
+
// float blend = smoothstep(threshold, 1.0, luma);
|
85
|
+
outputColor = sharp; //mix(inputColor, sharp, blend);
|
86
|
+
|
87
|
+
}
|
88
|
+
`
|
89
|
+
|
90
|
+
class _SharpeningEffect extends Effect {
|
91
|
+
constructor() {
|
92
|
+
super("Sharpening", frag, {
|
93
|
+
vertexShader: vert,
|
94
|
+
blendFunction: BlendFunction.NORMAL,
|
95
|
+
uniforms: new Map<string, Uniform<any>>([
|
96
|
+
["amount", new Uniform(.8)],
|
97
|
+
["radius", new Uniform(.5)],
|
98
|
+
// ["threshold", new Uniform(0)],
|
99
|
+
]),
|
100
|
+
});
|
101
|
+
}
|
102
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import { Object3D } from "three";
|
2
|
+
|
3
|
+
import { isDevEnvironment } from "../../engine/debug/index.js";
|
4
|
+
import { addComponent } from "../../engine/engine_components.js";
|
5
|
+
import { foreachComponentEnumerator } from "../../engine/engine_gameobject.js";
|
6
|
+
import { ConstructorConcrete, IComponent } from "../../engine/engine_types.js";
|
7
|
+
import { getParam } from "../../engine/engine_utils.js";
|
8
|
+
import { type PostProcessingEffect } from "./PostProcessingEffect.js";
|
9
|
+
|
10
|
+
export const debug = getParam("debugpost");
|
11
|
+
|
12
|
+
export type IPostProcessingManager = IComponent & {
|
13
|
+
get isPostProcessingManager(): boolean;
|
14
|
+
addEffect(effect: PostProcessingEffect): void;
|
15
|
+
removeEffect(effect: PostProcessingEffect): void;
|
16
|
+
}
|
17
|
+
|
18
|
+
|
19
|
+
let PostprocessingManagerType: ConstructorConcrete<IPostProcessingManager> | null = null;
|
20
|
+
|
21
|
+
export function setPostprocessingManagerType(type: ConstructorConcrete<IPostProcessingManager>) {
|
22
|
+
PostprocessingManagerType = type;
|
23
|
+
}
|
24
|
+
|
25
|
+
export function getPostProcessingManager(effect: PostProcessingEffect): IPostProcessingManager | null {
|
26
|
+
let manager: IPostProcessingManager | null = null;
|
27
|
+
let obj = effect.gameObject as Object3D | null;
|
28
|
+
while (obj) {
|
29
|
+
for (const comp of foreachComponentEnumerator(obj)) {
|
30
|
+
if ((comp as unknown as IPostProcessingManager).isPostProcessingManager === true) {
|
31
|
+
manager = comp as unknown as IPostProcessingManager;
|
32
|
+
break;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
obj = obj.parent;
|
36
|
+
}
|
37
|
+
if (!manager) {
|
38
|
+
if (PostprocessingManagerType) {
|
39
|
+
if (debug)
|
40
|
+
console.warn("Adding postprocessing manager to the scene.");
|
41
|
+
const scene = effect.scene;
|
42
|
+
manager = addComponent(scene, PostprocessingManagerType);
|
43
|
+
}
|
44
|
+
else {
|
45
|
+
if (isDevEnvironment())
|
46
|
+
console.warn("No post processing manager found");
|
47
|
+
}
|
48
|
+
}
|
49
|
+
return manager;
|
50
|
+
}
|