@needle-tools/engine 3.5.5-alpha.1 → 3.5.7-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 (68) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/needle-engine.js +14494 -14367
  3. package/dist/needle-engine.light.js +82420 -0
  4. package/dist/needle-engine.light.min.js +5057 -0
  5. package/dist/needle-engine.light.umd.cjs +5057 -0
  6. package/dist/needle-engine.min.js +331 -329
  7. package/dist/needle-engine.umd.cjs +327 -325
  8. package/lib/engine/engine_addressables.js +2 -2
  9. package/lib/engine/engine_addressables.js.map +1 -1
  10. package/lib/engine/engine_components.d.ts +2 -2
  11. package/lib/engine/engine_components.js +7 -2
  12. package/lib/engine/engine_components.js.map +1 -1
  13. package/lib/engine/engine_networking.d.ts +6 -3
  14. package/lib/engine/engine_networking.js +57 -30
  15. package/lib/engine/engine_networking.js.map +1 -1
  16. package/lib/engine-components/Component.d.ts +3 -0
  17. package/lib/engine-components/Component.js.map +1 -1
  18. package/lib/engine-components/SyncedRoom.d.ts +3 -0
  19. package/lib/engine-components/SyncedRoom.js +10 -6
  20. package/lib/engine-components/SyncedRoom.js.map +1 -1
  21. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +5 -3
  22. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -1
  23. package/lib/engine-components/export/usdz/USDZExporter.js +2 -1
  24. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  25. package/lib/engine-components/export/usdz/extensions/USDZText.d.ts +10 -3
  26. package/lib/engine-components/export/usdz/extensions/USDZText.js +88 -8
  27. package/lib/engine-components/export/usdz/extensions/USDZText.js.map +1 -1
  28. package/lib/engine-components/js-extensions/Object3D.js +4 -1
  29. package/lib/engine-components/js-extensions/Object3D.js.map +1 -1
  30. package/lib/engine-components/ui/Button.js +10 -0
  31. package/lib/engine-components/ui/Button.js.map +1 -1
  32. package/lib/engine-components/ui/Canvas.js +3 -2
  33. package/lib/engine-components/ui/Canvas.js.map +1 -1
  34. package/lib/engine-components/ui/CanvasGroup.js +5 -5
  35. package/lib/engine-components/ui/CanvasGroup.js.map +1 -1
  36. package/lib/engine-components/ui/Graphic.d.ts +3 -0
  37. package/lib/engine-components/ui/Graphic.js +19 -5
  38. package/lib/engine-components/ui/Graphic.js.map +1 -1
  39. package/lib/engine-components/ui/Interfaces.d.ts +4 -1
  40. package/lib/engine-components/ui/Interfaces.js.map +1 -1
  41. package/lib/engine-components/ui/RectTransform.d.ts +3 -1
  42. package/lib/engine-components/ui/RectTransform.js +22 -22
  43. package/lib/engine-components/ui/RectTransform.js.map +1 -1
  44. package/lib/engine-components/ui/Text.d.ts +3 -1
  45. package/lib/engine-components/ui/Text.js +6 -0
  46. package/lib/engine-components/ui/Text.js.map +1 -1
  47. package/lib/engine-components/webxr/WebXR.js +1 -2
  48. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  49. package/lib/tsconfig.tsbuildinfo +1 -1
  50. package/package.json +3 -2
  51. package/src/engine/engine_addressables.ts +1 -1
  52. package/src/engine/engine_components.ts +7 -2
  53. package/src/engine/engine_networking.ts +65 -34
  54. package/src/engine-components/Component.ts +3 -1
  55. package/src/engine-components/ParticleSystemModules.ts +1483 -1483
  56. package/src/engine-components/SyncedRoom.ts +11 -9
  57. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +9 -6
  58. package/src/engine-components/export/usdz/USDZExporter.ts +2 -1
  59. package/src/engine-components/export/usdz/extensions/USDZText.ts +99 -11
  60. package/src/engine-components/js-extensions/Object3D.ts +5 -1
  61. package/src/engine-components/ui/Button.ts +5 -0
  62. package/src/engine-components/ui/Canvas.ts +3 -2
  63. package/src/engine-components/ui/CanvasGroup.ts +7 -6
  64. package/src/engine-components/ui/Graphic.ts +27 -15
  65. package/src/engine-components/ui/Interfaces.ts +5 -1
  66. package/src/engine-components/ui/RectTransform.ts +32 -28
  67. package/src/engine-components/ui/Text.ts +9 -4
  68. package/src/engine-components/webxr/WebXR.ts +1 -1
@@ -1,6 +1,7 @@
1
1
  import { Behaviour } from "./Component";
