@pmndrs/viverse 0.1.11 → 0.1.13

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/README.md CHANGED
@@ -28,7 +28,7 @@ npm install three @react-three/fiber @react-three/viverse
28
28
 
29
29
  ```tsx
30
30
  const world = new BvhPhysicsWorld()
31
- world.addFixedBody(ground.scene)
31
+ world.addBody(ground.scene, false)
32
32
  const character = new SimpleCharacter(camera, world, canvas, { model: { url: profile.activeAvatar?.vrmUrl } })
33
33
  scene.add(character)
34
34
  ```
@@ -99,35 +99,30 @@ export class BvhCharacterPhysics {
99
99
  aabbox.min.addScalar(-radius);
100
100
  aabbox.max.addScalar(radius);
101
101
  let grounded = false;
102
- for (const bvh of this.world.getBodies()) {
103
- bvh.shapecast({
104
- intersectsBounds: (bounds) => bounds.intersectsBox(aabbox),
105
- intersectsTriangle: (tri) => {
106
- // Use your existing triangle vs segment closestPointToSegment
107
- const distance = tri.closestPointToSegment(segment, triPoint, capsulePoint);
108
- if (distance === 0) {
109
- const isCloserToSegmentStart = capsulePoint.distanceTo(segment.start) < capsulePoint.distanceTo(segment.end);
110
- if (isCloserToSegmentStart) {
111
- grounded = true;
112
- }
113
- const scaledDirection = capsulePoint.sub(isCloserToSegmentStart ? segment.start : segment.end);
114
- scaledDirection.y += radius;
115
- segment.start.add(scaledDirection);
116
- segment.end.add(scaledDirection);
117
- }
118
- else if (distance < radius) {
119
- const depthInsideCapsule = radius - distance;
120
- const direction = capsulePoint.sub(triPoint).divideScalar(distance);
121
- const slope = Math.tan(Math.acos(direction.dot(YAxis)));
122
- if (direction.y > 0 && slope <= maxGroundSlope) {
123
- grounded = true;
124
- }
125
- segment.start.addScaledVector(direction, depthInsideCapsule);
126
- segment.end.addScaledVector(direction, depthInsideCapsule);
127
- }
128
- },
129
- });
130
- }
102
+ this.world.shapecast((bounds) => bounds.intersectsBox(aabbox), (tri) => {
103
+ // Use your existing triangle vs segment closestPointToSegment
104
+ const distance = tri.closestPointToSegment(segment, triPoint, capsulePoint);
105
+ if (distance === 0) {
106
+ const isCloserToSegmentStart = capsulePoint.distanceTo(segment.start) < capsulePoint.distanceTo(segment.end);
107
+ if (isCloserToSegmentStart) {
108
+ grounded = true;
109
+ }
110
+ const scaledDirection = capsulePoint.sub(isCloserToSegmentStart ? segment.start : segment.end);
111
+ scaledDirection.y += radius;
112
+ segment.start.add(scaledDirection);
113
+ segment.end.add(scaledDirection);
114
+ }
115
+ else if (distance < radius) {
116
+ const depthInsideCapsule = radius - distance;
117
+ const direction = capsulePoint.sub(triPoint).divideScalar(distance);
118
+ const slope = Math.tan(Math.acos(direction.dot(YAxis)));
119
+ if (direction.y > 0 && slope <= maxGroundSlope) {
120
+ grounded = true;
121
+ }
122
+ segment.start.addScaledVector(direction, depthInsideCapsule);
123
+ segment.end.addScaledVector(direction, depthInsideCapsule);
124
+ }
125
+ });
131
126
  position.copy(segment.start);
132
127
  position.y -= radius;
133
128
  return grounded;
@@ -1,9 +1,14 @@
1
- import { Object3D, Ray } from 'three';
2
- import { MeshBVH } from 'three-mesh-bvh';
1
+ import { Box3, Object3D, Ray } from 'three';
2
+ import { ExtendedTriangle } from 'three-mesh-bvh';
3
3
  export declare class BvhPhysicsWorld {
4
- private readonly map;
5
- getBodies(): Iterable<MeshBVH>;
4
+ private map;
5
+ /**
6
+ * @deprecated use addBody(object, false) instead
7
+ */
6
8
  addFixedBody(object: Object3D): void;
7
- removeFixedBody(object: Object3D): void;
9
+ addBody(object: Object3D, kinematic: boolean): void;
10
+ removeBody(object: Object3D): void;
11
+ private computeMatrix;
12
+ shapecast(intersectsBounds: (box: Box3) => boolean, intersectsTriangle: (triangle: ExtendedTriangle) => void): void;
8
13
  raycast(ray: Ray, far: number): number | undefined;
9
14
  }
@@ -1,21 +1,97 @@
1
- import { computeBoundsTree, StaticGeometryGenerator } from 'three-mesh-bvh';
1
+ import { Box3, InstancedMesh, Matrix4, Ray, Vector3 } from 'three';
2
+ import { computeBoundsTree, StaticGeometryGenerator, ExtendedTriangle } from 'three-mesh-bvh';
3
+ const rayHelper = new Ray();
4
+ const farPointHelper = new Vector3();
5
+ const boxHelper = new Box3();
6
+ const triangleHelper = new ExtendedTriangle();
7
+ const matrixHelper = new Matrix4();
2
8
  export class BvhPhysicsWorld {
3
- map = new Map();
4
- getBodies() {
5
- return this.map.values();
6
- }
9
+ map = [];
10
+ /**
11
+ * @deprecated use addBody(object, false) instead
12
+ */
7
13
  addFixedBody(object) {
14
+ this.addBody(object, false);
15
+ }
16
+ addBody(object, kinematic) {
8
17
  object.updateWorldMatrix(true, true);
9
- const generator = new StaticGeometryGenerator(object);
10
- this.map.set(object, computeBoundsTree.apply(generator.generate()));
18
+ if (!(object instanceof InstancedMesh)) {
19
+ const parent = object.parent;
20
+ if (kinematic) {
21
+ object.parent = null;
22
+ object.updateMatrixWorld(true);
23
+ }
24
+ const geometry = new StaticGeometryGenerator(object).generate();
25
+ this.map.push({ object, bvh: computeBoundsTree.apply(geometry), kinematic });
26
+ if (kinematic) {
27
+ object.parent = parent;
28
+ object.updateMatrixWorld(true);
29
+ }
30
+ return;
31
+ }
32
+ if (object.children.length > 0) {
33
+ throw new Error(`cannot add InstancedMesh with children`);
34
+ }
35
+ const bvh = computeBoundsTree.apply(object.geometry);
36
+ for (let i = 0; i < object.instanceMatrix.count; i++) {
37
+ this.map.push({
38
+ object,
39
+ bvh,
40
+ instanceIndex: i,
41
+ kinematic,
42
+ });
43
+ }
11
44
  }
12
- removeFixedBody(object) {
13
- this.map.delete(object);
45
+ removeBody(object) {
46
+ this.map = this.map.filter((entry) => entry.object != object);
47
+ }
48
+ computeMatrix({ kinematic, object, instanceIndex }, target) {
49
+ if (!kinematic && instanceIndex == null) {
50
+ return false;
51
+ }
52
+ if (instanceIndex == null) {
53
+ target.copy(object.matrixWorld);
54
+ return true;
55
+ }
56
+ ;
57
+ object.getMatrixAt(instanceIndex, target);
58
+ target.premultiply(object.matrixWorld);
59
+ return true;
60
+ }
61
+ shapecast(intersectsBounds, intersectsTriangle) {
62
+ for (const entry of this.map) {
63
+ entry.bvh.shapecast({
64
+ intersectsBounds: (box) => {
65
+ boxHelper.copy(box);
66
+ if (this.computeMatrix(entry, matrixHelper)) {
67
+ boxHelper.applyMatrix4(matrixHelper);
68
+ }
69
+ return intersectsBounds(boxHelper);
70
+ },
71
+ intersectsTriangle: (triangle) => {
72
+ triangleHelper.copy(triangle);
73
+ if (this.computeMatrix(entry, matrixHelper)) {
74
+ triangleHelper.a.applyMatrix4(matrixHelper);
75
+ triangleHelper.b.applyMatrix4(matrixHelper);
76
+ triangleHelper.c.applyMatrix4(matrixHelper);
77
+ }
78
+ intersectsTriangle(triangleHelper);
79
+ },
80
+ });
81
+ }
14
82
  }
15
83
  raycast(ray, far) {
16
84
  let result;
17
- for (const body of this.getBodies()) {
18
- for (const intersection of body.raycast(ray, undefined, 0, far)) {
85
+ for (const entry of this.map.values()) {
86
+ rayHelper.copy(ray);
87
+ let farHelper = far;
88
+ if (this.computeMatrix(entry, matrixHelper)) {
89
+ matrixHelper.invert();
90
+ farPointHelper.copy(ray.origin).addScaledVector(ray.direction, far).applyMatrix4(matrixHelper);
91
+ rayHelper.applyMatrix4(matrixHelper);
92
+ farHelper = farPointHelper.distanceTo(rayHelper.origin);
93
+ }
94
+ for (const intersection of entry.bvh.raycast(rayHelper, undefined, 0, farHelper)) {
19
95
  if (result != null && intersection.distance >= result) {
20
96
  continue;
21
97
  }
package/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "peerDependencies": {
22
22
  "three": "*"
23
23
  },
24
- "version": "0.1.11",
24
+ "version": "0.1.13",
25
25
  "type": "module",
26
26
  "dependencies": {
27
27
  "@pixiv/three-vrm": "^3.4.2",