@needle-tools/engine 3.7.6-beta → 3.8.0-alpha

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.
Files changed (87) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/needle-engine.js +472 -87008
  3. package/dist/needle-engine.light.js +472 -84467
  4. package/dist/needle-engine.light.min.js +1 -5805
  5. package/dist/needle-engine.light.umd.cjs +1 -5805
  6. package/dist/needle-engine.min.js +1 -5818
  7. package/dist/needle-engine.umd.cjs +1 -5818
  8. package/lib/engine/debug/debug.d.ts +1 -1
  9. package/lib/engine/engine_context.d.ts +3 -1
  10. package/lib/engine/engine_context.js +17 -12
  11. package/lib/engine/engine_context.js.map +1 -1
  12. package/lib/engine/engine_lightdata.js +6 -7
  13. package/lib/engine/engine_lightdata.js.map +1 -1
  14. package/lib/engine/engine_networking_utils.d.ts +1 -1
  15. package/lib/engine/engine_networking_utils.js.map +1 -1
  16. package/lib/engine/engine_scenelighting.js +5 -5
  17. package/lib/engine/engine_scenelighting.js.map +1 -1
  18. package/lib/engine/extensions/NEEDLE_lightmaps.js +3 -3
  19. package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
  20. package/lib/engine/extensions/NEEDLE_render_objects.js +1 -1
  21. package/lib/engine/extensions/NEEDLE_render_objects.js.map +1 -1
  22. package/lib/engine/extensions/NEEDLE_techniques_webgl.js +4 -1
  23. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  24. package/lib/engine/extensions/extensions.js +17 -3
  25. package/lib/engine/extensions/extensions.js.map +1 -1
  26. package/lib/engine-components/Camera.js +3 -3
  27. package/lib/engine-components/Camera.js.map +1 -1
  28. package/lib/engine-components/DragControls.js +4 -3
  29. package/lib/engine-components/DragControls.js.map +1 -1
  30. package/lib/engine-components/GroundProjection.js +1 -1
  31. package/lib/engine-components/GroundProjection.js.map +1 -1
  32. package/lib/engine-components/Light.js +58 -50
  33. package/lib/engine-components/Light.js.map +1 -1
  34. package/lib/engine-components/Networking.d.ts +1 -1
  35. package/lib/engine-components/OrbitControls.js +4 -3
  36. package/lib/engine-components/OrbitControls.js.map +1 -1
  37. package/lib/engine-components/ParticleSystem.d.ts +2 -1
  38. package/lib/engine-components/ParticleSystem.js +11 -1
  39. package/lib/engine-components/ParticleSystem.js.map +1 -1
  40. package/lib/engine-components/ReflectionProbe.js +3 -3
  41. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  42. package/lib/engine-components/Renderer.js +7 -7
  43. package/lib/engine-components/Renderer.js.map +1 -1
  44. package/lib/engine-components/RendererLightmap.d.ts +2 -3
  45. package/lib/engine-components/RendererLightmap.js +16 -15
  46. package/lib/engine-components/RendererLightmap.js.map +1 -1
  47. package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +1 -1
  48. package/lib/engine-components/ui/BaseUIComponent.js +4 -0
  49. package/lib/engine-components/ui/BaseUIComponent.js.map +1 -1
  50. package/lib/engine-components/ui/Canvas.js +9 -1
  51. package/lib/engine-components/ui/Canvas.js.map +1 -1
  52. package/lib/engine-components/ui/PointerEvents.d.ts +1 -0
  53. package/lib/engine-components/ui/PointerEvents.js +5 -0
  54. package/lib/engine-components/ui/PointerEvents.js.map +1 -1
  55. package/lib/engine-components/utils/LookAt.js +7 -1
  56. package/lib/engine-components/utils/LookAt.js.map +1 -1
  57. package/lib/engine-components/webxr/WebARCameraBackground.d.ts +1 -1
  58. package/lib/engine-components/webxr/WebARCameraBackground.js +2 -2
  59. package/lib/engine-components/webxr/WebARCameraBackground.js.map +1 -1
  60. package/lib/engine-components/webxr/WebXR.js +6 -5
  61. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  62. package/lib/engine-components/webxr/WebXRPlaneTracking.d.ts +1 -1
  63. package/package.json +5 -5
  64. package/plugins/vite/vite-4.4-hack.js +25 -16
  65. package/src/engine/engine_context.ts +20 -13
  66. package/src/engine/engine_lightdata.ts +6 -8
  67. package/src/engine/engine_networking_utils.ts +1 -1
  68. package/src/engine/engine_scenelighting.ts +5 -5
  69. package/src/engine/extensions/NEEDLE_lightmaps.ts +3 -3
  70. package/src/engine/extensions/NEEDLE_render_objects.ts +10 -8
  71. package/src/engine/extensions/NEEDLE_techniques_webgl.ts +5 -1
  72. package/src/engine/extensions/extensions.ts +18 -3
  73. package/src/engine-components/Camera.ts +3 -3
  74. package/src/engine-components/DragControls.ts +7 -8
  75. package/src/engine-components/GroundProjection.ts +1 -1
  76. package/src/engine-components/Light.ts +62 -57
  77. package/src/engine-components/OrbitControls.ts +4 -3
  78. package/src/engine-components/ParticleSystem.ts +14 -0
  79. package/src/engine-components/ReflectionProbe.ts +3 -3
  80. package/src/engine-components/Renderer.ts +10 -10
  81. package/src/engine-components/RendererLightmap.ts +21 -20
  82. package/src/engine-components/ui/BaseUIComponent.ts +5 -0
  83. package/src/engine-components/ui/Canvas.ts +7 -1
  84. package/src/engine-components/ui/PointerEvents.ts +6 -0
  85. package/src/engine-components/utils/LookAt.ts +8 -1
  86. package/src/engine-components/webxr/WebARCameraBackground.ts +3 -3
  87. package/src/engine-components/webxr/WebXR.ts +6 -6
