@needle-tools/engine 2.67.5-pre → 2.67.7-pre

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 (56) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/needle-engine.js +8732 -8689
  3. package/dist/needle-engine.umd.cjs +227 -227
  4. package/lib/engine/engine_context.d.ts +170 -0
  5. package/lib/engine/engine_context.js +855 -0
  6. package/lib/engine/engine_context.js.map +1 -0
  7. package/lib/engine/engine_gizmos.js +7 -0
  8. package/lib/engine/engine_gizmos.js.map +1 -1
  9. package/lib/engine/engine_setup.d.ts +1 -166
  10. package/lib/engine/engine_setup.js +2 -841
  11. package/lib/engine/engine_setup.js.map +1 -1
  12. package/lib/engine/engine_time.d.ts +2 -0
  13. package/lib/engine/engine_time.js +4 -1
  14. package/lib/engine/engine_time.js.map +1 -1
  15. package/lib/engine-components/AnimatorController.js.map +1 -1
  16. package/lib/engine-components/postprocessing/Effects/DepthOfField.js +1 -0
  17. package/lib/engine-components/postprocessing/Effects/DepthOfField.js.map +1 -1
  18. package/lib/engine-components/postprocessing/Effects/Pixelation.js +0 -1
  19. package/lib/engine-components/postprocessing/Effects/Pixelation.js.map +1 -1
  20. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js +3 -3
  21. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js.map +1 -1
  22. package/lib/engine-components/postprocessing/PostProcessingEffect.js +3 -2
  23. package/lib/engine-components/postprocessing/PostProcessingEffect.js.map +1 -1
  24. package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +1 -0
  25. package/lib/engine-components/postprocessing/PostProcessingHandler.js +69 -22
  26. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  27. package/lib/engine-components/postprocessing/Volume.js +5 -5
  28. package/lib/engine-components/postprocessing/Volume.js.map +1 -1
  29. package/lib/engine-components/postprocessing/VolumeParameter.js +1 -1
  30. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  31. package/lib/engine-components/ui/Canvas.d.ts +4 -1
  32. package/lib/engine-components/ui/Canvas.js +17 -1
  33. package/lib/engine-components/ui/Canvas.js.map +1 -1
  34. package/lib/engine-components/ui/EventSystem.js +1 -2
  35. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  36. package/lib/engine-components/ui/Text.js +4 -0
  37. package/lib/engine-components/ui/Text.js.map +1 -1
  38. package/lib/engine-components/ui/Utils.js +6 -4
  39. package/lib/engine-components/ui/Utils.js.map +1 -1
  40. package/package.json +1 -1
  41. package/src/engine/engine_context.ts +957 -0
  42. package/src/engine/engine_gizmos.ts +7 -0
  43. package/src/engine/engine_setup.ts +2 -944
  44. package/src/engine/engine_time.ts +4 -1
  45. package/src/engine-components/AnimatorController.ts +2 -2
  46. package/src/engine-components/postprocessing/Effects/DepthOfField.ts +1 -0
  47. package/src/engine-components/postprocessing/Effects/Pixelation.ts +0 -1
  48. package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.ts +2 -2
  49. package/src/engine-components/postprocessing/PostProcessingEffect.ts +3 -2
  50. package/src/engine-components/postprocessing/PostProcessingHandler.ts +74 -29
  51. package/src/engine-components/postprocessing/Volume.ts +10 -10
  52. package/src/engine-components/postprocessing/VolumeParameter.ts +1 -1
  53. package/src/engine-components/ui/Canvas.ts +19 -1
  54. package/src/engine-components/ui/EventSystem.ts +1 -2
  55. package/src/engine-components/ui/Text.ts +3 -0
  56. package/src/engine-components/ui/Utils.ts +6 -4