2
2
  import * as utils from "../engine/engine_utils"
3
3
  import { serializable } from "../engine/engine_serialization_decorator";
4
+ import { getParam } from "../engine/engine_utils";
4
5
 
5
6
  const viewParamName = "view";
6
7
  const debug = utils.getParam("debugsyncedroom");
@@ -40,7 +41,9 @@ export class SyncedRoom extends Behaviour {
40
41
  this.context.connection.joinRoom(viewId, true);
41
42
  return;
42
43
  }
43
- this.tryJoinRoom();
44
+ // If setup to join a random room
45
+ if (this.joinRandomRoom || getParam(this.urlParameterName))
46
+ this.tryJoinRoom();
44
47
  }
45
48
 
46
49
  onDisable(): void {
@@ -48,6 +51,13 @@ export class SyncedRoom extends Behaviour {
48
51
  this.context.connection.leaveRoom(this.roomName);
49
52
  }
50
53
 
54
+ /** Will generate a random room name, set it as an URL parameter and attempt to join the room */
55
+ tryJoinRandomRoom() {
56
+ this.setRandomRoomUrlParameter();
57
+ this.tryJoinRoom();
58
+ }
59
+
60
+ /** Try to join the currently set roomName */
51
61
  tryJoinRoom(call: number = 0): boolean {
52
62
  if (call === undefined) call = 0;
53
63
  let hasRoomParameter = false;
@@ -78,12 +88,6 @@ export class SyncedRoom extends Behaviour {
78
88
  return false;
79
89
  }
80
90
 
81
- if (!this.roomName || this.roomName.length <= 0) {
82
- if (debug)
83
- console.error("Missing room name on \"" + this.name + "\". Make sure this is correctly configured in Unity", this.context.connection.isDebugEnabled ? this : "");
84
- return false;
85
- }
86
-
87
91
  if (!this.context.connection.isConnected) {
88
92
  this.context.connection.connect();
89
93
  }
@@ -157,8 +161,6 @@ export class SyncedRoom extends Behaviour {
157
161
  urlParams.set(viewParamName, this.context.connection.currentRoomViewId);
158
162
  return window.location.origin + window.location.pathname + "?" + urlParams.toString();
159
163
  }
160
-
161
-
162
164
  return null;
163
165
  }
164
166
  }
@@ -661,12 +661,6 @@ function addResources( object, context: USDZExporterContext ) {
661
661
 
662
662
  }
663
663
 
