@threlte/rapier 3.0.0-next.3 → 3.0.0-next.5
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/dist/components/Colliders/AutoColliders.svelte +1 -1
- package/dist/components/Colliders/Collider.svelte +1 -1
- package/dist/components/Colliders/Collider.svelte.d.ts +1 -1
- package/dist/components/RigidBody/RigidBody.svelte +8 -3
- package/dist/components/RigidBody/RigidBody.svelte.d.ts +1 -1
- package/dist/components/RigidBody/overrideTeleportMethods.d.ts +14 -0
- package/dist/components/RigidBody/overrideTeleportMethods.js +31 -0
- package/dist/components/World/InnerWorld.svelte +27 -5
- package/dist/components/World/InnerWorld.svelte.d.ts +2 -8
- package/dist/components/World/World.svelte +8 -56
- package/dist/components/World/World.svelte.d.ts +11 -3
- package/dist/lib/applyColliderActiveEvents.d.ts +1 -1
- package/dist/lib/createPhysicsStages.d.ts +15 -0
- package/dist/lib/createPhysicsStages.js +43 -0
- package/dist/lib/createPhysicsTasks.d.ts +19 -0
- package/dist/{hooks/useFrameHandler.js → lib/createPhysicsTasks.js} +109 -40
- package/dist/lib/createRapierContext.d.ts +14 -20
- package/dist/lib/createRapierContext.js +35 -11
- package/dist/lib/initRapier.svelte.d.ts +1 -0
- package/dist/lib/initRapier.svelte.js +16 -0
- package/dist/lib/keys.d.ts +2 -0
- package/dist/lib/keys.js +2 -0
- package/dist/types/types.d.ts +33 -4
- package/package.json +25 -6
- package/dist/hooks/useFrameHandler.d.ts +0 -3
|
@@ -10,7 +10,7 @@ import { useParentRigidbodyObject } from '../../lib/rigidBodyObjectContext';
|
|
|
10
10
|
import { applyColliderActiveEvents } from '../../lib/applyColliderActiveEvents';
|
|
11
11
|
import { createCollidersFromChildren } from '../../lib/createCollidersFromChildren';
|
|
12
12
|
import { eulerToQuaternion } from '../../lib/eulerToQuaternion';
|
|
13
|
-
let { shape = 'convexHull', restitution, restitutionCombineRule, friction, frictionCombineRule, sensor, contactForceEventThreshold, density, mass, centerOfMass, principalAngularInertia, angularInertiaLocalFrame, refresh = $bindable(() => create()), colliders = $bindable(), oncreate, oncollisionenter, oncollisionexit, oncontact, onsensorenter, onsensorexit, children
|
|
13
|
+
let { shape = 'convexHull', restitution, restitutionCombineRule, friction, frictionCombineRule, sensor, contactForceEventThreshold, density, mass, centerOfMass, principalAngularInertia, angularInertiaLocalFrame, refresh = $bindable(() => create()), colliders = $bindable(), oncreate, oncollisionenter, oncollisionexit, oncontact, onsensorenter, onsensorexit, children } = $props();
|
|
14
14
|
const group = new Group();
|
|
15
15
|
const { updateRef } = useCreateEvent(oncreate);
|
|
16
16
|
const rigidBody = useRigidBody();
|
|
@@ -16,7 +16,7 @@ let { shape, args, type, restitution, restitutionCombineRule, friction, friction
|
|
|
16
16
|
return;
|
|
17
17
|
collider.setTranslation(getWorldPosition(object));
|
|
18
18
|
collider.setRotation(getWorldQuaternion(object));
|
|
19
|
-
}), oncreate, oncollisionenter, oncollisionexit, oncontact, onsensorenter, onsensorexit, children
|
|
19
|
+
}), oncreate, oncollisionenter, oncollisionexit, oncontact, onsensorenter, onsensorexit, children } = $props();
|
|
20
20
|
const object = new Object3D();
|
|
21
21
|
const { updateRef } = useCreateEvent(oncreate);
|
|
22
22
|
const rigidBody = useRigidBody();
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ColliderEvents } from '../../types/types'
|
|
2
1
|
import type {
|
|
3
2
|
CoefficientCombineRule,
|
|
4
3
|
Collider as RapierCollider,
|
|
@@ -6,6 +5,7 @@ import type {
|
|
|
6
5
|
} from '@dimforge/rapier3d-compat'
|
|
7
6
|
import { SvelteComponent, type Snippet } from 'svelte'
|
|
8
7
|
import type { Euler, Vector3 } from 'three'
|
|
8
|
+
import type { ColliderEvents } from '../../types/types'
|
|
9
9
|
|
|
10
10
|
// ------------------ BASE ------------------
|
|
11
11
|
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
<script lang="ts">import { SceneGraphObject } from '@threlte/core';
|
|
2
2
|
import { onDestroy, setContext, tick } from 'svelte';
|
|
3
3
|
import { Object3D, Vector3 } from 'three';
|
|
4
|
+
import { initializeRigidBodyUserData, setInitialRigidBodyState } from '../../lib/createPhysicsTasks';
|
|
4
5
|
import { useRapier } from '../../hooks/useRapier';
|
|
5
6
|
import { getWorldPosition, getWorldQuaternion, getWorldScale } from '../../lib/getWorldTransforms';
|
|
6
7
|
import { parseRigidBodyType } from '../../lib/parseRigidBodyType';
|
|
7
8
|
import { setParentRigidbodyObject } from '../../lib/rigidBodyObjectContext';
|
|
8
9
|
import { useCreateEvent } from '../../lib/useCreateEvent';
|
|
10
|
+
import { overrideTeleportMethods } from './overrideTeleportMethods';
|
|
9
11
|
const { world, rapier, addRigidBodyToContext, removeRigidBodyFromContext } = useRapier();
|
|
10
|
-
let { linearVelocity, angularVelocity, type = 'dynamic', canSleep = true, gravityScale = 1, ccd = false, angularDamping = 0, linearDamping = 0, lockRotations = false, lockTranslations = false, enabledRotations = [true, true, true], enabledTranslations = [true, true, true], dominance = 0, enabled = true, userData = {}, rigidBody = $bindable(), oncreate, oncollisionenter, oncollisionexit, oncontact, onsensorenter, onsensorexit, onsleep, onwake } = $props();
|
|
12
|
+
let { linearVelocity, angularVelocity, type = 'dynamic', canSleep = true, gravityScale = 1, ccd = false, angularDamping = 0, linearDamping = 0, lockRotations = false, lockTranslations = false, enabledRotations = [true, true, true], enabledTranslations = [true, true, true], dominance = 0, enabled = true, userData = {}, rigidBody = $bindable(), oncreate, oncollisionenter, oncollisionexit, oncontact, onsensorenter, onsensorexit, onsleep, onwake, children } = $props();
|
|
11
13
|
/**
|
|
12
14
|
* Every RigidBody receives and forwards collision-related events
|
|
13
15
|
*/
|
|
14
16
|
const { updateRef } = useCreateEvent(oncreate);
|
|
15
17
|
const object = new Object3D();
|
|
18
|
+
initializeRigidBodyUserData(object);
|
|
16
19
|
/**
|
|
17
|
-
* isSleeping used for events "sleep" and "wake" in `
|
|
20
|
+
* isSleeping used for events "sleep" and "wake" in `createPhysicsTasks`
|
|
18
21
|
*/
|
|
19
22
|
object.userData.isSleeping = false;
|
|
20
23
|
/**
|
|
@@ -25,6 +28,7 @@ const desc = new rapier.RigidBodyDesc(parseRigidBodyType(type)).setCanSleep(canS
|
|
|
25
28
|
* Temporary RigidBody init
|
|
26
29
|
*/
|
|
27
30
|
let rigidBodyInternal = world.createRigidBody(desc);
|
|
31
|
+
overrideTeleportMethods(rigidBodyInternal, object);
|
|
28
32
|
rigidBody = rigidBodyInternal;
|
|
29
33
|
/**
|
|
30
34
|
* Apply transforms after the parent component added "object" to itself
|
|
@@ -36,6 +40,7 @@ const initPosition = async () => {
|
|
|
36
40
|
const parentWorldScale = object.parent ? getWorldScale(object.parent) : new Vector3(1, 1, 1);
|
|
37
41
|
const worldPosition = getWorldPosition(object).multiply(parentWorldScale);
|
|
38
42
|
const worldQuaternion = getWorldQuaternion(object);
|
|
43
|
+
setInitialRigidBodyState(object, worldPosition, worldQuaternion);
|
|
39
44
|
rigidBodyInternal.setTranslation(worldPosition, true);
|
|
40
45
|
rigidBodyInternal.setRotation(worldQuaternion, true);
|
|
41
46
|
updateRef(rigidBodyInternal);
|
|
@@ -114,5 +119,5 @@ onDestroy(() => {
|
|
|
114
119
|
</script>
|
|
115
120
|
|
|
116
121
|
<SceneGraphObject {object}>
|
|
117
|
-
|
|
122
|
+
{@render children?.({ rigidBody: rigidBodyInternal })}
|
|
118
123
|
</SceneGraphObject>
|
|
@@ -7,7 +7,7 @@ import type { RigidBodyEvents } from '../../types/types'
|
|
|
7
7
|
export type Boolean3Array = [x: boolean, y: boolean, z: boolean]
|
|
8
8
|
|
|
9
9
|
export type RigidBodyProps = {
|
|
10
|
-
rigidBody?: RapierRigidBody
|
|
10
|
+
rigidBody?: RapierRigidBody | undefined
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Specify the type of this rigid body
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RigidBody } from '@dimforge/rapier3d-compat';
|
|
2
|
+
import type { Object3D } from 'three';
|
|
3
|
+
export type ExtractMethods<ObjectType> = Pick<ObjectType, {
|
|
4
|
+
[Method in keyof ObjectType]: ObjectType[Method] extends (...args: any[]) => any ? Method : never;
|
|
5
|
+
}[keyof ObjectType]>;
|
|
6
|
+
/**
|
|
7
|
+
* When using a fixed framerate, Threlte is interpolating the position and
|
|
8
|
+
* rotation of RigidBody objects. Sometimes, this is not desirable, especially
|
|
9
|
+
* when using methods on the rigidbody that teleport the object, e.g. should
|
|
10
|
+
* lead to a sudden change in translation/rotation such as `rb.setTranslation`.
|
|
11
|
+
* These methods are overridden to reset the physics simulation position and
|
|
12
|
+
* rotation to the current object position and rotation.
|
|
13
|
+
*/
|
|
14
|
+
export declare const overrideTeleportMethods: (rb: RigidBody, object: Object3D) => void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const overrideMethods = {
|
|
2
|
+
position: ['setTranslation', 'setNextKinematicTranslation'],
|
|
3
|
+
rotation: ['setRotation', 'setNextKinematicRotation']
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* When using a fixed framerate, Threlte is interpolating the position and
|
|
7
|
+
* rotation of RigidBody objects. Sometimes, this is not desirable, especially
|
|
8
|
+
* when using methods on the rigidbody that teleport the object, e.g. should
|
|
9
|
+
* lead to a sudden change in translation/rotation such as `rb.setTranslation`.
|
|
10
|
+
* These methods are overridden to reset the physics simulation position and
|
|
11
|
+
* rotation to the current object position and rotation.
|
|
12
|
+
*/
|
|
13
|
+
export const overrideTeleportMethods = (rb, object) => {
|
|
14
|
+
const originalMethods = {};
|
|
15
|
+
overrideMethods.position.forEach((method) => {
|
|
16
|
+
originalMethods[method] = rb[method].bind(rb);
|
|
17
|
+
const proxy = (...args) => {
|
|
18
|
+
object.userData.physics.resetPosition = true;
|
|
19
|
+
return originalMethods[method](...args);
|
|
20
|
+
};
|
|
21
|
+
rb[method] = proxy;
|
|
22
|
+
});
|
|
23
|
+
overrideMethods.rotation.forEach((method) => {
|
|
24
|
+
originalMethods[method] = rb[method].bind(rb);
|
|
25
|
+
const proxy = (...args) => {
|
|
26
|
+
object.userData.physics.resetRotation = true;
|
|
27
|
+
return originalMethods[method](...args);
|
|
28
|
+
};
|
|
29
|
+
rb[method] = proxy;
|
|
30
|
+
});
|
|
31
|
+
};
|
|
@@ -1,19 +1,41 @@
|
|
|
1
1
|
<script lang="ts">import { onDestroy, setContext, tick } from 'svelte';
|
|
2
|
-
import { useFrameHandler } from '../../hooks/useFrameHandler';
|
|
3
2
|
import { createRapierContext } from '../../lib/createRapierContext';
|
|
4
|
-
let { gravity = [0, -9.81, 0], rawIntegrationParameters, rawIslands, rawBroadPhase, rawNarrowPhase, rawBodies, rawColliders, rawImpulseJoints, rawMultibodyJoints, rawCCDSolver, rawQueryPipeline, rawPhysicsPipeline, rawSerializationPipeline, rawDebugRenderPipeline,
|
|
5
|
-
const rapierContext = createRapierContext(
|
|
3
|
+
let { gravity = [0, -9.81, 0], rawIntegrationParameters, rawIslands, rawBroadPhase, rawNarrowPhase, rawBodies, rawColliders, rawImpulseJoints, rawMultibodyJoints, rawCCDSolver, rawQueryPipeline, rawPhysicsPipeline, rawSerializationPipeline, rawDebugRenderPipeline, framerate, autoStart = true, simulationStageOptions, synchronizationStageOptions, children } = $props();
|
|
4
|
+
const rapierContext = createRapierContext([
|
|
5
|
+
{ x: gravity[0], y: gravity[1], z: gravity[2] },
|
|
6
|
+
rawIntegrationParameters,
|
|
7
|
+
rawIslands,
|
|
8
|
+
rawBroadPhase,
|
|
9
|
+
rawNarrowPhase,
|
|
10
|
+
rawBodies,
|
|
11
|
+
rawColliders,
|
|
12
|
+
rawImpulseJoints,
|
|
13
|
+
rawMultibodyJoints,
|
|
14
|
+
rawCCDSolver,
|
|
15
|
+
rawQueryPipeline,
|
|
16
|
+
rawPhysicsPipeline,
|
|
17
|
+
rawSerializationPipeline,
|
|
18
|
+
rawDebugRenderPipeline
|
|
19
|
+
], {
|
|
20
|
+
framerate,
|
|
21
|
+
autoStart,
|
|
22
|
+
simulationStageOptions,
|
|
23
|
+
synchronizationStageOptions
|
|
24
|
+
});
|
|
6
25
|
setContext('threlte-rapier-context', rapierContext);
|
|
7
26
|
$effect.pre(() => {
|
|
8
27
|
if (gravity !== undefined) {
|
|
9
28
|
rapierContext.world.gravity = { x: gravity[0], y: gravity[1], z: gravity[2] };
|
|
10
29
|
}
|
|
11
30
|
});
|
|
12
|
-
|
|
31
|
+
$effect.pre(() => {
|
|
32
|
+
if (framerate !== undefined)
|
|
33
|
+
rapierContext.framerate.set(framerate);
|
|
34
|
+
});
|
|
13
35
|
onDestroy(async () => {
|
|
14
36
|
await tick();
|
|
15
37
|
rapierContext.world.free();
|
|
16
38
|
});
|
|
17
39
|
</script>
|
|
18
40
|
|
|
19
|
-
|
|
41
|
+
{@render children?.()}
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
2
|
import type { WorldProps } from './World.svelte';
|
|
3
3
|
declare const __propDef: {
|
|
4
|
-
props: WorldProps
|
|
5
|
-
children?: ((this: void) => typeof import("svelte").SnippetReturn & {
|
|
6
|
-
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
|
7
|
-
}) | undefined;
|
|
8
|
-
};
|
|
4
|
+
props: WorldProps;
|
|
9
5
|
events: {
|
|
10
6
|
[evt: string]: CustomEvent<any>;
|
|
11
7
|
};
|
|
12
|
-
slots: {
|
|
13
|
-
default: {};
|
|
14
|
-
};
|
|
8
|
+
slots: {};
|
|
15
9
|
};
|
|
16
10
|
export type InnerWorldProps = typeof __propDef.props;
|
|
17
11
|
export type InnerWorldEvents = typeof __propDef.events;
|
|
@@ -1,60 +1,12 @@
|
|
|
1
|
-
<script
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
>import RAPIER from '@dimforge/rapier3d-compat';
|
|
5
|
-
import { onMount } from 'svelte';
|
|
6
|
-
import { writable } from 'svelte/store';
|
|
7
|
-
/**
|
|
8
|
-
* RAPIER.init() should only be called once
|
|
9
|
-
*/
|
|
10
|
-
const initialized = writable(false);
|
|
1
|
+
<script lang="ts">import { initRapier } from '../../lib/initRapier.svelte';
|
|
2
|
+
import InnerWorld from './InnerWorld.svelte';
|
|
3
|
+
let { fallback, children, ...rest } = $props();
|
|
11
4
|
</script>
|
|
12
5
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* This is passed to the useTask handler.
|
|
17
|
-
* Use this to control when the rapier physics engine is updating the scene.
|
|
18
|
-
* @default undefined
|
|
19
|
-
*/
|
|
20
|
-
stage, fallback, children } = $props();
|
|
21
|
-
let error = $state(false);
|
|
22
|
-
const init = async () => {
|
|
23
|
-
if ($initialized)
|
|
24
|
-
return;
|
|
25
|
-
try {
|
|
26
|
-
await RAPIER.init();
|
|
27
|
-
$initialized = true;
|
|
28
|
-
}
|
|
29
|
-
catch (e) {
|
|
30
|
-
error = true;
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
onMount(init);
|
|
34
|
-
</script>
|
|
35
|
-
|
|
36
|
-
{#if $initialized}
|
|
37
|
-
<InnerWorld
|
|
38
|
-
{gravity}
|
|
39
|
-
{rawIntegrationParameters}
|
|
40
|
-
{rawIslands}
|
|
41
|
-
{rawBroadPhase}
|
|
42
|
-
{rawNarrowPhase}
|
|
43
|
-
{rawBodies}
|
|
44
|
-
{rawColliders}
|
|
45
|
-
{rawImpulseJoints}
|
|
46
|
-
{rawMultibodyJoints}
|
|
47
|
-
{rawCCDSolver}
|
|
48
|
-
{rawQueryPipeline}
|
|
49
|
-
{rawPhysicsPipeline}
|
|
50
|
-
{rawSerializationPipeline}
|
|
51
|
-
{rawDebugRenderPipeline}
|
|
52
|
-
{stage}
|
|
53
|
-
>
|
|
6
|
+
{#await initRapier() then _}
|
|
7
|
+
<InnerWorld {...rest}>
|
|
54
8
|
{@render children?.()}
|
|
55
9
|
</InnerWorld>
|
|
56
|
-
{
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
{@render fallback?.()}
|
|
60
|
-
{/if}
|
|
10
|
+
{:catch error}
|
|
11
|
+
{@render fallback?.(error)}
|
|
12
|
+
{/await}
|
|
@@ -18,6 +18,8 @@ import type { Vector3 } from 'three'
|
|
|
18
18
|
import type { Key, Stage } from '@threlte/core'
|
|
19
19
|
|
|
20
20
|
export type WorldProps = {
|
|
21
|
+
framerate?: number | 'varying'
|
|
22
|
+
autoStart?: boolean
|
|
21
23
|
gravity?: Parameters<Vector3['set']>
|
|
22
24
|
rawIntegrationParameters?: RawIntegrationParameters
|
|
23
25
|
rawIslands?: RawIslandManager
|
|
@@ -32,10 +34,16 @@ export type WorldProps = {
|
|
|
32
34
|
rawPhysicsPipeline?: RawPhysicsPipeline
|
|
33
35
|
rawSerializationPipeline?: RawSerializationPipeline
|
|
34
36
|
rawDebugRenderPipeline?: RawDebugRenderPipeline
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
simulationStageOptions?: {
|
|
38
|
+
before?: (Key | Stage) | (Key | Stage)[]
|
|
39
|
+
after?: (Key | Stage) | (Key | Stage)[]
|
|
40
|
+
}
|
|
41
|
+
synchronizationStageOptions?: {
|
|
42
|
+
before?: (Key | Stage) | (Key | Stage)[]
|
|
43
|
+
after?: (Key | Stage) | (Key | Stage)[]
|
|
44
|
+
}
|
|
37
45
|
children?: Snippet
|
|
38
|
-
fallback?: Snippet
|
|
46
|
+
fallback?: Snippet<[error: any]>
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
export default class World extends SvelteComponent<WorldProps> {}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { ColliderEvents, RigidBodyEvents } from '../types/types';
|
|
2
1
|
import { type Collider } from '@dimforge/rapier3d-compat';
|
|
2
|
+
import type { ColliderEvents, RigidBodyEvents } from '../types/types';
|
|
3
3
|
export declare const applyColliderActiveEvents: (collider: Collider, colliderEvents?: ColliderEvents, rigidBodyEvents?: RigidBodyEvents) => void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type CurrentWritable, type Key, type Stage } from '@threlte/core';
|
|
2
|
+
import type { Framerate } from '../types/types';
|
|
3
|
+
export declare const createPhysicsStages: (framerate: CurrentWritable<Framerate>, simulationOffset: CurrentWritable<number>, updateRigidBodySimulationData: CurrentWritable<boolean>, options?: {
|
|
4
|
+
simulationStageOptions?: {
|
|
5
|
+
before?: (Key | Stage) | (Key | Stage)[];
|
|
6
|
+
after?: (Key | Stage) | (Key | Stage)[];
|
|
7
|
+
};
|
|
8
|
+
synchronizationStageOptions?: {
|
|
9
|
+
before?: (Key | Stage) | (Key | Stage)[];
|
|
10
|
+
after?: (Key | Stage) | (Key | Stage)[];
|
|
11
|
+
};
|
|
12
|
+
}) => {
|
|
13
|
+
simulationStage: Stage;
|
|
14
|
+
synchronizationStage: Stage;
|
|
15
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useStage, useThrelte } from '@threlte/core';
|
|
2
|
+
import { simulationKey, synchronizationKey } from './keys';
|
|
3
|
+
export const createPhysicsStages = (framerate, simulationOffset, updateRigidBodySimulationData, options) => {
|
|
4
|
+
let fixedStepTimeAccumulator = 0;
|
|
5
|
+
let simulationTime = 0;
|
|
6
|
+
let lastSimulationTime = 0;
|
|
7
|
+
const { renderStage } = useThrelte();
|
|
8
|
+
const simulationStage = useStage(simulationKey, {
|
|
9
|
+
after: options?.simulationStageOptions?.after,
|
|
10
|
+
before: options?.simulationStageOptions?.before,
|
|
11
|
+
callback(delta, runTasks) {
|
|
12
|
+
if (framerate.current === 'varying') {
|
|
13
|
+
runTasks();
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
const rate = 1 / framerate.current;
|
|
17
|
+
simulationTime += delta;
|
|
18
|
+
fixedStepTimeAccumulator += delta;
|
|
19
|
+
const iterations = Math.ceil(fixedStepTimeAccumulator / rate);
|
|
20
|
+
for (let iteration = 0; iteration < iterations; iteration++) {
|
|
21
|
+
updateRigidBodySimulationData.set(iteration >= iterations - 2);
|
|
22
|
+
runTasks(rate);
|
|
23
|
+
fixedStepTimeAccumulator -= rate;
|
|
24
|
+
lastSimulationTime += rate;
|
|
25
|
+
}
|
|
26
|
+
simulationOffset.set((simulationTime - lastSimulationTime) / rate + 1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
const synchronizationStage = useStage(synchronizationKey, {
|
|
31
|
+
after: options?.synchronizationStageOptions?.after
|
|
32
|
+
? Array.isArray(options.synchronizationStageOptions.after)
|
|
33
|
+
? [...options.synchronizationStageOptions.after, simulationKey]
|
|
34
|
+
: [options.synchronizationStageOptions.after, simulationKey]
|
|
35
|
+
: simulationKey,
|
|
36
|
+
before: options?.synchronizationStageOptions?.before
|
|
37
|
+
? Array.isArray(options.synchronizationStageOptions.before)
|
|
38
|
+
? [...options.synchronizationStageOptions.before, renderStage]
|
|
39
|
+
: [options.synchronizationStageOptions.before, renderStage]
|
|
40
|
+
: renderStage
|
|
41
|
+
});
|
|
42
|
+
return { simulationStage, synchronizationStage };
|
|
43
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type World } from '@dimforge/rapier3d-compat';
|
|
2
|
+
import { type CurrentWritable, type Stage } from '@threlte/core';
|
|
3
|
+
import { Object3D, Quaternion, Vector3 } from 'three';
|
|
4
|
+
import type { ColliderEvents, Framerate, RigidBodyEvents } from '../types/types';
|
|
5
|
+
type PhysicsUserData = {
|
|
6
|
+
currentPosition: Vector3;
|
|
7
|
+
currentQuaternion: Quaternion;
|
|
8
|
+
lastPosition: Vector3;
|
|
9
|
+
lastQuaternion: Quaternion;
|
|
10
|
+
resetPosition: boolean;
|
|
11
|
+
resetRotation: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare const initializeRigidBodyUserData: (obj: Object3D) => PhysicsUserData;
|
|
14
|
+
export declare const setInitialRigidBodyState: (obj: Object3D, initialPosition: Vector3, initialQuaternion: Quaternion) => void;
|
|
15
|
+
export declare const createPhysicsTasks: (world: World, framerate: CurrentWritable<Framerate>, simulationOffset: CurrentWritable<number>, rigidBodyObjects: Map<number, Object3D>, updateRigidBodySimulationData: CurrentWritable<boolean>, colliderEventDispatchers: Map<number, ColliderEvents>, rigidBodyEventDispatchers: Map<number, RigidBodyEvents>, simulationStage: Stage, synchronizationStage: Stage) => {
|
|
16
|
+
simulationTask: import("@threlte/core").Task;
|
|
17
|
+
synchronizationTask: import("@threlte/core").Task;
|
|
18
|
+
};
|
|
19
|
+
export {};
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
import { EventQueue } from '@dimforge/rapier3d-compat';
|
|
2
2
|
import { useTask } from '@threlte/core';
|
|
3
|
-
import { derived } from 'svelte/store';
|
|
4
3
|
import { Object3D, Quaternion, Vector3 } from 'three';
|
|
4
|
+
import { simulationKey, synchronizationKey } from './keys';
|
|
5
5
|
const tempObject = new Object3D();
|
|
6
6
|
const tempVector3 = new Vector3();
|
|
7
7
|
const tempQuaternion = new Quaternion();
|
|
8
|
-
const getEventDispatchers = (
|
|
9
|
-
const collider1Events =
|
|
10
|
-
const collider2Events =
|
|
8
|
+
const getEventDispatchers = (collider1, collider2, colliderEventDispatchers, rigidBodyEventDispatchers) => {
|
|
9
|
+
const collider1Events = colliderEventDispatchers.get(collider1.handle);
|
|
10
|
+
const collider2Events = colliderEventDispatchers.get(collider2.handle);
|
|
11
11
|
const rigidBody1 = collider1.parent();
|
|
12
12
|
const rigidBody2 = collider2.parent();
|
|
13
|
-
const rigidBody1Events = rigidBody1
|
|
14
|
-
|
|
15
|
-
: undefined;
|
|
16
|
-
const rigidBody2Events = rigidBody2
|
|
17
|
-
? ctx.rigidBodyEventDispatchers.get(rigidBody2.handle)
|
|
18
|
-
: undefined;
|
|
13
|
+
const rigidBody1Events = rigidBody1 ? rigidBodyEventDispatchers.get(rigidBody1.handle) : undefined;
|
|
14
|
+
const rigidBody2Events = rigidBody2 ? rigidBodyEventDispatchers.get(rigidBody2.handle) : undefined;
|
|
19
15
|
return {
|
|
20
16
|
collider1Events,
|
|
21
17
|
collider2Events,
|
|
@@ -23,21 +19,48 @@ const getEventDispatchers = (ctx, collider1, collider2) => {
|
|
|
23
19
|
rigidBody2Events
|
|
24
20
|
};
|
|
25
21
|
};
|
|
26
|
-
|
|
22
|
+
const objectHasPhysicsUserData = (obj) => {
|
|
23
|
+
return obj.userData.physics !== undefined;
|
|
24
|
+
};
|
|
25
|
+
export const initializeRigidBodyUserData = (obj) => {
|
|
26
|
+
const userData = {
|
|
27
|
+
currentPosition: new Vector3(),
|
|
28
|
+
currentQuaternion: new Quaternion(),
|
|
29
|
+
lastPosition: new Vector3(),
|
|
30
|
+
lastQuaternion: new Quaternion(),
|
|
31
|
+
resetPosition: false,
|
|
32
|
+
resetRotation: false
|
|
33
|
+
};
|
|
34
|
+
obj.userData.physics = userData;
|
|
35
|
+
return userData;
|
|
36
|
+
};
|
|
37
|
+
export const setInitialRigidBodyState = (obj, initialPosition, initialQuaternion) => {
|
|
38
|
+
if (!objectHasPhysicsUserData(obj)) {
|
|
39
|
+
initializeRigidBodyUserData(obj);
|
|
40
|
+
}
|
|
41
|
+
const userData = obj.userData.physics;
|
|
42
|
+
userData.currentPosition.copy(initialPosition);
|
|
43
|
+
userData.lastPosition.copy(initialPosition);
|
|
44
|
+
userData.currentQuaternion.copy(initialQuaternion);
|
|
45
|
+
userData.lastQuaternion.copy(initialQuaternion);
|
|
46
|
+
};
|
|
47
|
+
export const createPhysicsTasks = (world, framerate, simulationOffset, rigidBodyObjects, updateRigidBodySimulationData, colliderEventDispatchers, rigidBodyEventDispatchers, simulationStage, synchronizationStage) => {
|
|
27
48
|
const eventQueue = new EventQueue(false);
|
|
28
|
-
const
|
|
29
|
-
// if (!eventQueue) return
|
|
30
|
-
const { world } = ctx;
|
|
49
|
+
const simulation = useTask(simulationKey, (delta) => {
|
|
31
50
|
// Set timestep to current delta, to allow for variable frame rates
|
|
32
51
|
// We cap the delta at 100, so that the physics simulation doesn't get wild
|
|
33
|
-
|
|
52
|
+
if (framerate.current === 'varying') {
|
|
53
|
+
world.timestep = Math.min(delta, 0.1);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
world.timestep = delta;
|
|
57
|
+
}
|
|
34
58
|
world.step(eventQueue);
|
|
35
|
-
|
|
36
|
-
ctx.rigidBodyObjects.forEach((mesh, handle) => {
|
|
59
|
+
rigidBodyObjects.forEach((mesh, handle) => {
|
|
37
60
|
const rigidBody = world.getRigidBody(handle);
|
|
38
61
|
if (!rigidBody || !rigidBody.isValid())
|
|
39
62
|
return;
|
|
40
|
-
const events =
|
|
63
|
+
const events = rigidBodyEventDispatchers.get(handle);
|
|
41
64
|
if (events) {
|
|
42
65
|
if (rigidBody.isSleeping() && !mesh.userData.isSleeping) {
|
|
43
66
|
events.onsleep?.();
|
|
@@ -50,21 +73,35 @@ export const useFrameHandler = (ctx, stage) => {
|
|
|
50
73
|
if (rigidBody.isSleeping() || rigidBody.isFixed() || !mesh.parent) {
|
|
51
74
|
return;
|
|
52
75
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
76
|
+
if (updateRigidBodySimulationData.current) {
|
|
77
|
+
const translation = rigidBody.translation();
|
|
78
|
+
const rotation = rigidBody.rotation();
|
|
79
|
+
if (objectHasPhysicsUserData(mesh)) {
|
|
80
|
+
const userData = mesh.userData.physics;
|
|
81
|
+
if (userData.resetPosition) {
|
|
82
|
+
userData.resetPosition = false;
|
|
83
|
+
userData.lastPosition.set(translation.x, translation.y, translation.z);
|
|
84
|
+
userData.currentPosition.set(translation.x, translation.y, translation.z);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
userData.lastPosition.copy(userData.currentPosition);
|
|
88
|
+
userData.currentPosition.set(translation.x, translation.y, translation.z);
|
|
89
|
+
}
|
|
90
|
+
if (userData.resetRotation) {
|
|
91
|
+
userData.resetRotation = false;
|
|
92
|
+
userData.lastQuaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
|
|
93
|
+
userData.currentQuaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
userData.lastQuaternion.copy(userData.currentQuaternion);
|
|
97
|
+
userData.currentQuaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
initializeRigidBodyUserData(mesh);
|
|
102
|
+
setInitialRigidBodyState(mesh, tempVector3.set(translation.x, translation.y, translation.z), tempQuaternion.set(rotation.x, rotation.y, rotation.z, rotation.w));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
68
105
|
});
|
|
69
106
|
eventQueue.drainContactForceEvents((e) => {
|
|
70
107
|
const collider1 = world.getCollider(e.collider1());
|
|
@@ -73,7 +110,7 @@ export const useFrameHandler = (ctx, stage) => {
|
|
|
73
110
|
if (!collider1 || !collider2) {
|
|
74
111
|
return;
|
|
75
112
|
}
|
|
76
|
-
const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(
|
|
113
|
+
const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(collider1, collider2, colliderEventDispatchers, rigidBodyEventDispatchers);
|
|
77
114
|
const rigidBody1 = collider1.parent();
|
|
78
115
|
const rigidBody2 = collider2.parent();
|
|
79
116
|
// Collider events
|
|
@@ -119,7 +156,7 @@ export const useFrameHandler = (ctx, stage) => {
|
|
|
119
156
|
if (!collider1 || !collider2) {
|
|
120
157
|
return;
|
|
121
158
|
}
|
|
122
|
-
const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(
|
|
159
|
+
const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(collider1, collider2, colliderEventDispatchers, rigidBodyEventDispatchers);
|
|
123
160
|
if (!collider1Events && !collider2Events && !rigidBody1Events && !rigidBody2Events) {
|
|
124
161
|
return;
|
|
125
162
|
}
|
|
@@ -226,9 +263,41 @@ export const useFrameHandler = (ctx, stage) => {
|
|
|
226
263
|
});
|
|
227
264
|
}
|
|
228
265
|
});
|
|
229
|
-
}, {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
266
|
+
}, {
|
|
267
|
+
stage: simulationStage
|
|
268
|
+
});
|
|
269
|
+
const synchronization = useTask(synchronizationKey, () => {
|
|
270
|
+
rigidBodyObjects.forEach((mesh) => {
|
|
271
|
+
if (!objectHasPhysicsUserData(mesh))
|
|
272
|
+
return;
|
|
273
|
+
const userData = mesh.userData.physics;
|
|
274
|
+
if (framerate.current === 'varying') {
|
|
275
|
+
tempObject.position.copy(userData.currentPosition);
|
|
276
|
+
tempObject.quaternion.copy(userData.currentQuaternion);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
tempObject.position
|
|
280
|
+
.copy(userData.lastPosition)
|
|
281
|
+
.lerp(userData.currentPosition, simulationOffset.current);
|
|
282
|
+
tempObject.quaternion
|
|
283
|
+
.copy(userData.lastQuaternion)
|
|
284
|
+
.slerp(userData.currentQuaternion, simulationOffset.current);
|
|
285
|
+
}
|
|
286
|
+
// Rapier has no concept of scale, so we use the mesh's scale
|
|
287
|
+
mesh.getWorldScale(tempVector3);
|
|
288
|
+
tempObject.scale.copy(tempVector3);
|
|
289
|
+
tempObject.updateMatrix();
|
|
290
|
+
if (mesh.parent)
|
|
291
|
+
tempObject.applyMatrix4(mesh.parent.matrixWorld.clone().invert());
|
|
292
|
+
tempObject.updateMatrix();
|
|
293
|
+
mesh.position.setFromMatrixPosition(tempObject.matrix);
|
|
294
|
+
mesh.rotation.setFromRotationMatrix(tempObject.matrix);
|
|
295
|
+
});
|
|
296
|
+
}, {
|
|
297
|
+
stage: synchronizationStage
|
|
298
|
+
});
|
|
299
|
+
return {
|
|
300
|
+
simulationTask: simulation.task,
|
|
301
|
+
synchronizationTask: synchronization.task
|
|
302
|
+
};
|
|
234
303
|
};
|
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { Collider, RigidBody } from '@dimforge/rapier3d-compat';
|
|
3
1
|
import RAPIER from '@dimforge/rapier3d-compat';
|
|
4
|
-
import type
|
|
5
|
-
import type {
|
|
6
|
-
export declare const createRapierContext: (gravity: RAPIER.Vector, rawIntegrationParameters?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawIntegrationParameters | undefined, rawIslands?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawIslandManager | undefined, rawBroadPhase?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawBroadPhase | undefined, rawNarrowPhase?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawNarrowPhase | undefined, rawBodies?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawRigidBodySet | undefined, rawColliders?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawColliderSet | undefined, rawImpulseJoints?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawImpulseJointSet | undefined, rawMultibodyJoints?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawMultibodyJointSet | undefined, rawCCDSolver?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawCCDSolver | undefined, rawQueryPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawQueryPipeline | undefined, rawPhysicsPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawPhysicsPipeline | undefined, rawSerializationPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawSerializationPipeline | undefined, rawDebugRenderPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawDebugRenderPipeline | undefined
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
pause: () => void;
|
|
19
|
-
resume: () => void;
|
|
20
|
-
paused: import("svelte/store").Readable<boolean>;
|
|
21
|
-
};
|
|
2
|
+
import { type Key, type Stage } from '@threlte/core';
|
|
3
|
+
import type { Framerate, RapierContext } from '../types/types';
|
|
4
|
+
export declare const createRapierContext: (worldArgs: [gravity: RAPIER.Vector, rawIntegrationParameters?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawIntegrationParameters | undefined, rawIslands?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawIslandManager | undefined, rawBroadPhase?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawBroadPhase | undefined, rawNarrowPhase?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawNarrowPhase | undefined, rawBodies?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawRigidBodySet | undefined, rawColliders?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawColliderSet | undefined, rawImpulseJoints?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawImpulseJointSet | undefined, rawMultibodyJoints?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawMultibodyJointSet | undefined, rawCCDSolver?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawCCDSolver | undefined, rawQueryPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawQueryPipeline | undefined, rawPhysicsPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawPhysicsPipeline | undefined, rawSerializationPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawSerializationPipeline | undefined, rawDebugRenderPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawDebugRenderPipeline | undefined], options: {
|
|
5
|
+
framerate?: Framerate;
|
|
6
|
+
autoStart?: boolean;
|
|
7
|
+
simulationStageOptions?: {
|
|
8
|
+
before?: (Key | Stage) | (Key | Stage)[];
|
|
9
|
+
after?: (Key | Stage) | (Key | Stage)[];
|
|
10
|
+
};
|
|
11
|
+
synchronizationStageOptions?: {
|
|
12
|
+
before?: (Key | Stage) | (Key | Stage)[];
|
|
13
|
+
after?: (Key | Stage) | (Key | Stage)[];
|
|
14
|
+
};
|
|
15
|
+
}) => RapierContext;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import RAPIER from '@dimforge/rapier3d-compat';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { currentWritable } from '@threlte/core';
|
|
3
|
+
import { derived, writable } from 'svelte/store';
|
|
4
|
+
import { createPhysicsStages } from './createPhysicsStages';
|
|
5
|
+
import { createPhysicsTasks } from './createPhysicsTasks';
|
|
6
|
+
export const createRapierContext = (worldArgs, options) => {
|
|
7
|
+
const world = new RAPIER.World(...worldArgs);
|
|
5
8
|
const colliderObjects = new Map();
|
|
6
9
|
const rigidBodyObjects = new Map();
|
|
7
10
|
const rigidBodyEventDispatchers = new Map();
|
|
@@ -42,11 +45,17 @@ export const createRapierContext = (...args) => {
|
|
|
42
45
|
rigidBodyObjects.delete(rigidBody.handle);
|
|
43
46
|
rigidBodyEventDispatchers.delete(rigidBody.handle);
|
|
44
47
|
};
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
const
|
|
48
|
+
const framerate = currentWritable(options.framerate ?? 'varying');
|
|
49
|
+
const simulationOffset = currentWritable(1);
|
|
50
|
+
const updateRigidBodySimulationData = currentWritable(false);
|
|
51
|
+
const { simulationStage, synchronizationStage } = createPhysicsStages(framerate, simulationOffset, updateRigidBodySimulationData, options);
|
|
52
|
+
const autostart = options.autoStart ?? true;
|
|
53
|
+
const paused = writable(!autostart);
|
|
54
|
+
if (!autostart) {
|
|
55
|
+
simulationStage.stop();
|
|
56
|
+
synchronizationStage.stop();
|
|
57
|
+
}
|
|
58
|
+
const { simulationTask, synchronizationTask } = createPhysicsTasks(world, framerate, simulationOffset, rigidBodyObjects, updateRigidBodySimulationData, colliderEventDispatchers, rigidBodyEventDispatchers, simulationStage, synchronizationStage);
|
|
50
59
|
return {
|
|
51
60
|
rapier: RAPIER,
|
|
52
61
|
world,
|
|
@@ -59,8 +68,23 @@ export const createRapierContext = (...args) => {
|
|
|
59
68
|
addRigidBodyToContext,
|
|
60
69
|
removeRigidBodyFromContext,
|
|
61
70
|
debug: writable(false),
|
|
62
|
-
pause
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
pause: () => {
|
|
72
|
+
paused.set(true);
|
|
73
|
+
simulationStage.stop();
|
|
74
|
+
synchronizationStage.stop();
|
|
75
|
+
},
|
|
76
|
+
resume: () => {
|
|
77
|
+
paused.set(false);
|
|
78
|
+
simulationStage.start();
|
|
79
|
+
synchronizationStage.start();
|
|
80
|
+
},
|
|
81
|
+
paused: derived(paused, (a) => a),
|
|
82
|
+
framerate,
|
|
83
|
+
simulationOffset,
|
|
84
|
+
simulationStage,
|
|
85
|
+
synchronizationStage,
|
|
86
|
+
updateRigidBodySimulationData,
|
|
87
|
+
simulationTask,
|
|
88
|
+
synchronizationTask
|
|
65
89
|
};
|
|
66
90
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const initRapier: () => true | Promise<void>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import RAPIER from '@dimforge/rapier3d-compat';
|
|
2
|
+
let initialized = false;
|
|
3
|
+
let promise;
|
|
4
|
+
export const initRapier = () => {
|
|
5
|
+
if (initialized)
|
|
6
|
+
return true;
|
|
7
|
+
if (!promise) {
|
|
8
|
+
promise = new Promise((resolve) => {
|
|
9
|
+
RAPIER.init().then(() => {
|
|
10
|
+
initialized = true;
|
|
11
|
+
resolve();
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
return promise;
|
|
16
|
+
};
|
package/dist/lib/keys.js
ADDED
package/dist/types/types.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/// <reference types="svelte" />
|
|
2
|
-
import type
|
|
3
|
-
import
|
|
4
|
-
import type {
|
|
2
|
+
import { World, type Collider, type RigidBody, type TempContactManifold, type Vector } from '@dimforge/rapier3d-compat';
|
|
3
|
+
import RAPIER from '@dimforge/rapier3d-compat';
|
|
4
|
+
import type { CurrentWritable, Stage, Task } from '@threlte/core';
|
|
5
|
+
import type { Readable, Writable } from 'svelte/store';
|
|
6
|
+
import type { Object3D } from 'three';
|
|
5
7
|
export type ColliderShapes = 'ball' | 'capsule' | 'segment' | 'triangle' | 'roundTriangle' | 'polyline' | 'trimesh' | 'cuboid' | 'roundCuboid' | 'heightfield' | 'cylinder' | 'roundCylinder' | 'cone' | 'roundCone' | 'convexHull' | 'convexMesh' | 'roundConvexHull' | 'roundConvexMesh';
|
|
6
8
|
export type AutoCollidersShapes = 'cuboid' | 'ball' | 'trimesh' | 'convexHull' | 'capsule';
|
|
7
9
|
export type ColliderEvents = {
|
|
@@ -45,7 +47,6 @@ export type RigidBodyEvents = ColliderEvents & {
|
|
|
45
47
|
onsleep?: () => void;
|
|
46
48
|
onwake?: () => void;
|
|
47
49
|
};
|
|
48
|
-
export type RapierContext = ReturnType<typeof createRapierContext>;
|
|
49
50
|
export type CollisionGroupsContext = Writable<number> | undefined;
|
|
50
51
|
export type RigidBodyUserData = {
|
|
51
52
|
events?: RigidBodyEvents;
|
|
@@ -59,3 +60,31 @@ export type CollisionGroupsBitMask = (0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
|
|
|
59
60
|
* Used in the <Attractor> component
|
|
60
61
|
*/
|
|
61
62
|
export type GravityType = 'static' | 'linear' | 'newtonian';
|
|
63
|
+
export type Framerate = number | 'varying';
|
|
64
|
+
export type RapierContext = {
|
|
65
|
+
rapier: typeof RAPIER;
|
|
66
|
+
world: World;
|
|
67
|
+
colliderObjects: Map<number, Object3D>;
|
|
68
|
+
rigidBodyObjects: Map<number, Object3D>;
|
|
69
|
+
rigidBodyEventDispatchers: Map<number, RigidBodyEvents>;
|
|
70
|
+
colliderEventDispatchers: Map<number, ColliderEvents>;
|
|
71
|
+
addColliderToContext: (collider: Collider, object: Object3D, props: ColliderEvents) => void;
|
|
72
|
+
removeColliderFromContext: (collider: Collider) => void;
|
|
73
|
+
addRigidBodyToContext: (rigidBody: RigidBody, object: Object3D, events: RigidBodyEvents) => void;
|
|
74
|
+
removeRigidBodyFromContext: (rigidBody: RigidBody) => void;
|
|
75
|
+
debug: Writable<boolean>;
|
|
76
|
+
pause: () => void;
|
|
77
|
+
resume: () => void;
|
|
78
|
+
paused: Readable<boolean>;
|
|
79
|
+
framerate: CurrentWritable<Framerate>;
|
|
80
|
+
simulationStage: Stage;
|
|
81
|
+
simulationTask: Task;
|
|
82
|
+
synchronizationStage: Stage;
|
|
83
|
+
synchronizationTask: Task;
|
|
84
|
+
/**
|
|
85
|
+
* This number tells us how far we're off in the simulation stage as opposed
|
|
86
|
+
* to the render stage
|
|
87
|
+
*/
|
|
88
|
+
simulationOffset: CurrentWritable<number>;
|
|
89
|
+
updateRigidBodySimulationData: CurrentWritable<boolean>;
|
|
90
|
+
};
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@threlte/rapier",
|
|
3
|
-
"version": "3.0.0-next.
|
|
3
|
+
"version": "3.0.0-next.5",
|
|
4
4
|
"author": "Grischa Erbe <hello@legrisch.com> (https://legrisch.com)",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"description": "Components and hooks to use the Rapier physics engine in Threlte",
|
|
6
7
|
"devDependencies": {
|
|
7
|
-
"@dimforge/rapier3d-compat": "^0.
|
|
8
|
+
"@dimforge/rapier3d-compat": "^0.13.1",
|
|
8
9
|
"@sveltejs/adapter-auto": "^3.2.0",
|
|
9
10
|
"@sveltejs/kit": "^2.5.5",
|
|
10
11
|
"@sveltejs/package": "^2.3.1",
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
"prettier-plugin-svelte": "^3.2.2",
|
|
22
23
|
"publint": "^0.2.7",
|
|
23
24
|
"rimraf": "^5.0.5",
|
|
24
|
-
"svelte": "5.0.0-next.
|
|
25
|
+
"svelte": "5.0.0-next.133",
|
|
25
26
|
"svelte-check": "^3.6.9",
|
|
26
27
|
"svelte-preprocess": "^5.1.3",
|
|
27
28
|
"svelte2tsx": "^0.7.6",
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
"type-fest": "^4.15.0",
|
|
31
32
|
"typescript": "^5.4.5",
|
|
32
33
|
"vite": "^5.2.8",
|
|
33
|
-
"@threlte/core": "8.0.0-next.
|
|
34
|
+
"@threlte/core": "8.0.0-next.9"
|
|
34
35
|
},
|
|
35
36
|
"peerDependencies": {
|
|
36
37
|
"@dimforge/rapier3d-compat": ">=0.12",
|
|
@@ -38,6 +39,24 @@
|
|
|
38
39
|
"three": ">=0.152"
|
|
39
40
|
},
|
|
40
41
|
"type": "module",
|
|
42
|
+
"keywords": [
|
|
43
|
+
"threlte",
|
|
44
|
+
"rapier",
|
|
45
|
+
"svelte",
|
|
46
|
+
"three",
|
|
47
|
+
"three.js",
|
|
48
|
+
"3d",
|
|
49
|
+
"physics"
|
|
50
|
+
],
|
|
51
|
+
"homepage": "https://threlte.xyz",
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "https://github.com/threlte/threlte.git",
|
|
55
|
+
"directory": "packages/rapier"
|
|
56
|
+
},
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "https://github.com/threlte/threlte/issues"
|
|
59
|
+
},
|
|
41
60
|
"exports": {
|
|
42
61
|
".": {
|
|
43
62
|
"types": "./dist/index.d.ts",
|
|
@@ -54,8 +73,8 @@
|
|
|
54
73
|
"package": "svelte-kit sync && svelte-package && node ./scripts/cleanupPackage.js && publint",
|
|
55
74
|
"check": "svelte-check --tsconfig ./tsconfig.json",
|
|
56
75
|
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
|
|
57
|
-
"lint": "prettier --check
|
|
58
|
-
"format": "prettier --write
|
|
76
|
+
"lint": "prettier --check .",
|
|
77
|
+
"format": "prettier --write .",
|
|
59
78
|
"cleanup": "rimraf node_modules .svelte-kit dist"
|
|
60
79
|
}
|
|
61
80
|
}
|