@@ -20,11 +20,13 @@ export class Time {
20
20
 
21
21
  get frameCount() { return this.frame; }
22
22
  get smoothedFps() { return this._smoothedFps; }
23
+ get smoothedDeltaTime() { return 1 / this._smoothedFps; }
23
24
 
24
25
 
25
26
  private clock = new Clock();
26
27
 
27
28
  private _smoothedFps: number = 0;
29
+ private _smoothedDeltaTime: number = 0;
28
30
  private _fpsSamples: number[] = [];
29
31
  private _fpsSampleIndex: number = 0;
30
32
 
@@ -47,6 +49,7 @@ export class Time {
47
49
  let sum = 0;
48
50
  for (let i = 0; i < this._fpsSamples.length; i++)
49
51
  sum += this._fpsSamples[i];
50
- this._smoothedFps = 1 / (sum / this._fpsSamples.length);
52
+ this._smoothedDeltaTime = sum / this._fpsSamples.length;
53
+ this._smoothedFps = 1 / this._smoothedDeltaTime;
51
54
  }
52
55
  }
@@ -432,9 +432,9 @@ export class AnimatorController {
432
432
  case AnimatorConditionMode.IfNot:
433
433
  return param.value === false;
434
434
  case AnimatorConditionMode.Greater:
435
- return param.value > cond.threshold;
435
+ return param.value as number > cond.threshold;
436
436
  case AnimatorConditionMode.Less:
437
- return param.value < cond.threshold;
437
+ return param.value as number < cond.threshold;
438
438
  case AnimatorConditionMode.Equals:
439
439
  return param.value === cond.threshold;
440
440
  case AnimatorConditionMode.NotEqual:
@@ -59,6 +59,7 @@ export class DepthOfField extends PostProcessingEffect {
59
59
  worldFocusRange: .2,
60
60
  focalLength: 1,
61
61
  bokehScale: 20,
62
+ resolutionScale: 1,
62
63
  });
63
64
 
