Needle Engine

Changes between version 3.10.4-beta and 3.10.5-beta
Files changed (17) hide show
  1. src/engine-components/CameraUtils.ts +5 -1
  2. src/engine-components/CharacterController.ts +6 -1
  3. src/engine/engine_context.ts +4 -4
  4. src/engine/engine_input.ts +3 -0
  5. src/engine/engine_networking.ts +1 -0
  6. src/engine/engine_serialization_builtin_serializer.ts +4 -3
  7. src/engine/engine_utils_screenshot.ts +4 -3
  8. src/engine/extensions/NEEDLE_progressive.ts +1 -1
  9. src/engine/extensions/NEEDLE_techniques_webgl.ts +3 -3
  10. src/engine-components/OrbitControls.ts +10 -0
  11. src/engine-components/ParticleSystem.ts +1 -1
  12. src/engine-components-experimental/networking/PlayerSync.ts +25 -16
  13. src/engine-components/ui/RectTransform.ts +4 -4
  14. src/engine-components/Skybox.ts +2 -2
  15. src/engine-components/SpriteRenderer.ts +1 -1
  16. src/engine-components/export/usdz/ThreeUSDZExporter.ts +4 -3
  17. src/engine-components/VideoPlayer.ts +2 -2
src/engine-components/CameraUtils.ts CHANGED
@@ -34,7 +34,10 @@
34
34
  });
35
35
 
