@needle-tools/engine 4.11.0-next.8bfb2f5 → 4.11.0
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/components.needle.json +1 -1
- package/dist/{gltf-progressive-CXVECA3a.js → gltf-progressive-BvlZQAkt.js} +3 -3
- 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-lul9TfB2.js → needle-engine.bundle-Dh4X0Qy5.js} +6264 -6202
- package/dist/{needle-engine.bundle-8EmDJd2O.umd.cjs → needle-engine.bundle-DhRclTK5.umd.cjs} +142 -142
- package/dist/{needle-engine.bundle-DtF-fcok.min.js → needle-engine.bundle-IPerDSpg.min.js} +144 -144
- 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/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-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 +31 -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/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/ScrollFollow.js +1 -2
- package/lib/engine-components/web/ScrollFollow.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 +3 -3
- package/plugins/vite/index.js +4 -1
- package/plugins/vite/needle-app.js +103 -57
- package/src/engine/js-extensions/Object3D.ts +24 -0
- 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 +27 -3
- 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/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/ScrollFollow.ts +1 -1
- 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
|
@@ -45,8 +45,13 @@ export const needleApp = (command, config, userSettings) => {
|
|
|
45
45
|
// refs: context.chunk.referencedFiles,
|
|
46
46
|
// });
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
const
|
|
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);
|
|
50
55
|
await writeFile(`${outputDir}/needle-app.js`, webComponent, (err) => {
|
|
51
56
|
if (err) {
|
|
52
57
|
console.error("[needle-app] could not create needle-app.js", err);
|
|
@@ -71,78 +76,119 @@ export const needleApp = (command, config, userSettings) => {
|
|
|
71
76
|
|
|
72
77
|
/**
|
|
73
78
|
* @param {string} filepath
|
|
74
|
-
* @param {string
|
|
79
|
+
* @param {string | null} src
|
|
75
80
|
* @returns {string}
|
|
76
81
|
*/
|
|
77
|
-
function generateNeedleEmbedWebComponent(filepath,
|
|
82
|
+
function generateNeedleEmbedWebComponent(filepath, src) {
|
|
78
83
|
|
|
79
84
|
|
|
80
85
|
// filepath is e.g. `assets/index-XXXXXXXX.js`
|
|
81
86
|
// we want to make sure the path is correct relative to where the component will be used
|
|
82
87
|
// this script will be emitted in the output directory root (e.g. needle-embed.js)
|
|
83
88
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
const componentName = 'needle-app';
|
|
87
|
-
const className = 'NeedleApp';
|
|
89
|
+
const componentDefaultName = 'needle-app';
|
|
88
90
|
|
|
89
91
|
return `
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
height: 100%;
|
|
111
|
-
}
|
|
112
|
-
</style>
|
|
113
|
-
\`;
|
|
114
|
-
this.shadowRoot.appendChild(template.content.cloneNode(true));
|
|
115
|
-
|
|
116
|
-
const script = document.createElement('script');
|
|
117
|
-
script.type = 'module';
|
|
118
|
-
const url = new URL('.', import.meta.url);
|
|
119
|
-
let basePath = this.getAttribute('base-path') || \`\${url.protocol}//\${url.host}\${url.pathname}\`;
|
|
120
|
-
while(basePath.endsWith('/')) {
|
|
121
|
-
basePath = basePath.slice(0, -1);
|
|
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;
|
|
122
112
|
}
|
|
123
|
-
script.src = this.getAttribute('script-src') || \`\${basePath}/${filepath}\`;
|
|
124
|
-
this.shadowRoot.appendChild(script);
|
|
125
113
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
+
}
|
|
129
155
|
|
|
130
|
-
|
|
131
|
-
|
|
156
|
+
onConnectedCallback() {
|
|
157
|
+
console.debug('NeedleEmbed connected to the DOM');
|
|
158
|
+
}
|
|
132
159
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
+
}
|
|
136
168
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
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");
|
|
141
175
|
|
|
176
|
+
for(const attr of knownAttributes) {
|
|
177
|
+
|
|
178
|
+
if(attr === "src") continue; // already handled above
|
|
142
179
|
|
|
143
|
-
if
|
|
144
|
-
|
|
145
|
-
|
|
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.\`);
|
|
146
192
|
}
|
|
147
193
|
`
|
|
148
194
|
}
|
|
@@ -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);
|
|
@@ -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
|
*/
|
|
@@ -10,6 +10,9 @@ export class UsageMarker extends Behaviour
|
|
|
10
10
|
public usedBy: any = null;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* An empty component that can be used to mark an object as interactable.
|
|
15
|
+
* @group Components
|
|
16
|
+
*/
|
|
14
17
|
/** @deprecated */
|
|
15
18
|
export class Interactable extends Behaviour {}
|
|
@@ -255,7 +255,12 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
255
255
|
* @default 1
|
|
256
256
|
*/
|
|
257
257
|
@serializable()
|
|
258
|
-
targetLerpDuration
|
|
258
|
+
get targetLerpDuration() { return this._lookTargetLerpDuration; }
|
|
259
|
+
set targetLerpDuration(v) { this._lookTargetLerpDuration = v; }
|
|
260
|
+
private _lookTargetLerpDuration: number = 1;
|
|
261
|
+
|
|
262
|
+
@serializable(Object3D)
|
|
263
|
+
targetBounds: Object3D | null = null;
|
|
259
264
|
|
|
260
265
|
/**
|
|
261
266
|
* Rotate the camera left (or right) by the specified angle in radians.
|
|
@@ -326,7 +331,6 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
326
331
|
private _lookTargetStartPosition: Vector3 = new Vector3();
|
|
327
332
|
private _lookTargetEndPosition: Vector3 = new Vector3();
|
|
328
333
|
private _lookTargetLerp01: number = 0;
|
|
329
|
-
private _lookTargetLerpDuration: number = 0;
|
|
330
334
|
|
|
331
335
|
private _cameraLerpActive: boolean = false;
|
|
332
336
|
private _cameraStartPosition: Vector3 = new Vector3();
|
|
@@ -685,6 +689,26 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
685
689
|
}
|
|
686
690
|
}
|
|
687
691
|
|
|
692
|
+
if (this.targetBounds) {
|
|
693
|
+
// #region target bounds
|
|
694
|
+
const targetVector = this._controls.target;
|
|
695
|
+
const boundsCenter = this.targetBounds.worldPosition;
|
|
696
|
+
const boundsHalfSize = getTempVector(this.targetBounds.worldScale).multiplyScalar(0.5);
|
|
697
|
+
const min = getTempVector(boundsCenter).sub(boundsHalfSize);
|
|
698
|
+
const max = getTempVector(boundsCenter).add(boundsHalfSize);
|
|
699
|
+
const newTarget = getTempVector(this._controls.target).clamp(min, max);
|
|
700
|
+
const duration = .1;
|
|
701
|
+
if (duration <= 0) targetVector.copy(newTarget);
|
|
702
|
+
else targetVector.lerp(newTarget, this.context.time.deltaTime / duration);
|
|
703
|
+
if (this._lookTargetLerpActive) {
|
|
704
|
+
if (duration <= 0) this._lookTargetEndPosition.copy(newTarget);
|
|
705
|
+
else this._lookTargetEndPosition.lerp(newTarget, this.context.time.deltaTime / (duration * 5));
|
|
706
|
+
}
|
|
707
|
+
if (debug) {
|
|
708
|
+
Gizmos.DrawWireBox(boundsCenter, boundsHalfSize.multiplyScalar(2), 0xffaa00);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
688
712
|
|
|
689
713
|
if (this._controls) {
|
|
690
714
|
if (this.debugLog)
|
|
@@ -1000,7 +1024,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1000
1024
|
*/
|
|
1001
1025
|
fitCamera(options?: OrbitFitCameraOptions);
|
|
1002
1026
|
/** @deprecated Use fitCamera(options) */
|
|
1003
|
-
fitCamera(objects?: Object3D | Array<Object3D>, options?: Omit<OrbitFitCameraOptions, "objects">);
|
|
1027
|
+
fitCamera(objects?: Object3D | Array<Object3D>, options?: Omit<OrbitFitCameraOptions, "objects">);
|
|
1004
1028
|
fitCamera(objectsOrOptions?: Object3D | Array<Object3D> | OrbitFitCameraOptions, options?: OrbitFitCameraOptions): void {
|
|
1005
1029
|
|
|
1006
1030
|
|
|
@@ -134,7 +134,12 @@ class TransformWatch {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/**
|
|
137
|
-
* A Rigidbody is used together with a Collider to create physical interactions between objects in the scene.
|
|
137
|
+
* A Rigidbody is used together with a Collider to create physical interactions between objects in the scene.
|
|
138
|
+
*
|
|
139
|
+
* - Example: https://samples.needle.tools/physics-basic
|
|
140
|
+
* - Example: https://samples.needle.tools/physics-playground
|
|
141
|
+
* - Example: https://samples.needle.tools/physics-&-animation
|
|
142
|
+
*
|
|
138
143
|
* @category Physics
|
|
139
144
|
* @group Components
|
|
140
145
|
*/
|