64
65
  this.focusDistance.onValueChanged = v => {
@@ -17,7 +17,6 @@ export class PixelationEffect extends PostProcessingEffect {
17
17
  const effect = new PixelationEffectPP();
18
18
 
19
19
  this.granularity.onValueChanged = v => {
20
- console.log(v);
21
20
  effect.granularity = v;
22
21
  }
23
22
 
@@ -37,7 +37,7 @@ export class ScreenSpaceAmbientOcclusion extends PostProcessingEffect {
37
37
  const normalPass = new NormalPass(this.context.scene, cam);
38
38
  const depthDownsamplingPass = new DepthDownsamplingPass({
39
39
  normalBuffer: normalPass.texture,
40
- resolutionScale: 0.5
40
+ resolutionScale: .5
41
41
  });
42
42
 
43
43
  const ssao = this._ssao = new SSAOEffect(cam!, normalPass.texture, {
@@ -47,7 +47,7 @@ export class ScreenSpaceAmbientOcclusion extends PostProcessingEffect {
47
47
  worldProximityThreshold: .1,
48
48
  worldProximityFalloff: 2,
49
49
  intensity: 1,
50
- // blendFunction: BlendFunction.MULTIPLY,
50
+ blendFunction: BlendFunction.MULTIPLY,
51
51
  });
52
52
 
53
53
  this.intensity.onValueChanged = newValue => {
@@ -83,12 +83,13 @@ export abstract class PostProcessingEffect extends Component implements IEffectP
83
83
  if (typeof data === "object") {
84
84
  const types = this["$serializedTypes"];
85
85
  if (types) {
86
- for (const fieldName in Object.keys(types)) {
86
+ for (const fieldName of Object.keys(types)) {
87
87
  const type = types[fieldName];
88
88
  if (type === VolumeParameter) {
89
89
  const value = data[fieldName];
90
90
  if (value !== undefined) {
91
- this[fieldName].value = value;
91
+ const parameter = this[fieldName];
92
+ parameter.value = value;
92
93
  }
93
94
  }
94
95
  }
@@ -1,10 +1,11 @@
1
1
  import { HalfFloatType, sRGBEncoding, WebGLRenderTarget } from "three";
2
2
  import { Context } from "../../engine/engine_setup";
3
- import { getParam } from "../../engine/engine_utils";
4
- import { Effect, EffectComposer, EffectPass, Pass, RenderPass } from "postprocessing";
3
+ import { getParam, isMobileDevice } from "../../engine/engine_utils";
4
+ import { BloomEffect, BrightnessContrastEffect, ChromaticAberrationEffect, DepthDownsamplingPass, DepthOfFieldEffect, Effect, EffectComposer, EffectPass, HueSaturationEffect, NormalPass, Pass, PixelationEffect, RenderPass, SelectiveBloomEffect, SSAOEffect, VignetteEffect } from "postprocessing";
5
5
  import { showBalloonWarning } from "../../engine/debug/debug";
6
6
  import { Camera } from "../Camera";
7
7
  import { PostProcessingEffect } from "./PostProcessingEffect";
8
+ import { Constructor } from "../../engine/engine_serialization_core";
8
9
 
9
10
  const debug = getParam("debugpost");
10
11
 
@@ -98,7 +99,6 @@ export class PostProcessingHandler {
98
99
  }
99
100
 
100
101
  this.applyEffects(context);
101
-
102
102
  }
103
103
 
104
104
 
@@ -106,11 +106,11 @@ export class PostProcessingHandler {
106
106
  private applyEffects(context: Context) {
107
107
 
108
108
  const effectsOrPasses = this._effects;
109
- const camera = context.mainCameraComponent as Camera;
110
- const renderer = context.renderer;
111
-
112
109
  if (effectsOrPasses.length <= 0) return;
113
110
 
111
+ const camera = context.mainCameraComponent as Camera;
112
+ const renderer = context.renderer;
113
+ const scene = context.scene;
114
114
  const cam = camera.cam;
115
115
 
116
116
  // create composer and set active on context
@@ -119,45 +119,90 @@ export class PostProcessingHandler {
119
119
  this._composer = new EffectComposer(renderer, {
120
120
  frameBufferType: HalfFloatType,
121
121
  stencilBuffer: true,
122
- // multisampling: 2,
122
+ multisampling: isMobileDevice() ? 0 : 8,
123
123
  });
124
124
  }
125
125
  context.composer = this._composer;
126
126
  const composer = context.composer;
127
127
  composer.setMainCamera(cam);
128
128
  composer.setRenderer(renderer);
129
+ composer.setMainScene(scene);
130
+
129
131
  for (const prev of composer.passes)
130
132
  prev.dispose();
131
133
  composer.removeAllPasses();
132
- composer.addPass(new RenderPass(context.scene, cam));
133
-
134
-
135
- if (debug)
136
- console.log("Set effects or passes", camera, effectsOrPasses, composer);
137
-
138
- // TODO: enforce correct order of effects (e.g. DOF before Bloom)
139
134
 
140
- const effects: Array<Effect> = [];
141
-
142
- for (const ef of effectsOrPasses) {
143
- if (ef instanceof Effect)
144
- effects.push(ef as Effect);
145
- else if (ef instanceof Pass) {
135
+ // Render to screen pass
136
+ const screenpass = new RenderPass(scene, cam);
137
+ screenpass.mainScene = scene;
138
+ composer.addPass(screenpass);
139
+
140
+ try {
141
+ this.orderEffects();
142
+
143
+ const effects: Array<Effect> = [];
144
+
145
+ for (const ef of effectsOrPasses) {
146
+ if (ef instanceof Effect)
147
+ effects.push(ef as Effect);
148
+ else if (ef instanceof Pass) {
149
+ const pass = new EffectPass(cam, ...effects);
150
+ pass.mainScene = scene;
151
+ pass.name = effects.map(e => e.constructor.name).join(", ");
152
+ pass.enabled = true;
153
+ // composer.addPass(pass);
154
+ effects.length = 0;
155
+ composer.addPass(ef as Pass);
156
+ }
157
+ }
158
+
159
+ // create and apply uber pass
160
+ if (effects.length > 0) {
146
161
  const pass = new EffectPass(cam, ...effects);
147
- pass.name = effects.map(e => e.constructor.name).join(", ");
162
+ pass.mainScene = scene;
148
163
  pass.enabled = true;
149
164
  composer.addPass(pass);
150
- effects.length = 0;
151
- composer.addPass(ef as Pass);
152
165
  }
153
166
  }
154
-
155
- // create and apply uber pass
156
- if (effects.length > 0) {
157
- const pass = new EffectPass(cam, ...effects);
158
- pass.enabled = true;
159
- composer.addPass(pass);
167
+ catch(e) {
168
+ console.error("Error while applying postprocessing effects", e);
169
+ composer.removeAllPasses();
170
+ composer.addPass(screenpass);
160
171
  }
172
+
173
+
174
+ if (debug)
175
+ console.log("PostProcessing Passes", effectsOrPasses, "->", composer.passes);
176
+ }
177
+
178
+ private orderEffects() {
179
+ if (debug) console.log("Before ordering effects", [...this._effects]);
180
+ // TODO: enforce correct order of effects (e.g. DOF before Bloom)
181
+ const effects = this._effects;
182
+ effects.sort((a, b) => {
183
+ const aidx = effectsOrder.indexOf(a.constructor as any);
184
+ const bidx = effectsOrder.indexOf(b.constructor as any);
185
+ // Unknown effects should be rendered first
186
+ if (aidx < 0 && bidx < 0) return -1;
187
+ if (aidx < 0) return 1;
188
+ if (bidx < 0) return -1;
189
+ return aidx - bidx;
190
+ });
191
+ if (debug) console.log("After ordering effects", [...this._effects]);
161
192
  }
162
193
  }
163
194
 
195
+
196
+ const effectsOrder: Array<Constructor<Effect | Pass>> = [
197
+ NormalPass,
198
+ DepthDownsamplingPass,
199
+ SSAOEffect,
200
+ DepthOfFieldEffect,
201
+ BloomEffect,
202
+ SelectiveBloomEffect,
203
+ VignetteEffect,
204
+ HueSaturationEffect,
205
+ ChromaticAberrationEffect,
206
+ BrightnessContrastEffect,
207
+ PixelationEffect,
208
+ ];
@@ -42,15 +42,18 @@ export class Volume extends Behaviour implements IEditorModificationReceiver {
42
42
 
43
43
  onBeforeRender(): void {
44
44
  if (!this.context.isInXR) {
45
-
46
- if (this.context.composer && (this.context.composer instanceof EffectComposer) === false) {
47
- return;
48
- }
49
-
45
+
46
+ if (this.context.composer && (this.context.composer instanceof EffectComposer) === false) {
47
+ return;
48
+ }
49
+
50
50
  // Wait for the first frame to be rendered before creating because then we know we have a camera (issue 135)
51
51
  if (this.context.mainCamera) {
52
- if (!this._postprocessing || !this._postprocessing.isActive)
52
+ if (!this._postprocessing || !this._postprocessing.isActive) {
53
53
  this.apply();
54
+ // TODO: remove this workaround for postprocessing rendering not working correctly when applied for the first time
55
+ this.apply();
56
+ }
54
57
  }
55
58
 
56
59
  if (this.context.composer) {
@@ -59,9 +62,6 @@ export class Volume extends Behaviour implements IEditorModificationReceiver {
59
62
  if (this.context.mainCamera)
60
63
  this.context.composer.setMainCamera(this.context.mainCamera);
61
64
  }
62
- if (this.context.renderer) {
63
- this.context.renderer.autoClear = false;
64
- }
65
65
  }
66
66
  }
67
67
 
@@ -106,9 +106,9 @@ export class Volume extends Behaviour implements IEditorModificationReceiver {
106
106
  if (!this._postprocessing)
107
107
  this._postprocessing = new PostProcessingHandler(this.context);
108
108
  this._postprocessing.apply(this._effects);
109
+ this._applyPostQueue();
109
110
  }
110
111
 
111
- this._applyPostQueue();
112
112
  }
113
113
 
114
114
  private unapply() {
@@ -15,7 +15,7 @@ export class VolumeParameter {
15
15
  const value = val ? this._lastActiveSetValue : this._defaultValue;
16
16
  this.processValue(value, true);
17
17
  }
18
- private _active: boolean = false;
18
+ private _active: boolean = true;
19
19
 
20
20
 
21
21
 
@@ -8,11 +8,13 @@ import { getComponentsInChildren } from "../../engine/engine_components";
8
8
  import { IComponent } from "../../engine/engine_types";
9
9
  import { GameObject } from "../Component";
10
10
  import { showBalloonMessage, showBalloonWarning } from "../../engine/debug";
11
+ import { Object3D } from "three";
11
12
 
12
13
  export enum RenderMode {
13
14
  ScreenSpaceOverlay = 0,
14
15
  ScreenSpaceCamera = 1,
15
16
  WorldSpace = 2,
17
+ Undefined = -1,
16
18
  }
17
19
 
18
20
  export class Canvas extends UIRootComponent {
@@ -74,7 +76,7 @@ export class Canvas extends UIRootComponent {
74
76
  this._renderMode = val;
75
77
  this.onRenderSettingsChanged();
76
78
  }
77
- private _renderMode: RenderMode = -1;
79
+ private _renderMode: RenderMode = RenderMode.Undefined;
78
80
 
79
81
  private _rootCanvas!: Canvas;
80
82
 
@@ -109,12 +111,28 @@ export class Canvas extends UIRootComponent {
109
111
  }
110
112
 
111
113
  private previousAspect: number = -1;
114
+ private previousParent: Object3D | null = null;
112
115
 
113
116
  onBeforeRender() {
114
117
  if (this.isScreenSpace && this.context.mainCameraComponent && this.context.mainCameraComponent.aspect !== this.previousAspect) {
115
118
  this.previousAspect = this.context.mainCameraComponent.aspect;
116
119
  this.updateRenderMode();
117
120
  }
121
+ else if(this.renderOnTop){
122
+ // This is just a test but in reality it should be combined with all world canvases with render on top in one render pass
123
+ this.previousParent = this.gameObject.parent;
124
+ this.gameObject.removeFromParent();
125
+ }
126
+ }
127
+
128
+ onAfterRender(): void {
129
+ if (this.renderOnTop && this.previousParent && this.context.mainCamera) {
130
+ this.previousParent.add(this.gameObject);
131
+ this.context.renderer.autoClear = false;
132
+ this.context.renderer.clearDepth();
133
+ this.context.renderer.render(this.gameObject, this.context.mainCamera);
134
+ this.context.renderer.autoClear = true;
135
+ }
118
136
  }
119
137
 
120
138
  applyRenderSettings(){
@@ -382,8 +382,7 @@ export class EventSystem extends Behaviour {
382
382
  const actualGo = parent[$shadowDomOwner].gameObject;
383
383
  if (actualGo) {
384
384
  const res = UIRaycastUtils.isInteractable(actualGo, this.out);
385
- // console.log(actualGo, res);
386
- if (!res) return this.out.canvasGroup?.interactable ?? false;
385
+ if (!res) return false;
387
386
  canvasGroup = this.out.canvasGroup ?? null;
388
387
 
389
388
  const handled = this.handleMeshUIIntersection(object, pressedOrClicked);
@@ -214,6 +214,9 @@ export class Text extends Graphic {
214
214
 
215
215
  this.getAlignment(opts, isTextIntermediate);
216
216
  const block = rt.createNewBlock(opts);
217
+ // The text block should never write depth to avoid z-fighting
218
+ const mat = block["backgroundMaterial"];
219
+ if(mat) mat.depthWrite = false;
217
220
  if (content) {
218
221
  if (Array.isArray(content)) {
219
222
  block.add(...content);
@@ -34,11 +34,13 @@ export function updateRenderSettings(shadowComponent: THREE.Object3D, settings:
34
34
  // console.log(shadowComponent)
35
35
  const mat = shadowComponent["material"];
36
36
  if (mat?.isMaterial === true) {
37
- // console.log(shadowComponent, shadowComponent.name);
38
- // console.log(mat, component.renderOnTop, component.doubleSided, component.depthWrite);
39
- mat.depthTest = !settings.renderOnTop ?? true;
37
+ const parent = shadowComponent.parent;
38
+ if (parent && parent["isText"] === true) {
39
+ // console.log(shadowComponent, shadowComponent.name);
40
+ }
41
+ // mat.depthTest = !settings.renderOnTop ?? true;
42
+ // mat.depthWrite = settings.depthWrite ?? false;
40
43
  mat.side = (settings.doubleSided ?? true) ? DoubleSide : FrontSide;
41
- mat.depthWrite = settings.depthWrite ?? false;
42
44
  mat.shadowSide = settings.doubleSided ? DoubleSide : FrontSide;
43
45
  shadowComponent.castShadow = settings.castShadows ? settings.castShadows : false;
44
46
  shadowComponent.receiveShadow = settings.receiveShadows ? settings.receiveShadows : false;