@@ -4,6 +4,7 @@
|
|
4
4
|
// We dont want to export everything in the extensions
|
5
5
|
export * from "./js-extensions/RGBAColor";
|
6
6
|
export * from "./js-extensions/Object3D";
|
7
|
+
export * from "./XRFlag"
|
7
8
|
|
8
9
|
export * from "./export"
|
9
10
|
export * from "./postprocessing"
|
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
export * from "./extensions
|
2
|
+
export * from "./extensions"
|
3
3
|
export * from "./engine_addressables";
|
4
4
|
export * from "./engine_application"
|
5
5
|
export * from "./engine_assetdatabase"
|
@@ -27,11 +27,13 @@
|
|
27
27
|
export * from "./engine_playerview"
|
28
28
|
export * from "./engine_physics"
|
29
29
|
export * from "./engine_physics.types"
|
30
|
+
export * from "./engine_scenelighting"
|
30
31
|
export * from "./engine_input";
|
31
32
|
export * from "./engine_math";
|
32
33
|
export * from "./js-extensions";
|
33
34
|
export * from "./engine_scenetools";
|
34
35
|
export * from "./engine_serialization";
|
36
|
+
export { type ISerializable } from "./engine_serialization_core";
|
35
37
|
export * from "./engine_texture";
|
36
38
|
export * from "./engine_three_utils";
|
37
39
|
export * from "./engine_time";
|
@@ -470,7 +470,13 @@
|
|
470
470
|
|
471
471
|
/** @internal */
|
472
472
|
__internalEnable(): boolean {
|
473
|
-
|
473
|
+
// Don't change enable before awake
|
474
|
+
// But a user can change enable during awake
|
475
|
+
if (!this.__didAwake) return false;
|
476
|
+
if (this.__didEnable) {
|
477
|
+
this.__isEnabled = true;
|
478
|
+
return false;
|
479
|
+
}
|
474
480
|
// console.trace("INTERNAL ENABLE");
|
475
481
|
this.__didEnable = true;
|
476
482
|
this.onEnable();
|
@@ -480,7 +486,13 @@
|
|
480
486
|
|
481
487
|
/** @internal */
|
482
488
|
__internalDisable() {
|
483
|
-
|
489
|
+
// Don't change enable before awake
|
490
|
+
// But a user can change enable during awake
|
491
|
+
if (!this.__didAwake) return;
|
492
|
+
if (!this.__didEnable) {
|
493
|
+
this.__isEnabled = false;
|
494
|
+
return;
|
495
|
+
}
|
484
496
|
this.__didEnable = false;
|
485
497
|
this.onDisable();
|
486
498
|
this.__isEnabled = false;
|
@@ -496,7 +508,7 @@
|
|
496
508
|
|
497
509
|
|
498
510
|
get enabled(): boolean {
|
499
|
-
return this.__isEnabled
|
511
|
+
return typeof this.__isEnabled === "boolean" ? this.__isEnabled : true; // if it has no enabled field it is always enabled
|
500
512
|
}
|
501
513
|
set enabled(val: boolean) {
|
502
514
|
// when called from animationclip we receive numbers
|
@@ -18,7 +18,7 @@
|
|
18
18
|
import { logHierarchy } from './engine_three_utils';
|
19
19
|
|
20
20
|
import * as Stats from 'three/examples/jsm/libs/stats.module';
|
21
|
-
import { RendererData } from './
|
21
|
+
import { RendererData as SceneLighting } from './engine_scenelighting';
|
22
22
|
import { Addressables } from './engine_addressables';
|
23
23
|
import { Application } from './engine_application';
|
24
24
|
import { LightDataRegistry, ILightDataRegistry } from './engine_lightdata';
|
@@ -225,7 +225,9 @@
|
|
225
225
|
*/
|
226
226
|
assets: AssetDatabase;
|
227
227
|
mainLight: ILight | null = null;
|
228
|
-
|
228
|
+
/** @deprecated Use sceneLighting */
|
229
|
+
get rendererData() { return this.sceneLighting }
|
230
|
+
sceneLighting: SceneLighting;
|
229
231
|
addressables: Addressables;
|
230
232
|
lightmaps: ILightDataRegistry;
|
231
233
|
players: PlayerViewManager;
|
@@ -278,7 +280,7 @@
|
|
278
280
|
this.physics = new Physics(this);
|
279
281
|
this.connection = new NetworkConnection(this);
|
280
282
|
this.assets = new AssetDatabase();
|
281
|
-
this.
|
283
|
+
this.sceneLighting = new SceneLighting(this);
|
282
284
|
this.addressables = new Addressables(this);
|
283
285
|
this.lightmaps = new LightDataRegistry(this);
|
284
286
|
this.players = new PlayerViewManager(this);
|
@@ -176,7 +176,6 @@
|
|
176
176
|
this._loadingElement = existing || document.createElement("div");
|
177
177
|
|
178
178
|
const loadingStyle: LoadingStyleOption = this._element.getAttribute("loading-style") as LoadingStyleOption;
|
179
|
-
console.log(loadingStyle);
|
180
179
|
|
181
180
|
const hasLicense = hasProLicense();
|
182
181
|
if (!existing) {
|
@@ -267,8 +267,10 @@
|
|
267
267
|
if (activeInHierarchy) {
|
268
268
|
if (comp.enabled) {
|
269
269
|
utils.safeInvoke(comp.__internalAwake.bind(comp));
|
270
|
-
comp
|
271
|
-
|
270
|
+
if (comp.enabled) {
|
271
|
+
comp["__didEnable"] = true;
|
272
|
+
comp.onEnable();
|
273
|
+
}
|
272
274
|
}
|
273
275
|
}
|
274
276
|
else {
|
@@ -1,236 +0,0 @@
|
|
1
|
-
import { Vector4, EquirectangularReflectionMapping, sRGBEncoding, WebGLCubeRenderTarget, Texture, LightProbe, Color, SphericalHarmonics3 } from "three";
|
2
|
-
import { LightProbeGenerator } from "three/examples/jsm/lights/LightProbeGenerator.js"
|
3
|
-
import { Context } from "./engine_setup";
|
4
|
-
import { SceneLightSettings } from "./extensions/NEEDLE_lighting_settings";
|
5
|
-
import { createFlatTexture, createTrilightTexture } from "./engine_shaders";
|
6
|
-
import { getParam } from "./engine_utils";
|
7
|
-
import { SourceIdentifier } from "./engine_types";
|
8
|
-
|
9
|
-
const debug = getParam("debugenvlight");
|
10
|
-
|
11
|
-
|
12
|
-
export declare type SphericalHarmonicsData = {
|
13
|
-
array: number[],
|
14
|
-
texture: WebGLCubeRenderTarget | Texture,
|
15
|
-
lightProbe?: LightProbe
|
16
|
-
}
|
17
|
-
|
18
|
-
export enum AmbientMode {
|
19
|
-
Skybox = 0,
|
20
|
-
Trilight = 1,
|
21
|
-
Flat = 3,
|
22
|
-
Custom = 4,
|
23
|
-
}
|
24
|
-
|
25
|
-
export enum DefaultReflectionMode {
|
26
|
-
Skybox = 0,
|
27
|
-
Custom = 1,
|
28
|
-
}
|
29
|
-
|
30
|
-
export class RendererData {
|
31
|
-
|
32
|
-
private context: Context;
|
33
|
-
|
34
|
-
constructor(context: Context) {
|
35
|
-
this.context = context;
|
36
|
-
this.context.pre_update_callbacks.push(this.preUpdate.bind(this))
|
37
|
-
}
|
38
|
-
|
39
|
-
private _currentReflectionId?: SourceIdentifier;
|
40
|
-
private sceneLightSettings?: Map<SourceIdentifier, SceneLightSettings>;
|
41
|
-
|
42
|
-
private preUpdate() {
|
43
|
-
const time = this.context.time;
|
44
|
-
this._timevec4.x = time.time;
|
45
|
-
this._timevec4.y = Math.sin(time.time);
|
46
|
-
this._timevec4.z = Math.cos(time.time);
|
47
|
-
this._timevec4.w = time.deltaTime;
|
48
|
-
}
|
49
|
-
|
50
|
-
private _timevec4: Vector4 = new Vector4();
|
51
|
-
get timeVec4(): Vector4 {
|
52
|
-
return this._timevec4;
|
53
|
-
}
|
54
|
-
|
55
|
-
get environmentIntensity(): number {
|
56
|
-
if (!this.sceneLightSettings) return 1;
|
57
|
-
if (!this._currentReflectionId) return 1;
|
58
|
-
const settings = this.sceneLightSettings.get(this._currentReflectionId);
|
59
|
-
if(settings)
|
60
|
-
return settings.ambientIntensity;// * Math.PI * .5;
|
61
|
-
return 1;
|
62
|
-
}
|
63
|
-
|
64
|
-
registerSceneLightSettings(sceneLightSettings: SceneLightSettings) {
|
65
|
-
const sourceId = sceneLightSettings.sourceId;
|
66
|
-
if(!sourceId){
|
67
|
-
console.error("Missing source id for scene light settings, can not register:", sceneLightSettings);
|
68
|
-
return;
|
69
|
-
}
|
70
|
-
if (debug) console.log("Register lighting settings", sceneLightSettings?.sourceId, sceneLightSettings);
|
71
|
-
if (!this.sceneLightSettings) this.sceneLightSettings = new Map();
|
72
|
-
this.sceneLightSettings.set(sourceId, sceneLightSettings);
|
73
|
-
}
|
74
|
-
|
75
|
-
registerReflection(sourceId: SourceIdentifier, reflectionTexture: Texture) {
|
76
|
-
if (debug) console.log("Register reflection", sourceId, reflectionTexture);
|
77
|
-
const h = new LightData(this.context, reflectionTexture, 1);
|
78
|
-
this._lighting[sourceId] = h;
|
79
|
-
}
|
80
|
-
|
81
|
-
getReflection(sourceId: SourceIdentifier): LightData | null | undefined {
|
82
|
-
return this._lighting[sourceId];
|
83
|
-
}
|
84
|
-
|
85
|
-
enableReflection(sourceId: SourceIdentifier) {
|
86
|
-
const previousId = this._currentReflectionId;
|
87
|
-
this._currentReflectionId = sourceId;
|
88
|
-
const settings = this.sceneLightSettings?.get(sourceId);
|
89
|
-
|
90
|
-
if (debug) {
|
91
|
-
console.log("Enable reflection", sourceId, settings ? AmbientMode[settings.ambientMode] : "Unknown ambient mode");
|
92
|
-
}
|
93
|
-
|
94
|
-
switch (settings?.ambientMode) {
|
95
|
-
case AmbientMode.Skybox:
|
96
|
-
case AmbientMode.Custom:
|
97
|
-
// only set environment reflection when ambient mode is skybox or custom
|
98
|
-
const existing = this.getReflection(sourceId);
|
99
|
-
if (existing && existing.Source) {
|
100
|
-
if (debug) console.log("Setting environment reflection", existing.Source);
|
101
|
-
const scene = this.context.scene;
|
102
|
-
const tex = existing.Source;
|
103
|
-
tex.encoding = sRGBEncoding;
|
104
|
-
tex.mapping = EquirectangularReflectionMapping;
|
105
|
-
scene.environment = tex;
|
106
|
-
return;
|
107
|
-
}
|
108
|
-
else if (debug) console.warn("Could not find reflection for source", sourceId);
|
109
|
-
break;
|
110
|
-
}
|
111
|
-
|
112
|
-
if (settings?.environmentReflectionSource === DefaultReflectionMode.Custom) {
|
113
|
-
switch (settings?.ambientMode) {
|
114
|
-
case AmbientMode.Trilight:
|
115
|
-
if (settings.ambientTrilight) {
|
116
|
-
const colors = settings.ambientTrilight;
|
117
|
-
const tex = createTrilightTexture(colors[0], colors[1], colors[2], 64, 64);
|
118
|
-
tex.encoding = sRGBEncoding;
|
119
|
-
tex.mapping = EquirectangularReflectionMapping;
|
120
|
-
this.context.scene.environment = tex;
|
121
|
-
}
|
122
|
-
else console.error("Missing ambient trilight", settings.sourceId);
|
123
|
-
return;
|
124
|
-
case AmbientMode.Flat:
|
125
|
-
if (settings.ambientLight) {
|
126
|
-
const tex = createFlatTexture(settings.ambientLight, 64);
|
127
|
-
tex.encoding = sRGBEncoding;
|
128
|
-
tex.mapping = EquirectangularReflectionMapping;
|
129
|
-
this.context.scene.environment = tex;
|
130
|
-
}
|
131
|
-
else console.error("Missing ambientlight", settings.sourceId);
|
132
|
-
return;
|
133
|
-
default:
|
134
|
-
return;
|
135
|
-
}
|
136
|
-
}
|
137
|
-
}
|
138
|
-
|
139
|
-
disableReflection(sourceId?: SourceIdentifier) {
|
140
|
-
if (sourceId && sourceId !== this._currentReflectionId) return;
|
141
|
-
const scene = this.context.scene;
|
142
|
-
scene.environment = null;
|
143
|
-
}
|
144
|
-
|
145
|
-
async getSceneLightingData(sourceId: SourceIdentifier): Promise<SphericalHarmonicsData> {
|
146
|
-
if (debug)
|
147
|
-
console.log("GET SCENE LIGHT DATA", sourceId);
|
148
|
-
|
149
|
-
// const existing = this.getReflection(sourceId);
|
150
|
-
// const sh = existing?.getSphericalHarmonicsArray(this.sceneLightSettings?.ambientIntensity ?? 1);
|
151
|
-
// if (sh) {
|
152
|
-
// console.log("HAS EXISTING", sh, existing);
|
153
|
-
// return sh;
|
154
|
-
// }
|
155
|
-
|
156
|
-
// fallback
|
157
|
-
if (this._waitPromise) return this._waitPromise;
|
158
|
-
this._waitPromise = new Promise((res, _rej) => {
|
159
|
-
let interval = setInterval(async () => {
|
160
|
-
const ex = this.getReflection(sourceId);
|
161
|
-
if (ex) {
|
162
|
-
clearInterval(interval);
|
163
|
-
res(ex.getSphericalHarmonicsArray(this.environmentIntensity ?? 1)!);
|
164
|
-
}
|
165
|
-
}, 10);
|
166
|
-
});
|
167
|
-
return this._waitPromise;
|
168
|
-
}
|
169
|
-
|
170
|
-
private _waitPromise?: Promise<SphericalHarmonicsData>;
|
171
|
-
private _lighting: { [sourceId: SourceIdentifier]: LightData } = {};
|
172
|
-
|
173
|
-
}
|
174
|
-
|
175
|
-
export class LightData {
|
176
|
-
|
177
|
-
get Source(): Texture { return this._source; }
|
178
|
-
get Array(): number[] | undefined { return this._sphericalHarmonicsArray; }
|
179
|
-
|
180
|
-
private _context: Context;
|
181
|
-
private _source: Texture;
|
182
|
-
private _sphericalHarmonics: SphericalHarmonics3 | null = null;
|
183
|
-
private _sphericalHarmonicsArray?: number[];
|
184
|
-
private _ambientScale: number = 1;
|
185
|
-
private _lightProbe?: LightProbe;
|
186
|
-
|
187
|
-
constructor(context: Context, tex: Texture, ambientScale: number = 1) {
|
188
|
-
this._context = context;
|
189
|
-
this._source = tex;
|
190
|
-
this._ambientScale = ambientScale;
|
191
|
-
tex.mapping = EquirectangularReflectionMapping;
|
192
|
-
tex.encoding = sRGBEncoding;
|
193
|
-
}
|
194
|
-
|
195
|
-
getSphericalHarmonicsArray(intensityFactor: number = 1): SphericalHarmonicsData | null {
|
196
|
-
if (this._sphericalHarmonicsArray?.length && this._source) {
|
197
|
-
return { array: this._sphericalHarmonicsArray, texture: this._source, lightProbe: this._lightProbe };
|
198
|
-
}
|
199
|
-
|
200
|
-
try {
|
201
|
-
const reflection = this._source;
|
202
|
-
let rt: WebGLCubeRenderTarget | null = null;
|
203
|
-
if (reflection) {
|
204
|
-
if (debug) console.log("GENERATING LIGHT PROBE", reflection, this.Source);
|
205
|
-
const size = Math.min(reflection.image.width, 512);
|
206
|
-
const target = new WebGLCubeRenderTarget(size);
|
207
|
-
rt = target.fromEquirectangularTexture(this._context.renderer, reflection);
|
208
|
-
this._source = rt.texture;
|
209
|
-
}
|
210
|
-
|
211
|
-
this._sphericalHarmonicsArray = [];
|
212
|
-
if (rt) {
|
213
|
-
const sampledProbe = LightProbeGenerator.fromCubeRenderTarget(this._context.renderer, rt);
|
214
|
-
this._lightProbe = sampledProbe;
|
215
|
-
const lightFactor = (this._ambientScale * (intensityFactor * intensityFactor * Math.PI * .5)) - 1;
|
216
|
-
// console.log(intensityFactor, lightFactor);
|
217
|
-
this._sphericalHarmonics = sampledProbe.sh;
|
218
|
-
this._sphericalHarmonicsArray = this._sphericalHarmonics.toArray();
|
219
|
-
if (this._sphericalHarmonicsArray) {
|
220
|
-
const factor = ((intensityFactor) / (Math.PI * .5));
|
221
|
-
for (let i = 0; i < this._sphericalHarmonicsArray.length; i++) {
|
222
|
-
this._sphericalHarmonicsArray[i] *= factor;
|
223
|
-
}
|
224
|
-
sampledProbe.sh.scale(lightFactor);
|
225
|
-
if (this._source)
|
226
|
-
return { array: this._sphericalHarmonicsArray, texture: this._source, lightProbe: sampledProbe };
|
227
|
-
}
|
228
|
-
}
|
229
|
-
}
|
230
|
-
catch (err) {
|
231
|
-
console.error(err);
|
232
|
-
}
|
233
|
-
|
234
|
-
return null;
|
235
|
-
}
|
236
|
-
}
|
@@ -3,7 +3,7 @@
|
|
3
3
|
import { AnimationClip, Material, Mesh, Object3D, Texture } from "three";
|
4
4
|
import { Context } from "./engine_setup";
|
5
5
|
import { isPersistentAsset } from "./extensions/NEEDLE_persistent_assets";
|
6
|
-
import { SourceIdentifier } from "./engine_types";
|
6
|
+
import { ConstructorConcrete, SourceIdentifier } from "./engine_types";
|
7
7
|
import { debugExtension } from "../engine/engine_default_parameters";
|
8
8
|
import { LogType, addLog } from "./debug/debug_overlay";
|
9
9
|
import { isLocalNetwork } from "./engine_networking_utils";
|
@@ -12,7 +12,6 @@
|
|
12
12
|
const debug = getParam("debugserializer");
|
13
13
|
|
14
14
|
|
15
|
-
export type Constructor<T> = { new(...args: any[]): T };
|
16
15
|
export declare type NodeToObjectMap = { [nodeId: string]: Object3D };
|
17
16
|
export declare type ObjectToNodeMap = { [uuid: string]: number };
|
18
17
|
|
@@ -125,7 +124,7 @@
|
|
125
124
|
// }
|
126
125
|
// }
|
127
126
|
|
128
|
-
constructor(type:
|
127
|
+
constructor(type: ConstructorConcrete<any> | ConstructorConcrete<any>[]) {
|
129
128
|
if (Array.isArray(type)) {
|
130
129
|
for (const key of type)
|
131
130
|
helper.register(key.name, this);
|
@@ -141,7 +140,7 @@
|
|
141
140
|
|
142
141
|
|
143
142
|
export interface ITypeInformation {
|
144
|
-
type?:
|
143
|
+
type?: ConstructorConcrete<any>;
|
145
144
|
}
|
146
145
|
|
147
146
|
/** holds information if a field was undefined before serialization. This gives us info if we might want to warn the user about missing attributes */
|
@@ -182,7 +181,7 @@
|
|
182
181
|
objectToNode?: ObjectToNodeMap;
|
183
182
|
context?: Context;
|
184
183
|
path?: string;
|
185
|
-
type?:
|
184
|
+
type?: ConstructorConcrete<any>;
|
186
185
|
/** holds information if a field was undefined before serialization. This gives us info if we might want to warn the user about missing attributes */
|
187
186
|
implementationInformation?: ImplementationInformation;
|
188
187
|
|
@@ -193,7 +192,7 @@
|
|
193
192
|
|
194
193
|
|
195
194
|
export interface ISerializable {
|
196
|
-
$serializedTypes?: { [key: string]:
|
195
|
+
$serializedTypes?: { [key: string]: ConstructorConcrete<any> | ITypeInformation | null };
|
197
196
|
// onDeserialize?(context: SerializationContext): void;
|
198
197
|
// example:
|
199
198
|
/* $serializedTypes : {
|
@@ -337,7 +336,7 @@
|
|
337
336
|
}
|
338
337
|
// it can also just contain a constructor
|
339
338
|
else {
|
340
|
-
const constructor = typeInfoOrConstructor as
|
339
|
+
const constructor = typeInfoOrConstructor as ConstructorConcrete<any>;
|
341
340
|
return deserializeObjectWithType(data, constructor, context, undefined, obj[key]);
|
342
341
|
}
|
343
342
|
}
|
@@ -460,7 +459,7 @@
|
|
460
459
|
serializer?: ITypeSerializer
|
461
460
|
}
|
462
461
|
|
463
|
-
function deserializeObjectWithType(data: any, typeOrConstructor:
|
462
|
+
function deserializeObjectWithType(data: any, typeOrConstructor: ConstructorConcrete<any>, context: SerializationContext, typeContext?: TypeDeserializeReference, currentValue?: any): any {
|
464
463
|
|
465
464
|
// e.g. @serializable((data) => { })
|
466
465
|
let typeIsFunction = typeof typeOrConstructor === "function" && (typeOrConstructor.prototype === undefined);
|
@@ -1,3 +1,4 @@
|
|
1
1
|
export * from "./WebXR";
|
2
2
|
export * from "./WebXRPlaneTracking";
|
3
|
+
export * from "./WebXRImageTracking";
|
3
4
|
export * from "./WebXRController";
|
@@ -2,11 +2,12 @@
|
|
2
2
|
import { GLTF, GLTFLoaderPlugin, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader";
|
3
3
|
import { SourceIdentifier } from "../engine_types";
|
4
4
|
import { Behaviour, GameObject } from "../../engine-components/Component";
|
5
|
-
import { AmbientMode, DefaultReflectionMode } from "../
|
5
|
+
import { AmbientMode, DefaultReflectionMode } from "../engine_scenelighting";
|
6
6
|
import { LightmapType } from "./NEEDLE_lightmaps";
|
7
7
|
import { getParam } from "../engine_utils";
|
8
8
|
import { Context } from "../engine_setup";
|
9
9
|
import { LightProbe } from "three";
|
10
|
+
import { ContextEvent, ContextRegistry } from "../engine_context_registry";
|
10
11
|
|
11
12
|
export const EXTENSION_NAME = "NEEDLE_lighting_settings";
|
12
13
|
const debug = getParam("debugenvlight");
|
@@ -42,7 +43,7 @@
|
|
42
43
|
const ext: LightingSettings = extensions[EXTENSION_NAME];
|
43
44
|
if (ext) {
|
44
45
|
if (debug)
|
45
|
-
console.log("
|
46
|
+
console.log("Loaded \"" + this.name + "\", src: \"" + this.sourceId + "\"", ext);
|
46
47
|
let settings: SceneLightSettings | undefined = undefined;
|
47
48
|
// If the result scene has only one child we add the LightingSettingsComponent to that child
|
48
49
|
if (_result.scene.children.length === 1) {
|
@@ -50,10 +51,9 @@
|
|
50
51
|
settings = GameObject.addNewComponent(_result.scene.children[0], SceneLightSettings, false);
|
51
52
|
}
|
52
53
|
// if the scene already has multiple children we add it as a new object
|
53
|
-
else
|
54
|
-
{
|
54
|
+
else {
|
55
55
|
const lightSettings = new Object3D();
|
56
|
-
lightSettings.name = "
|
56
|
+
lightSettings.name = "LightSettings " + this.sourceId;
|
57
57
|
_result.scene.add(lightSettings);
|
58
58
|
settings = GameObject.addNewComponent(lightSettings, SceneLightSettings, false);
|
59
59
|
}
|
@@ -64,7 +64,6 @@
|
|
64
64
|
settings.ambientTrilight = ext.ambientTrilight.map(c => new Color().fromArray(c));
|
65
65
|
settings.ambientMode = ext.ambientMode;
|
66
66
|
settings.environmentReflectionSource = ext.environmentReflectionSource;
|
67
|
-
if (this.context) this.context.rendererData.registerSceneLightSettings(settings);
|
68
67
|
}
|
69
68
|
}
|
70
69
|
return null;
|
@@ -72,6 +71,12 @@
|
|
72
71
|
|
73
72
|
}
|
74
73
|
|
74
|
+
ContextRegistry.registerCallback(ContextEvent.ContextCreated, e => {
|
75
|
+
const ctx = e.context as Context;
|
76
|
+
const lightingSettings = GameObject.findObjectOfType(SceneLightSettings, ctx as Context);
|
77
|
+
if (lightingSettings?.sourceId) ctx.sceneLighting.enable(lightingSettings.sourceId);
|
78
|
+
})
|
79
|
+
|
75
80
|
// exists once per gltf scene root (if it contains reflection)
|
76
81
|
// when enabled it does currently automatically set the reflection
|
77
82
|
// this might not be desireable
|
@@ -85,6 +90,7 @@
|
|
85
90
|
|
86
91
|
private _hasReflection: boolean = false;
|
87
92
|
private _ambientLightObj?: AmbientLight;
|
93
|
+
private _hemisphereLightObj?: HemisphereLight;
|
88
94
|
// used when skybox is used to support ambient intensity for "non custom shaders"
|
89
95
|
private _lightProbeObj?: LightProbe;
|
90
96
|
|
@@ -94,11 +100,15 @@
|
|
94
100
|
const tex = this.context.lightmaps.tryGet(this.sourceId, type, 0);
|
95
101
|
this._hasReflection = tex !== null && tex !== undefined;
|
96
102
|
if (tex)
|
97
|
-
this.context.
|
103
|
+
this.context.sceneLighting.internalRegisterReflection(this.sourceId, tex);
|
98
104
|
}
|
99
105
|
|
106
|
+
this.enabled = false;
|
107
|
+
this.context.sceneLighting.internalRegisterSceneLightSettings(this);
|
108
|
+
|
100
109
|
if (debug) {
|
101
110
|
window.addEventListener("keydown", evt => {
|
111
|
+
if(this.destroyed) return;
|
102
112
|
switch (evt.key) {
|
103
113
|
case "l":
|
104
114
|
this.enabled = !this.enabled;
|
@@ -108,17 +118,17 @@
|
|
108
118
|
}
|
109
119
|
}
|
110
120
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
}
|
121
|
+
onDestroy(): void {
|
122
|
+
this.context.sceneLighting.internalUnregisterSceneLightSettings(this);
|
123
|
+
}
|
124
|
+
|
125
|
+
onEnable(): void {
|
126
|
+
if (debug) console.warn("💡🟡 >>> Enable lighting", this.sourceId, this);
|
127
|
+
|
119
128
|
if (this.ambientMode == AmbientMode.Flat) {
|
120
129
|
if (this.ambientLight && !this._ambientLightObj) {
|
121
130
|
this._ambientLightObj = new AmbientLight(this.ambientLight, this.ambientIntensity);
|
131
|
+
if (debug) console.log("Created ambient light", this.sourceId, this._ambientLightObj)
|
122
132
|
}
|
123
133
|
if (this._ambientLightObj) {
|
124
134
|
this.gameObject.add(this._ambientLightObj)
|
@@ -129,23 +139,24 @@
|
|
129
139
|
if (this.ambientTrilight) {
|
130
140
|
const ground = this.ambientTrilight[0];
|
131
141
|
const sky = this.ambientTrilight[this.ambientTrilight.length - 1];
|
132
|
-
|
133
|
-
this.gameObject.add(
|
142
|
+
this._hemisphereLightObj = new HemisphereLight(sky, ground, this.ambientIntensity);
|
143
|
+
this.gameObject.add(this._hemisphereLightObj)
|
134
144
|
}
|
135
145
|
}
|
136
146
|
else {
|
137
147
|
if (this._ambientLightObj)
|
138
148
|
this._ambientLightObj.removeFromParent();
|
149
|
+
if (this._hemisphereLightObj)
|
150
|
+
this._hemisphereLightObj.removeFromParent();
|
139
151
|
|
140
152
|
// create light probe object
|
141
153
|
if (!this._lightProbeObj) {
|
142
154
|
if (this.sourceId) {
|
143
|
-
this.context.
|
155
|
+
this.context.sceneLighting.internalGetSceneLightingData(this.sourceId).then(data => {
|
144
156
|
if (!data) return;
|
145
157
|
this._lightProbeObj = data.lightProbe;
|
146
158
|
if (this.enabled && !this.destroyed && this._lightProbeObj) {
|
147
|
-
if (debug)
|
148
|
-
console.log("Add", this.sourceId, data);
|
159
|
+
if (debug) console.log("Add", this.sourceId, data);
|
149
160
|
this.gameObject.add(this._lightProbeObj);
|
150
161
|
}
|
151
162
|
});
|
@@ -159,16 +170,20 @@
|
|
159
170
|
}
|
160
171
|
|
161
172
|
if (this.sourceId)
|
162
|
-
this.context.
|
173
|
+
this.context.sceneLighting.internalEnableReflection(this.sourceId);
|
163
174
|
|
164
175
|
}
|
165
176
|
|
166
177
|
onDisable() {
|
167
178
|
if (debug)
|
168
|
-
console.
|
169
|
-
if (this._lightProbeObj)
|
170
|
-
|
179
|
+
console.warn("💡⚫ <<< Disable lighting:", this.sourceId, this);
|
180
|
+
if (this._lightProbeObj)
|
181
|
+
this._lightProbeObj.removeFromParent();
|
182
|
+
if (this._ambientLightObj)
|
183
|
+
this._ambientLightObj.removeFromParent();
|
184
|
+
if (this._hemisphereLightObj)
|
185
|
+
this._hemisphereLightObj.removeFromParent();
|
171
186
|
if (this.sourceId)
|
172
|
-
this.context.
|
187
|
+
this.context.sceneLighting.internalDisableReflection(this.sourceId);
|
173
188
|
}
|
174
189
|
}
|
@@ -118,7 +118,7 @@
|
|
118
118
|
console.error("Missing context");
|
119
119
|
return;
|
120
120
|
}
|
121
|
-
const data = await context.
|
121
|
+
const data = await context.sceneLighting.internalGetSceneLightingData(this.identifier);
|
122
122
|
if (!data || !data.array) {
|
123
123
|
console.warn("Missing lighting data for custom shader, getSceneLightingData did not return anything");
|
124
124
|
return;
|
@@ -210,10 +210,10 @@
|
|
210
210
|
// this._lastFrame = context.time.frame;
|
211
211
|
|
212
212
|
if (this.uniforms["_TimeParameters"]) {
|
213
|
-
this.uniforms["_TimeParameters"].value = context.
|
213
|
+
this.uniforms["_TimeParameters"].value = context.sceneLighting.timeVec4;
|
214
214
|
}
|
215
215
|
else if (this.uniforms["_Time"]) {
|
216
|
-
this.uniforms["_Time"].value = context.
|
216
|
+
this.uniforms["_Time"].value = context.sceneLighting.timeVec4;
|
217
217
|
}
|
218
218
|
|
219
219
|
const mainLight: ILight | null = context.mainLight;
|
@@ -5,7 +5,7 @@
|
|
5
5
|
import { showBalloonWarning } from "../../engine/debug/debug";
|
6
6
|
import { Camera } from "../Camera";
|
7
7
|
import { PostProcessingEffect } from "./PostProcessingEffect";
|
8
|
-
import { Constructor } from "../../engine/
|
8
|
+
import { Constructor } from "../../engine/engine_types";
|
9
9
|
|
10
10
|
const debug = getParam("debugpost");
|
11
11
|
|
@@ -617,7 +617,7 @@
|
|
617
617
|
|
618
618
|
if (material.envMapIntensity !== undefined) {
|
619
619
|
const factor = this.hasLightmap ? Math.PI : 1;
|
620
|
-
material.envMapIntensity = Math.max(0, this.context.
|
620
|
+
material.envMapIntensity = Math.max(0, this.context.sceneLighting.environmentIntensity / factor);
|
621
621
|
}
|
622
622
|
// if (this._reflectionProbe?.texture) {
|
623
623
|
// material.envMap = this._reflectionProbe.texture;
|
@@ -1,5 +1,4 @@
|
|
1
1
|
import { AssetReference } from "../engine/engine_addressables";
|
2
|
-
import { NeedleEngineHTMLElement } from "../engine/engine_element";
|
3
2
|
import { InputEvents } from "../engine/engine_input";
|
4
3
|
import { isLocalNetwork } from "../engine/engine_networking_utils";
|
5
4
|
import { ContextEvent, ContextRegistry } from "../engine/engine_context_registry";
|
@@ -11,9 +10,14 @@
|
|
11
10
|
|
12
11
|
const ENGINE_ELEMENT_SCENE_ATTRIBUTE_NAME = "scene";
|
13
12
|
|
14
|
-
ContextRegistry.registerCallback(ContextEvent.ContextRegistered, _ => {
|
15
|
-
|
16
|
-
|
13
|
+
ContextRegistry.registerCallback(ContextEvent.ContextRegistered, async _ => {
|
14
|
+
// We need to defer import to not get issues with circular dependencies
|
15
|
+
import("../engine/engine_element").then(res => {
|
16
|
+
const webcomponent = res.NeedleEngineHTMLElement;
|
17
|
+
if(debug) console.log("SceneSwitcher: registering scene attribute", webcomponent.observedAttributes);
|
18
|
+
if (!webcomponent.observedAttributes.includes(ENGINE_ELEMENT_SCENE_ATTRIBUTE_NAME))
|
19
|
+
webcomponent.observedAttributes.push(ENGINE_ELEMENT_SCENE_ATTRIBUTE_NAME);
|
20
|
+
});
|
17
21
|
});
|
18
22
|
|
19
23
|
const couldNotLoadScenePromise = Promise.resolve(false);
|
@@ -42,7 +46,11 @@
|
|
42
46
|
@serializable()
|
43
47
|
useSwipe: boolean = true;
|
44
48
|
|
49
|
+
/** when enabled will automatically apply the environment scene lights */
|
50
|
+
@serializable()
|
51
|
+
useSceneLighting: boolean = true;
|
45
52
|
|
53
|
+
|
46
54
|
private _currentIndex: number = -1;
|
47
55
|
private _currentScene: AssetReference | undefined = undefined;
|
48
56
|
private _engineElementOverserver: MutationObserver | undefined = undefined;
|
@@ -191,6 +199,8 @@
|
|
191
199
|
}
|
192
200
|
if (this._currentIndex === index) {
|
193
201
|
GameObject.add(scene.asset, this.gameObject);
|
202
|
+
if (this.useSceneLighting)
|
203
|
+
this.context.sceneLighting.enable(scene)
|
194
204
|
// save the loaded scene as an url parameter
|
195
205
|
if (this.queryParameterName?.length)
|
196
206
|
setParamWithoutReload(this.queryParameterName, index.toString(), this.useHistory);
|
@@ -17,7 +17,7 @@
|
|
17
17
|
set overrideState(val: boolean) {
|
18
18
|
if (this._active === val) return;
|
19
19
|
this._active = val;
|
20
|
-
const value = val ? this.
|
20
|
+
const value = val ? this._valueRaw : this._defaultValue;
|
21
21
|
this.processValue(value, true);
|
22
22
|
}
|
23
23
|
private _active: boolean = true;
|
@@ -26,13 +26,13 @@
|
|
26
26
|
|
27
27
|
@serializable()
|
28
28
|
get value() {
|
29
|
-
return this.
|
29
|
+
return this._valueRaw;
|
30
30
|
}
|
31
31
|
set value(val: any) {
|
32
32
|
this.processValue(val, false);
|
33
33
|
}
|
34
34
|
private _value: any;
|
35
|
-
private
|
35
|
+
private _valueRaw?: any;
|
36
36
|
|
37
37
|
|
38
38
|
set defaultValue(val: any) {
|
@@ -43,7 +43,7 @@
|
|
43
43
|
|
44
44
|
/** enforce the value to be set and onValueChanged to be called if assigned */
|
45
45
|
__init() {
|
46
|
-
this.processValue(this.
|
46
|
+
this.processValue(this._valueRaw, true);
|
47
47
|
}
|
48
48
|
|
49
49
|
/** called to modify a changing value before it is saved */
|
@@ -65,9 +65,10 @@
|
|
65
65
|
// with the value that is expected to received when the parameter is disabled)
|
66
66
|
this._value = this._defaultValue;
|
67
67
|
val = this._defaultValue;
|
68
|
+
this._valueRaw = val;
|
68
69
|
}
|
69
70
|
else {
|
70
|
-
this.
|
71
|
+
this._valueRaw = val;
|
71
72
|
if (this._active && this.valueProcessor)
|
72
73
|
val = this.valueProcessor(val);
|
73
74
|
this._value = val;
|
@@ -80,7 +81,7 @@
|
|
80
81
|
|
81
82
|
private testIfValueChanged(newValue: any): boolean {
|
82
83
|
|
83
|
-
if (this.
|
84
|
+
if (this._valueRaw === newValue)
|
84
85
|
return false;
|
85
86
|
|
86
87
|
// TODO: may need checks for colors or vectors (check by xyz,rgb because they might come in as anonymous objects via editor modifications)
|
@@ -0,0 +1,307 @@
|
|
1
|
+
import { Vector4, EquirectangularReflectionMapping, sRGBEncoding, WebGLCubeRenderTarget, Texture, LightProbe, Color, SphericalHarmonics3 } from "three";
|
2
|
+
import { LightProbeGenerator } from "three/examples/jsm/lights/LightProbeGenerator.js"
|
3
|
+
import { Context } from "./engine_setup";
|
4
|
+
import { SceneLightSettings } from "./extensions/NEEDLE_lighting_settings";
|
5
|
+
import { createFlatTexture, createTrilightTexture } from "./engine_shaders";
|
6
|
+
import { getParam } from "./engine_utils";
|
7
|
+
import { SourceIdentifier } from "./engine_types";
|
8
|
+
import { AssetReference } from "./engine_addressables";
|
9
|
+
|
10
|
+
const debug = getParam("debugenvlight");
|
11
|
+
|
12
|
+
|
13
|
+
export declare type SphericalHarmonicsData = {
|
14
|
+
array: number[],
|
15
|
+
texture: WebGLCubeRenderTarget | Texture,
|
16
|
+
lightProbe?: LightProbe
|
17
|
+
}
|
18
|
+
|
19
|
+
export enum AmbientMode {
|
20
|
+
Skybox = 0,
|
21
|
+
Trilight = 1,
|
22
|
+
Flat = 3,
|
23
|
+
Custom = 4,
|
24
|
+
}
|
25
|
+
|
26
|
+
export enum DefaultReflectionMode {
|
27
|
+
Skybox = 0,
|
28
|
+
Custom = 1,
|
29
|
+
}
|
30
|
+
|
31
|
+
export class RendererData {
|
32
|
+
|
33
|
+
private context: Context;
|
34
|
+
|
35
|
+
constructor(context: Context) {
|
36
|
+
this.context = context;
|
37
|
+
this.context.pre_update_callbacks.push(this.preUpdate.bind(this))
|
38
|
+
}
|
39
|
+
|
40
|
+
private _currentLightSettingsId?: SourceIdentifier;
|
41
|
+
private _sceneLightSettings?: Map<SourceIdentifier, SceneLightSettings>;
|
42
|
+
|
43
|
+
private preUpdate() {
|
44
|
+
const time = this.context.time;
|
45
|
+
this._timevec4.x = time.time;
|
46
|
+
this._timevec4.y = Math.sin(time.time);
|
47
|
+
this._timevec4.z = Math.cos(time.time);
|
48
|
+
this._timevec4.w = time.deltaTime;
|
49
|
+
}
|
50
|
+
|
51
|
+
private _timevec4: Vector4 = new Vector4();
|
52
|
+
get timeVec4(): Vector4 {
|
53
|
+
return this._timevec4;
|
54
|
+
}
|
55
|
+
|
56
|
+
/** the current environment intensity */
|
57
|
+
get environmentIntensity(): number {
|
58
|
+
if (!this._sceneLightSettings) return 1;
|
59
|
+
if (!this._currentLightSettingsId) return 1;
|
60
|
+
const settings = this._sceneLightSettings.get(this._currentLightSettingsId);
|
61
|
+
if (settings)
|
62
|
+
return settings.ambientIntensity;// * Math.PI * .5;
|
63
|
+
return 1;
|
64
|
+
}
|
65
|
+
|
66
|
+
/** Get all currently registered scene light settings */
|
67
|
+
get sceneLightSettings() { return this._sceneLightSettings?.values() }
|
68
|
+
|
69
|
+
/** set the scene lighting from a specific scene. Will disable any previously enabled lighting settings */
|
70
|
+
enable(sourceId: SourceIdentifier | AssetReference) {
|
71
|
+
if(sourceId instanceof AssetReference)
|
72
|
+
sourceId = sourceId.uri;
|
73
|
+
const settings = this._sceneLightSettings?.get(sourceId);
|
74
|
+
if (!settings) {
|
75
|
+
return false;
|
76
|
+
}
|
77
|
+
if (debug) console.log("Enable scene light settings", sourceId, settings);
|
78
|
+
if (sourceId !== this._currentLightSettingsId && this._currentLightSettingsId) {
|
79
|
+
this.disable(this._currentLightSettingsId);
|
80
|
+
}
|
81
|
+
this._currentLightSettingsId = sourceId;
|
82
|
+
settings.enabled = true;
|
83
|
+
return true;
|
84
|
+
}
|
85
|
+
|
86
|
+
/** disable the lighting of a specific scene, will only have any effect if it is currently active */
|
87
|
+
disable(sourceId: SourceIdentifier | AssetReference) {
|
88
|
+
if(sourceId instanceof AssetReference)
|
89
|
+
sourceId = sourceId.uri;
|
90
|
+
if (sourceId === null || sourceId === undefined) return false;
|
91
|
+
const settings = this._sceneLightSettings?.get(sourceId);
|
92
|
+
if (!settings) {
|
93
|
+
return false;
|
94
|
+
}
|
95
|
+
if (debug) console.log("Disable scene light settings", sourceId, settings);
|
96
|
+
settings.enabled = false;
|
97
|
+
return true;
|
98
|
+
}
|
99
|
+
|
100
|
+
/** Disables the currently active scene lighting (if any), returns the id of the previously active lighting */
|
101
|
+
disableCurrent() : SourceIdentifier | null {
|
102
|
+
if (this._currentLightSettingsId) {
|
103
|
+
const prev = this._currentLightSettingsId;
|
104
|
+
this.disable(this._currentLightSettingsId);
|
105
|
+
return prev
|
106
|
+
}
|
107
|
+
return null;
|
108
|
+
}
|
109
|
+
|
110
|
+
|
111
|
+
/** @internal */
|
112
|
+
internalRegisterSceneLightSettings(sceneLightSettings: SceneLightSettings) {
|
113
|
+
const sourceId = sceneLightSettings.sourceId;
|
114
|
+
if (!sourceId) {
|
115
|
+
console.error("Missing source id for scene light settings, can not register:", sceneLightSettings);
|
116
|
+
return;
|
117
|
+
}
|
118
|
+
if (debug) console.log("Register " + sceneLightSettings?.sourceId + " lighting", sceneLightSettings);
|
119
|
+
if (!this._sceneLightSettings) this._sceneLightSettings = new Map();
|
120
|
+
this._sceneLightSettings.set(sourceId, sceneLightSettings);
|
121
|
+
}
|
122
|
+
|
123
|
+
/** @internal */
|
124
|
+
internalUnregisterSceneLightSettings(sceneLightSettings: SceneLightSettings) {
|
125
|
+
const sourceId = sceneLightSettings.sourceId;
|
126
|
+
if (!sourceId) {
|
127
|
+
console.error("Missing source id for scene light settings, can not unregister:", sceneLightSettings);
|
128
|
+
return;
|
129
|
+
}
|
130
|
+
if (debug) console.log("Unregister " + sceneLightSettings?.sourceId + " lighting", sceneLightSettings);
|
131
|
+
if (!this._sceneLightSettings) return;
|
132
|
+
this._sceneLightSettings.delete(sourceId);
|
133
|
+
}
|
134
|
+
|
135
|
+
/** @internal */
|
136
|
+
internalRegisterReflection(sourceId: SourceIdentifier, reflectionTexture: Texture) {
|
137
|
+
if (debug) console.log("Register reflection", sourceId, reflectionTexture);
|
138
|
+
const h = new LightData(this.context, reflectionTexture, 1);
|
139
|
+
this._lighting[sourceId] = h;
|
140
|
+
}
|
141
|
+
|
142
|
+
/** @internal */
|
143
|
+
internalGetReflection(sourceId: SourceIdentifier): LightData | null | undefined {
|
144
|
+
return this._lighting[sourceId];
|
145
|
+
}
|
146
|
+
|
147
|
+
private __currentReflectionId: SourceIdentifier | null = null;
|
148
|
+
|
149
|
+
/** @internal */
|
150
|
+
internalEnableReflection(sourceId: SourceIdentifier) {
|
151
|
+
this.__currentReflectionId = sourceId;
|
152
|
+
const settings = this._sceneLightSettings?.get(sourceId);
|
153
|
+
|
154
|
+
if (debug) {
|
155
|
+
console.log("Enable reflection", sourceId, settings ? AmbientMode[settings.ambientMode] : "Unknown ambient mode");
|
156
|
+
}
|
157
|
+
|
158
|
+
switch (settings?.ambientMode) {
|
159
|
+
case AmbientMode.Skybox:
|
160
|
+
case AmbientMode.Custom:
|
161
|
+
// only set environment reflection when ambient mode is skybox or custom
|
162
|
+
const existing = this.internalGetReflection(sourceId);
|
163
|
+
if (existing && existing.Source) {
|
164
|
+
if (debug) console.log("Setting environment reflection", existing);
|
165
|
+
const scene = this.context.scene;
|
166
|
+
const tex = existing.Source;
|
167
|
+
tex.encoding = sRGBEncoding;
|
168
|
+
tex.mapping = EquirectangularReflectionMapping;
|
169
|
+
scene.environment = tex;
|
170
|
+
return;
|
171
|
+
}
|
172
|
+
else if (debug) console.warn("Could not find reflection for source", sourceId);
|
173
|
+
break;
|
174
|
+
}
|
175
|
+
|
176
|
+
if (settings?.environmentReflectionSource === DefaultReflectionMode.Custom) {
|
177
|
+
switch (settings?.ambientMode) {
|
178
|
+
case AmbientMode.Trilight:
|
179
|
+
if (settings.ambientTrilight) {
|
180
|
+
const colors = settings.ambientTrilight;
|
181
|
+
const tex = createTrilightTexture(colors[0], colors[1], colors[2], 64, 64);
|
182
|
+
tex.encoding = sRGBEncoding;
|
183
|
+
tex.mapping = EquirectangularReflectionMapping;
|
184
|
+
this.context.scene.environment = tex;
|
185
|
+
}
|
186
|
+
else console.error("Missing ambient trilight", settings.sourceId);
|
187
|
+
return;
|
188
|
+
case AmbientMode.Flat:
|
189
|
+
if (settings.ambientLight) {
|
190
|
+
const tex = createFlatTexture(settings.ambientLight, 64);
|
191
|
+
tex.encoding = sRGBEncoding;
|
192
|
+
tex.mapping = EquirectangularReflectionMapping;
|
193
|
+
this.context.scene.environment = tex;
|
194
|
+
}
|
195
|
+
else console.error("Missing ambientlight", settings.sourceId);
|
196
|
+
return;
|
197
|
+
default:
|
198
|
+
return;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
/** @internal */
|
204
|
+
internalDisableReflection(sourceId?: SourceIdentifier) {
|
205
|
+
if (sourceId && sourceId !== this.__currentReflectionId) {
|
206
|
+
if(debug) console.log("Not disabling reflection for", sourceId, "because it is not the current light settings id", this.__currentReflectionId)
|
207
|
+
return;
|
208
|
+
}
|
209
|
+
if (debug) console.log("Disable reflection", sourceId)
|
210
|
+
const scene = this.context.scene;
|
211
|
+
scene.environment = null;
|
212
|
+
}
|
213
|
+
|
214
|
+
/** @internal */
|
215
|
+
async internalGetSceneLightingData(sourceId: SourceIdentifier): Promise<SphericalHarmonicsData> {
|
216
|
+
if (debug)
|
217
|
+
console.log("GET SCENE LIGHT DATA", sourceId);
|
218
|
+
|
219
|
+
// const existing = this.getReflection(sourceId);
|
220
|
+
// const sh = existing?.getSphericalHarmonicsArray(this.sceneLightSettings?.ambientIntensity ?? 1);
|
221
|
+
// if (sh) {
|
222
|
+
// console.log("HAS EXISTING", sh, existing);
|
223
|
+
// return sh;
|
224
|
+
// }
|
225
|
+
|
226
|
+
// fallback
|
227
|
+
if (this._waitPromise) return this._waitPromise;
|
228
|
+
this._waitPromise = new Promise((res, _rej) => {
|
229
|
+
let interval = setInterval(async () => {
|
230
|
+
const ex = this.internalGetReflection(sourceId);
|
231
|
+
if (ex) {
|
232
|
+
clearInterval(interval);
|
233
|
+
res(ex.getSphericalHarmonicsArray(this.environmentIntensity ?? 1)!);
|
234
|
+
}
|
235
|
+
}, 10);
|
236
|
+
});
|
237
|
+
return this._waitPromise;
|
238
|
+
}
|
239
|
+
|
240
|
+
private _waitPromise?: Promise<SphericalHarmonicsData>;
|
241
|
+
private _lighting: { [sourceId: SourceIdentifier]: LightData } = {};
|
242
|
+
|
243
|
+
}
|
244
|
+
|
245
|
+
export class LightData {
|
246
|
+
|
247
|
+
get Source(): Texture { return this._source; }
|
248
|
+
get Array(): number[] | undefined { return this._sphericalHarmonicsArray; }
|
249
|
+
|
250
|
+
private _context: Context;
|
251
|
+
private _source: Texture;
|
252
|
+
private _sphericalHarmonics: SphericalHarmonics3 | null = null;
|
253
|
+
private _sphericalHarmonicsArray?: number[];
|
254
|
+
private _ambientScale: number = 1;
|
255
|
+
private _lightProbe?: LightProbe;
|
256
|
+
|
257
|
+
constructor(context: Context, tex: Texture, ambientScale: number = 1) {
|
258
|
+
this._context = context;
|
259
|
+
this._source = tex;
|
260
|
+
this._ambientScale = ambientScale;
|
261
|
+
tex.mapping = EquirectangularReflectionMapping;
|
262
|
+
tex.encoding = sRGBEncoding;
|
263
|
+
}
|
264
|
+
|
265
|
+
getSphericalHarmonicsArray(intensityFactor: number = 1): SphericalHarmonicsData | null {
|
266
|
+
if (this._sphericalHarmonicsArray?.length && this._source) {
|
267
|
+
return { array: this._sphericalHarmonicsArray, texture: this._source, lightProbe: this._lightProbe };
|
268
|
+
}
|
269
|
+
|
270
|
+
try {
|
271
|
+
const reflection = this._source;
|
272
|
+
let rt: WebGLCubeRenderTarget | null = null;
|
273
|
+
if (reflection) {
|
274
|
+
if (debug) console.log("GENERATING LIGHT PROBE", reflection, this.Source);
|
275
|
+
const size = Math.min(reflection.image.width, 512);
|
276
|
+
const target = new WebGLCubeRenderTarget(size);
|
277
|
+
rt = target.fromEquirectangularTexture(this._context.renderer, reflection);
|
278
|
+
// Not sure why we did assign the resulting texture here again but this causes rendering to break when toggling env lighting (e.g. on website) because this texture will then be set as the scene.environment
|
279
|
+
// this._source = rt.texture;
|
280
|
+
}
|
281
|
+
|
282
|
+
this._sphericalHarmonicsArray = [];
|
283
|
+
if (rt) {
|
284
|
+
const sampledProbe = LightProbeGenerator.fromCubeRenderTarget(this._context.renderer, rt);
|
285
|
+
this._lightProbe = sampledProbe;
|
286
|
+
const lightFactor = (this._ambientScale * (intensityFactor * intensityFactor * Math.PI * .5)) - 1;
|
287
|
+
// console.log(intensityFactor, lightFactor);
|
288
|
+
this._sphericalHarmonics = sampledProbe.sh;
|
289
|
+
this._sphericalHarmonicsArray = this._sphericalHarmonics.toArray();
|
290
|
+
if (this._sphericalHarmonicsArray) {
|
291
|
+
const factor = ((intensityFactor) / (Math.PI * .5));
|
292
|
+
for (let i = 0; i < this._sphericalHarmonicsArray.length; i++) {
|
293
|
+
this._sphericalHarmonicsArray[i] *= factor;
|
294
|
+
}
|
295
|
+
sampledProbe.sh.scale(lightFactor);
|
296
|
+
if (this._source)
|
297
|
+
return { array: this._sphericalHarmonicsArray, texture: this._source, lightProbe: sampledProbe };
|
298
|
+
}
|
299
|
+
}
|
300
|
+
}
|
301
|
+
catch (err) {
|
302
|
+
console.error(err);
|
303
|
+
}
|
304
|
+
|
305
|
+
return null;
|
306
|
+
}
|
307
|
+
}
|
@@ -0,0 +1,5 @@
|
|
1
|
+
export * from "./extensions"
|
2
|
+
export * from "./NEEDLE_animator_controller_model"
|
3
|
+
export * from "./NEEDLE_progressive"
|
4
|
+
export { CustomShader } from "./NEEDLE_techniques_webgl"
|
5
|
+
export { SceneLightSettings } from "./NEEDLE_lighting_settings"
|