@needle-tools/engine 4.7.0-next.4ec920e → 4.7.0-next.85b31db

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 (24) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/{needle-engine.bundle-DDM6UaI6.js → needle-engine.bundle-BU7SVSOA.js} +570 -559
  3. package/dist/{needle-engine.bundle-CaRf1SjI.umd.cjs → needle-engine.bundle-BtzGxNl0.umd.cjs} +29 -26
  4. package/dist/{needle-engine.bundle-C00XXoql.min.js → needle-engine.bundle-CvL6D2s2.min.js} +30 -27
  5. package/dist/needle-engine.js +2 -2
  6. package/dist/needle-engine.min.js +1 -1
  7. package/dist/needle-engine.umd.cjs +1 -1
  8. package/lib/engine-components/postprocessing/Effects/Antialiasing.js +8 -1
  9. package/lib/engine-components/postprocessing/Effects/Antialiasing.js.map +1 -1
  10. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.js +1 -1
  11. package/lib/engine-components/postprocessing/PostProcessingHandler.js +15 -1
  12. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  13. package/lib/engine-components/postprocessing/Volume.js +1 -1
  14. package/lib/engine-components/postprocessing/Volume.js.map +1 -1
  15. package/package.json +1 -1
  16. package/plugins/types/userconfig.d.ts +2 -0
  17. package/plugins/vite/alias.js +48 -38
  18. package/plugins/vite/index.js +2 -0
  19. package/plugins/vite/materialx.js +30 -0
  20. package/plugins/vite/transform.js +1 -0
  21. package/src/engine-components/postprocessing/Effects/Antialiasing.ts +8 -1
  22. package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.ts +1 -1
  23. package/src/engine-components/postprocessing/PostProcessingHandler.ts +14 -2
  24. package/src/engine-components/postprocessing/Volume.ts +1 -1
@@ -3,14 +3,33 @@ import path from 'path';
3
3
 
4
4
  const projectDir = process.cwd() + "/";
5
5
 
6
+ /**
7
+ * @typedef {"auto-resolve" | ((res: string, packageName: string, index: number, path: string) => string | null | void)} PackageResolveValue
8
+ */
9
+
6
10
  /** these are alias callbacks as in the vite.alias dictionary
7
11
  * the first argument is the already resoled absolute path (it is only invoked if the path was found in node_modules)
8
12
  * the 2,3,4 args are the same as in vite.alias (packageName, index, path);
9
13
  */
10
14
  /**
11
- * @type {Record<string, null | ((res: string, packageName: string, index: number, path: string) => string | null | void)>}
15
+ * @type {Record<string, PackageResolveValue>}
12
16
  */
13
17
  const packages_to_resolve = {
18
+ // We are currently overriding "three" resolution to ensure that all dependencies resolve to the same three.js version.
19
+ // This is hacky, but the alternative is potentially having conflicting three.js versions since some packages are
20
+ // stubborn with their peer dependencies or just slow (slower as we) with updating.
21
+ // NOT adding this allows node.js to correctly resolve `exports` specified in three.js package.json;
22
+ // since we're overriding resolution here we need to manually resolve the subset of exports that we use.
23
+ 'three/addons': (res, packageName, index, path) => {
24
+ return "three/examples/jsm";
25
+ },
26
+ 'three/nodes': (res, packageName, index, path) => {
27
+ return "three/examples/jsm/nodes/Nodes.js";
28
+ },
29
+ 'three': (res, packageName, index, _path) => {
30
+ return path.resolve(projectDir, 'node_modules', 'three');
31
+ },
32
+
14
33
  // Handle all previous imports where users did import using @needle-engine/src
15
34
  '@needle-tools/engine/src': (res, packageName, index, path) => {
16
35
  // resolve old engine/src imports UNLESS it's the asap plugin (the asap plugin currently only exists in the src folder)
@@ -31,13 +50,12 @@ const packages_to_resolve = {
31
50
  }
32
51
  },
33
52
 
34
- /*
35
- Removed. Three.js is manually resolved below to ensure all dependencies resolve to the same three.js version.
36
- 'three': null,
37
- */
38
- 'peerjs': null,
39
- 'websocket-ts': null,
40
- 'md5': null,
53
+ // Auto resolve to 'node_modules/<name>' or '@needle-tools/engine/node_modules/<name>'
54
+ 'peerjs': "auto-resolve",
55
+ 'websocket-ts': "auto-resolve",
56
+ 'md5': "auto-resolve",
57
+ 'postprocessing': "auto-resolve",
58
+ '@dimforge/rapier3d-compat': "auto-resolve",
41
59
  }