@@ -10,7 +10,7 @@ import { NEEDLE_render_objects } from "../engine/extensions/NEEDLE_render_object
10
10
  import { NEEDLE_progressive } from "../engine/extensions/NEEDLE_progressive";
11
11
  import { NEED_UPDATE_INSTANCE_KEY } from "../engine/engine_instancing";
12
12
  import { IRenderer, ISharedMaterials } from "../engine/engine_types";
13
- import { debug, ReflectionProbe } from "./ReflectionProbe";
13
+ import { ReflectionProbe } from "./ReflectionProbe";
14
14
  import { setCustomVisibility } from "../engine/js-extensions/Layers";
15
15
  import { isLocalNetwork } from "../engine/engine_networking_utils";
16
16
  import { showBalloonWarning } from "../engine/debug/debug";
@@ -20,7 +20,6 @@ export { InstancingUtil } from "../engine/engine_instancing";
20
20
 
21
21
  const debugRenderer = getParam("debugrenderer");
22
22
  const suppressInstancing = getParam("noInstancing");
23
- const debugLightmap = getParam("debuglightmaps") ? true : false;
24
23
  const debugInstancing = getParam("debuginstancing");
25
24
  const debugProgressiveLoading = getParam("debugprogressive");
26
25
  const suppressProgressiveLoading = getParam("noprogressive");
@@ -184,7 +183,7 @@ class SharedMaterialArray implements ISharedMaterials {
184
183
  this.changed = true;
185
184
  }
186
185
 
