@needle-tools/engine 4.9.0-alpha.4 → 4.9.0-next.ce04b9f
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/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-Bi2IbHHS.umd.cjs → needle-engine.bundle-DHAUN6T_.umd.cjs} +129 -129
- package/dist/{needle-engine.bundle-Bs7Jz8Xi.min.js → needle-engine.bundle-a5_4RZjH.min.js} +128 -128
- package/dist/{needle-engine.bundle-HZA484FG.js → needle-engine.bundle-qHhlH-u4.js} +4867 -4717
- package/dist/needle-engine.js +556 -552
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/codegen/register_types.js +8 -0
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_physics_rapier.js +8 -8
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine-components/Animation.d.ts +1 -0
- package/lib/engine-components/Animation.js +9 -0
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/EventTrigger.js.map +1 -1
- package/lib/engine-components/api.d.ts +1 -0
- package/lib/engine-components/api.js +1 -0
- package/lib/engine-components/api.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +4 -0
- package/lib/engine-components/codegen/components.js +4 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/physics/Attractor.d.ts +8 -0
- package/lib/engine-components/physics/Attractor.js +42 -0
- package/lib/engine-components/physics/Attractor.js.map +1 -0
- package/lib/engine-components/web/Clickthrough.d.ts +19 -0
- package/lib/engine-components/web/Clickthrough.js +57 -0
- package/lib/engine-components/web/Clickthrough.js.map +1 -0
- package/lib/engine-components/web/CursorFollow.d.ts +12 -0
- package/lib/engine-components/web/CursorFollow.js +46 -0
- package/lib/engine-components/web/CursorFollow.js.map +1 -0
- package/lib/engine-components/web/ScrollFollow.d.ts +27 -0
- package/lib/engine-components/web/ScrollFollow.js +85 -0
- package/lib/engine-components/web/ScrollFollow.js.map +1 -0
- package/lib/engine-components/web/index.d.ts +3 -0
- package/lib/engine-components/web/index.js +4 -0
- package/lib/engine-components/web/index.js.map +1 -0
- package/package.json +2 -2
- package/src/engine/codegen/register_types.ts +8 -0
- package/src/engine/engine_physics_rapier.ts +11 -11
- package/src/engine-components/Animation.ts +9 -0
- package/src/engine-components/EventTrigger.ts +0 -1
- package/src/engine-components/api.ts +1 -0
- package/src/engine-components/codegen/components.ts +4 -0
- package/src/engine-components/physics/Attractor.ts +35 -0
- package/src/engine-components/web/Clickthrough.ts +60 -0
- package/src/engine-components/web/CursorFollow.ts +49 -0
- package/src/engine-components/web/ScrollFollow.ts +91 -0
- package/src/engine-components/web/index.ts +3 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Behaviour } from "../Component.js";
|
|
2
|
+
export declare class CursorFollow extends Behaviour {
|
|
3
|
+
/**
|
|
4
|
+
* Damping for the movement, set to 0 for instant movement
|
|
5
|
+
* @default 0
|
|
6
|
+
*/
|
|
7
|
+
damping: number;
|
|
8
|
+
private _distance;
|
|
9
|
+
updateDistance(): void;
|
|
10
|
+
/** @internal */
|
|
11
|
+
update(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
|
8
|
+
import { getTempVector } from "../../engine/engine_three_utils.js";
|
|
9
|
+
import { Behaviour } from "../Component.js";
|
|
10
|
+
export class CursorFollow extends Behaviour {
|
|
11
|
+
/**
|
|
12
|
+
* Damping for the movement, set to 0 for instant movement
|
|
13
|
+
* @default 0
|
|
14
|
+
*/
|
|
15
|
+
damping = 0;
|
|
16
|
+
_distance = -1;
|
|
17
|
+
updateDistance() {
|
|
18
|
+
this._distance = this.gameObject.worldPosition.distanceTo(this.context.mainCamera.worldPosition);
|
|
19
|
+
}
|
|
20
|
+
/** @internal */
|
|
21
|
+
update() {
|
|
22
|
+
// continuously update distance in case camera or object moves
|
|
23
|
+
this.updateDistance();
|
|
24
|
+
// follow cursor in screenspace but maintain initial distance from camera
|
|
25
|
+
const cursor = this.context.input.mousePositionRC;
|
|
26
|
+
const camera = this.context.mainCamera;
|
|
27
|
+
const cameraPosition = camera.worldPosition;
|
|
28
|
+
// create ray from camera through cursor position
|
|
29
|
+
const rayDirection = getTempVector(cursor.x, cursor.y, 1).unproject(camera);
|
|
30
|
+
rayDirection.sub(cameraPosition).normalize();
|
|
31
|
+
// position object at initial distance along the ray
|
|
32
|
+
const newPosition = rayDirection.multiplyScalar(this._distance).add(cameraPosition);
|
|
33
|
+
if (this.damping > 0) {
|
|
34
|
+
const pos = this.gameObject.worldPosition;
|
|
35
|
+
pos.lerp(newPosition, this.context.time.deltaTime / this.damping);
|
|
36
|
+
this.gameObject.worldPosition = pos;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.gameObject.worldPosition = newPosition;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
__decorate([
|
|
44
|
+
serializable()
|
|
45
|
+
], CursorFollow.prototype, "damping", void 0);
|
|
46
|
+
//# sourceMappingURL=CursorFollow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CursorFollow.js","sourceRoot":"","sources":["../../../src/engine-components/web/CursorFollow.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gDAAgD,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,MAAM,OAAO,YAAa,SAAQ,SAAS;IAEvC;;;OAGG;IAEH,OAAO,GAAW,CAAC,CAAC;IAGZ,SAAS,GAAW,CAAC,CAAC,CAAC;IAC/B,cAAc;QACV,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACrG,CAAC;IAGD,gBAAgB;IAChB,MAAM;QACF,8DAA8D;QAC9D,IAAI,CAAC,cAAc,EAAE,CAAC;QAEtB,yEAAyE;QACzE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QACvC,MAAM,cAAc,GAAG,MAAM,CAAC,aAAa,CAAC;QAE5C,iDAAiD;QACjD,MAAM,YAAY,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC5E,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,SAAS,EAAE,CAAC;QAE7C,oDAAoD;QACpD,MAAM,WAAW,GAAG,YAAY,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACpF,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE;YAClB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;YAC1C,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;YAClE,IAAI,CAAC,UAAU,CAAC,aAAa,GAAG,GAAG,CAAC;SACvC;aACI;YACD,IAAI,CAAC,UAAU,CAAC,aAAa,GAAG,WAAW,CAAC;SAC/C;IAEL,CAAC;CAEJ;AApCG;IADC,YAAY,EAAE;6CACK"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Behaviour } from "../Component.js";
|
|
2
|
+
export declare class ScrollFollow extends Behaviour {
|
|
3
|
+
/**
|
|
4
|
+
* Target object(s) to follow the scroll position of the page. If null, the main camera is used.
|
|
5
|
+
*/
|
|
6
|
+
target: object[] | object | null;
|
|
7
|
+
/**
|
|
8
|
+
* Damping for the movement, set to 0 for instant movement
|
|
9
|
+
* @default 0
|
|
10
|
+
*/
|
|
11
|
+
damping: number;
|
|
12
|
+
mode: "window";
|
|
13
|
+
/**
|
|
14
|
+
* Current scroll value in "pages" (0 = top of page, 1 = bottom of page)
|
|
15
|
+
*/
|
|
16
|
+
get currentValue(): number;
|
|
17
|
+
private current_value;
|
|
18
|
+
private target_value;
|
|
19
|
+
/** @internal */
|
|
20
|
+
onEnable(): void;
|
|
21
|
+
/** @internal */
|
|
22
|
+
onDisable(): void;
|
|
23
|
+
/** @internal */
|
|
24
|
+
lateUpdate(): void;
|
|
25
|
+
private updateCurrentScroll;
|
|
26
|
+
private applyScroll;
|
|
27
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Object3D } from "three";
|
|
8
|
+
import { serializable } from "../../engine/engine_serialization.js";
|
|
9
|
+
import { Mathf } from "../../engine/engine_math.js";
|
|
10
|
+
import { Behaviour } from "../Component.js";
|
|
11
|
+
import { Animation, PlayableDirector } from "../api.js";
|
|
12
|
+
export class ScrollFollow extends Behaviour {
|
|
13
|
+
/**
|
|
14
|
+
* Target object(s) to follow the scroll position of the page. If null, the main camera is used.
|
|
15
|
+
*/
|
|
16
|
+
target = null;
|
|
17
|
+
/**
|
|
18
|
+
* Damping for the movement, set to 0 for instant movement
|
|
19
|
+
* @default 0
|
|
20
|
+
*/
|
|
21
|
+
damping = 0;
|
|
22
|
+
mode = "window";
|
|
23
|
+
/**
|
|
24
|
+
* Current scroll value in "pages" (0 = top of page, 1 = bottom of page)
|
|
25
|
+
*/
|
|
26
|
+
get currentValue() {
|
|
27
|
+
return this.current_value;
|
|
28
|
+
}
|
|
29
|
+
current_value = 0;
|
|
30
|
+
target_value = 0;
|
|
31
|
+
/** @internal */
|
|
32
|
+
onEnable() {
|
|
33
|
+
window.addEventListener("wheel", this.updateCurrentScroll, { passive: true });
|
|
34
|
+
}
|
|
35
|
+
/** @internal */
|
|
36
|
+
onDisable() {
|
|
37
|
+
window.removeEventListener("wheel", this.updateCurrentScroll);
|
|
38
|
+
}
|
|
39
|
+
/** @internal */
|
|
40
|
+
lateUpdate() {
|
|
41
|
+
// apply damping if any
|
|
42
|
+
if (this.damping > 0) {
|
|
43
|
+
this.current_value = Mathf.lerp(this.current_value, this.target_value, this.context.time.deltaTime / this.damping);
|
|
44
|
+
}
|
|
45
|
+
// apply scroll to target(s)
|
|
46
|
+
if (Array.isArray(this.target)) {
|
|
47
|
+
this.target.forEach(t => t && this.applyScroll(t));
|
|
48
|
+
}
|
|
49
|
+
else if (this.target) {
|
|
50
|
+
this.applyScroll(this.target);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
updateCurrentScroll = () => {
|
|
54
|
+
switch (this.mode) {
|
|
55
|
+
case "window":
|
|
56
|
+
this.target_value = window.scrollY / (document.body.scrollHeight - window.innerHeight);
|
|
57
|
+
if (isNaN(this.target_value) || !isFinite(this.target_value))
|
|
58
|
+
this.target_value = 0;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
if (this.damping <= 0) {
|
|
62
|
+
this.current_value = this.target_value;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
applyScroll(target) {
|
|
66
|
+
if (target instanceof PlayableDirector) {
|
|
67
|
+
target.time = this.current_value * target.duration;
|
|
68
|
+
if (!target.isPlaying)
|
|
69
|
+
target.evaluate();
|
|
70
|
+
}
|
|
71
|
+
else if (target instanceof Animation) {
|
|
72
|
+
target.time = this.current_value * target.duration;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
__decorate([
|
|
77
|
+
serializable([Behaviour, Object3D])
|
|
78
|
+
], ScrollFollow.prototype, "target", void 0);
|
|
79
|
+
__decorate([
|
|
80
|
+
serializable()
|
|
81
|
+
], ScrollFollow.prototype, "damping", void 0);
|
|
82
|
+
__decorate([
|
|
83
|
+
serializable()
|
|
84
|
+
], ScrollFollow.prototype, "mode", void 0);
|
|
85
|
+
//# sourceMappingURL=ScrollFollow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScrollFollow.js","sourceRoot":"","sources":["../../../src/engine-components/web/ScrollFollow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine-components/web/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "4.9.0-
|
|
3
|
+
"version": "4.9.0-next.ce04b9f",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.",
|
|
5
5
|
"main": "dist/needle-engine.min.js",
|
|
6
6
|
"exports": {
|
|
@@ -168,4 +168,4 @@
|
|
|
168
168
|
"module": "lib/needle-engine.js",
|
|
169
169
|
"typings": "lib/needle-engine.d.ts",
|
|
170
170
|
"types": "lib/needle-engine.d.ts"
|
|
171
|
-
}
|
|
171
|
+
}
|
|
@@ -67,6 +67,7 @@ import { CameraTargetReachedEvent } from "../../engine-components/OrbitControls.
|
|
|
67
67
|
import { OrbitControls } from "../../engine-components/OrbitControls.js";
|
|
68
68
|
import { ParticleSystemRenderer } from "../../engine-components/particlesystem/ParticleSystem.js";
|
|
69
69
|
import { ParticleSystem } from "../../engine-components/particlesystem/ParticleSystem.js";
|
|
70
|
+
import { Attractor } from "../../engine-components/physics/Attractor.js";
|
|
70
71
|
import { PlayerColor } from "../../engine-components/PlayerColor.js";
|
|
71
72
|
import { Antialiasing } from "../../engine-components/postprocessing/Effects/Antialiasing.js";
|
|
72
73
|
import { BloomEffect } from "../../engine-components/postprocessing/Effects/BloomEffect.js";
|
|
@@ -136,6 +137,9 @@ import { LookAt } from "../../engine-components/utils/LookAt.js";
|
|
|
136
137
|
import { OpenURL } from "../../engine-components/utils/OpenURL.js";
|
|
137
138
|
import { VideoPlayer } from "../../engine-components/VideoPlayer.js";
|
|
138
139
|
import { Voip } from "../../engine-components/Voip.js";
|
|
140
|
+
import { ClickThrough } from "../../engine-components/web/Clickthrough.js";
|
|
141
|
+
import { CursorFollow } from "../../engine-components/web/CursorFollow.js";
|
|
142
|
+
import { ScrollFollow } from "../../engine-components/web/ScrollFollow.js";
|
|
139
143
|
import { Avatar } from "../../engine-components/webxr/Avatar.js";
|
|
140
144
|
import { XRControllerFollow } from "../../engine-components/webxr/controllers/XRControllerFollow.js";
|
|
141
145
|
import { XRControllerModel } from "../../engine-components/webxr/controllers/XRControllerModel.js";
|
|
@@ -219,6 +223,7 @@ TypeStore.add("CameraTargetReachedEvent", CameraTargetReachedEvent);
|
|
|
219
223
|
TypeStore.add("OrbitControls", OrbitControls);
|
|
220
224
|
TypeStore.add("ParticleSystemRenderer", ParticleSystemRenderer);
|
|
221
225
|
TypeStore.add("ParticleSystem", ParticleSystem);
|
|
226
|
+
TypeStore.add("Attractor", Attractor);
|
|
222
227
|
TypeStore.add("PlayerColor", PlayerColor);
|
|
223
228
|
TypeStore.add("Antialiasing", Antialiasing);
|
|
224
229
|
TypeStore.add("BloomEffect", BloomEffect);
|
|
@@ -288,6 +293,9 @@ TypeStore.add("LookAt", LookAt);
|
|
|
288
293
|
TypeStore.add("OpenURL", OpenURL);
|
|
289
294
|
TypeStore.add("VideoPlayer", VideoPlayer);
|
|
290
295
|
TypeStore.add("Voip", Voip);
|
|
296
|
+
TypeStore.add("ClickThrough", ClickThrough);
|
|
297
|
+
TypeStore.add("CursorFollow", CursorFollow);
|
|
298
|
+
TypeStore.add("ScrollFollow", ScrollFollow);
|
|
291
299
|
TypeStore.add("Avatar", Avatar);
|
|
292
300
|
TypeStore.add("XRControllerFollow", XRControllerFollow);
|
|
293
301
|
TypeStore.add("XRControllerModel", XRControllerModel);
|
|
@@ -164,13 +164,13 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
164
164
|
this.validate();
|
|
165
165
|
const body = this.internal_getRigidbody(rigidbody);
|
|
166
166
|
if (body) body.addForce(force, wakeup)
|
|
167
|
-
else console.warn("
|
|
167
|
+
else if (this._isInitialized) console.warn("Physics Body doesn't exist: can not apply force (does your object with the Rigidbody have a collider?)");
|
|
168
168
|
}
|
|
169
169
|
addImpulse(rigidbody: IRigidbody, force: Vec3, wakeup: boolean) {
|
|
170
170
|
this.validate();
|
|
171
171
|
const body = this.internal_getRigidbody(rigidbody);
|
|
172
172
|
if (body) body.applyImpulse(force, wakeup);
|
|
173
|
-
else console.warn("
|
|
173
|
+
else if (this._isInitialized) console.warn("Physics Body doesn't exist: can not apply impulse (does your object with the Rigidbody have a collider?)");
|
|
174
174
|
}
|
|
175
175
|
getLinearVelocity(comp: IRigidbody | ICollider): Vec3 | null {
|
|
176
176
|
this.validate();
|
|
@@ -206,14 +206,14 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
206
206
|
this.validate();
|
|
207
207
|
const body = this.internal_getRigidbody(rb);
|
|
208
208
|
if (body) body.applyImpulse(vec, wakeup);
|
|
209
|
-
else console.warn("Rigidbody doesn't exist: can not apply impulse (does your object with the Rigidbody have a collider?)");
|
|
209
|
+
else if (this._isInitialized) console.warn("Rigidbody doesn't exist: can not apply impulse (does your object with the Rigidbody have a collider?)");
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
wakeup(rb: IRigidbody) {
|
|
213
213
|
this.validate();
|
|
214
214
|
const body = this.internal_getRigidbody(rb);
|
|
215
215
|
if (body) body.wakeUp();
|
|
216
|
-
else console.warn("Rigidbody doesn't exist: can not wake up (does your object with the Rigidbody have a collider?)");
|
|
216
|
+
else if (this._isInitialized) console.warn("Rigidbody doesn't exist: can not wake up (does your object with the Rigidbody have a collider?)");
|
|
217
217
|
}
|
|
218
218
|
isSleeping(rb: IRigidbody) {
|
|
219
219
|
this.validate();
|
|
@@ -224,13 +224,13 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
224
224
|
this.validate();
|
|
225
225
|
const body = this.internal_getRigidbody(rb);
|
|
226
226
|
if (body) body.setAngvel(vec, wakeup);
|
|
227
|
-
else console.warn("Rigidbody doesn't exist: can not set angular velocity (does your object with the Rigidbody have a collider?)");
|
|
227
|
+
else if (this._isInitialized) console.warn("Rigidbody doesn't exist: can not set angular velocity (does your object with the Rigidbody have a collider?)");
|
|
228
228
|
}
|
|
229
229
|
setLinearVelocity(rb: IRigidbody, vec: Vec3, wakeup: boolean) {
|
|
230
230
|
this.validate();
|
|
231
231
|
const body = this.internal_getRigidbody(rb);
|
|
232
232
|
if (body) body.setLinvel(vec, wakeup);
|
|
233
|
-
else console.warn("Rigidbody doesn't exist: can not set linear velocity (does your object with the Rigidbody have a collider?)");
|
|
233
|
+
else if (this._isInitialized) console.warn("Rigidbody doesn't exist: can not set linear velocity (does your object with the Rigidbody have a collider?)");
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
private readonly context?: IContext;
|
|
@@ -273,7 +273,7 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
273
273
|
if (debugPhysics) console.trace("Loading rapier physics engine");
|
|
274
274
|
const module = await MODULES.RAPIER_PHYSICS.load();
|
|
275
275
|
// https://github.com/dimforge/rapier/issues/811
|
|
276
|
-
await module.init();
|
|
276
|
+
await module.init();
|
|
277
277
|
}
|
|
278
278
|
if (debugPhysics) console.log("Physics engine initialized, creating world...");
|
|
279
279
|
this._world = new MODULES.RAPIER_PHYSICS.MODULE.World(this._gravity);
|
|
@@ -673,7 +673,7 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
673
673
|
}
|
|
674
674
|
|
|
675
675
|
async addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, extraScale?: Vector3) {
|
|
676
|
-
|
|
676
|
+
|
|
677
677
|
// capture the geometry before waiting for phyiscs engine
|
|
678
678
|
let geo = mesh.geometry;
|
|
679
679
|
if (!geo) {
|
|
@@ -714,13 +714,13 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
714
714
|
}
|
|
715
715
|
|
|
716
716
|
if (!collider.activeAndEnabled) return;
|
|
717
|
-
|
|
717
|
+
|
|
718
718
|
|
|
719
719
|
// let positions = geo.getAttribute("position").array as Float32Array;
|
|
720
720
|
const indices = geo.index?.array as Uint32Array;
|
|
721
|
-
|
|
721
|
+
|
|
722
722
|
const scale = collider.gameObject.worldScale.clone();
|
|
723
|
-
if(extraScale) scale.multiply(extraScale);
|
|
723
|
+
if (extraScale) scale.multiply(extraScale);
|
|
724
724
|
|
|
725
725
|
// scaling seems not supported yet https://github.com/dimforge/rapier/issues/243
|
|
726
726
|
if (Math.abs(scale.x - 1) > 0.0001 || Math.abs(scale.y - 1) > 0.0001 || Math.abs(scale.z - 1) > 0.0001) {
|
|
@@ -130,6 +130,15 @@ export class Animation extends Behaviour implements IAnimationComponent {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
get duration() {
|
|
134
|
+
if (this.actions) {
|
|
135
|
+
for (const action of this.actions) {
|
|
136
|
+
if (action.isRunning()) return action.getClip().duration;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
133
142
|
private _tempAnimationClipBeforeGameObjectExisted: AnimationClip | null = null;
|
|
134
143
|
/**
|
|
135
144
|
* Get the first animation clip in the animations array
|
|
@@ -56,6 +56,7 @@ export type { DropListenerNetworkEventArguments, DropListenerOnDropArguments } f
|
|
|
56
56
|
export { type FitCameraOptions } from "./OrbitControls.js";
|
|
57
57
|
export * from "./particlesystem/api.js"
|
|
58
58
|
export * from "./splines/index.js";
|
|
59
|
+
export * from "./web/index.js";
|
|
59
60
|
|
|
60
61
|
// for correct type resolution in JSDoc
|
|
61
62
|
import type { PhysicsMaterial } from "../engine/engine_physics.types.js";
|
|
@@ -115,6 +115,7 @@ export { InheritVelocityModule } from "../particlesystem/ParticleSystemModules.j
|
|
|
115
115
|
export { SizeBySpeedModule } from "../particlesystem/ParticleSystemModules.js";
|
|
116
116
|
export { ColorBySpeedModule } from "../particlesystem/ParticleSystemModules.js";
|
|
117
117
|
export { ParticleSubEmitter } from "../particlesystem/ParticleSystemSubEmitter.js";
|
|
118
|
+
export { Attractor } from "../physics/Attractor.js";
|
|
118
119
|
export { PlayerColor } from "../PlayerColor.js";
|
|
119
120
|
export { Antialiasing } from "../postprocessing/Effects/Antialiasing.js";
|
|
120
121
|
export { BloomEffect } from "../postprocessing/Effects/BloomEffect.js";
|
|
@@ -202,6 +203,9 @@ export { LookAt } from "../utils/LookAt.js";
|
|
|
202
203
|
export { OpenURL } from "../utils/OpenURL.js";
|
|
203
204
|
export { VideoPlayer } from "../VideoPlayer.js";
|
|
204
205
|
export { Voip } from "../Voip.js";
|
|
206
|
+
export { ClickThrough } from "../web/Clickthrough.js";
|
|
207
|
+
export { CursorFollow } from "../web/CursorFollow.js";
|
|
208
|
+
export { ScrollFollow } from "../web/ScrollFollow.js";
|
|
205
209
|
export { Avatar } from "../webxr/Avatar.js";
|
|
206
210
|
export { XRControllerFollow } from "../webxr/controllers/XRControllerFollow.js";
|
|
207
211
|
export { XRControllerModel } from "../webxr/controllers/XRControllerModel.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Behaviour } from "../Component.js";
|
|
2
|
+
import { Rigidbody } from "../RigidBody.js";
|
|
3
|
+
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export class Attractor extends Behaviour {
|
|
8
|
+
|
|
9
|
+
@serializable()
|
|
10
|
+
strength: number = 1;
|
|
11
|
+
|
|
12
|
+
@serializable()
|
|
13
|
+
radius: number = 2;
|
|
14
|
+
|
|
15
|
+
@serializable(Rigidbody)
|
|
16
|
+
targets: Rigidbody[] = [];
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
update() {
|
|
20
|
+
const wp = this.gameObject.worldPosition;
|
|
21
|
+
const factor = -this.strength * this.context.time.deltaTime;
|
|
22
|
+
this.targets.forEach(t => {
|
|
23
|
+
if(!t) return;
|
|
24
|
+
const dir = t.gameObject.worldPosition.sub(wp);
|
|
25
|
+
const length = dir.length();
|
|
26
|
+
if (length > this.radius) return;
|
|
27
|
+
let _factor = factor;
|
|
28
|
+
if (length > 1) _factor /= length * length;
|
|
29
|
+
else _factor /= Math.max(.05, length);
|
|
30
|
+
t.applyImpulse(dir.multiplyScalar(_factor));
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { NEPointerEvent } from "../../engine/engine_input.js";
|
|
2
|
+
import { Behaviour } from "../Component.js";
|
|
3
|
+
import { onStart } from "../../engine/engine_lifecycle_api.js";
|
|
4
|
+
|
|
5
|
+
// Automatically add ClickThrough component if "clickthrough" attribute is present on the needle-engine element
|
|
6
|
+
onStart(ctx => {
|
|
7
|
+
const attribute = ctx.domElement.getAttribute("clickthrough");
|
|
8
|
+
if (attribute !== null && attribute !== "0" && attribute !== "false") {
|
|
9
|
+
ctx.scene.addComponent(ClickThrough);
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* ClickThrough component allows pointer events to "click through" the 3D canvas to HTML elements behind it.
|
|
16
|
+
*
|
|
17
|
+
* This is useful if you have a transparent canvas overlaying HTML content and want to interact with the HTML content through the transparent areas of the canvas.
|
|
18
|
+
*
|
|
19
|
+
* Usage Options:
|
|
20
|
+
* - Add the ClickThrough component to any GameObject in your scene.
|
|
21
|
+
* - Alternatively, add the `clickthrough` attribute to the `<needle-engine>` HTML element (e.g. `<needle-engine clickthrough></needle-engine>`).
|
|
22
|
+
*
|
|
23
|
+
* @link Example https://stackblitz.com/~/github.com/needle-engine/sample-3d-over-html
|
|
24
|
+
*/
|
|
25
|
+
export class ClickThrough extends Behaviour {
|
|
26
|
+
onEnable() {
|
|
27
|
+
// Register for pointer down and pointer move event
|
|
28
|
+
this.context.input.addEventListener('pointerdown', this.onPointerEvent);
|
|
29
|
+
this.context.input.addEventListener('pointermove', this.onPointerEvent, {
|
|
30
|
+
queue: 100,
|
|
31
|
+
});
|
|
32
|
+
window.addEventListener("touchend", this.onTouchEnd, { passive: true });
|
|
33
|
+
}
|
|
34
|
+
onDisable() {
|
|
35
|
+
this.context.input.removeEventListener('pointerdown', this.onPointerEvent);
|
|
36
|
+
this.context.input.removeEventListener('pointermove', this.onPointerEvent);
|
|
37
|
+
window.removeEventListener("touchend", this.onTouchEnd);
|
|
38
|
+
this.context.domElement.style.pointerEvents = 'all';
|
|
39
|
+
}
|
|
40
|
+
onPointerEnter() {
|
|
41
|
+
/** do nothing, necessary to raycast children */
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private onPointerEvent = (evt: NEPointerEvent) => {
|
|
45
|
+
if (evt.pointerId > 0) return;
|
|
46
|
+
const intersections = evt.intersections;
|
|
47
|
+
// If we don't had any intersections during the 3D raycasting then we disable pointer events for the needle-engine element so that content BEHIND the 3D element can receive pointer events
|
|
48
|
+
if (intersections?.length <= 0) {
|
|
49
|
+
this.context.domElement.style.pointerEvents = 'none';
|
|
50
|
+
} else {
|
|
51
|
+
this.context.domElement.style.pointerEvents = 'all';
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
private onTouchEnd = (_evt: TouchEvent) => {
|
|
56
|
+
setTimeout(() => {
|
|
57
|
+
this.context.domElement.style.pointerEvents = 'all';
|
|
58
|
+
}, 100);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
|
2
|
+
import { getTempVector } from "../../engine/engine_three_utils.js";
|
|
3
|
+
import { Behaviour } from "../Component.js";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class CursorFollow extends Behaviour {
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Damping for the movement, set to 0 for instant movement
|
|
10
|
+
* @default 0
|
|
11
|
+
*/
|
|
12
|
+
@serializable()
|
|
13
|
+
damping: number = 0;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
private _distance: number = -1;
|
|
17
|
+
updateDistance() {
|
|
18
|
+
this._distance = this.gameObject.worldPosition.distanceTo(this.context.mainCamera.worldPosition);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/** @internal */
|
|
23
|
+
update() {
|
|
24
|
+
// continuously update distance in case camera or object moves
|
|
25
|
+
this.updateDistance();
|
|
26
|
+
|
|
27
|
+
// follow cursor in screenspace but maintain initial distance from camera
|
|
28
|
+
const cursor = this.context.input.mousePositionRC;
|
|
29
|
+
const camera = this.context.mainCamera;
|
|
30
|
+
const cameraPosition = camera.worldPosition;
|
|
31
|
+
|
|
32
|
+
// create ray from camera through cursor position
|
|
33
|
+
const rayDirection = getTempVector(cursor.x, cursor.y, 1).unproject(camera);
|
|
34
|
+
rayDirection.sub(cameraPosition).normalize();
|
|
35
|
+
|
|
36
|
+
// position object at initial distance along the ray
|
|
37
|
+
const newPosition = rayDirection.multiplyScalar(this._distance).add(cameraPosition);
|
|
38
|
+
if (this.damping > 0) {
|
|
39
|
+
const pos = this.gameObject.worldPosition;
|
|
40
|
+
pos.lerp(newPosition, this.context.time.deltaTime / this.damping);
|
|
41
|
+
this.gameObject.worldPosition = pos;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
this.gameObject.worldPosition = newPosition;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Object3D } from "three";
|
|
2
|
+
import { serializable } from "../../engine/engine_serialization.js";
|
|
3
|
+
import { Mathf } from "../../engine/engine_math.js";
|
|
4
|
+
import { Behaviour } from "../Component.js";
|
|
5
|
+
import { Animation, PlayableDirector } from "../api.js";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export class ScrollFollow extends Behaviour {
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Target object(s) to follow the scroll position of the page. If null, the main camera is used.
|
|
13
|
+
*/
|
|
14
|
+
@serializable([Behaviour, Object3D])
|
|
15
|
+
target: object[] | object | null = null;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Damping for the movement, set to 0 for instant movement
|
|
19
|
+
* @default 0
|
|
20
|
+
*/
|
|
21
|
+
@serializable()
|
|
22
|
+
damping: number = 0;
|
|
23
|
+
|
|
24
|
+
@serializable()
|
|
25
|
+
mode: "window" = "window";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Current scroll value in "pages" (0 = top of page, 1 = bottom of page)
|
|
29
|
+
*/
|
|
30
|
+
get currentValue() {
|
|
31
|
+
return this.current_value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private current_value: number = 0;
|
|
35
|
+
private target_value: number = 0;
|
|
36
|
+
|
|
37
|
+
/** @internal */
|
|
38
|
+
onEnable() {
|
|
39
|
+
window.addEventListener("wheel", this.updateCurrentScroll, { passive: true });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** @internal */
|
|
43
|
+
onDisable() {
|
|
44
|
+
window.removeEventListener("wheel", this.updateCurrentScroll);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** @internal */
|
|
48
|
+
lateUpdate() {
|
|
49
|
+
|
|
50
|
+
// apply damping if any
|
|
51
|
+
if (this.damping > 0) {
|
|
52
|
+
this.current_value = Mathf.lerp(this.current_value, this.target_value, this.context.time.deltaTime / this.damping);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// apply scroll to target(s)
|
|
56
|
+
if (Array.isArray(this.target)) {
|
|
57
|
+
this.target.forEach(t => t && this.applyScroll(t));
|
|
58
|
+
}
|
|
59
|
+
else if (this.target) {
|
|
60
|
+
this.applyScroll(this.target);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
private updateCurrentScroll = () => {
|
|
67
|
+
|
|
68
|
+
switch (this.mode) {
|
|
69
|
+
case "window":
|
|
70
|
+
this.target_value = window.scrollY / (document.body.scrollHeight - window.innerHeight);
|
|
71
|
+
if (isNaN(this.target_value) || !isFinite(this.target_value)) this.target_value = 0;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (this.damping <= 0) {
|
|
76
|
+
this.current_value = this.target_value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private applyScroll(target: object) {
|
|
82
|
+
if (target instanceof PlayableDirector) {
|
|
83
|
+
target.time = this.current_value * target.duration;
|
|
84
|
+
if (!target.isPlaying) target.evaluate();
|
|
85
|
+
}
|
|
86
|
+
else if (target instanceof Animation) {
|
|
87
|
+
target.time = this.current_value * target.duration;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
}
|