@needle-tools/engine 4.11.0-next.91b9cf1 → 4.11.0-next.cc37c71
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.
- package/CHANGELOG.md +7 -1
- package/README.md +3 -1
- package/components.needle.json +1 -1
- package/dist/{gltf-progressive-B63NpN_i.js → gltf-progressive-BvlZQAkt.js} +4 -4
- package/dist/{gltf-progressive-D4Z_Khp3.min.js → gltf-progressive-CftVUJy3.min.js} +1 -1
- package/dist/{gltf-progressive-CHeORqEv.umd.cjs → gltf-progressive-GwdQV1Qx.umd.cjs} +1 -1
- package/dist/{needle-engine.bundle-D4dsuq2U.js → needle-engine.bundle-BPZ6emFK.js} +7858 -7724
- package/dist/{needle-engine.bundle-DtfAXDjU.umd.cjs → needle-engine.bundle-CTY0RgBZ.umd.cjs} +150 -150
- package/dist/needle-engine.bundle-JV2ghuCa.min.js +1652 -0
- package/dist/needle-engine.d.ts +6 -0
- package/dist/needle-engine.js +4 -4
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-DQ2pynXW.js → postprocessing-CJC0Npcd.js} +2 -2
- package/dist/{postprocessing-BsnRNRRS.umd.cjs → postprocessing-DrM4PWU3.umd.cjs} +1 -1
- package/dist/{postprocessing-BHMVuZQ1.min.js → postprocessing-l7zsdO_Q.min.js} +1 -1
- package/dist/{three-qw28ZtTy.min.js → three-BDW9I486.min.js} +13 -13
- package/dist/{three-CJSAehtG.js → three-MHVqtJYj.js} +1 -0
- package/dist/{three-examples-Doq0rvFU.js → three-examples-C5Ht-QFN.js} +1 -1
- package/dist/{three-examples-Deqc1bNw.umd.cjs → three-examples-CgwGHSgz.umd.cjs} +1 -1
- package/dist/{three-examples-BivkhnvN.min.js → three-examples-fvEPSC8L.min.js} +1 -1
- package/dist/{three-B-jwTHao.umd.cjs → three-iFaDq9U3.umd.cjs} +13 -13
- package/dist/{three-mesh-ui-CktOi6oI.js → three-mesh-ui-BjWTTk1R.js} +1 -1
- package/dist/{three-mesh-ui-CsHwj9cJ.umd.cjs → three-mesh-ui-Bm32sS2a.umd.cjs} +1 -1
- package/dist/{three-mesh-ui-DhYXcXZe.min.js → three-mesh-ui-CLdkp21K.min.js} +1 -1
- package/dist/{vendor-BcsPRUmt.umd.cjs → vendor-CAWj5cBK.umd.cjs} +2 -2
- package/dist/{vendor-CyfN5nor.js → vendor-DJBpoQcM.js} +608 -599
- package/dist/{vendor-DyavoogU.min.js → vendor-DWGd3dEf.min.js} +20 -20
- package/lib/engine/engine_physics.js +25 -2
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/js-extensions/Object3D.d.ts +6 -0
- package/lib/engine/js-extensions/Object3D.js +15 -0
- package/lib/engine/js-extensions/Object3D.js.map +1 -1
- package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +2 -1
- package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
- package/lib/engine-components/Collider.d.ts +26 -0
- package/lib/engine-components/Collider.js +26 -0
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/ContactShadows.d.ts +11 -2
- package/lib/engine-components/ContactShadows.js +11 -2
- package/lib/engine-components/ContactShadows.js.map +1 -1
- package/lib/engine-components/DropListener.d.ts +3 -0
- package/lib/engine-components/DropListener.js +44 -21
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/Duplicatable.d.ts +2 -2
- package/lib/engine-components/Duplicatable.js +2 -2
- package/lib/engine-components/EventList.d.ts +18 -1
- package/lib/engine-components/EventList.js +18 -1
- package/lib/engine-components/EventList.js.map +1 -1
- package/lib/engine-components/GroundProjection.d.ts +3 -0
- package/lib/engine-components/GroundProjection.js +3 -0
- package/lib/engine-components/GroundProjection.js.map +1 -1
- package/lib/engine-components/Interactable.d.ts +4 -0
- package/lib/engine-components/Interactable.js +4 -0
- package/lib/engine-components/Interactable.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +4 -2
- package/lib/engine-components/OrbitControls.js +33 -3
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/RigidBody.d.ts +5 -0
- package/lib/engine-components/RigidBody.js +5 -0
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SeeThrough.js +20 -0
- package/lib/engine-components/SeeThrough.js.map +1 -1
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +4 -2
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +69 -14
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -1
- package/lib/engine-components/splines/SplineWalker.d.ts +43 -4
- package/lib/engine-components/splines/SplineWalker.js +88 -12
- package/lib/engine-components/splines/SplineWalker.js.map +1 -1
- package/lib/engine-components/ui/Text.js +6 -1
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/engine-components/utils/LookAt.d.ts +3 -0
- package/lib/engine-components/utils/LookAt.js +3 -0
- package/lib/engine-components/utils/LookAt.js.map +1 -1
- package/lib/engine-components/utils/OpenURL.d.ts +2 -1
- package/lib/engine-components/utils/OpenURL.js +2 -1
- package/lib/engine-components/utils/OpenURL.js.map +1 -1
- package/lib/engine-components/web/Clickthrough.d.ts +2 -0
- package/lib/engine-components/web/Clickthrough.js +23 -1
- package/lib/engine-components/web/Clickthrough.js.map +1 -1
- package/lib/engine-components/web/ScrollFollow.d.ts +1 -9
- package/lib/engine-components/web/ScrollFollow.js +13 -30
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/lib/engine-components/web/ViewBox.d.ts +16 -0
- package/lib/engine-components/web/ViewBox.js +35 -3
- package/lib/engine-components/web/ViewBox.js.map +1 -1
- package/lib/engine-components/webxr/WebARCameraBackground.d.ts +2 -0
- package/lib/engine-components/webxr/WebARCameraBackground.js +2 -0
- package/lib/engine-components/webxr/WebARCameraBackground.js.map +1 -1
- package/lib/engine-components/webxr/WebARSessionRoot.d.ts +1 -1
- package/lib/engine-components/webxr/WebARSessionRoot.js +1 -1
- package/lib/engine-components/webxr/WebXR.d.ts +2 -0
- package/lib/engine-components/webxr/WebXR.js +2 -0
- package/lib/engine-components/webxr/WebXR.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.d.ts +29 -0
- package/lib/engine-components/webxr/WebXRImageTracking.js +29 -0
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/package.json +2 -2
- package/plugins/common/needle-engine.js +41 -0
- package/plugins/common/worker.js +129 -0
- package/plugins/vite/asap.js +5 -23
- package/plugins/vite/dependencies.js +21 -11
- package/plugins/vite/index.js +7 -0
- package/plugins/vite/needle-app.js +194 -0
- package/src/engine/engine_physics.ts +27 -2
- package/src/engine/js-extensions/Object3D.ts +24 -0
- package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +3 -1
- package/src/engine-components/Collider.ts +27 -1
- package/src/engine-components/ContactShadows.ts +12 -4
- package/src/engine-components/DropListener.ts +45 -24
- package/src/engine-components/Duplicatable.ts +2 -2
- package/src/engine-components/EventList.ts +18 -1
- package/src/engine-components/GroundProjection.ts +4 -1
- package/src/engine-components/Interactable.ts +4 -1
- package/src/engine-components/OrbitControls.ts +32 -5
- package/src/engine-components/RigidBody.ts +6 -1
- package/src/engine-components/SeeThrough.ts +42 -2
- package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +117 -17
- package/src/engine-components/splines/SplineWalker.ts +99 -14
- package/src/engine-components/ui/Text.ts +11 -2
- package/src/engine-components/utils/LookAt.ts +3 -0
- package/src/engine-components/utils/OpenURL.ts +3 -2
- package/src/engine-components/web/Clickthrough.ts +28 -1
- package/src/engine-components/web/ScrollFollow.ts +16 -34
- package/src/engine-components/web/ViewBox.ts +35 -5
- package/src/engine-components/webxr/WebARCameraBackground.ts +2 -0
- package/src/engine-components/webxr/WebARSessionRoot.ts +1 -1
- package/src/engine-components/webxr/WebXR.ts +2 -0
- package/src/engine-components/webxr/WebXRImageTracking.ts +30 -3
- package/dist/needle-engine.bundle-B8HfDBoL.min.js +0 -1652
|
@@ -8,23 +8,26 @@ export const preloadScriptPaths = [];
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @param {import('../types').userSettings} userSettings
|
|
11
|
+
* @returns {import('vite').Plugin[]}
|
|
11
12
|
*/
|
|
12
13
|
export const needleDependencies = (command, config, userSettings) => {
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* @type {import('vite').Plugin}
|
|
16
17
|
*/
|
|
17
|
-
return
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
return [
|
|
19
|
+
{
|
|
20
|
+
name: 'needle:dependencies',
|
|
21
|
+
enforce: 'pre',
|
|
22
|
+
/**
|
|
23
|
+
* @param {import('vite').UserConfig} config
|
|
24
|
+
*/
|
|
25
|
+
config: (config, env) => {
|
|
26
|
+
handleOptimizeDeps(config);
|
|
27
|
+
handleManualChunks(config);
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
]
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
const excludeDependencies = [
|
|
@@ -167,6 +170,13 @@ function handleManualChunks(config) {
|
|
|
167
170
|
return name;
|
|
168
171
|
}
|
|
169
172
|
}
|
|
173
|
+
// else if(chunk.name === 'index') {
|
|
174
|
+
// console.log(chunk);
|
|
175
|
+
// debugger
|
|
176
|
+
// // this is the main chunk
|
|
177
|
+
// // we don't want to add a hash here to be able to easily import the main script
|
|
178
|
+
// return `index.js`;
|
|
179
|
+
// }
|
|
170
180
|
return `assets/[name].[hash].js`;
|
|
171
181
|
}
|
|
172
182
|
|
package/plugins/vite/index.js
CHANGED
|
@@ -63,11 +63,16 @@ export { needleImportsLogger } from "./imports-logger.js";
|
|
|
63
63
|
import { needleBuildInfo } from "./buildinfo.js";
|
|
64
64
|
export { needleBuildInfo } from "./buildinfo.js";
|
|
65
65
|
|
|
66
|
+
import { needleApp } from "./needle-app.js";
|
|
67
|
+
export { needleApp } from "./needle-app.js";
|
|
68
|
+
|
|
66
69
|
import { needleServer } from "./server.js";
|
|
67
70
|
import { needleNPM } from "./npm.js";
|
|
68
71
|
import { needleTransformCode } from "./transform.js";
|
|
69
72
|
import { needleMaterialXLoader } from "./materialx.js";
|
|
70
73
|
import { needleLogger } from "./logger.js";
|
|
74
|
+
import { viteFixWorkerImport } from "../common/worker.js";
|
|
75
|
+
|
|
71
76
|
export { needleServer } from "./server.js";
|
|
72
77
|
|
|
73
78
|
|
|
@@ -137,6 +142,8 @@ export const needlePlugins = async (command, config = undefined, userSettings =
|
|
|
137
142
|
needleServer(command, config, userSettings),
|
|
138
143
|
needleNPM(command, config, userSettings),
|
|
139
144
|
needleMaterialXLoader(command, config, userSettings),
|
|
145
|
+
needleApp(command, config, userSettings),
|
|
146
|
+
viteFixWorkerImport()
|
|
140
147
|
];
|
|
141
148
|
|
|
142
149
|
const asap = await needleAsap(command, config, userSettings);
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { writeFile } from 'fs';
|
|
2
|
+
import { tryParseNeedleEngineSrcAttributeFromHtml } from '../common/needle-engine.js';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {'serve' | 'build'} command
|
|
8
|
+
* @param {{} | undefined | null} config
|
|
9
|
+
* @param {import('../types').userSettings} userSettings
|
|
10
|
+
* @returns {import('vite').Plugin[] | null}
|
|
11
|
+
*/
|
|
12
|
+
export const needleApp = (command, config, userSettings) => {
|
|
13
|
+
|
|
14
|
+
if (command !== "build") {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** @type {Array<import("rollup").OutputChunk>} */
|
|
19
|
+
const entryFiles = new Array();
|
|
20
|
+
|
|
21
|
+
let outputDir = "dist";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @type {import('vite').Plugin}
|
|
25
|
+
*/
|
|
26
|
+
return [
|
|
27
|
+
{
|
|
28
|
+
name: 'needle:app',
|
|
29
|
+
enforce: "post",
|
|
30
|
+
configResolved(config) {
|
|
31
|
+
outputDir = config.build.outDir || "dist";
|
|
32
|
+
},
|
|
33
|
+
transformIndexHtml: {
|
|
34
|
+
handler: async function (html, context) {
|
|
35
|
+
const name = context.filename;
|
|
36
|
+
if (name.includes("index.html")) {
|
|
37
|
+
if (context.chunk?.isEntry) {
|
|
38
|
+
try {
|
|
39
|
+
entryFiles.push(context.chunk);
|
|
40
|
+
const path = context.chunk.fileName;
|
|
41
|
+
// console.log("[needle-dependencies] entry chunk imports", {
|
|
42
|
+
// name: context.chunk.fileName,
|
|
43
|
+
// imports: context.chunk.imports,
|
|
44
|
+
// dynamicImports: context.chunk.dynamicImports,
|
|
45
|
+
// refs: context.chunk.referencedFiles,
|
|
46
|
+
// });
|
|
47
|
+
|
|
48
|
+
// TODO: here we try to find the main asset (entrypoint) for this web app. It's a bit hacky right now but we have to assign this url directly to make it work with `gen.js` where multiple needle-apps are on different (or the same) pages.
|
|
49
|
+
const attribute_src = tryParseNeedleEngineSrcAttributeFromHtml(html);
|
|
50
|
+
const imported_glbs = Array.from(context.chunk.viteMetadata?.importedAssets?.values() || [])?.filter(f => f.endsWith(".glb") || f.endsWith(".gltf"));
|
|
51
|
+
|
|
52
|
+
const main_asset = attribute_src?.[0] || imported_glbs?.[0];
|
|
53
|
+
|
|
54
|
+
const webComponent = generateNeedleEmbedWebComponent(path, main_asset);
|
|
55
|
+
await writeFile(`${outputDir}/needle-app.js`, webComponent, (err) => {
|
|
56
|
+
if (err) {
|
|
57
|
+
console.error("[needle-app] could not create needle-app.js", err);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
console.log("[needle-app] created needle-app.js");
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
console.warn("WARN: could not create needle-app.js\n", e);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {string} filepath
|
|
79
|
+
* @param {string | null} src
|
|
80
|
+
* @returns {string}
|
|
81
|
+
*/
|
|
82
|
+
function generateNeedleEmbedWebComponent(filepath, src) {
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
// filepath is e.g. `assets/index-XXXXXXXX.js`
|
|
86
|
+
// we want to make sure the path is correct relative to where the component will be used
|
|
87
|
+
// this script will be emitted in the output directory root (e.g. needle-embed.js)
|
|
88
|
+
|
|
89
|
+
const componentDefaultName = 'needle-app';
|
|
90
|
+
|
|
91
|
+
return `
|
|
92
|
+
|
|
93
|
+
// Needle Engine attributes we want to allow to be overriden
|
|
94
|
+
const knownAttributes = [
|
|
95
|
+
"src",
|
|
96
|
+
"background-color",
|
|
97
|
+
"background-image",
|
|
98
|
+
"environment-image",
|
|
99
|
+
"focus-rect",
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
const scriptUrl = new URL(import.meta.url);
|
|
103
|
+
const componentName = scriptUrl.searchParams.get("component-name") || '${componentDefaultName}';
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
if (!customElements.get(componentName)) {
|
|
107
|
+
console.debug(\`Defining needle-app as <\${componentName}>\`);
|
|
108
|
+
customElements.define(componentName, class extends HTMLElement {
|
|
109
|
+
|
|
110
|
+
static get observedAttributes() {
|
|
111
|
+
return knownAttributes;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
constructor() {
|
|
115
|
+
super();
|
|
116
|
+
this.attachShadow({ mode: 'open' });
|
|
117
|
+
const template = document.createElement('template');
|
|
118
|
+
template.innerHTML = \`
|
|
119
|
+
<style>
|
|
120
|
+
:host {
|
|
121
|
+
position: relative;
|
|
122
|
+
display: block;
|
|
123
|
+
width: max(360px 100%);
|
|
124
|
+
height: max(240px, 100%);
|
|
125
|
+
margin: 0;
|
|
126
|
+
padding: 0;
|
|
127
|
+
}
|
|
128
|
+
needle-engine {
|
|
129
|
+
position: absolute;
|
|
130
|
+
top: 0;
|
|
131
|
+
left: 0;
|
|
132
|
+
width: 100%;
|
|
133
|
+
height: 100%;
|
|
134
|
+
}
|
|
135
|
+
</style>
|
|
136
|
+
\`;
|
|
137
|
+
this.shadowRoot.appendChild(template.content.cloneNode(true));
|
|
138
|
+
|
|
139
|
+
const script = document.createElement('script');
|
|
140
|
+
script.type = 'module';
|
|
141
|
+
const url = new URL('.', import.meta.url);
|
|
142
|
+
this.basePath = this.getAttribute('base-path') || \`\${url.protocol}//\${url.host}\${url.pathname}\`;
|
|
143
|
+
while(this.basePath.endsWith('/')) {
|
|
144
|
+
this.basePath = this.basePath.slice(0, -1);
|
|
145
|
+
}
|
|
146
|
+
script.src = this.getAttribute('script-src') || \`\${this.basePath}/${filepath}\`;
|
|
147
|
+
this.shadowRoot.appendChild(script);
|
|
148
|
+
|
|
149
|
+
this.needleEngine = document.createElement('needle-engine');
|
|
150
|
+
this.updateAttributes();
|
|
151
|
+
this.shadowRoot.appendChild(this.needleEngine);
|
|
152
|
+
|
|
153
|
+
console.debug(this.basePath, script.src, this.needleEngine.getAttribute("src"));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
onConnectedCallback() {
|
|
157
|
+
console.debug('NeedleEmbed connected to the DOM');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
disconnectedCallback() {
|
|
161
|
+
console.debug('NeedleEmbed disconnected from the DOM');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
165
|
+
console.debug(\`NeedleApp attribute changed: \${name} from \${oldValue} to \${newValue}\`);
|
|
166
|
+
this.updateAttributes();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
updateAttributes() {
|
|
170
|
+
console.debug("NeedleApp updating attributes");
|
|
171
|
+
|
|
172
|
+
const src = this.getAttribute('src') || ${src?.length ? `\`\${this.basePath}/${src}\`` : null};
|
|
173
|
+
if(src) this.needleEngine.setAttribute("src", src);
|
|
174
|
+
else this.needleEngine.removeAttribute("src");
|
|
175
|
+
|
|
176
|
+
for(const attr of knownAttributes) {
|
|
177
|
+
|
|
178
|
+
if(attr === "src") continue; // already handled above
|
|
179
|
+
|
|
180
|
+
if(this.hasAttribute(attr)) {
|
|
181
|
+
this.needleEngine.setAttribute(attr, this.getAttribute(attr));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
this.needleEngine.removeAttribute(attr);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
console.warn(\`needle-app <\${componentName}> already defined.\`);
|
|
192
|
+
}
|
|
193
|
+
`
|
|
194
|
+
}
|
|
@@ -572,6 +572,9 @@ declare module 'three' {
|
|
|
572
572
|
|
|
573
573
|
|
|
574
574
|
namespace NEMeshBVH {
|
|
575
|
+
|
|
576
|
+
let failedToCreateMeshBVHWorker = 0;
|
|
577
|
+
|
|
575
578
|
export function runMeshBVHRaycast(method: Raycaster | Sphere, mesh: Mesh, results: Intersection[], context: Pick<Context, "xr">, options: { allowSlowRaycastFallback?: boolean }): boolean {
|
|
576
579
|
if (!mesh.geometry) {
|
|
577
580
|
return false;
|
|
@@ -630,6 +633,10 @@ namespace NEMeshBVH {
|
|
|
630
633
|
|| geom.index && geom.index?.["isInterleavedBufferAttribute"]) {
|
|
631
634
|
canUseWorker = false;
|
|
632
635
|
}
|
|
636
|
+
else if (failedToCreateMeshBVHWorker > 10) {
|
|
637
|
+
// if we failed to create a worker multiple times, don't try again
|
|
638
|
+
canUseWorker = false;
|
|
639
|
+
}
|
|
633
640
|
|
|
634
641
|
// if we have a worker use that
|
|
635
642
|
if (canUseWorker && _GenerateMeshBVHWorker) {
|
|
@@ -646,8 +653,23 @@ namespace NEMeshBVH {
|
|
|
646
653
|
}
|
|
647
654
|
// if there are no workers available, create a new one
|
|
648
655
|
if (!workerInstance && workerInstances.length < 3) {
|
|
649
|
-
|
|
650
|
-
|
|
656
|
+
try {
|
|
657
|
+
workerInstance = new _GenerateMeshBVHWorker();
|
|
658
|
+
workerInstances.push(workerInstance);
|
|
659
|
+
}
|
|
660
|
+
catch (err) {
|
|
661
|
+
const isSecurityError = err instanceof DOMException && err.name === "SecurityError";
|
|
662
|
+
if (isSecurityError) {
|
|
663
|
+
console.warn("Failed to create MeshBVH worker, falling back to main thread generation. This can happen when running from file://, if the browser does not support workers or if the browser is blocking workers for other reasons.");
|
|
664
|
+
console.debug(err);
|
|
665
|
+
failedToCreateMeshBVHWorker += 10;
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
668
|
+
console.error("Failed to create MeshBVH worker");
|
|
669
|
+
console.debug(err);
|
|
670
|
+
}
|
|
671
|
+
failedToCreateMeshBVHWorker++;
|
|
672
|
+
}
|
|
651
673
|
}
|
|
652
674
|
|
|
653
675
|
if (workerInstance != null && !workerInstance.running) {
|
|
@@ -806,6 +828,9 @@ namespace NEMeshBVH {
|
|
|
806
828
|
if (debugPhysics || isDevEnvironment()) {
|
|
807
829
|
console.warn("Failed to setup mesh bvh worker");
|
|
808
830
|
}
|
|
831
|
+
else {
|
|
832
|
+
console.debug("Failed to setup mesh bvh worker", _err);
|
|
833
|
+
}
|
|
809
834
|
})
|
|
810
835
|
.finally(() => {
|
|
811
836
|
isRequestingWorker = false;
|
|
@@ -157,6 +157,14 @@ declare module 'three' {
|
|
|
157
157
|
* Added by Needle Engine.
|
|
158
158
|
*/
|
|
159
159
|
get worldUp(): Vector3;
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Check if the given object is contained in the hierarchy of this object or if it's the same object.
|
|
164
|
+
* @param object The object to check.
|
|
165
|
+
* @returns True if the object is contained in the hierarchy, false otherwise.
|
|
166
|
+
*/
|
|
167
|
+
contains(object: Object3D | null | undefined): boolean;
|
|
160
168
|
}
|
|
161
169
|
}
|
|
162
170
|
|
|
@@ -356,5 +364,21 @@ if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldUp")) {
|
|
|
356
364
|
|
|
357
365
|
|
|
358
366
|
|
|
367
|
+
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "contains")) {
|
|
368
|
+
Object.defineProperty(Object3D.prototype, "contains", {
|
|
369
|
+
value: function (object: Object3D | null | undefined): boolean {
|
|
370
|
+
if (!object) return false;
|
|
371
|
+
if (this === object) return true;
|
|
372
|
+
for (const child of this.children) {
|
|
373
|
+
if (child.contains(object)) return true;
|
|
374
|
+
}
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
|
|
359
383
|
// do this after adding the component extensions
|
|
360
384
|
registerPrototypeExtensions(Object3D);
|
|
@@ -4,14 +4,16 @@ import { MeshBVH } from 'three-mesh-bvh';
|
|
|
4
4
|
// Modified according to https://github.com/gkjohnson/three-mesh-bvh/issues/636#issuecomment-2209571751
|
|
5
5
|
import { WorkerBase } from "three-mesh-bvh/src/workers/utils/WorkerBase.js";
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
export class GenerateMeshBVHWorker extends WorkerBase {
|
|
8
9
|
|
|
9
10
|
constructor() {
|
|
10
11
|
// TODO: make mesh bvh worker "work" for prebundled CDN loading
|
|
11
12
|
// https://linear.app/needle/issue/NE-6572
|
|
12
13
|
// Also we don't use toplevel imports to not completely fail to load needle-engine where loading the worker fails
|
|
13
|
-
// const
|
|
14
|
+
// const meta_url = import.meta.url;
|
|
14
15
|
// const getWorker = () => new Worker(url, { type: 'module' })
|
|
16
|
+
// console.log(meta_url, url, getWorker());
|
|
15
17
|
super(new Worker(new URL('three-mesh-bvh/src/workers/generateMeshBVH.worker.js', import.meta.url), { type: 'module' }));
|
|
16
18
|
this.name = 'GenerateMeshBVHWorker';
|
|
17
19
|
|
|
@@ -16,7 +16,13 @@ import { Rigidbody } from "./RigidBody.js";
|
|
|
16
16
|
/**
|
|
17
17
|
* Collider is the base class for all colliders. A collider is a physical shape that is used to detect collisions with other objects in the scene.
|
|
18
18
|
* Colliders are used in combination with a {@link Rigidbody} to create physical interactions between objects.
|
|
19
|
-
* Colliders are registered with the physics engine when they are enabled and removed when they are disabled.
|
|
19
|
+
* Colliders are registered with the physics engine when they are enabled and removed when they are disabled.
|
|
20
|
+
*
|
|
21
|
+
* - Example: https://samples.needle.tools/physics-basic
|
|
22
|
+
* - Example: https://samples.needle.tools/physics-playground
|
|
23
|
+
* - Example: https://samples.needle.tools/physics-&-animation
|
|
24
|
+
*
|
|
25
|
+
*
|
|
20
26
|
* @category Physics
|
|
21
27
|
* @group Components
|
|
22
28
|
*/
|
|
@@ -112,6 +118,11 @@ export class Collider extends Behaviour implements ICollider {
|
|
|
112
118
|
/**
|
|
113
119
|
* SphereCollider represents a sphere-shaped collision volume.
|
|
114
120
|
* Useful for objects that are roughly spherical in shape or need a simple collision boundary.
|
|
121
|
+
*
|
|
122
|
+
* - Example: https://samples.needle.tools/physics-basic
|
|
123
|
+
* - Example: https://samples.needle.tools/physics-playground
|
|
124
|
+
* - Example: https://samples.needle.tools/physics-&-animation
|
|
125
|
+
*
|
|
115
126
|
* @category Physics
|
|
116
127
|
* @group Components
|
|
117
128
|
*/
|
|
@@ -158,6 +169,11 @@ export class SphereCollider extends Collider implements ISphereCollider {
|
|
|
158
169
|
/**
|
|
159
170
|
* BoxCollider represents a box-shaped collision volume.
|
|
160
171
|
* Ideal for rectangular objects or objects that need a simple cuboid collision boundary.
|
|
172
|
+
*
|
|
173
|
+
* - Example: https://samples.needle.tools/physics-basic
|
|
174
|
+
* - Example: https://samples.needle.tools/physics-playground
|
|
175
|
+
* - Example: https://samples.needle.tools/physics-&-animation
|
|
176
|
+
*
|
|
161
177
|
* @category Physics
|
|
162
178
|
* @group Components
|
|
163
179
|
*/
|
|
@@ -260,6 +276,11 @@ export class BoxCollider extends Collider implements IBoxCollider {
|
|
|
260
276
|
/**
|
|
261
277
|
* MeshCollider creates a collision shape from a mesh geometry.
|
|
262
278
|
* Allows for complex collision shapes that match the exact geometry of an object.
|
|
279
|
+
*
|
|
280
|
+
* - Example: https://samples.needle.tools/physics-basic
|
|
281
|
+
* - Example: https://samples.needle.tools/physics-playground
|
|
282
|
+
* - Example: https://samples.needle.tools/physics-&-animation
|
|
283
|
+
*
|
|
263
284
|
* @category Physics
|
|
264
285
|
* @group Components
|
|
265
286
|
*/
|
|
@@ -343,6 +364,11 @@ export class MeshCollider extends Collider {
|
|
|
343
364
|
/**
|
|
344
365
|
* CapsuleCollider represents a capsule-shaped collision volume (cylinder with hemispherical ends).
|
|
345
366
|
* Ideal for character controllers and objects that need a rounded collision shape.
|
|
367
|
+
*
|
|
368
|
+
* - Example: https://samples.needle.tools/physics-basic
|
|
369
|
+
* - Example: https://samples.needle.tools/physics-playground
|
|
370
|
+
* - Example: https://samples.needle.tools/physics-&-animation
|
|
371
|
+
*
|
|
346
372
|
* @category Physics
|
|
347
373
|
* @group Components
|
|
348
374
|
*/
|
|
@@ -44,10 +44,19 @@ type FitParameters = {
|
|
|
44
44
|
// - node can simply be scaled in Y to adjust max. ground height
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
* ContactShadows is a component that allows to display contact shadows in the scene.
|
|
47
|
+
* ContactShadows is a component that allows to display contact shadows in the scene. It has options for darkness, opacity and blur of the shadows.
|
|
48
|
+
*
|
|
49
|
+
* - Example: https://samples.needle.tools/contact-shadows
|
|
50
|
+
*
|
|
51
|
+
* ## Usage
|
|
52
|
+
* You can use {@link ContactShadows.auto} to automatically create a ContactShadows instance for the scene or you can add the component to an object in the scene. Note that the scale of the object will be used to define the size of the shadow area.
|
|
53
|
+
*
|
|
54
|
+
* ContactShadows can also be enabled on the `<needle-engine>` web component directly by adding the `contactshadows` attribute. The value of the attribute will be used as opacity and darkness of the shadows: `<needle-engine contactshadows="0.7">`.
|
|
55
|
+
*
|
|
56
|
+
*
|
|
48
57
|
* @category Rendering
|
|
49
58
|
* @group Components
|
|
50
|
-
|
|
59
|
+
*/
|
|
51
60
|
export class ContactShadows extends Behaviour {
|
|
52
61
|
|
|
53
62
|
private static readonly _instances: Map<Context, ContactShadows> = new Map();
|
|
@@ -362,8 +371,7 @@ export class ContactShadows extends Behaviour {
|
|
|
362
371
|
!this.depthMaterial || !this.shadowCamera ||
|
|
363
372
|
!this.blurPlane || !this.shadowGroup || !this.plane ||
|
|
364
373
|
!this.horizontalBlurMaterial || !this.verticalBlurMaterial) {
|
|
365
|
-
if (debug)
|
|
366
|
-
console.error("ContactShadows: not initialized yet");
|
|
374
|
+
if (debug) console.error("ContactShadows: not initialized yet");
|
|
367
375
|
return;
|
|
368
376
|
}
|
|
369
377
|
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Box3, Object3D, Vector2, Vector3 } from "three";
|
|
2
2
|
|
|
3
3
|
import { isDevEnvironment } from "../engine/debug/index.js";
|
|
4
4
|
import { AnimationUtils } from "../engine/engine_animation.js";
|
|
5
|
-
import { addComponent } from "../engine/engine_components.js";
|
|
6
5
|
import { Context } from "../engine/engine_context.js";
|
|
7
6
|
import { destroy } from "../engine/engine_gameobject.js";
|
|
8
7
|
import { Gizmos } from "../engine/engine_gizmos.js";
|
|
9
8
|
import { getLoader } from "../engine/engine_gltf.js";
|
|
10
9
|
import { BlobStorage } from "../engine/engine_networking_blob.js";
|
|
11
10
|
import { PreviewHelper } from "../engine/engine_networking_files.js";
|
|
12
|
-
import {
|
|
11
|
+
import { InstantiateIdProvider } from "../engine/engine_networking_instantiate.js";
|
|
13
12
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
14
13
|
import { fitObjectIntoVolume, getBoundingBox, placeOnSurface } from "../engine/engine_three_utils.js";
|
|
15
|
-
import {
|
|
14
|
+
import { Model, Vec3 } from "../engine/engine_types.js";
|
|
16
15
|
import { getParam, setParamWithoutReload } from "../engine/engine_utils.js";
|
|
17
16
|
import { determineMimeTypeFromExtension } from "../engine/engine_utils_format.js";
|
|
18
|
-
import { Animation } from "./Animation.js";
|
|
19
17
|
import { Behaviour } from "./Component.js";
|
|
20
18
|
import { EventList } from "./EventList.js";
|
|
19
|
+
import { Renderer } from "./Renderer.js";
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
22
|
* Debug mode can be enabled with the URL parameter `?debugdroplistener`, which
|
|
@@ -116,6 +115,8 @@ const blobKeyName = "blob";
|
|
|
116
115
|
* If {@link useNetworking} is enabled, the DropListener will automatically synchronize dropped files to other connected clients.
|
|
117
116
|
* Enable {@link fitIntoVolume} to automatically scale dropped objects to fit within the volume defined by {@link fitVolumeSize}.
|
|
118
117
|
*
|
|
118
|
+
* - Example: [DropListener Sample](https://droplistener-zubcksz1veaoo.needle.run/)
|
|
119
|
+
*
|
|
119
120
|
* The following events are dispatched by the DropListener:
|
|
120
121
|
* - **object-added** - dispatched when a new object is added to the scene
|
|
121
122
|
* - **file-dropped** - dispatched when a file is dropped into the scene
|
|
@@ -214,7 +215,14 @@ export class DropListener extends Behaviour {
|
|
|
214
215
|
}
|
|
215
216
|
|
|
216
217
|
|
|
217
|
-
|
|
218
|
+
awake() {
|
|
219
|
+
for (const ch of this.gameObject.children) {
|
|
220
|
+
if (this.dropArea && ch.contains(this.dropArea)) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
this._addedObjects.push(ch);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
218
226
|
|
|
219
227
|
// #region internals
|
|
220
228
|
|
|
@@ -223,7 +231,15 @@ export class DropListener extends Behaviour {
|
|
|
223
231
|
this.context.renderer.domElement.addEventListener("dragover", this.onDrag);
|
|
224
232
|
this.context.renderer.domElement.addEventListener("drop", this.onDrop);
|
|
225
233
|
window.addEventListener("paste", this.handlePaste);
|
|
226
|
-
this.context.connection.beginListen("droplistener", this.onNetworkEvent)
|
|
234
|
+
this.context.connection.beginListen("droplistener", this.onNetworkEvent);
|
|
235
|
+
if (isDevEnvironment()) {
|
|
236
|
+
if (this.dropArea) {
|
|
237
|
+
const anyRenderer = this.dropArea.getComponentInChildren(Renderer);
|
|
238
|
+
if (!anyRenderer) {
|
|
239
|
+
console.warn("[DropListener] The assigned DropArea does not seem to have a renderer/mesh. Drag and Drop events will not be detected.");
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
227
243
|
}
|
|
228
244
|
/** @internal */
|
|
229
245
|
onDisable(): void {
|
|
@@ -287,6 +303,7 @@ export class DropListener extends Behaviour {
|
|
|
287
303
|
* @param evt The drag event
|
|
288
304
|
*/
|
|
289
305
|
private onDrag = (evt: DragEvent) => {
|
|
306
|
+
if(debug) console.debug("DropListener Drag", evt, this.context.connection.allowEditing);
|
|
290
307
|
if (this.context.connection.allowEditing === false) return;
|
|
291
308
|
// necessary to get drop event
|
|
292
309
|
evt.preventDefault();
|
|
@@ -298,9 +315,9 @@ export class DropListener extends Behaviour {
|
|
|
298
315
|
* @param evt The drop event
|
|
299
316
|
*/
|
|
300
317
|
private onDrop = async (evt: DragEvent) => {
|
|
318
|
+
if (debug) console.debug("DropListener Drop", evt, this.context.connection.allowEditing);
|
|
301
319
|
if (this.context.connection.allowEditing === false) return;
|
|
302
320
|
|
|
303
|
-
if (debug) console.log(evt);
|
|
304
321
|
if (!evt?.dataTransfer) return;
|
|
305
322
|
// If the event is marked as handled for droplisteners then ignore it
|
|
306
323
|
if (evt["droplistener:handled"]) return;
|
|
@@ -473,7 +490,7 @@ export class DropListener extends Behaviour {
|
|
|
473
490
|
if (doDestroy) {
|
|
474
491
|
for (const prev of this._addedObjects) {
|
|
475
492
|
if (prev.parent === this.gameObject) {
|
|
476
|
-
destroy(
|
|
493
|
+
prev.destroy();
|
|
477
494
|
}
|
|
478
495
|
}
|
|
479
496
|
}
|
|
@@ -596,24 +613,28 @@ export class DropListener extends Behaviour {
|
|
|
596
613
|
* @returns True if the drop is valid (either no drop area is set or the drop occurred inside it)
|
|
597
614
|
*/
|
|
598
615
|
private testIfIsInDropArea(ctx: DropContext): boolean {
|
|
616
|
+
const screenPoint = this.context.input.convertScreenspaceToRaycastSpace(ctx.screenposition.clone());
|
|
617
|
+
const hits = this.context.physics.raycast({
|
|
618
|
+
screenPoint,
|
|
619
|
+
recursive: true,
|
|
620
|
+
testObject: obj => {
|
|
621
|
+
// Ignore hits on the already added objects, they don't count as part of the dropzone
|
|
622
|
+
if (this._addedObjects.some(o => o.contains(obj))) return false;
|
|
623
|
+
return true;
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
if (!hits.length) {
|
|
627
|
+
if (isDevEnvironment()) console.log(`Dropped outside of drop area for DropListener \"${this.name}\".`);
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
const hit = hits[0];
|
|
599
632
|
if (this.dropArea) {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
targets: [this.dropArea],
|
|
603
|
-
screenPoint,
|
|
604
|
-
recursive: true,
|
|
605
|
-
testObject: obj => {
|
|
606
|
-
// Ignore hits on the already added objects, they don't count as part of the dropzone
|
|
607
|
-
if (this._addedObjects.includes(obj)) return false;
|
|
608
|
-
return true;
|
|
609
|
-
}
|
|
610
|
-
});
|
|
611
|
-
if (!hits.length) {
|
|
612
|
-
if (isDevEnvironment()) console.log(`Dropped outside of drop area for DropListener \"${this.name}\".`);
|
|
613
|
-
return false;
|
|
633
|
+
if (this.dropArea.contains(hit.object)) {
|
|
634
|
+
return true;
|
|
614
635
|
}
|
|
615
636
|
}
|
|
616
|
-
return
|
|
637
|
+
return false;
|
|
617
638
|
}
|
|
618
639
|
|
|
619
640
|
}
|
|
@@ -12,8 +12,8 @@ import { type IPointerEventHandler, PointerEventData } from "./ui/PointerEvents.
|
|
|
12
12
|
import { ObjectRaycaster } from "./ui/Raycaster.js";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* The Duplicatable component is used to duplicate a assigned {@link GameObject} when a pointer event occurs on the
|
|
16
|
-
*
|
|
15
|
+
* The Duplicatable component is used to duplicate a assigned {@link GameObject} when a pointer event occurs on the object.
|
|
16
|
+
*
|
|
17
17
|
* @category Interactivity
|
|
18
18
|
* @group Components
|
|
19
19
|
*/
|
|
@@ -97,7 +97,24 @@ export class EventListEvent<TArgs extends any> extends Event { //implements Arra
|
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
|
-
* The EventList is a class that can be used to create a list of event listeners that can be invoked
|
|
100
|
+
* The EventList is a class that can be used to create a list of event listeners that can be invoked.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* // create an event list
|
|
105
|
+
* const onClick = new EventList<(event: MouseEvent) => void>();
|
|
106
|
+
*
|
|
107
|
+
* // add an event listener
|
|
108
|
+
* onClick.addEventListener((event) => {
|
|
109
|
+
* console.log("Clicked!", event);
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* // invoke the event list
|
|
113
|
+
* onClick.invoke(new MouseEvent("click"));
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @category Events
|
|
117
|
+
* @group Utilities
|
|
101
118
|
*/
|
|
102
119
|
export class EventList<TArgs extends any = any> implements IEventList {
|
|
103
120
|
|
|
@@ -10,7 +10,10 @@ import { Behaviour } from "./Component.js";
|
|
|
10
10
|
const debug = getParam("debuggroundprojection");
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* GroundProjectedEnv creates a ground projection of the current environment map.
|
|
13
|
+
* GroundProjectedEnv creates a ground projection of the current environment map.
|
|
14
|
+
*
|
|
15
|
+
* - Example https://engine.needle.tools/samples/ground-projection
|
|
16
|
+
*
|
|
14
17
|
* @category Rendering
|
|
15
18
|
* @group Components
|
|
16
19
|
*/
|