@playcanvas/web-components 0.1.9 → 0.1.11
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/LICENSE +1 -1
- package/README.md +38 -6
- package/dist/app.d.ts +11 -0
- package/dist/components/camera-component.d.ts +37 -0
- package/dist/components/light-component.d.ts +46 -0
- package/dist/components/sound-component.d.ts +1 -1
- package/dist/entity.d.ts +7 -0
- package/dist/fog.d.ts +28 -0
- package/dist/pwc.cjs +451 -38
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +451 -38
- package/dist/pwc.js.map +1 -1
- package/dist/pwc.min.js +1 -1
- package/dist/pwc.min.js.map +1 -1
- package/dist/pwc.mjs +452 -39
- package/dist/pwc.mjs.map +1 -1
- package/package.json +16 -15
- package/src/app.ts +180 -1
- package/src/components/camera-component.ts +92 -3
- package/src/components/light-component.ts +103 -3
- package/src/components/script-component.ts +22 -13
- package/src/entity.ts +88 -1
- package/src/fog.ts +121 -0
- package/src/material.ts +2 -2
package/src/app.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Application, FILLMODE_FILL_WINDOW, Keyboard, Mouse, RESOLUTION_AUTO } from 'playcanvas';
|
|
1
|
+
import { Application, CameraComponent, FILLMODE_FILL_WINDOW, Keyboard, Mouse, Picker, RESOLUTION_AUTO } from 'playcanvas';
|
|
2
2
|
|
|
3
3
|
import { AssetElement } from './asset';
|
|
4
4
|
import { AsyncElement } from './async-element';
|
|
@@ -27,6 +27,24 @@ class AppElement extends AsyncElement {
|
|
|
27
27
|
|
|
28
28
|
private _hierarchyReady = false;
|
|
29
29
|
|
|
30
|
+
private _picker: Picker | null = null;
|
|
31
|
+
|
|
32
|
+
private _hasPointerListeners: { [key: string]: boolean } = {
|
|
33
|
+
pointerenter: false,
|
|
34
|
+
pointerleave: false,
|
|
35
|
+
pointerdown: false,
|
|
36
|
+
pointerup: false,
|
|
37
|
+
pointermove: false
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
private _hoveredEntity: EntityElement | null = null;
|
|
41
|
+
|
|
42
|
+
private _pointerHandlers: { [key: string]: EventListener | null } = {
|
|
43
|
+
pointermove: null,
|
|
44
|
+
pointerdown: null,
|
|
45
|
+
pointerup: null
|
|
46
|
+
};
|
|
47
|
+
|
|
30
48
|
/**
|
|
31
49
|
* The PlayCanvas application instance.
|
|
32
50
|
*/
|
|
@@ -71,6 +89,8 @@ class AppElement extends AsyncElement {
|
|
|
71
89
|
this.app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
|
|
72
90
|
this.app.setCanvasResolution(RESOLUTION_AUTO);
|
|
73
91
|
|
|
92
|
+
this._pickerCreate();
|
|
93
|
+
|
|
74
94
|
// Get all pc-asset elements that are direct children of the pc-app element
|
|
75
95
|
const assetElements = this.querySelectorAll<AssetElement>(':scope > pc-asset');
|
|
76
96
|
Array.from(assetElements).forEach((assetElement) => {
|
|
@@ -113,6 +133,8 @@ class AppElement extends AsyncElement {
|
|
|
113
133
|
}
|
|
114
134
|
|
|
115
135
|
disconnectedCallback() {
|
|
136
|
+
this._pickerDestroy();
|
|
137
|
+
|
|
116
138
|
// Clean up the application
|
|
117
139
|
if (this.app) {
|
|
118
140
|
this.app.destroy();
|
|
@@ -135,6 +157,163 @@ class AppElement extends AsyncElement {
|
|
|
135
157
|
}
|
|
136
158
|
}
|
|
137
159
|
|
|
160
|
+
_pickerCreate() {
|
|
161
|
+
const { width, height } = this.app!.graphicsDevice;
|
|
162
|
+
this._picker = new Picker(this.app!, width, height);
|
|
163
|
+
|
|
164
|
+
// Create bound handlers but don't attach them yet
|
|
165
|
+
this._pointerHandlers.pointermove = this._onPointerMove.bind(this) as EventListener;
|
|
166
|
+
this._pointerHandlers.pointerdown = this._onPointerDown.bind(this) as EventListener;
|
|
167
|
+
this._pointerHandlers.pointerup = this._onPointerUp.bind(this) as EventListener;
|
|
168
|
+
|
|
169
|
+
// Listen for pointer listeners being added/removed
|
|
170
|
+
['pointermove', 'pointerdown', 'pointerup', 'pointerenter', 'pointerleave'].forEach((type) => {
|
|
171
|
+
this.addEventListener(`${type}:connect`, () => this._onPointerListenerAdded(type));
|
|
172
|
+
this.addEventListener(`${type}:disconnect`, () => this._onPointerListenerRemoved(type));
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_pickerDestroy() {
|
|
177
|
+
if (this._canvas) {
|
|
178
|
+
Object.entries(this._pointerHandlers).forEach(([type, handler]) => {
|
|
179
|
+
if (handler) {
|
|
180
|
+
this._canvas!.removeEventListener(type, handler);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this._picker = null;
|
|
186
|
+
this._pointerHandlers = {
|
|
187
|
+
pointermove: null,
|
|
188
|
+
pointerdown: null,
|
|
189
|
+
pointerup: null
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
_onPointerMove(event: PointerEvent) {
|
|
194
|
+
if (!this._picker || !this.app) return;
|
|
195
|
+
|
|
196
|
+
const camera = this.app!.root.findComponent('camera') as CameraComponent;
|
|
197
|
+
if (!camera) return;
|
|
198
|
+
|
|
199
|
+
const canvasRect = this._canvas!.getBoundingClientRect();
|
|
200
|
+
const x = event.clientX - canvasRect.left;
|
|
201
|
+
const y = event.clientY - canvasRect.top;
|
|
202
|
+
|
|
203
|
+
this._picker.prepare(camera, this.app!.scene);
|
|
204
|
+
const selection = this._picker.getSelection(x, y);
|
|
205
|
+
|
|
206
|
+
// Get the currently hovered entity by walking up the hierarchy
|
|
207
|
+
let newHoverEntity = null;
|
|
208
|
+
if (selection.length > 0) {
|
|
209
|
+
let node = selection[0].node;
|
|
210
|
+
while (node && !newHoverEntity) {
|
|
211
|
+
const entityElement = this.querySelector(`pc-entity[name="${node.name}"]`) as EntityElement;
|
|
212
|
+
if (entityElement) {
|
|
213
|
+
newHoverEntity = entityElement;
|
|
214
|
+
}
|
|
215
|
+
node = node.parent;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Handle enter/leave events
|
|
220
|
+
if (this._hoveredEntity !== newHoverEntity) {
|
|
221
|
+
if (this._hoveredEntity && this._hoveredEntity.hasListeners('pointerleave')) {
|
|
222
|
+
this._hoveredEntity.dispatchEvent(new PointerEvent('pointerleave', event));
|
|
223
|
+
}
|
|
224
|
+
if (newHoverEntity && newHoverEntity.hasListeners('pointerenter')) {
|
|
225
|
+
newHoverEntity.dispatchEvent(new PointerEvent('pointerenter', event));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Update hover state
|
|
230
|
+
this._hoveredEntity = newHoverEntity;
|
|
231
|
+
|
|
232
|
+
// Handle pointermove event
|
|
233
|
+
if (newHoverEntity && newHoverEntity.hasListeners('pointermove')) {
|
|
234
|
+
newHoverEntity.dispatchEvent(new PointerEvent('pointermove', event));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
_onPointerDown(event: PointerEvent) {
|
|
239
|
+
if (!this._picker || !this.app) return;
|
|
240
|
+
|
|
241
|
+
const camera = this.app!.root.findComponent('camera') as CameraComponent;
|
|
242
|
+
if (!camera) return;
|
|
243
|
+
|
|
244
|
+
const canvasRect = this._canvas!.getBoundingClientRect();
|
|
245
|
+
const x = event.clientX - canvasRect.left;
|
|
246
|
+
const y = event.clientY - canvasRect.top;
|
|
247
|
+
|
|
248
|
+
this._picker.prepare(camera, this.app!.scene);
|
|
249
|
+
const selection = this._picker.getSelection(x, y);
|
|
250
|
+
|
|
251
|
+
if (selection.length > 0) {
|
|
252
|
+
let node = selection[0].node;
|
|
253
|
+
while (node) {
|
|
254
|
+
const entityElement = this.querySelector(`pc-entity[name="${node.name}"]`) as EntityElement;
|
|
255
|
+
if (entityElement && entityElement.hasListeners('pointerdown')) {
|
|
256
|
+
entityElement.dispatchEvent(new PointerEvent('pointerdown', event));
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
node = node.parent;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
_onPointerUp(event: PointerEvent) {
|
|
265
|
+
if (!this._picker || !this.app) return;
|
|
266
|
+
|
|
267
|
+
const camera = this.app!.root.findComponent('camera') as CameraComponent;
|
|
268
|
+
if (!camera) return;
|
|
269
|
+
|
|
270
|
+
const canvasRect = this._canvas!.getBoundingClientRect();
|
|
271
|
+
const x = event.clientX - canvasRect.left;
|
|
272
|
+
const y = event.clientY - canvasRect.top;
|
|
273
|
+
|
|
274
|
+
this._picker.prepare(camera, this.app!.scene);
|
|
275
|
+
const selection = this._picker.getSelection(x, y);
|
|
276
|
+
|
|
277
|
+
if (selection.length > 0) {
|
|
278
|
+
const entityElement = this.querySelector(`pc-entity[name="${selection[0].node.name}"]`) as EntityElement;
|
|
279
|
+
if (entityElement && entityElement.hasListeners('pointerup')) {
|
|
280
|
+
entityElement.dispatchEvent(new PointerEvent('pointerup', event));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
_onPointerListenerAdded(type: string) {
|
|
286
|
+
if (!this._hasPointerListeners[type] && this._canvas) {
|
|
287
|
+
this._hasPointerListeners[type] = true;
|
|
288
|
+
|
|
289
|
+
// For enter/leave events, we need the move handler
|
|
290
|
+
const handler = (type === 'pointerenter' || type === 'pointerleave') ?
|
|
291
|
+
this._pointerHandlers.pointermove :
|
|
292
|
+
this._pointerHandlers[type];
|
|
293
|
+
|
|
294
|
+
if (handler) {
|
|
295
|
+
this._canvas.addEventListener(type === 'pointerenter' || type === 'pointerleave' ? 'pointermove' : type, handler);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
_onPointerListenerRemoved(type: string) {
|
|
301
|
+
const hasListeners = Array.from(this.querySelectorAll<EntityElement>('pc-entity'))
|
|
302
|
+
.some(entity => entity.hasListeners(type));
|
|
303
|
+
|
|
304
|
+
if (!hasListeners && this._canvas) {
|
|
305
|
+
this._hasPointerListeners[type] = false;
|
|
306
|
+
|
|
307
|
+
const handler = (type === 'pointerenter' || type === 'pointerleave') ?
|
|
308
|
+
this._pointerHandlers.pointermove :
|
|
309
|
+
this._pointerHandlers[type];
|
|
310
|
+
|
|
311
|
+
if (handler) {
|
|
312
|
+
this._canvas.removeEventListener(type === 'pointerenter' || type === 'pointerleave' ? 'pointermove' : type, handler);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
138
317
|
/**
|
|
139
318
|
* Sets the alpha flag.
|
|
140
319
|
* @param value - The alpha flag.
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import { PROJECTION_ORTHOGRAPHIC, PROJECTION_PERSPECTIVE,
|
|
1
|
+
import { CameraComponent, Color, Vec4, GAMMA_NONE, GAMMA_SRGB, PROJECTION_ORTHOGRAPHIC, PROJECTION_PERSPECTIVE, TONEMAP_LINEAR, TONEMAP_FILMIC, TONEMAP_NEUTRAL, TONEMAP_ACES2, TONEMAP_ACES, TONEMAP_HEJL, TONEMAP_NONE, XRTYPE_VR } from 'playcanvas';
|
|
2
2
|
|
|
3
3
|
import { ComponentElement } from './component';
|
|
4
4
|
import { parseColor, parseVec4 } from '../utils';
|
|
5
5
|
|
|
6
|
+
const tonemaps = new Map([
|
|
7
|
+
['none', TONEMAP_NONE],
|
|
8
|
+
['linear', TONEMAP_LINEAR],
|
|
9
|
+
['filmic', TONEMAP_FILMIC],
|
|
10
|
+
['hejl', TONEMAP_HEJL],
|
|
11
|
+
['aces', TONEMAP_ACES],
|
|
12
|
+
['aces2', TONEMAP_ACES2],
|
|
13
|
+
['neutral', TONEMAP_NEUTRAL]
|
|
14
|
+
]);
|
|
15
|
+
|
|
6
16
|
/**
|
|
7
17
|
* The CameraComponentElement interface provides properties and methods for manipulating
|
|
8
18
|
* `<pc-camera>` elements. The CameraComponentElement interface also inherits the properties and
|
|
@@ -29,6 +39,10 @@ class CameraComponentElement extends ComponentElement {
|
|
|
29
39
|
|
|
30
40
|
private _frustumCulling = true;
|
|
31
41
|
|
|
42
|
+
private _gamma: 'none' | 'srgb' = 'srgb';
|
|
43
|
+
|
|
44
|
+
private _horizontalFov = false;
|
|
45
|
+
|
|
32
46
|
private _nearClip = 0.1;
|
|
33
47
|
|
|
34
48
|
private _orthographic = false;
|
|
@@ -41,6 +55,8 @@ class CameraComponentElement extends ComponentElement {
|
|
|
41
55
|
|
|
42
56
|
private _scissorRect = new Vec4(0, 0, 1, 1);
|
|
43
57
|
|
|
58
|
+
private _tonemap: 'none' | 'linear' | 'filmic' | 'hejl' | 'aces' | 'aces2' | 'neutral' = 'none';
|
|
59
|
+
|
|
44
60
|
/** @ignore */
|
|
45
61
|
constructor() {
|
|
46
62
|
super('camera');
|
|
@@ -57,12 +73,15 @@ class CameraComponentElement extends ComponentElement {
|
|
|
57
73
|
flipFaces: this._flipFaces,
|
|
58
74
|
fov: this._fov,
|
|
59
75
|
frustumCulling: this._frustumCulling,
|
|
76
|
+
gammaCorrection: this._gamma === 'srgb' ? GAMMA_SRGB : GAMMA_NONE,
|
|
77
|
+
horizontalFov: this._horizontalFov,
|
|
60
78
|
nearClip: this._nearClip,
|
|
61
79
|
orthographic: this._orthographic,
|
|
62
80
|
orthoHeight: this._orthoHeight,
|
|
63
81
|
priority: this._priority,
|
|
64
82
|
rect: this._rect,
|
|
65
|
-
scissorRect: this._scissorRect
|
|
83
|
+
scissorRect: this._scissorRect,
|
|
84
|
+
toneMapping: tonemaps.get(this._tonemap)
|
|
66
85
|
};
|
|
67
86
|
}
|
|
68
87
|
|
|
@@ -266,6 +285,45 @@ class CameraComponentElement extends ComponentElement {
|
|
|
266
285
|
return this._frustumCulling;
|
|
267
286
|
}
|
|
268
287
|
|
|
288
|
+
/**
|
|
289
|
+
* Sets the gamma correction of the camera.
|
|
290
|
+
* @param value - The gamma correction.
|
|
291
|
+
*/
|
|
292
|
+
set gamma(value: 'none' | 'srgb') {
|
|
293
|
+
this._gamma = value;
|
|
294
|
+
if (this.component) {
|
|
295
|
+
this.component.gammaCorrection = value === 'srgb' ? GAMMA_SRGB : GAMMA_NONE;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Gets the gamma correction of the camera.
|
|
301
|
+
* @returns The gamma correction.
|
|
302
|
+
*/
|
|
303
|
+
get gamma(): 'none' | 'srgb' {
|
|
304
|
+
return this._gamma;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Sets whether the camera's field of view (fov) is horizontal or vertical. Defaults to false
|
|
309
|
+
* (meaning it is vertical be default).
|
|
310
|
+
* @param value - Whether the camera's field of view is horizontal.
|
|
311
|
+
*/
|
|
312
|
+
set horizontalFov(value: boolean) {
|
|
313
|
+
this._horizontalFov = value;
|
|
314
|
+
if (this.component) {
|
|
315
|
+
this.component.horizontalFov = value;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Gets whether the camera's field of view (fov) is horizontal or vertical.
|
|
321
|
+
* @returns Whether the camera's field of view is horizontal.
|
|
322
|
+
*/
|
|
323
|
+
get horizontalFov(): boolean {
|
|
324
|
+
return this._horizontalFov;
|
|
325
|
+
}
|
|
326
|
+
|
|
269
327
|
/**
|
|
270
328
|
* Sets the near clip distance of the camera.
|
|
271
329
|
* @param value - The near clip distance.
|
|
@@ -380,6 +438,25 @@ class CameraComponentElement extends ComponentElement {
|
|
|
380
438
|
return this._scissorRect;
|
|
381
439
|
}
|
|
382
440
|
|
|
441
|
+
/**
|
|
442
|
+
* Sets the tone mapping of the camera.
|
|
443
|
+
* @param value - The tone mapping.
|
|
444
|
+
*/
|
|
445
|
+
set tonemap(value: 'none' | 'linear' | 'filmic' | 'hejl' | 'aces' | 'aces2' | 'neutral') {
|
|
446
|
+
this._tonemap = value;
|
|
447
|
+
if (this.component) {
|
|
448
|
+
this.component.toneMapping = tonemaps.get(value) ?? TONEMAP_NONE;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Gets the tone mapping of the camera.
|
|
454
|
+
* @returns The tone mapping.
|
|
455
|
+
*/
|
|
456
|
+
get tonemap(): 'none' | 'linear' | 'filmic' | 'hejl' | 'aces' | 'aces2' | 'neutral' {
|
|
457
|
+
return this._tonemap;
|
|
458
|
+
}
|
|
459
|
+
|
|
383
460
|
static get observedAttributes() {
|
|
384
461
|
return [
|
|
385
462
|
...super.observedAttributes,
|
|
@@ -392,12 +469,15 @@ class CameraComponentElement extends ComponentElement {
|
|
|
392
469
|
'flip-faces',
|
|
393
470
|
'fov',
|
|
394
471
|
'frustum-culling',
|
|
472
|
+
'gamma',
|
|
473
|
+
'horizontal-fov',
|
|
395
474
|
'near-clip',
|
|
396
475
|
'orthographic',
|
|
397
476
|
'ortho-height',
|
|
398
477
|
'priority',
|
|
399
478
|
'rect',
|
|
400
|
-
'scissor-rect'
|
|
479
|
+
'scissor-rect',
|
|
480
|
+
'tonemap'
|
|
401
481
|
];
|
|
402
482
|
}
|
|
403
483
|
|
|
@@ -432,6 +512,12 @@ class CameraComponentElement extends ComponentElement {
|
|
|
432
512
|
case 'frustum-culling':
|
|
433
513
|
this.frustumCulling = newValue !== 'false';
|
|
434
514
|
break;
|
|
515
|
+
case 'gamma':
|
|
516
|
+
this.gamma = newValue as 'none' | 'srgb';
|
|
517
|
+
break;
|
|
518
|
+
case 'horizontal-fov':
|
|
519
|
+
this.horizontalFov = this.hasAttribute('horizontal-fov');
|
|
520
|
+
break;
|
|
435
521
|
case 'near-clip':
|
|
436
522
|
this.nearClip = parseFloat(newValue);
|
|
437
523
|
break;
|
|
@@ -450,6 +536,9 @@ class CameraComponentElement extends ComponentElement {
|
|
|
450
536
|
case 'scissor-rect':
|
|
451
537
|
this.scissorRect = parseVec4(newValue);
|
|
452
538
|
break;
|
|
539
|
+
case 'tonemap':
|
|
540
|
+
this.tonemap = newValue as 'none' | 'linear' | 'filmic' | 'hejl' | 'aces' | 'aces2' | 'neutral';
|
|
541
|
+
break;
|
|
453
542
|
}
|
|
454
543
|
}
|
|
455
544
|
}
|
|
@@ -1,8 +1,20 @@
|
|
|
1
|
-
import { Color, LightComponent } from 'playcanvas';
|
|
1
|
+
import { Color, LightComponent, SHADOW_PCF1_16F, SHADOW_PCF1_32F, SHADOW_PCF3_16F, SHADOW_PCF3_32F, SHADOW_PCF5_16F, SHADOW_PCF5_32F, SHADOW_PCSS_32F, SHADOW_VSM_16F, SHADOW_VSM_32F } from 'playcanvas';
|
|
2
2
|
|
|
3
3
|
import { ComponentElement } from './component';
|
|
4
4
|
import { parseColor } from '../utils';
|
|
5
5
|
|
|
6
|
+
const shadowTypes = new Map([
|
|
7
|
+
['pcf1-16f', SHADOW_PCF1_16F],
|
|
8
|
+
['pcf1-32f', SHADOW_PCF1_32F],
|
|
9
|
+
['pcf3-16f', SHADOW_PCF3_16F],
|
|
10
|
+
['pcf3-32f', SHADOW_PCF3_32F],
|
|
11
|
+
['pcf5-16f', SHADOW_PCF5_16F],
|
|
12
|
+
['pcf5-32f', SHADOW_PCF5_32F],
|
|
13
|
+
['vsm-16f', SHADOW_VSM_16F],
|
|
14
|
+
['vsm-32f', SHADOW_VSM_32F],
|
|
15
|
+
['pcss-32f', SHADOW_PCSS_32F]
|
|
16
|
+
]);
|
|
17
|
+
|
|
6
18
|
/**
|
|
7
19
|
* The LightComponentElement interface provides properties and methods for manipulating
|
|
8
20
|
* `<pc-light>` elements. The LightComponentElement interface also inherits the properties and
|
|
@@ -29,10 +41,16 @@ class LightComponentElement extends ComponentElement {
|
|
|
29
41
|
|
|
30
42
|
private _shadowDistance = 16;
|
|
31
43
|
|
|
44
|
+
private _shadowIntensity = 1;
|
|
45
|
+
|
|
32
46
|
private _shadowResolution = 1024;
|
|
33
47
|
|
|
48
|
+
private _shadowType: 'pcf1-16f' | 'pcf1-32f' | 'pcf3-16f' | 'pcf3-32f' | 'pcf5-16f' | 'pcf5-32f' | 'vsm-16f' | 'vsm-32f' | 'pcss-32f' = 'pcf3-32f';
|
|
49
|
+
|
|
34
50
|
private _type = 'directional';
|
|
35
51
|
|
|
52
|
+
private _vsmBias = 0.01;
|
|
53
|
+
|
|
36
54
|
/** @ignore */
|
|
37
55
|
constructor() {
|
|
38
56
|
super('light');
|
|
@@ -49,8 +67,11 @@ class LightComponentElement extends ComponentElement {
|
|
|
49
67
|
range: this._range,
|
|
50
68
|
shadowBias: this._shadowBias,
|
|
51
69
|
shadowDistance: this._shadowDistance,
|
|
70
|
+
shadowIntensity: this._shadowIntensity,
|
|
52
71
|
shadowResolution: this._shadowResolution,
|
|
53
|
-
|
|
72
|
+
shadowType: shadowTypes.get(this._shadowType),
|
|
73
|
+
type: this._type,
|
|
74
|
+
vsmBias: this._vsmBias
|
|
54
75
|
};
|
|
55
76
|
}
|
|
56
77
|
|
|
@@ -233,6 +254,25 @@ class LightComponentElement extends ComponentElement {
|
|
|
233
254
|
return this._shadowDistance;
|
|
234
255
|
}
|
|
235
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Sets the shadow intensity of the light.
|
|
259
|
+
* @param value - The shadow intensity.
|
|
260
|
+
*/
|
|
261
|
+
set shadowIntensity(value: number) {
|
|
262
|
+
this._shadowIntensity = value;
|
|
263
|
+
if (this.component) {
|
|
264
|
+
this.component.shadowIntensity = value;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Gets the shadow intensity of the light.
|
|
270
|
+
* @returns The shadow intensity.
|
|
271
|
+
*/
|
|
272
|
+
get shadowIntensity() {
|
|
273
|
+
return this._shadowIntensity;
|
|
274
|
+
}
|
|
275
|
+
|
|
236
276
|
/**
|
|
237
277
|
* Sets the shadow resolution of the light.
|
|
238
278
|
* @param value - The shadow resolution.
|
|
@@ -252,6 +292,35 @@ class LightComponentElement extends ComponentElement {
|
|
|
252
292
|
return this._shadowResolution;
|
|
253
293
|
}
|
|
254
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Sets the shadow type of the light.
|
|
297
|
+
* @param value - The shadow type. Can be:
|
|
298
|
+
*
|
|
299
|
+
* - `pcf1-16f` - 1-tap percentage-closer filtered shadow map with 16-bit depth.
|
|
300
|
+
* - `pcf1-32f` - 1-tap percentage-closer filtered shadow map with 32-bit depth.
|
|
301
|
+
* - `pcf3-16f` - 3-tap percentage-closer filtered shadow map with 16-bit depth.
|
|
302
|
+
* - `pcf3-32f` - 3-tap percentage-closer filtered shadow map with 32-bit depth.
|
|
303
|
+
* - `pcf5-16f` - 5-tap percentage-closer filtered shadow map with 16-bit depth.
|
|
304
|
+
* - `pcf5-32f` - 5-tap percentage-closer filtered shadow map with 32-bit depth.
|
|
305
|
+
* - `vsm-16f` - Variance shadow map with 16-bit depth.
|
|
306
|
+
* - `vsm-32f` - Variance shadow map with 32-bit depth.
|
|
307
|
+
* - `pcss-32f` - Percentage-closer soft shadow with 32-bit depth.
|
|
308
|
+
*/
|
|
309
|
+
set shadowType(value: 'pcf1-16f' | 'pcf1-32f' | 'pcf3-16f' | 'pcf3-32f' | 'pcf5-16f' | 'pcf5-32f' | 'vsm-16f' | 'vsm-32f' | 'pcss-32f') {
|
|
310
|
+
this._shadowType = value;
|
|
311
|
+
if (this.component) {
|
|
312
|
+
this.component.shadowType = shadowTypes.get(value) ?? SHADOW_PCF3_32F;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Gets the shadow type of the light.
|
|
318
|
+
* @returns The shadow type.
|
|
319
|
+
*/
|
|
320
|
+
get shadowType() {
|
|
321
|
+
return this._shadowType;
|
|
322
|
+
}
|
|
323
|
+
|
|
255
324
|
/**
|
|
256
325
|
* Sets the type of the light.
|
|
257
326
|
* @param value - The type.
|
|
@@ -276,6 +345,25 @@ class LightComponentElement extends ComponentElement {
|
|
|
276
345
|
return this._type;
|
|
277
346
|
}
|
|
278
347
|
|
|
348
|
+
/**
|
|
349
|
+
* Sets the VSM bias of the light.
|
|
350
|
+
* @param value - The VSM bias.
|
|
351
|
+
*/
|
|
352
|
+
set vsmBias(value: number) {
|
|
353
|
+
this._vsmBias = value;
|
|
354
|
+
if (this.component) {
|
|
355
|
+
this.component.vsmBias = value;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Gets the VSM bias of the light.
|
|
361
|
+
* @returns The VSM bias.
|
|
362
|
+
*/
|
|
363
|
+
get vsmBias() {
|
|
364
|
+
return this._vsmBias;
|
|
365
|
+
}
|
|
366
|
+
|
|
279
367
|
static get observedAttributes() {
|
|
280
368
|
return [
|
|
281
369
|
...super.observedAttributes,
|
|
@@ -288,8 +376,11 @@ class LightComponentElement extends ComponentElement {
|
|
|
288
376
|
'range',
|
|
289
377
|
'shadow-bias',
|
|
290
378
|
'shadow-distance',
|
|
379
|
+
'shadow-intensity',
|
|
291
380
|
'shadow-resolution',
|
|
292
|
-
'type'
|
|
381
|
+
'shadow-type',
|
|
382
|
+
'type',
|
|
383
|
+
'vsm-bias'
|
|
293
384
|
];
|
|
294
385
|
}
|
|
295
386
|
|
|
@@ -327,9 +418,18 @@ class LightComponentElement extends ComponentElement {
|
|
|
327
418
|
case 'shadow-resolution':
|
|
328
419
|
this.shadowResolution = Number(newValue);
|
|
329
420
|
break;
|
|
421
|
+
case 'shadow-intensity':
|
|
422
|
+
this.shadowIntensity = Number(newValue);
|
|
423
|
+
break;
|
|
424
|
+
case 'shadow-type':
|
|
425
|
+
this.shadowType = newValue as 'pcf1-16f' | 'pcf1-32f' | 'pcf3-16f' | 'pcf3-32f' | 'pcf5-16f' | 'pcf5-32f' | 'vsm-16f' | 'vsm-32f' | 'pcss-32f';
|
|
426
|
+
break;
|
|
330
427
|
case 'type':
|
|
331
428
|
this.type = newValue;
|
|
332
429
|
break;
|
|
430
|
+
case 'vsm-bias':
|
|
431
|
+
this.vsmBias = Number(newValue);
|
|
432
|
+
break;
|
|
333
433
|
}
|
|
334
434
|
}
|
|
335
435
|
}
|
|
@@ -4,10 +4,6 @@ import { ComponentElement } from './component';
|
|
|
4
4
|
import { ScriptElement } from './script';
|
|
5
5
|
import { AssetElement } from '../asset';
|
|
6
6
|
|
|
7
|
-
const tmpV2 = new Vec2();
|
|
8
|
-
const tmpV3 = new Vec3();
|
|
9
|
-
const tmpV4 = new Vec4();
|
|
10
|
-
|
|
11
7
|
// Add these interfaces at the top of the file, after the imports
|
|
12
8
|
interface ScriptAttributesChangeEvent extends CustomEvent {
|
|
13
9
|
detail: { attributes: any };
|
|
@@ -76,23 +72,36 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
76
72
|
}
|
|
77
73
|
}
|
|
78
74
|
|
|
79
|
-
// Handle
|
|
80
|
-
if (Array.isArray(value)) {
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
// Handle arrays
|
|
76
|
+
if (value && typeof value === 'object' && Array.isArray(value)) {
|
|
77
|
+
// If it's an array of objects, recursively apply to each object
|
|
78
|
+
if (value.length > 0 && typeof value[0] === 'object') {
|
|
79
|
+
target[key] = value.map((item) => {
|
|
80
|
+
const obj = {};
|
|
81
|
+
for (const itemKey in item) {
|
|
82
|
+
applyValue(obj, itemKey, item[itemKey]);
|
|
83
|
+
}
|
|
84
|
+
return obj;
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Handle vectors
|
|
90
|
+
if (value.length === 2 && typeof value[0] === 'number') {
|
|
91
|
+
target[key] = new Vec2(value[0], value[1]);
|
|
83
92
|
return;
|
|
84
93
|
}
|
|
85
|
-
if (
|
|
86
|
-
target[key] =
|
|
94
|
+
if (value.length === 3 && typeof value[0] === 'number') {
|
|
95
|
+
target[key] = new Vec3(value[0], value[1], value[2]);
|
|
87
96
|
return;
|
|
88
97
|
}
|
|
89
|
-
if (
|
|
90
|
-
target[key] =
|
|
98
|
+
if (value.length === 4 && typeof value[0] === 'number') {
|
|
99
|
+
target[key] = new Vec4(value[0], value[1], value[2], value[3]);
|
|
91
100
|
return;
|
|
92
101
|
}
|
|
93
102
|
}
|
|
94
103
|
|
|
95
|
-
// Handle nested objects
|
|
104
|
+
// Handle nested objects (non-array)
|
|
96
105
|
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
97
106
|
if (!target[key] || typeof target[key] !== 'object') {
|
|
98
107
|
target[key] = {};
|