664
- if ( ! ( material.uuid in context.materials ) ) {
665
-
666
- context.materials[ material.uuid ] = material;
667
-
668
- }
669
-
670
664
  } else {
671
665
 
672
666
  console.warn( 'THREE.USDZExporter: Unsupported material type (USDZ only supports MeshStandardMaterial)', name );
@@ -675,6 +669,15 @@ function addResources( object, context: USDZExporterContext ) {
675
669
 
676
670
  }
677
671
 
672
+ if( material ) {
673
+
674
+ if ( ! ( material.uuid in context.materials ) ) {
675
+
676
+ context.materials[ material.uuid ] = material;
677
+
678
+ }
679
+ }
680
+
678
681
  for ( const ch of object.children ) {
679
682
 
680
683
  addResources( ch, context );
@@ -15,6 +15,7 @@ import { WebARSessionRoot } from "../../webxr/WebARSessionRoot";
15
15
  import { hasProLicense } from "../../../engine/engine_license";
16
16
  import { BehaviorExtension } from "./extensions/behavior/Behaviour";
17
17
  import { AudioExtension } from "./extensions/behavior/AudioExtension";
18
+ import { TextExtension } from "./extensions/USDZText";
18
19
 
19
20
  const debug = getParam("debugusdz");
20
21
 
@@ -66,7 +67,6 @@ export class USDZExporter extends Behaviour {
66
67
  private webARSessionRoot: WebARSessionRoot | undefined;
67
68
 
68
69
  start() {
69
- console.log(this.customUsdzFile);
70
70
  if (debug) {
71
71
  console.log(this);
72
72
  console.log("Debug USDZ, press 't' to export")
@@ -97,6 +97,7 @@ export class USDZExporter extends Behaviour {
97
97
  if (this.interactive) {
98
98
  this.extensions.push(new BehaviorExtension());
99
99
  this.extensions.push(new AudioExtension());
100
+ this.extensions.push(new TextExtension());
100
101
  }
101
102
  }
102
103
 
@@ -1,5 +1,11 @@
1
+ import { IUSDExporterExtension } from "../Extension";
1
2
  import { IBehaviorElement } from "../extensions/behavior/BehavioursBuilder";
2
- import { USDDocument, USDWriter } from "../ThreeUSDZExporter";
3
+ import { USDDocument, USDObject, USDWriter, USDZExporterContext } from "../ThreeUSDZExporter";
4
+ import { GameObject } from "../../../Component";
5
+ import { Text } from "../../../ui/Text"
6
+ import { RectTransform } from "../../../ui/RectTransform";
7
+ import { Color, Material, Matrix4, MeshStandardMaterial, Object3D, Vector3 } from "three";
8
+ import { TextAnchor } from "../../../ui/Text";
3
9
 
4
10
 
5
11
  export enum TextWrapMode {
@@ -41,6 +47,8 @@ export class USDZText implements IBehaviorElement {
41
47
  horizontalAlignment?: HorizontalAlignment;
42
48
  verticalAlignment?: VerticalAlignment;
43
49
 
50
+ material?: Material;
51
+
44
52
  setDepth(depth: number): USDZText {
45
53
  this.depth = depth;
46
54
  return this;
@@ -94,6 +102,10 @@ export class USDZText implements IBehaviorElement {
94
102
  if (this.verticalAlignment)
95
103
  writer.appendLine(`token verticalAlignment = "${this.verticalAlignment}"`);
96
104
 
105
+ if (this.material !== undefined) {
106
+ writer.appendLine(`rel material:binding = </Materials/Material_${this.material.id}>`)
107
+ }
108
+
97
109
  writer.closeBlock();
98
110
 
99
111
  }
@@ -120,22 +132,98 @@ export class TextBuilder {
120
132
  text.height = height;
121
133
  text.horizontalAlignment = horizontal;
122
134
  text.verticalAlignment = vertical;
123
- if (wrapMode)
135
+ if (wrapMode !== undefined)
124
136
  text.wrapMode = wrapMode;
125
137
  return text;
126
138
  }
127
139
  }
128
140
 
141
+ const rotateYAxisMatrix = new Matrix4().makeRotationY(Math.PI);
142
+
143
+ export class TextExtension implements IUSDExporterExtension {
144
+ get extensionName(): string {
145
+ return "text";
146
+ }
147
+
148
+ onExportObject(object: Object3D, model: USDObject, _context: USDZExporterContext) {
149
+
150
+ const text = GameObject.getComponent(object, Text);
151
+ if (text) {
152
+ const rt = GameObject.getComponent(object, RectTransform);
153
+ let width = 100;
154
+ let height = 100;
155
+ if (rt) {
156
+ width = rt.width;
157
+ height = rt.height;
158
+ }
159
+ const newModel = model.clone();
160
+ newModel.matrix = rotateYAxisMatrix.clone();
161
+ const color = new Color().copySRGBToLinear(text.color);
162
+ newModel.material = new MeshStandardMaterial({ color: color, emissive: color });
163
+ model.add(newModel);
164
+
165
+ // model.matrix.scale(new Vector3(100, 100, 100));
166
+ newModel.addEventListener("serialize", (writer: USDWriter, _context: USDZExporterContext) => {
167
+ const textObj = TextBuilder.multiLine(text.text, width, height, HorizontalAlignment.center, VerticalAlignment.bottom, TextWrapMode.flowing);
168
+ this.setTextAlignment(textObj, text.alignment);
169
+ this.setOverflow(textObj, text);
170
+ if (newModel.material)
171
+ textObj.material = newModel.material;
172
+ textObj.pointSize = this.convertToTextSize(text.fontSize);
173
+ textObj.depth = .001;
174
+ textObj.writeTo(undefined, writer);
175
+ });
176
+ }
177
+ }
178
+
179
+ private convertToTextSize(pixel: number) {
180
+ return 1 / 0.0502 * 144 * pixel;
181
+ }
182
+
183
+ private setOverflow(textObj: USDZText, text: Text) {
184
+ if (text.horizontalOverflow) {
185
+ textObj.wrapMode = TextWrapMode.singleLine;
186
+ }
187
+ else {
188
+ textObj.wrapMode = TextWrapMode.flowing;
189
+ }
190
+ }
129
191
 
130
- export class TextExtension {
131
- onExportObject(_object, model, _context) {
132
- model.addEventListener("serialize", (writer, _context) => {
133
- const text = TextBuilder.multiLine("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
134
- 1, 1, HorizontalAlignment.justified, VerticalAlignment.top);
135
- text.pointSize = 300;
136
- text.depth = .01;
137
- text.writeTo(undefined, writer);
138
- });
192
+ private setTextAlignment(text: USDZText, alignment: TextAnchor) {
193
+ switch (alignment) {
194
+ case TextAnchor.LowerLeft:
195
+ case TextAnchor.MiddleLeft:
196
+ case TextAnchor.UpperLeft:
197
+ text.horizontalAlignment = HorizontalAlignment.left;
198
+ break;
199
+ case TextAnchor.LowerCenter:
200
+ case TextAnchor.MiddleCenter:
201
+ case TextAnchor.UpperCenter:
202
+ text.horizontalAlignment = HorizontalAlignment.center;
203
+ break;
204
+ case TextAnchor.LowerRight:
205
+ case TextAnchor.MiddleRight:
206
+ case TextAnchor.UpperRight:
207
+ text.horizontalAlignment = HorizontalAlignment.right;
208
+ break;
209
+ }
210
+ switch (alignment) {
211
+ case TextAnchor.LowerLeft:
212
+ case TextAnchor.LowerCenter:
213
+ case TextAnchor.LowerRight:
214
+ text.verticalAlignment = VerticalAlignment.bottom;
215
+ break;
216
+ case TextAnchor.MiddleLeft:
217
+ case TextAnchor.MiddleCenter:
218
+ case TextAnchor.MiddleRight:
219
+ text.verticalAlignment = VerticalAlignment.middle;
220
+ break;
221
+ case TextAnchor.UpperLeft:
222
+ case TextAnchor.UpperCenter:
223
+ case TextAnchor.UpperRight:
224
+ text.verticalAlignment = VerticalAlignment.top;
225
+ break;
226
+ }
139
227
  }
140
228
  }
141
229
 
@@ -2,7 +2,7 @@ import { applyPrototypeExtensions, registerPrototypeExtensions } from "./Extensi
2
2
  import { Object3D } from "three";
3
3
  import { Constructor, ConstructorConcrete, IComponent } from "../../engine/engine_types"
4
4
  import { IComponent as Component } from "../../engine/engine_types";
5
- import { addNewComponent, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, removeComponent } from "../../engine/engine_components";
5
+ import { moveComponentInstance, addNewComponent, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, removeComponent } from "../../engine/engine_components";
6
6
  import { isActiveSelf, setActive, destroy } from "../../engine/engine_gameobject";
7
7
 
8
8
  // used to decorate cloned object3D objects with the same added components defined above
@@ -24,6 +24,10 @@ Object3D.prototype["destroy"] = function () {
24
24
  destroy(this);
25
25
  }
26
26
 
27
+ Object3D.prototype["addComponent"] = function <T extends IComponent>(instance: T) {
28
+ return moveComponentInstance(this, instance);
29
+ }
30
+
27
31
  Object3D.prototype["addNewComponent"] = function <T extends Component>(type: ConstructorConcrete<T>) {
28
32
  return addNewComponent(this, new type());
29
33
  }
@@ -68,6 +68,7 @@ export class Button extends Behaviour implements IPointerEventHandler {
68
68
  if (debug)
69
69
  console.log("Button Enter", this.animationTriggers?.highlightedTrigger, this.animator);
70
70
  this._isHovered = true;
71
+ if (!this.interactable) return;
71
72
  if (this.transition == Transition.Animation && this.animationTriggers && this.animator) {
72
73
  this.animator.setTrigger(this.animationTriggers.highlightedTrigger);
73
74
  }
@@ -81,6 +82,7 @@ export class Button extends Behaviour implements IPointerEventHandler {
81
82
  if (debug)
82
83
  console.log("Button Exit", this.animationTriggers?.highlightedTrigger, this.animator);
83
84
  this._isHovered = false;
85
+ if (!this.interactable) return;
84
86
  if (this.transition == Transition.Animation && this.animationTriggers && this.animator) {
85
87
  this.animator.setTrigger(this.animationTriggers.normalTrigger);
86
88
  }
@@ -93,6 +95,7 @@ export class Button extends Behaviour implements IPointerEventHandler {
93
95
  onPointerDown(_) {
94
96
  if (debug)
95
97
  console.log("Button Down", this.animationTriggers?.highlightedTrigger, this.animator);
98
+ if (!this.interactable) return;
96
99
  if (this.transition == Transition.Animation && this.animationTriggers && this.animator) {
97
100
  this.animator.setTrigger(this.animationTriggers.pressedTrigger);
98
101
  }
@@ -104,6 +107,7 @@ export class Button extends Behaviour implements IPointerEventHandler {
104
107
  onPointerUp(_) {
105
108
  if (debug)
106
109
  console.warn("Button Up", this.animationTriggers?.highlightedTrigger, this.animator, this._isHovered);
110
+ if (!this.interactable) return;
107
111
  if (this.transition == Transition.Animation && this.animationTriggers && this.animator) {
108
112
  this.animator.setTrigger(this._isHovered ? this.animationTriggers.highlightedTrigger : this.animationTriggers.normalTrigger);
109
113
  }
@@ -113,6 +117,7 @@ export class Button extends Behaviour implements IPointerEventHandler {
113
117
  }
114
118
 
115
119
  onPointerClick(_args: PointerEventData) {
120
+ if (!this.interactable) return;
116
121
  if (debug) {
117
122
  console.warn("Button Click", this.onClick);
118
123
  showBalloonMessage("CLICKED button " + this.name + " at " + this.context.time.frameCount);
@@ -208,7 +208,7 @@ export class Canvas extends UIRootComponent implements ICanvas {
208
208
  }
209
209
 
210
210
  onAfterRenderRoutine = () => {
211
- if ((this.screenspace || this.renderMode) && this.previousParent && this.context.mainCamera) {
211
+ if ((this.screenspace || this.renderOnTop) && this.previousParent && this.context.mainCamera) {
212
212
  if (this.screenspace) {
213
213
  const camObj = this.context.mainCamera;
214
214
  camObj?.add(this.gameObject);
@@ -293,7 +293,8 @@ export class Canvas extends UIRootComponent implements ICanvas {
293
293
  let camera = this.context.mainCameraComponent;
294
294
  let planeDistance: number = 10;
295
295
  if (camera && camera.nearClipPlane > 0 && camera.farClipPlane > 0) {
296
- planeDistance = Mathf.lerp(camera.nearClipPlane, camera.farClipPlane, .5);
296
+ // TODO: this is a hack/workaround for event system currently only passing events to the nearest object
297
+ planeDistance = Mathf.lerp(camera.nearClipPlane, camera.farClipPlane, .15);
297
298
  }
298
299
  if (this._renderMode === RenderMode.ScreenSpaceCamera) {
299
300
  if (this.worldCamera)
@@ -1,8 +1,9 @@
1
1
  import { Graphic } from "./Graphic";
2
2
  import { FrameEvent } from "../../engine/engine_setup";
3
3
  import { Behaviour, GameObject } from "../Component";
4
- import { ICanvasGroup } from "./Interfaces";
4
+ import { ICanvasGroup, IHasAlphaFactor } from "./Interfaces";
5
5
  import { serializable } from "../../engine/engine_serialization_decorator";
6
+ import { BaseUIComponent } from "./BaseUIComponent";
6
7
 
7
8
 
8
9
  export class CanvasGroup extends Behaviour implements ICanvasGroup {
@@ -38,12 +39,12 @@ export class CanvasGroup extends Behaviour implements ICanvasGroup {
38
39
  this.applyChangesNow();
39
40
  }
40
41
 
41
- private _buffer : Graphic[] = [];
42
+ private _buffer: Graphic[] = [];
42
43
  private applyChangesNow() {
43
- for (const ch of GameObject.getComponentsInChildren(this.gameObject, Graphic, this._buffer)) {
44
- const col = ch.color;
45
- col.alpha = this._alpha;
46
- ch.color = col;
44
+ for (const ch of GameObject.getComponentsInChildren(this.gameObject, BaseUIComponent, this._buffer)) {
45
+ const hasAlphaFactor = ch as any as IHasAlphaFactor;
46
+ if (hasAlphaFactor.setAlphaFactor)
47
+ hasAlphaFactor.setAlphaFactor(this._alpha);
47
48
  }
48
49
  }
49
50
  }
@@ -9,12 +9,12 @@ import { onChange, scheduleAction } from "./Utils"
9
9
  import { GameObject } from '../Component';
10
10
  import SimpleStateBehavior from "three-mesh-ui/examples/behaviors/states/SimpleStateBehavior"
11
11
  import { Outline } from './Outline';
12
- import { BehaviorExtension, UsdzBehaviour } from '../../engine-components/export/usdz/extensions/behavior/Behaviour';
13
- import { USDObject } from '../../engine-components/export/usdz/ThreeUSDZExporter';
14
12
 
15
- const _colorStateObject: { backgroundColor: Color, backgroundOpacity: number } = {
13
+ const _colorStateObject: { backgroundColor: Color, backgroundOpacity: number, borderColor: Color, borderOpacity: number } = {
16
14
  backgroundColor: new Color(1, 1, 1),
17
15
  backgroundOpacity: 1,
16
+ borderColor: new Color(1, 1, 1),
17
+ borderOpacity: 1,
18
18
  };
19
19
 
20
20
  export class Graphic extends BaseUIComponent implements IGraphic, IRectTransformChangedReceiver {
@@ -35,10 +35,23 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
35
35
  this._color.copy(col);
36
36
  }
37
37
 
38
+ private _alphaFactor: number = 1;
39
+ setAlphaFactor(factor: number) {
40
+ this._alphaFactor = factor;
41
+ this.onColorChanged();
42
+ }
43
+ get alphaFactor() {
44
+ return this._alphaFactor;
45
+ }
46
+
38
47
  protected onColorChanged() {
39
- _colorStateObject.backgroundColor = this._color;
40
- _colorStateObject.backgroundOpacity = this._color.alpha;
41
- this.uiObject?.set(_colorStateObject);
48
+ if (this.uiObject) {
49
+ _colorStateObject.backgroundColor = this._color;
50
+ _colorStateObject.backgroundOpacity = this._color.alpha * this._alphaFactor;
51
+ this.applyEffects(_colorStateObject, this._alphaFactor);
52
+ this.uiObject.set(_colorStateObject);
53
+ this.markDirty();
54
+ }
42
55
  }
43
56
 
44
57
  // used via animations
@@ -52,10 +65,9 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
52
65
  protected uiObject: ThreeMeshUI.Block | null = null;
53
66
  private _color: RGBAColor = null!;
54
67
 
55
-
56
68
  private _rect: RectTransform | null = null;
57
69
 
58
- private _stateManager : SimpleStateBehavior | null = null;
70
+ private _stateManager: SimpleStateBehavior | null = null;
59
71
 
60
72
  protected get rectTransform(): RectTransform {
61
73
  if (!this._rect) {
@@ -65,7 +77,7 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
65
77
  }
66
78
 
67
79
  onParentRectTransformChanged() {
68
- this.uiObject?.set({ width: this.rectTransform.width, height:this.rectTransform.height })
80
+ this.uiObject?.set({ width: this.rectTransform.width, height: this.rectTransform.height })
69
81
  this.markDirty();
70
82
  }
71
83
 
@@ -73,7 +85,7 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
73
85
  super.__internalNewInstanceCreated();
74
86
  this._rect = null;
75
87
  this.uiObject = null;
76
- if(this._color) this._color = this._color.clone();
88
+ if (this._color) this._color = this._color.clone();
77
89
  }
78
90
 
79
91
  setState(state: string) {
@@ -93,7 +105,7 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
93
105
  // ie : (::firstChild::hover::disabled) where firstchild, hover and disabled are all on different channels
94
106
  // In order to keep needle Raycaster and EventSystem intact, I added in v7 a SimpleStateBehavior, which acts as previously
95
107
 
96
- if( !this._stateManager ) this._stateManager = new SimpleStateBehavior(this.uiObject);
108
+ if (!this._stateManager) this._stateManager = new SimpleStateBehavior(this.uiObject);
97
109
  //@ts-ignore
98
110
  this.uiObject.setupState(state.state, state.attributes);
99
111
  }
@@ -159,13 +171,13 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
159
171
  }
160
172
  protected onAfterCreated() { }
161
173
 
162
- private applyEffects(opts){
174
+ private applyEffects(opts, alpha: number = 1) {
163
175
  const outline = this.gameObject?.getComponent(Outline);
164
176
  if (outline) {
165
177
  if (outline.effectDistance) opts.borderWidth = Math.max(Math.abs(outline.effectDistance.x), Math.abs(outline.effectDistance.y));
166
178
  if (outline.effectColor) {
167
179
  opts.borderColor = outline.effectColor;
168
- opts.borderOpacity = outline.effectColor.alpha;
180
+ opts.borderOpacity = outline.effectColor.alpha * alpha;
169
181
  }
170
182
  }
171
183
  }
@@ -177,8 +189,8 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
177
189
  this.setOptions({ backgroundOpacity: 0 });
178
190
  if (tex) {
179
191
  // workaround for https://github.com/needle-tools/needle-engine-support/issues/109
180
- if(tex.encoding === sRGBEncoding) {
181
- if(Graphic.textureCache.has(tex)) {
192
+ if (tex.encoding === sRGBEncoding) {
193
+ if (Graphic.textureCache.has(tex)) {
182
194
  tex = Graphic.textureCache.get(tex)!;
183
195
  } else {
184
196
  const clone = tex.clone();
@@ -14,7 +14,11 @@ export interface ICanvasGroup {
14
14
  interactable: boolean;
15
15
  }
16
16
 
17
- export interface IGraphic extends IComponent {
17
+ export interface IHasAlphaFactor {
18
+ setAlphaFactor(val: number);
19
+ }
20
+
21
+ export interface IGraphic extends IComponent, IHasAlphaFactor {
18
22
  get isGraphic(): boolean;
19
23
  raycastTarget: boolean;
20
24
  }
@@ -2,12 +2,11 @@ import * as ThreeMeshUI from 'three-mesh-ui'
2
2
  import { BaseUIComponent } from "./BaseUIComponent";
3
3
  import { DocumentedOptions as ThreeMeshUIEveryOptions } from "three-mesh-ui/build/types/core/elements/MeshUIBaseElement";
4
4
  import { serializable } from "../../engine/engine_serialization_decorator";
5
- import { Color, Matrix4, Object3D, Quaternion, Vector2, Vector3 } from "three";
6
- import { EventSystem } from "./EventSystem";
5
+ import { Matrix4, Object3D, Quaternion, Vector2, Vector3 } from "three";
7
6
  import { getParam } from "../../engine/engine_utils";
8
7
  import { onChange } from "./Utils";
9
8
  import { foreachComponentEnumerator } from "../../engine/engine_gameobject";
10
- import { ICanvas, IRectTransform, IRectTransformChangedReceiver, ILayoutGroup } from "./Interfaces";
9
+ import { ICanvas, IRectTransform, IRectTransformChangedReceiver } from "./Interfaces";
11
10
  import { GameObject } from '../Component';
12
11
 
13
12
  const debug = getParam("debugui");
@@ -43,14 +42,14 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
43
42
  get rotation() { return this.gameObject.quaternion; }
44
43
  get scale(): Vector3 { return this.gameObject.scale; }
45
44
 
46
- private _anchoredPosition!: Vector3;
45
+ private _anchoredPosition!: Vector2;
47
46
 
48
- @serializable(Vector3)
47
+ @serializable(Vector2)
49
48
  get anchoredPosition() {
50
- if (!this._anchoredPosition) this._anchoredPosition = new Vector3();
49
+ if (!this._anchoredPosition) this._anchoredPosition = new Vector2();
51
50
  return this._anchoredPosition;
52
51
  }
53
- private set anchoredPosition(value: Vector3) {
52
+ private set anchoredPosition(value: Vector2) {
54
53
  this._anchoredPosition = value;
55
54
  }
56
55
 
@@ -99,17 +98,24 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
99
98
  private lastMatrix!: Matrix4;
100
99
  private rectBlock!: Object3D;
101
100
  private _transformNeedsUpdate: boolean = false;
101
+ private _initialPosition!: Vector3;
102
102
 
103
103
  awake() {
104
104
  super.awake();
105
+ // this is required if an animator animated the transform anchoring
106
+ if (!this._anchoredPosition)
107
+ this._anchoredPosition = new Vector2();
108
+
105
109
  this.lastMatrix = new Matrix4();
106
110
  this.rectBlock = new Object3D();
107
111
  // Is this legacy? Not sure if this is still needed
108
112
  this.rectBlock.position.z = .1;
109
113
  this.rectBlock.name = this.name;
110
114
 
111
- // this is required if an animator animated the transform anchoring
112
- if (!this._anchoredPosition) this._anchoredPosition = new Vector3();
115
+ // TODO: get rid of the initial position
116
+ this._initialPosition = this.gameObject.position.clone();
117
+ this._initialPosition.z = 0;
118
+ this.onApplyTransform("RectTransform awake");
113
119
 
114
120
  // TODO: we need to replace this with the watch that e.g. Rigibody is using (or the one in utils?)
115
121
  // perhaps we can also just manually check the few properties in the update loops?
@@ -119,20 +125,6 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
119
125
  onChange(this, "pivot", () => { this.markDirty(); });
120
126
  onChange(this, "anchorMin", () => { this.markDirty(); });
121
127
  onChange(this, "anchorMax", () => { this.markDirty(); });
122
-
123
- // When exported with an anchored position offset we remove it here
124
- // because it would otherwise be applied twice when the anchoring is animated
125
- // Maybe we can get rid of this workaround if we just set the mesh ui position from the
126
- // anchored position value but then we would have to make sure if a user/the engine updates
127
- // "position" the change would also land in anchoredPosition
128
- // Another solution would perhaps be to get rid of the extra "anchoredPosition" vector3
129
- // and instead use the same vector3 instance on both "position" and "anchoredPosition"
130
- // But I'm also not sure if this will not cause issues elsewhere later / be confusing?
131
- // (that being said we can make anchoredPosition hidden)
132
- if (!this.isRoot()) {
133
- this.gameObject.position.x += this.anchoredPosition.x;
134
- this.gameObject.position.y -= this.anchoredPosition.y;
135
- }
136
128
  }
137
129
 
138
130
  onEnable() {
@@ -155,7 +147,7 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
155
147
  }
156
148
 
157
149
  get isDirty() {
158
- if(!this._transformNeedsUpdate) this._transformNeedsUpdate = !this.lastMatrix.equals(this.gameObject.matrix);
150
+ if (!this._transformNeedsUpdate) this._transformNeedsUpdate = !this.lastMatrix.equals(this.gameObject.matrix);
159
151
  return this._transformNeedsUpdate;
160
152
  }
161
153
 
@@ -199,7 +191,6 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
199
191
  else
200
192
  this._parentRectTransform = undefined;
201
193
  this._transformNeedsUpdate = false;
202
- this.lastMatrix.copy(this.gameObject.matrix);
203
194
 
204
195
  if (debugLayout) console.warn("RectTransform → ApplyTransform", this.name + " because " + reason);
205
196
 
@@ -223,7 +214,8 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
223
214
  tempVec.set(0, 0, 0);
224
215
  this.applyAnchoring(tempVec);
225
216
  tempVec.z += this.offset;
226
- tempVec.z -= this.gameObject.position.z;
217
+ // tempVec.z -= this.gameObject.position.z;
218
+
227
219
  tempMatrix.identity();
228
220
  tempMatrix.setPosition(tempVec.x, tempVec.y, tempVec.z);
229
221
  uiobject.matrix.premultiply(tempMatrix);
@@ -236,6 +228,8 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
236
228
  if (!canvas.screenspace) uiobject.rotation.y = Math.PI;
237
229
  }
238
230
 
231
+ this.lastMatrix.copy(this.gameObject.matrix);
232
+
239
233
  // iterate other components on this object that might need to know about the transform change
240
234
  // e.g. Graphic components should update their width and height
241
235
  const includeChildren = true;
@@ -259,10 +253,20 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
259
253
  // }
260
254
  // }
261
255
 
256
+ private _lastAnchoring!: Vector2;
257
+
262
258
  /** applies the position offset to the passed in vector */
263
259
  private applyAnchoring(pos: Vector3) {
264
- pos.x += this.anchoredPosition.x;
265
- pos.y += this.anchoredPosition.y;
260
+
261
+ if (!this._lastAnchoring) this._lastAnchoring = new Vector2();
262
+ const diff = this._lastAnchoring.sub(this._anchoredPosition)
263
+ this.gameObject.position.x += diff.x;
264
+ this.gameObject.position.y += diff.y;
265
+ this._lastAnchoring.copy(this._anchoredPosition);
266
+
267
+ pos.x += (this._initialPosition.x - this.gameObject.position.x);
268
+ pos.y += (this._initialPosition.y - this.gameObject.position.y);
269
+ pos.z += (this._initialPosition.z - this.gameObject.position.z);
266
270
 
267
271
  const parent = this._parentRectTransform;
268
272
  if (parent) {
@@ -6,7 +6,7 @@ import { updateRenderSettings } from './Utils';
6
6
  import { Canvas } from './Canvas';
7
7
  import { serializable } from '../../engine/engine_serialization_decorator';
8
8
  import { getParam, resolveUrl } from '../../engine/engine_utils';
9
- import { ICanvas } from './Interfaces';
9
+ import { ICanvas, IHasAlphaFactor } from './Interfaces';
10
10
 
11
11
  const debug = getParam("debugtext");
12
12
 
@@ -38,7 +38,7 @@ export enum FontStyle {
38
38
  BoldAndItalic = 3,
39
39
  }
40
40
 
41
- export class Text extends Graphic {
41
+ export class Text extends Graphic implements IHasAlphaFactor {
42
42
 
43
43
  @serializable()
44
44
  alignment: TextAnchor = TextAnchor.UpperLeft;
@@ -55,6 +55,13 @@ export class Text extends Graphic {
55
55
  @serializable()
56
56
  fontStyle: FontStyle = FontStyle.Normal;
57
57
 
58
+ // private _alphaFactor : number = 1;
59
+ setAlphaFactor(factor: number): void {
60
+ super.setAlphaFactor(factor);
61
+ this.uiObject?.set({ fontOpacity: this.color.alpha * this.alphaFactor });
62
+ this.markDirty();
63
+ }
64
+
58
65
  @serializable()
59
66
  get text(): string {
60
67
  return this._text;
@@ -78,11 +85,9 @@ export class Text extends Graphic {
78
85
  }
79
86
 
80
87
  set fontSize(val: number) {
81
-
82
88
  // Setting that kind of property in a parent, would cascade to each 'non-overrided' children.
83
89
  this._fontSize = val;
84
90
  this.uiObject?.set({ fontSize: val });
85
-
86
91
  }
87
92
 
88
93