36
36
  ContextRegistry.registerCallback(ContextEvent.ContextCreated, (evt) => {
37
- if (!evt.context.mainCamera) return;
37
+ if (!evt.context.mainCamera) {
38
+ if(debug) console.log("Will not auto-fit because a default camera exists");
39
+ return;
40
+ }
38
41
 
39
42
  // check if the <needle-engine controls> is not set to false
40
43
  const engineElement = evt.context.domElement as NeedleEngineHTMLElement
@@ -44,6 +47,7 @@
44
47
  // Check if something else already acts as a camera controller
45
48
  const existing = getCameraController(evt.context.mainCamera);
46
49
  if (existing?.isCameraController === true) {
50
+ if(debug) console.log("Will not auto-fit because a camera controller exists");
47
51
  return;
48
52
  }
49
53
 
src/engine-components/CharacterController.ts CHANGED
@@ -27,6 +27,12 @@
27
27
  return this.rigidbody;
28
28
  }
29
29
 
30
+ private _activeGroundCollisions!: Set<Collision>;
31
+
32
+ awake(): void {
33
+ this._activeGroundCollisions = new Set<Collision>();
34
+ }
35
+
30
36
  onEnable() {
31
37
  let rb = this.rigidbody;
32
38
  let collider = this.gameObject.getComponent(CapsuleCollider);
@@ -53,7 +59,6 @@
53
59
  this.gameObject.position.add(vec);
54
60
  }
55
61
 
56
- private _activeGroundCollisions: Set<Collision> = new Set();
57
62
 
58
63
  onCollisionEnter(col: Collision) {
59
64
  for (const contact of col.contacts) {
src/engine/engine_context.ts CHANGED
@@ -375,13 +375,13 @@
375
375
  const height = this.domHeight * scaleFactor;
376
376
  const camera = this.mainCamera as PerspectiveCamera;
377
377
  this.updateAspect(camera);
378
- this.renderer.setSize(width, height);
378
+ this.renderer.setSize(width, height, true);
379
379
  this.renderer.setPixelRatio(window.devicePixelRatio);
380
380
  // avoid setting pixel values here since this can cause pingpong updates
381
381
  // e.g. when system scale is set to 125%
382
382
  // https://github.com/needle-tools/needle-engine-support/issues/69
383
- this.renderer.domElement.style.width = "100%";
384
- this.renderer.domElement.style.height = "100%";
383
+ // this.renderer.domElement.style.width = "100%";
384
+ // this.renderer.domElement.style.height = "100%";
385
385
  if (this.composer) {
386
386
  this.composer.setSize?.call(this.composer, width, height);
387
387
  if ("setPixelRatio" in this.composer && typeof this.composer.setPixelRatio === "function")
@@ -1028,7 +1028,7 @@
1028
1028
  }
1029
1029
  const rt = this._renderTarget;
1030
1030
  if (rt.texture) {
1031
- rt.texture.encoding = this.renderer.outputEncoding;
1031
+ rt.texture.colorSpace = this.renderer.outputColorSpace;
1032
1032
  }
1033
1033
  const prevTarget = this.renderer.getRenderTarget();
1034
1034
  this.renderer.setRenderTarget(rt);
src/engine/engine_input.ts CHANGED
@@ -297,10 +297,13 @@
297
297
  return ["Space"];
298
298
  }
299
299
  switch (keyName) {
300
+ case "shift":
300
301
  case "Shift":
301
302
  return ["ShiftLeft", "ShiftRight"];
303
+ case "control":
302
304
  case "Control":
303
305
  return ["ControlLeft", "ControlRight"];
306
+ case "alt":
304
307
  case "Alt":
305
308
  return ["AltLeft", "AltRight"];
306
309
  }
src/engine/engine_networking.ts CHANGED
@@ -39,6 +39,7 @@
39
39
  LeftRoom = "left-room",
40
40
  UserJoinedRoom = "user-joined-room",
41
41
  UserLeftRoom = "user-left-room",
42
+ RoomStateSent = "room-state-sent",
42
43
  }
43
44
 
44
45
  export class JoinedRoomResponse {
src/engine/engine_serialization_builtin_serializer.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  import { CallInfo, EventList } from "../engine-components/EventList";
7
7
  import { Color, Object3D, Texture, WebGLRenderTarget } from "three";
8
8
  import { RenderTexture } from "./engine_texture";
9
- import { isDevEnvironment } from "../engine/debug/debug";
9
+ import { isDevEnvironment, showBalloonMessage, showBalloonWarning } from "../engine/debug/debug";
10
10
  import { resolveUrl } from "./engine_utils";
11
11
 
12
12
  // export class SourcePath {
@@ -241,9 +241,10 @@
241
241
  const hasMethod = call.method?.length > 0;
242
242
  if (target && hasMethod) {
243
243
  const printWarningMethodNotFound = () => {
244
- const uppercaseMethodName = call.method[0].toLowerCase() + call.method.slice(1);
244
+ const uppercaseMethodName = call.method[0].toUpperCase() + call.method.slice(1);
245
245
  if (typeof target[uppercaseMethodName] === "function") {
246
- console.warn(`Could not find method ${call.method} on object ${target.name}. Please rename ${call.method} to ${uppercaseMethodName}?`, target, typeof target[call.method]);
246
+ console.warn(`Could not find method ${call.method} on object ${target.name}. Please rename ${call.method} to ${uppercaseMethodName}?`, target[uppercaseMethodName], " in script: ", target);
247
+ showBalloonWarning("EventList methods must start with lowercase letter, see console for details");
247
248
  return;
248
249
  }
249
250
  else {
src/engine/engine_utils_screenshot.ts CHANGED
@@ -19,8 +19,9 @@
19
19
  const canvas = context.renderer.domElement;
20
20
 
21
21
  // set the desired output size
22
- context.renderer.setSize(width, height);
23
- // update the camera apsect and matrix
22
+ context.renderer.setSize(width, height, false);
23
+
24
+ // update the camera aspect and matrix
24
25
  if (camera instanceof PerspectiveCamera)
25
26
  context.updateAspect(camera, width, height);
26
27
 
@@ -33,7 +34,7 @@
33
34
  return dataUrl;
34
35
  }
35
36
  finally {
36
- context.renderer.setSize(prevWidth, prevHeight);
37
+ context.renderer.setSize(prevWidth, prevHeight, false);
37
38
  context.updateSize();
38
39
  }
39
40
 
src/engine/extensions/NEEDLE_progressive.ts CHANGED
@@ -251,7 +251,7 @@
251
251
  (tex as any).guid = progressiveInfo.guid;
252
252
  tex.flipY = false;
253
253
  tex.needsUpdate = true;
254
- tex.encoding = current.encoding;
254
+ tex.colorSpace = current.colorSpace;
255
255
  if (debug)
256
256
  console.log(progressiveInfo, tex);
257
257
  }
src/engine/extensions/NEEDLE_techniques_webgl.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { GLTFLoaderPlugin, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader";
2
2
  import { FindShaderTechniques, whiteDefaultTexture, ToUnityMatrixArray, SetUnitySphericalHarmonics } from '../engine_shaders';
3
- import { AlwaysDepth, BackSide, Camera, DoubleSide, EqualDepth, FrontSide, GLSL3, GreaterDepth, GreaterEqualDepth, IUniform, LessDepth, LessEqualDepth, LinearEncoding, Material, Matrix4, NotEqualDepth, Object3D, RawShaderMaterial, Vector3, Vector4 } from 'three';
3
+ import { AlwaysDepth, BackSide, Camera, DoubleSide, EqualDepth, FrontSide, GLSL3, GreaterDepth, GreaterEqualDepth, IUniform, LessDepth, LessEqualDepth, LinearEncoding, LinearSRGBColorSpace, Material, Matrix4, NotEqualDepth, Object3D, RawShaderMaterial, Texture, Vector3, Vector4 } from 'three';
4
4
  import { Context } from '../engine_setup';
5
5
  import { getParam } from "../engine_utils";
6
6
  import * as SHADERDATA from "../shaders/shaderData"
@@ -420,8 +420,8 @@
420
420
  const texIndex = Number.parseInt(indexString);
421
421
  if (texIndex >= 0) {
422
422
  const tex = await this.parser.getDependency("texture", texIndex);
423
- if (tex) {
424
- tex.encoding = LinearEncoding;
423
+ if (tex instanceof Texture) {
424
+ tex.colorSpace = LinearSRGBColorSpace;
425
425
  tex.needsUpdate = true;
426
426
  }
427
427
  uniforms[key] = { value: tex };
src/engine-components/OrbitControls.ts CHANGED
@@ -12,6 +12,7 @@
12
12
  import { ICameraController } from "../engine/engine_types";
13
13
  import { setCameraController } from "../engine/engine_camera";
14
14
  import { SyncedTransform } from "./SyncedTransform";
15
+ import { tryGetUIComponent } from "./ui/Utils";
15
16
 
16
17
  const freeCam = getParam("freecam");
17
18
  const debugCameraFit = getParam("debugcamerafit");
@@ -336,6 +337,14 @@
336
337
  const rc = this.context.physics.raycast();
337
338
  for (const hit of rc) {
338
339
  if (hit.distance > 0 && GameObject.isActiveInHierarchy(hit.object)) {
340
+
341
+ const uiComponent = tryGetUIComponent(hit.object);
342
+ if (uiComponent) {
343
+ const canvas = uiComponent.canvas;
344
+ if (canvas?.screenspace) {
345
+ break;
346
+ }
347
+ }
339
348
  // if (hit.object && hit.object.parent) {
340
349
  // const par: any = hit.object.parent;
341
350
  // if (par.isUI) continue;
@@ -380,6 +389,7 @@
380
389
  // ignore Box3Helpers
381
390
  if (object instanceof Box3Helper) continue;
382
391
  if (object instanceof GridHelper) continue;
392
+ object.updateMatrixWorld();
383
393
  box.expandByObject(object, true);
384
394
  }
385
395
 
src/engine-components/ParticleSystem.ts CHANGED
@@ -586,7 +586,7 @@
586
586
  if (mat && mat["map"]) {
587
587
  const tex = mat["map"]!;
588
588
  tex.premultiplyAlpha = false;
589
- tex.encoding = THREE.LinearEncoding;
589
+ tex.colorSpace = THREE.LinearSRGBColorSpace;
590
590
  return tex;
591
591
  }
592
592
  return createFlatTexture(new RGBAColor(1, 1, 1, 1), 1)
src/engine-components-experimental/networking/PlayerSync.ts CHANGED
@@ -7,34 +7,38 @@
7
7
  import { getParam } from "../../engine/engine_utils";
8
8
 
9
9
  import { Object3D } from "three";
10
+ import { EventList } from "../../engine-components/EventList";
10
11
 
12
+
11
13
  const debug = getParam("debugplayersync");
12
14
 
13
15
  export class PlayerSync extends Behaviour {
14
16
  @serializable(AssetReference)
15
17
  asset?: AssetReference;
16
18
 
17
- private joinedRoomFunction?: Function;
19
+ @serializable(EventList)
20
+ onPlayerSpawned?: EventList;
18
21
 
19
22
  awake(): void {
20
23
  this.watchTabVisible();
21
- this.joinedRoomFunction = this.onUserJoined.bind(this);
22
24
  }
23
25
 
24
26
  onEnable(): void {
25
- this.context.connection.beginListen(RoomEvents.JoinedRoom, this.joinedRoomFunction!)
27
+ this.context.connection.beginListen(RoomEvents.RoomStateSent, this.onJoinedRoom);
26
28
  }
27
29
  onDisable(): void {
28
- this.context.connection.stopListen(RoomEvents.JoinedRoom, this.joinedRoomFunction!)
30
+ this.context.connection.stopListen(RoomEvents.RoomStateSent, this.onJoinedRoom)
29
31
  }
30
32
 
31
- private async onUserJoined(_model) {
33
+ private onJoinedRoom = async (_model) => {
32
34
  if (debug) console.log("PlayerSync.onUserJoined", _model);
35
+
33
36
  const instance = await this.asset?.instantiateSynced({ parent: this.gameObject }, true);
34
37
  if (instance) {
35
38
  let pl = GameObject.getComponent(instance, PlayerState);
36
39
  if (pl) {
37
40
  pl.owner = this.context.connection.connectionId!;
41
+ this.onPlayerSpawned?.invoke(instance);
38
42
  }
39
43
  else {
40
44
  console.error("<strong>Failed finding PlayerState on " + this.asset?.uri + "</strong>: please make sure the asset has a PlayerState component!");
@@ -44,15 +48,6 @@
44
48
  else{
45
49
  console.warn("PlayerSync: failed instantiating asset!")
46
50
  }
47
-
48
- // TODO: previously created instances are not re-created when re-joining room
49
- // const inRoom = this.context.connection.usersInRoom();
50
- // console.log(inRoom);
51
- // for (const user of inRoom) {
52
- // if(user !== this.context.connection.connectionId) {
53
- // console.log(this.context.connection.tryGetState(this.asset.uri))
54
- // }
55
- // }
56
51
  }
57
52
 
58
53
  private watchTabVisible() {
@@ -130,7 +125,12 @@
130
125
  }
131
126
  }
132
127
 
133
- @syncField("onOwnerChange")
128
+
129
+ public onOwnerChangeEvent = new EventList();
130
+ public onFirstOwnerChangeEvent = new EventList();
131
+ public hasOwner = false;
132
+
133
+ @syncField(PlayerState.prototype.onOwnerChange)
134
134
  owner?: string;
135
135
 
136
136
  get isLocalPlayer(): boolean {
@@ -151,6 +151,15 @@
151
151
  newValue: newOwner
152
152
  }
153
153
 
154
+ // call local events
155
+ if(!this.hasOwner) {
156
+ this.hasOwner = true;
157
+ this.onFirstOwnerChangeEvent?.invoke(detail);
158
+ }
159
+
160
+ this.onOwnerChangeEvent?.invoke(detail);
161
+
162
+ // call remote events
154
163
  if (this.owner === this.context.connection.connectionId) {
155
164
  PlayerState._local.push(this);
156
165
  // console.warn(this.gameObject.guid, this.guid, this.owner, this.isLocalPlayer, PlayerState.isLocalPlayer(this));
@@ -164,7 +173,7 @@
164
173
  }
165
174
 
166
175
  awake(): void {
167
- PlayerState.all.push(this);
176
+ PlayerState.all.push(this);
168
177
  if(debug) console.log("Registered new PlayerState", this, PlayerState.all.length-1, PlayerState.all)
169
178
 
170
179
  this.context.connection.beginListen(RoomEvents.UserLeftRoom, (model: { userId: string }) => {
src/engine-components/ui/RectTransform.ts CHANGED
@@ -63,10 +63,10 @@
63
63
  @serializable(Vector2)
64
64
  anchorMax: Vector2 = new Vector2(1, 1);
65
65
 
66
- @serializable(Vector2)
67
- offsetMin: Vector2 = new Vector2(0, 0);
68
- @serializable(Vector2)
69
- offsetMax: Vector2 = new Vector2(0, 0);
66
+ // @serializable(Vector2)
67
+ // offsetMin: Vector2 = new Vector2(0, 0);
68
+ // @serializable(Vector2)
69
+ // offsetMax: Vector2 = new Vector2(0, 0);
70
70
 
71
71
  get width() {
72
72
  if (this.anchorMin.x !== this.anchorMax.x) {
src/engine-components/Skybox.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  import { Behaviour, GameObject } from "./Component";
3
3
  import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
4
4
  import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader";
5
- import { EquirectangularRefractionMapping, NeverDepth, sRGBEncoding, Texture, TextureLoader } from "three"
5
+ import { EquirectangularRefractionMapping, NeverDepth, SRGBColorSpace, sRGBEncoding, Texture, TextureLoader } from "three"
6
6
  import { syncField } from "../engine/engine_networking_auto";
7
7
  import { Camera } from "./Camera";
8
8
  import { addAttributeChangeCallback, getParam, removeAttributeChangeCallback } from "../engine/engine_utils";
@@ -164,7 +164,7 @@
164
164
  const nameIndex = url.lastIndexOf("/");
165
165
  envMap.name = url.substring(nameIndex >= 0 ? nameIndex + 1 : 0);
166
166
  if (this._loader instanceof TextureLoader) {
167
- envMap.encoding = sRGBEncoding;
167
+ envMap.colorSpace = SRGBColorSpace;
168
168
  }
169
169
  this._prevLoadedEnvironment = envMap;
170
170
  this.applySkybox();
src/engine-components/SpriteRenderer.ts CHANGED
@@ -108,7 +108,7 @@
108
108
  const slice = this.spriteSheet.sprites[index];
109
109
  let tex = slice?.texture;
110
110
  if (!tex) return;
111
- tex.encoding = THREE.sRGBEncoding;
111
+ tex.colorSpace = THREE.SRGBColorSpace;
112
112
  if (tex.minFilter == NearestFilter && tex.magFilter == NearestFilter)
113
113
  tex.anisotropy = 1;
114
114
  tex.needsUpdate = true;
src/engine-components/export/usdz/ThreeUSDZExporter.ts CHANGED
@@ -24,6 +24,7 @@
24
24
  Object3D,
25
25
  MeshBasicMaterial,
26
26
  SkinnedMesh,
27
+ SRGBColorSpace,
27
28
  } from 'three';
28
29
  import * as fflate from 'three/examples/jsm/libs/fflate.module.js';
29
30
 
@@ -716,7 +717,7 @@
716
717
 
717
718
  }
718
719
 
719
- function copyTexture( texture ) {
720
+ function copyTexture( texture : Texture ) {
720
721
 
721
722
  const geometry = new PlaneGeometry( 2, 2, 1, 1 );
722
723
  const material = new ShaderMaterial( {
@@ -724,7 +725,7 @@
724
725
  blitTexture: new Uniform( texture ),
725
726
  },
726
727
  defines: {
727
- IS_SRGB: texture.encoding == sRGBEncoding,
728
+ IS_SRGB: texture.colorSpace == SRGBColorSpace,
728
729
  },
729
730
  vertexShader: `
730
731
  varying vec2 vUv;
@@ -764,7 +765,7 @@
764
765
  renderer.render( scene, cam );
765
766
 
766
767
  const tex = new Texture( renderer.domElement );
767
- tex.encoding = texture.encoding;
768
+ tex.colorSpace = texture.colorSpace;
768
769
  return tex;
769
770
 
770
771
  }
src/engine-components/VideoPlayer.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Behaviour, GameObject } from "./Component";
2
2
  import { serializable } from "../engine/engine_serialization_decorator";
3
- import { Material, Mesh, Object3D, ShaderMaterial, sRGBEncoding, Texture, Vector2, Vector4, VideoTexture } from "three";
3
+ import { Material, Mesh, Object3D, ShaderMaterial, SRGBColorSpace, sRGBEncoding, Texture, Vector2, Vector4, VideoTexture } from "three";
4
4
  import { awaitInput } from "../engine/engine_input_utils";
5
5
  import { getParam } from "../engine/engine_utils";
6
6
  import { Renderer } from "./Renderer";
@@ -344,7 +344,7 @@
344
344
  if (!this._videoTexture)
345
345
  this._videoTexture = new VideoTexture(this._videoElement);
346
346
  this._videoTexture.flipY = false;
347
- this._videoTexture.encoding = sRGBEncoding;
347
+ this._videoTexture.colorSpace = SRGBColorSpace;
348
348
  this.handleBeginPlaying(playAutomatically);
349
349
  if (debug)
350
350
  console.log(this, playAutomatically);