187
- private getMaterial(index: number) : Material | null {
186
+ private getMaterial(index: number): Material | null {
188
187
  index = this.resolveIndex(index);
189
188
  if (index < 0) return null;
190
189
  const obj = this._targets;
@@ -347,7 +346,7 @@ export class Renderer extends Behaviour implements IRenderer {
347
346
  if (debugRenderer) console.log("Renderer ", this.name, this);
348
347
  this.clearInstancingState();
349
348
 
350
- if (this.probeAnchor && debug) this.probeAnchor.add(new AxesHelper(.2));
349
+ if (this.probeAnchor && debugRenderer) this.probeAnchor.add(new AxesHelper(.2));
351
350
 
352
351
  this._reflectionProbe = null;
353
352
 
@@ -364,11 +363,12 @@ export class Renderer extends Behaviour implements IRenderer {
364
363
  for (let i = 0; i < this.gameObject.children.length; i++) {
365
364
  const ch = this.gameObject.children[i];
366
365
  // ignore nested groups or objects that have their own renderer (aka their own render order settings)
367
- if (ch.type !== "Mesh" || GameObject.getComponent(ch, Renderer)) continue;
366
+ if (!this.isMeshOrSkinnedMesh(ch) || GameObject.getComponent(ch, Renderer)) continue;
368
367
  if (this.renderOrder.length <= index) {
369
368
  console.error("Incorrect element count", this);
370
369
  break;
371
370
  }
371
+ // if(debugRenderer) console.log("Setting render order", ch, this.renderOrder[index])
372
372
  ch.renderOrder = this.renderOrder[index];
373
373
  index += 1;
374
374
  }
@@ -419,7 +419,7 @@ export class Renderer extends Behaviour implements IRenderer {
419
419
  this._lightmaps.push(rm);
420
420
  }
421
421
  const rm = this._lightmaps[0];
422
- rm.init(this.lightmapIndex, this.lightmapScaleOffset, tex, debugLightmap);
422
+ rm.init(this.lightmapIndex, this.lightmapScaleOffset, tex);
423
423
  }
424
424
  else {
425
425
  if (mat)
@@ -439,7 +439,7 @@ export class Renderer extends Behaviour implements IRenderer {
439
439
  }
440
440
  else
441
441
  rm = this._lightmaps[i];
442
- rm.init(this.lightmapIndex, this.lightmapScaleOffset, tex, debugLightmap);
442
+ rm.init(this.lightmapIndex, this.lightmapScaleOffset, tex);
443
443
  // onBeforeRender is not called when the renderer is on a group
444
444
  // this is an issue we probably also need to handle for custom shaders
445
445
  // and need a better solution, but for now this fixes lightmaps for multimaterial objects
@@ -449,7 +449,7 @@ export class Renderer extends Behaviour implements IRenderer {
449
449
  }
450
450
  }
451
451
  else {
452
- if (debug) console.warn("Lightmap not found", this.sourceId, this.lightmapIndex);
452
+ if (debugRenderer) console.warn("Lightmap not found", this.sourceId, this.lightmapIndex);
453
453
  }
454
454
  }
455
455
 
@@ -562,7 +562,7 @@ export class Renderer extends Behaviour implements IRenderer {
562
562
  else {
563
563
  this.applySettings(this.gameObject);
564
564
  }
565
-
565
+
566
566
  if (this.sharedMaterials.changed) {
567
567
  this.sharedMaterials.changed = false;
568
568
  this.applyLightmapping();
@@ -605,7 +605,7 @@ export class Renderer extends Behaviour implements IRenderer {
605
605
  }
606
606
  }
607
607
 
608
-
608
+
609
609
  if (this.reflectionProbeUsage !== ReflectionProbeUsage.Off && this._reflectionProbe) {
610
610
  this._reflectionProbe.onSet(this);
611
611
  }
@@ -1,7 +1,9 @@
1
1
  import { Behaviour, GameObject } from "./Component";
2
- import * as THREE from "three";
3
- import { Texture } from "three";
2
+ import { Material, Mesh, ShaderMaterial, Texture, Vector4 } from "three";
4
3
  import { Context, OnRenderCallback } from "../engine/engine_setup";
4
+ import { getParam } from "../engine/engine_utils";
5
+
6
+ const debug = getParam("debuglightmaps");
5
7
 
6
8
  // this component is automatically added by the Renderer if the object has lightmap uvs AND we have a lightmap
7
9
  // for multimaterial objects GLTF exports a "Group" with the renderer component
@@ -19,20 +21,20 @@ export class RendererLightmap {
19
21
  }
20
22
 
21
23
  lightmapIndex: number = -1;
22
- lightmapScaleOffset: THREE.Vector4 = new THREE.Vector4(1, 1, 0, 0);
24
+ lightmapScaleOffset: THREE.Vector4 = new Vector4(1, 1, 0, 0);
23
25
 
24
26
  private context: Context;
25
27
  private gameObject: GameObject;
26
- private lightmapTexture: THREE.Texture | null = null;
27
- private lightmapScaleOffsetUniform = { value: new THREE.Vector4(1, 1, 0, 0) };
28
- private lightmapUniform: { value: THREE.Texture | null } = { value: null };
28
+ private lightmapTexture: Texture | null = null;
29
+ private lightmapScaleOffsetUniform = { value: new Vector4(1, 1, 0, 0) };
30
+ private lightmapUniform: { value: Texture | null } = { value: null };
29
31
 
30
32
  constructor(gameObject: GameObject, context: Context) {
31
33
  this.gameObject = gameObject;
32
34
  this.context = context;
33
35
  }
34
36
 
35
- init(lightmapIndex: number, lightmapScaleOffset: THREE.Vector4, lightmapTexture: THREE.Texture, debug: boolean = false) {
37
+ init(lightmapIndex: number, lightmapScaleOffset: Vector4, lightmapTexture: Texture) {
36
38
  console.assert(this.gameObject !== undefined && this.gameObject !== null, "Missing gameobject", this);
37
39
 
38
40
  this.lightmapIndex = lightmapIndex;
@@ -40,8 +42,7 @@ export class RendererLightmap {
40
42
  this.lightmapScaleOffset = lightmapScaleOffset;
41
43
  this.lightmapTexture = lightmapTexture;
42
44
 
43
- const debugLightmaps = debug;
44
- if (debugLightmaps) this.setLightmapDebugMaterial();
45
+ if (debug) this.setLightmapDebugMaterial();
45
46
  this.applyLightmap();
46
47
  }
47
48
 
@@ -68,15 +69,16 @@ export class RendererLightmap {
68
69
 
69
70
  console.assert(this.gameObject.type === "Mesh", "Lightmap only works on meshes", this);
70
71
 
71
- const mesh = this.gameObject as unknown as THREE.Mesh;
72
+ const mesh = this.gameObject as unknown as Mesh;
72
73
  // TODO: ensure uv2 exists
73
- if (!mesh.geometry.getAttribute("uv2"))
74
- mesh.geometry.setAttribute("uv2", mesh.geometry.getAttribute("uv"));
74
+ if (!mesh.geometry.getAttribute("uv1"))
75
+ mesh.geometry.setAttribute("uv1", mesh.geometry.getAttribute("uv"));
75
76
 
76
- const mat = this.gameObject["material"].clone();
77
+ const mat: Material = this.gameObject["material"].clone();
77
78
  this.gameObject["material"] = mat;
78
79
 
79
80
  this.gameObject["material"].onBeforeCompile = (shader, _) => {
81
+ shader.lightMapUv = "uv1";
80
82
  shader.uniforms.lightmap = this.lightmapUniform;
81
83
  shader.uniforms.lightmapScaleOffset = this.lightmapScaleOffsetUniform;
82
84
  };
@@ -107,13 +109,12 @@ export class RendererLightmap {
107
109
  private setLightmapDebugMaterial() {
108
110
 
109
111
  // debug lightmaps
110
- this.gameObject["material"] = new THREE.ShaderMaterial({
112
+ this.gameObject["material"] = new ShaderMaterial({
111
113
  vertexShader: `
112
- attribute vec2 uv2;
113
- varying vec2 vUv2;
114
+ varying vec2 vUv1;
114
115
  void main()
115
116
  {
116
- vUv2 = uv2;
117
+ vUv1 = uv1;
117
118
  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
118
119
  }
119
120
  `,
@@ -121,7 +122,7 @@ export class RendererLightmap {
121
122
  uniform sampler2D lightmap;
122
123
  uniform float lightMapIntensity;
123
124
  uniform vec4 lightmapScaleOffset;
124
- varying vec2 vUv2;
125
+ varying vec2 vUv1;
125
126
 
126
127
  // took from threejs 05fc79cd52b79e8c3e8dec1e7dca72c5c39983a4
127
128
  vec4 conv_sRGBToLinear( in vec4 value ) {
@@ -129,7 +130,7 @@ export class RendererLightmap {
129
130
  }
130
131
 
131
132
  void main() {
132
- vec2 lUv = vUv2.xy * lightmapScaleOffset.xy + vec2(lightmapScaleOffset.z, (1. - (lightmapScaleOffset.y + lightmapScaleOffset.w)));
133
+ vec2 lUv = vUv1.xy * lightmapScaleOffset.xy + vec2(lightmapScaleOffset.z, (1. - (lightmapScaleOffset.y + lightmapScaleOffset.w)));
133
134
 
134
135
  vec4 lightMapTexel = texture2D( lightmap, lUv);
135
136
  // The range of RGBM lightmaps goes from 0 to 34.49 (5^2.2) in linear space, and from 0 to 5 in gamma space.
@@ -138,7 +139,7 @@ export class RendererLightmap {
138
139
  //lightMapTexel = conv_sRGBToLinear(lightMapTexel);
139
140
  // lightMapTexel.rgb = vec3(1.);
140
141
 
141
- // gl_FragColor = vec4(vUv2.xy, 0, 1);
142
+ // gl_FragColor = vec4(vUv1.xy, 0, 1);
142
143
  gl_FragColor = lightMapTexel;
143
144
  }
144
145
  `,
@@ -6,8 +6,11 @@ import { showGizmos } from '../../engine/engine_default_parameters';
6
6
  import { AxesHelper, Object3D } from 'three';
7
7
  import { ICanvas, IGraphic } from './Interfaces';
8
8
  import { ShadowCastingMode } from '../Renderer';
9
+ import { getParam } from '../../engine/engine_utils';
9
10
  export const includesDir = "./include";
10
11
 
12
+ const debug = getParam("debugshadowcomponents");
13
+
11
14
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
12
15
 
13
16
 
@@ -128,6 +131,8 @@ export class BaseUIComponent extends Behaviour {
128
131
  // otherwise it will fail when object are enabled at runtime
129
132
  if (needsUpdate)
130
133
  ThreeMeshUI.update();
134
+
135
+ if(debug) console.log(this.shadowComponent)
131
136
  }
132
137
 
133
138
 
@@ -190,6 +190,7 @@ export class Canvas extends UIRootComponent implements ICanvas {
190
190
  }
191
191
 
192
192
  onBeforeRenderRoutine = () => {
193
+ if(this.context.isInVR) return;
193
194
  this.previousParent = this.gameObject.parent;
194
195
  // console.log(this.previousParent?.name + "/" + this.gameObject.name);
195
196
 
@@ -208,6 +209,7 @@ export class Canvas extends UIRootComponent implements ICanvas {
208
209
  }
209
210
 
210
211
  onAfterRenderRoutine = () => {
212
+ if(this.context.isInVR) return;
211
213
  if ((this.screenspace || this.renderOnTop) && this.previousParent && this.context.mainCamera) {
212
214
  if (this.screenspace) {
213
215
  const camObj = this.context.mainCamera;
@@ -215,7 +217,10 @@ export class Canvas extends UIRootComponent implements ICanvas {
215
217
  } else {
216
218
  this.previousParent.add(this.gameObject);
217
219
  }
220
+ const prevAutoClearDepth = this.context.renderer.autoClear;
221
+ const prevAutoClearColor = this.context.renderer.autoClearColor;
218
222
  this.context.renderer.autoClear = false;
223
+ this.context.renderer.autoClearColor = false;
219
224
  this.context.renderer.clearDepth();
220
225
  this.onUpdateRenderMode(true);
221
226
  this.handleLayoutUpdates();
@@ -223,7 +228,8 @@ export class Canvas extends UIRootComponent implements ICanvas {
223
228
  // this.handleLayoutUpdates();
224
229
  EventSystem.ensureUpdateMeshUI(ThreeMeshUI, this.context);
225
230
  this.context.renderer.render(this.gameObject, this.context.mainCamera);
226
- this.context.renderer.autoClear = true;
231
+ this.context.renderer.autoClear = prevAutoClearDepth;
232
+ this.context.renderer.autoClearColor = prevAutoClearColor;
227
233
  this.previousParent.add(this.gameObject);
228
234
  }
229
235
  this._lastMatrixWorld?.copy(this.gameObject.matrixWorld);
@@ -48,6 +48,12 @@ export class PointerEventData implements IInputEventArgs {
48
48
  this.event = events;
49
49
  this.input = input;
50
50
  }
51
+
52
+ clone() {
53
+ const clone = new PointerEventData(this.input, this.event);
54
+ Object.assign(clone, this);
55
+ return clone;
56
+ }
51
57
  }
52
58
 
53
59
  export interface IPointerDownHandler {
@@ -34,8 +34,15 @@ export class LookAt extends Behaviour implements UsdzBehaviour {
34
34
  if (this.keepUpDirection)
35
35
  lookTarget.y = lookFrom.y;
36
36
 
37
- if (this.copyTargetRotation)
37
+ if (this.copyTargetRotation) {
38
38
  setWorldQuaternion(this.gameObject, getWorldQuaternion(target));
39
+
40
+ // look at forward again so we don't get any roll
41
+ if (this.keepUpDirection) {
42
+ const forwardPoint = lookFrom.sub(this.forward);
43
+ this.gameObject.lookAt(forwardPoint);
44
+ }
45
+ }
39
46
  else
40
47
  this.gameObject.lookAt(lookTarget);
41
48
 
@@ -3,7 +3,6 @@ import { serializable } from "../../engine/engine_serialization_decorator";
3
3
  import { RGBAColor } from "../js-extensions/RGBAColor"
4
4
  import { WebXR } from "./WebXR";
5
5
  import {
6
- Camera as ThreeCamera,
7
6
  Scene,
8
7
  Texture,
9
8
  Mesh, MeshBasicMaterial,
@@ -11,7 +10,8 @@ import {
11
10
  PlaneGeometry,
12
11
  ShaderLib,
13
12
  ShaderMaterial,
14
- DoubleSide
13
+ DoubleSide,
14
+ PerspectiveCamera
15
15
  } from "three";
16
16
 
17
17
  export class WebARCameraBackground extends Behaviour {
@@ -53,7 +53,7 @@ export class WebARCameraBackground extends Behaviour {
53
53
  const geometry = new PlaneGeometry();
54
54
  const scene = new Scene();
55
55
  scene.add(new Mesh(geometry, material));
56
- const camera = new ThreeCamera();
56
+ const camera = new PerspectiveCamera();
57
57
 
58
58
  return function forceTextureInitialization(renderer, texture) {
59
59
  material.map = texture;
@@ -1,4 +1,4 @@
1
- import { ArrayCamera, Color, Euler, EventDispatcher, Group, Matrix4, Mesh, MeshBasicMaterial, Object3D, Quaternion, RingGeometry, Texture, Vector3 } from 'three';
1
+ import { ArrayCamera, Color, Euler, EventDispatcher, Group, Matrix4, Mesh, MeshBasicMaterial, Object3D, Quaternion, RingGeometry, Texture, Vector3, WebXRArrayCamera } from 'three';
2
2
  import { ARButton } from '../../include/three/ARButton.js';
3
3
  import { VRButton } from '../../include/three/VRButton.js';
4
4
 
@@ -393,7 +393,7 @@ export class WebXR extends Behaviour {
393
393
  private _originalXRRigRotation: Quaternion = new Quaternion();
394
394
 
395
395
  private onEnterXR(session: XRSession, frame: XRFrame) {
396
- console.log("[XR] session begin", session);
396
+ console.log("[XR] session begin", session, frame);
397
397
  WebXR._isInXr = true;
398
398
 
399
399
  this.ensureRig();
@@ -414,16 +414,16 @@ export class WebXR extends Behaviour {
414
414
  // we set layers to sync raycasting and have a similar behaviour to unity
415
415
  const xr = this.context.renderer.xr;
416
416
  if (this.context.mainCamera) {
417
- //@ts-ignore
418
- const cam = xr.getCamera(this.context.mainCamera) as ArrayCamera;
417
+ const cam = xr.getCamera() as WebXRArrayCamera;
418
+ if(debugWebXR) console.log("WebXRCamera", cam);
419
419
  const cull = this.context.mainCameraComponent?.cullingMask;
420
- if(cull !== undefined){
420
+ if(cam && cull !== undefined){
421
421
  for (const c of cam.cameras) {
422
422
  c.layers.mask = cull;
423
423
  }
424
424
  cam.layers.mask = cull;
425
425
  }
426
- else {
426
+ else if (cam) {
427
427
  for (const c of cam.cameras) {
428
428
  c.layers.enableAll();
429
429
  }