42
60
 
43
61
  /**
@@ -67,6 +85,7 @@ export const needleViteAlias = (command, config, userSettings) => {
67
85
  }
68
86
 
69
87
 
88
+ /** @type {import("vite").Plugin} */
70
89
  const aliasPlugin = {
71
90
  name: "needle-alias",
72
91
  config(config) {
@@ -75,11 +94,9 @@ export const needleViteAlias = (command, config, userSettings) => {
75
94
  if (!config.resolve.alias) config.resolve.alias = {};
76
95
  const aliasDict = config.resolve.alias;
77
96
 
78
- addThreeJSResolvers(aliasDict);
79
-
80
97
  for (const name in packages_to_resolve) {
81
98
  if (!aliasDict[name]) {
82
- addPathResolver(name, aliasDict, packages_to_resolve[name]);
99
+ addPathResolver(name, aliasDict, packages_to_resolve[name], debug ?? false);
83
100
  }
84
101
  }
85
102
 
@@ -127,43 +144,36 @@ export const needleViteAlias = (command, config, userSettings) => {
127
144
  if (debug) return [debuggingPlugin, aliasPlugin];
128
145
  return [aliasPlugin];
129
146
 
130
- function addThreeJSResolvers(aliasDict) {
131
- // We are currently overriding "three" resolution to ensure that all dependencies resolve to the same three.js version.
132
- // This is hacky, but the alternative is potentially having conflicting three.js versions since some packages are
133
- // stubborn with their peer dependencies or just slow (slower as we) with updating.
134
- // NOT adding this allows node.js to correctly resolve `exports` specified in three.js package.json;
135
- // since we're overriding resolution here we need to manually resolve the subset of exports that we use.
136
- aliasDict['three/addons'] = (res, packageName, index, path) => {
137
- return "three/examples/jsm";
138
- };
139
- aliasDict['three/nodes'] = (res, packageName, index, path) => {
140
- return "three/examples/jsm/nodes/Nodes.js";
141
- };
142
- aliasDict['three'] = (res, packageName, index, _path) => {
143
- return path.resolve(projectDir, 'node_modules', 'three');
144
- };
145
- }
146
-
147
- function addPathResolver(name, aliasDict, cb) {
147
+ /**
148
+ * Adds a path resolver to the alias dictionary.
149
+ * @param {string} name - The name of the package to resolve.
150
+ * @param {import("vite").AliasOptions} aliasDict - The alias dictionary to add the resolver to.
151
+ * @param {PackageResolveValue | null} value - A callback function to override the default resolution behavior.
152
+ * @param {boolean} debug - Whether to log debug information.
153
+ * @returns {void}
154
+ */
155
+ function addPathResolver(name, aliasDict, value, debug) {
148
156
  // If a package at the node_modules path exist we resolve the request there
149
157
  // introduced in 89a50718c38940abb99ee16c5e029065e41d7d65
150
- const fullpath = path.resolve(projectDir, 'node_modules', name);
151
- if (typeof cb !== "function") cb = null;
152
- const isDevEnvironment = process.env.NODE_ENV === "development";
158
+ const callback = typeof value === "function" ? value : null;
159
+
160
+ let fullpath = path.resolve(projectDir, 'node_modules', name);
161
+ if (!existsSync(fullpath)) {
162
+ fullpath = path.resolve(projectDir, 'node_modules', "@needle-tools/engine", "node_modules", name);
163
+ }
153
164
 
154
165
  if (existsSync(fullpath)) {
155
166
  aliasDict[name] = (packageName, index, path) => {
156
- if (cb !== null && !isDevEnvironment) {
157
- const overrideResult = cb(fullpath, packageName, index, path);
158
- if (overrideResult !== undefined)
167
+ if (callback !== null) {
168
+ const overrideResult = callback(fullpath, packageName, index, path);
169
+ if (typeof overrideResult === "string")
159
170
  if (existsSync(overrideResult)) {
160
- console.warn(`[needle-alias] \"${path}\" was requested and resolved to \"${overrideResult}\"`);
171
+ if (debug) console.warn(`[needle-alias] \"${path}\" was requested and resolved to \"${overrideResult}\"`);
161
172
  return overrideResult;
162
173
  }
163
174
  }
164
175
 
165
- if (path != packageName) {
166
- // TODO: we might want to check if the package.json exports contains the path to see if it's valid
176
+ if (debug && path != packageName) {
167
177
  console.warn(`[needle-alias] \"${path}\" was requested and resolved to \"${fullpath}\"`);
168
178
  }
169
179
 
@@ -66,6 +66,7 @@ export { needleBuildInfo } from "./buildinfo.js";
66
66
  import { needleServer } from "./server.js";
67
67
  import { needleNPM } from "./npm.js";
68
68
  import { needleTransformCode } from "./transform.js";
69
+ import { needleMaterialXLoader } from "./materialx.js";
69
70
  export { needleServer } from "./server.js";
70
71
 
71
72
 
@@ -133,6 +134,7 @@ export const needlePlugins = async (command, config = undefined, userSettings =
133
134
  needlePWA(command, config, userSettings),
134
135
  needleServer(command, config, userSettings),
135
136
  needleNPM(command, config, userSettings),
137
+ needleMaterialXLoader(command, config, userSettings),
136
138
  ];
137
139
 
138
140
  const asap = await needleAsap(command, config, userSettings);
@@ -0,0 +1,30 @@
1
+ import { existsSync } from 'fs';
2
+
3
+ const materialx_packagejson_path = "node_modules/@needle-tools/materialx/package.json";
4
+ const materialx_import_chunk =
5
+ `import { useNeedleMaterialX } from "@needle-tools/materialx/needle";
6
+ useNeedleMaterialX();
7
+ `
8
+
9
+ /**
10
+ * Vite plugin to automatically setup the MaterialX loader for Needle Engine.
11
+ * @param {string} command
12
+ * @param {object} config
13
+ * @param {import('../types/userconfig.js').userSettings} userSettings
14
+ * @returns {import('vite').Plugin}
15
+ */
16
+ export const needleMaterialXLoader = (command, config, userSettings) => {
17
+
18
+ return {
19
+ name: 'needle-materialx-loader',
20
+ transform: (code, id) => {
21
+ if (id.endsWith("src/main.ts")) {
22
+ if (userSettings?.loadMaterialX !== false && existsSync(materialx_packagejson_path)) {
23
+ console.log("[needle-materialx-loader] Adding MaterialX import to main.ts");
24
+ code = materialx_import_chunk + "\n" + code;
25
+ }
26
+ }
27
+ return code;
28
+ }
29
+ }
30
+ }
@@ -3,6 +3,7 @@
3
3
 
4
4
  /**
5
5
  * @param {import('../types').userSettings} userSettings
6
+ * @returns {import('vite').Plugin[]}
6
7
  */
7
8
  export const needleTransformCode = (command, config, userSettings) => {
8
9
 
@@ -1,10 +1,13 @@
1
1
  import { MODULES } from "../../../engine/engine_modules.js";
2
2
  import { serializable } from "../../../engine/engine_serialization.js";
3
+ import { getParam } from "../../../engine/engine_utils.js";
3
4
  import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
4
5
  import { VolumeParameter } from "../VolumeParameter.js";
5
6
  import { registerCustomEffectType } from "../VolumeProfile.js";
6
7
 
7
8
 
9
+ const debug = getParam("debugpost");
10
+
8
11
 
9
12
  export enum QualityLevel {
10
13
  LOW = 0,
@@ -32,15 +35,19 @@ export class Antialiasing extends PostProcessingEffect {
32
35
 
33
36
  onCreateEffect(): EffectProviderResult {
34
37
  const effect = new MODULES.POSTPROCESSING.MODULE.SMAAEffect({
35
- preset: MODULES.POSTPROCESSING.MODULE.SMAAPreset.HIGH,
38
+ preset: this.preset?.value ?? MODULES.POSTPROCESSING.MODULE.SMAAPreset.HIGH,
36
39
  edgeDetectionMode: MODULES.POSTPROCESSING.MODULE.EdgeDetectionMode.LUMA,
37
40
  // Keep predication mode disabled (default) since it looks better
38
41
  // predicationMode: MODULES.POSTPROCESSING.MODULE.PredicationMode.DEPTH,
39
42
  });
40
43
 
41
44
  this.preset.onValueChanged = (newValue) => {
45
+ if(debug) console.log("Antialiasing preset changed to", newValue);
42
46
  effect.applyPreset(newValue);
43
47
  };
48
+ // setInterval(()=> {
49
+ // effect.applyPreset(Math.floor(Math.random()*3))
50
+ // }, 1000)
44
51
 
45
52
  // effect.edgeDetectionMaterial.edgeDetectionThreshold = .01;
46
53
 
@@ -124,7 +124,7 @@ export class ScreenSpaceAmbientOcclusionN8 extends PostProcessingEffect {
124
124
  cam,
125
125
  width, height
126
126
  ) as N8AOPostPass;
127
- ssao.name = "SSAO N8";
127
+ ssao.name = "SSAO_N8";
128
128
 
129
129
  const mode = ScreenSpaceAmbientOcclusionN8QualityMode[this.quality];
130
130
  ssao.setQualityMode(mode);
@@ -162,9 +162,11 @@ export class PostProcessingHandler {
162
162
  const res = component.apply(ctx);
163
163
  if (!res) continue;
164
164
 
165
+ const name = component.typeName || component.constructor.name;
165
166
 
166
167
  if (Array.isArray(res)) {
167
168
  for (const effect of res) {
169
+ if (!validateEffect(name, effect)) continue;
168
170
  this._effects.push({
169
171
  effect,
170
172
  typeName: component.typeName,
@@ -173,12 +175,23 @@ export class PostProcessingHandler {
173
175
  }
174
176
  }
175
177
  else {
178
+ if (!validateEffect(name, res)) continue;
176
179
  this._effects.push({
177
180
  effect: res,
178
181
  typeName: component.typeName,
179
182
  priority: component.order
180
183
  });
181
184
  }
185
+
186
+ function validateEffect(source: string, effect: Effect | Pass): boolean {
187
+ if (!effect) {
188
+ return false;
189
+ }
190
+ if (!(effect instanceof MODULES.POSTPROCESSING.MODULE.Effect || effect instanceof MODULES.POSTPROCESSING.MODULE.Pass)) {
191
+ console.warn(`PostprocessingEffect ${source} created neither Effect nor Pass - this might be caused by a bundler error or false import. Below you find some possible solutions:\n- If you create custom effect try creating it like this: 'new NEEDLE_ENGINE_MODULES.POSTPROCESSING.MODULE.Effect(...)' instead of 'new Effect(...)'`);
192
+ }
193
+ return true;
194
+ }
182
195
  }
183
196
  }
184
197
  else {
@@ -403,7 +416,7 @@ export class PostProcessingHandler {
403
416
  if (attributes & convolution) {
404
417
  if (debug) console.log("[PostProcessing] Convolution effect: " + ef.name);
405
418
  if (hasConvolutionEffectInArray) {
406
- if (debug) console.log("[PostProcessing] Merging effects with convolution", effectsToMerge.map(e => e.name).join(", "));
419
+ if (debug) console.log("[PostProcessing] Merging effects [" + effectsToMerge.map(e => e.name).join(", ") + "]");
407
420
  this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
408
421
  }
409
422
  hasConvolutionEffectInArray = true;
@@ -448,7 +461,6 @@ export class PostProcessingHandler {
448
461
  }
449
462
  foundEnabled = true;
450
463
  }
451
-
452
464
  pass.renderToScreen = renderToScreen;
453
465
 
454
466
  if ((pass as any)?.configuration !== undefined) {
@@ -194,7 +194,7 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
194
194
  if (this._postprocessing.multisampling !== 0) {
195
195
  this._postprocessing.multisampling = 0;
196
196
  if (debug || isDevEnvironment()) {
197
- console.warn(`[PostProcessing] Disabling multisampling you're using SMAA and have set the 'multisampling: auto' on your PostprocessingManager/Volume component. If you need anti-aliasing, consider adding an Antialiasing component or SMAA effect to the PostprocessingManager.`);
197
+ console.log(`[PostProcessing] multisampling is disabled because it's set to 'auto' on your PostprocessingManager/Volume component that also has an SMAA effect.\n\nIf you need multisampling consider changing 'auto' to a fixed value (e.g. 4).`);
198
198
  }
199
199
  }
200
200
  }