@threecyborgs/wasm-box3d-three 0.1.1 → 0.1.2
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/index.d.ts +2 -2
- package/dist/index.js +172 -39
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -8,10 +8,10 @@ export type ThreeBodyMeshManagerOptions = {
|
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
export type ThreeBodyMeshManager = {
|
|
11
|
-
meshes: ThreeNamespace.
|
|
11
|
+
readonly meshes: ThreeNamespace.Object3D[];
|
|
12
|
+
arenaMeshes: ThreeNamespace.Mesh[];
|
|
12
13
|
sync(physics: Box3DDemo): void;
|
|
13
14
|
dispose(): void;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
export declare function createThreeBodyMeshManager(options: ThreeBodyMeshManagerOptions): ThreeBodyMeshManager;
|
|
17
|
-
|
package/dist/index.js
CHANGED
|
@@ -9,83 +9,216 @@ export function createThreeBodyMeshManager({ THREE, scene, materialFactory } = {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const boxGeometry = new THREE.BoxGeometry(1, 1, 1);
|
|
12
|
-
const sphereGeometry = new THREE.SphereGeometry(0.5,
|
|
13
|
-
const
|
|
12
|
+
const sphereGeometry = new THREE.SphereGeometry(0.5, 12, 8);
|
|
13
|
+
const arenaMeshes = [];
|
|
14
|
+
const instanceMatrix = new THREE.Matrix4();
|
|
15
|
+
const instancePosition = new THREE.Vector3();
|
|
16
|
+
const instanceQuaternion = new THREE.Quaternion();
|
|
17
|
+
const instanceScale = new THREE.Vector3();
|
|
18
|
+
const instanceColor = new THREE.Color();
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
let boxInstances;
|
|
21
|
+
let sphereInstances;
|
|
22
|
+
let boxCapacity = 0;
|
|
23
|
+
let sphereCapacity = 0;
|
|
24
|
+
let lastBoxColorCount = -1;
|
|
25
|
+
let lastSphereColorCount = -1;
|
|
26
|
+
|
|
27
|
+
function getRecordAt(bodyData, offset) {
|
|
28
|
+
return {
|
|
29
|
+
position: { x: bodyData[offset], y: bodyData[offset + 1], z: bodyData[offset + 2] },
|
|
30
|
+
quaternion: { x: bodyData[offset + 3], y: bodyData[offset + 4], z: bodyData[offset + 5], w: bodyData[offset + 6] },
|
|
31
|
+
size: { x: bodyData[offset + 7], y: bodyData[offset + 8], z: bodyData[offset + 9] },
|
|
32
|
+
shapeType: bodyData[offset + 10],
|
|
33
|
+
color: { r: bodyData[offset + 11], g: bodyData[offset + 12], b: bodyData[offset + 13] },
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isArenaBoundAt(index, bodyData, offset) {
|
|
38
|
+
return (
|
|
39
|
+
index < 5 &&
|
|
40
|
+
bodyData[offset + 10] === RenderShapeType.box &&
|
|
41
|
+
(bodyData[offset + 7] > 10 || bodyData[offset + 8] > 5 || bodyData[offset + 9] > 10)
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function makeArenaMaterial(record, index) {
|
|
16
46
|
if (materialFactory) {
|
|
17
47
|
return materialFactory(record);
|
|
18
48
|
}
|
|
19
49
|
|
|
20
50
|
return new THREE.MeshStandardMaterial({
|
|
21
51
|
color: new THREE.Color(record.color.r, record.color.g, record.color.b),
|
|
22
|
-
roughness:
|
|
23
|
-
metalness: 0.
|
|
52
|
+
roughness: 0.82,
|
|
53
|
+
metalness: 0.0,
|
|
54
|
+
transparent: true,
|
|
55
|
+
opacity: index === 0 ? 0.22 : 0.34,
|
|
56
|
+
depthWrite: false,
|
|
57
|
+
side: THREE.DoubleSide,
|
|
58
|
+
wireframe: index !== 0,
|
|
24
59
|
});
|
|
25
60
|
}
|
|
26
61
|
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
color: { r: bodyData[offset + 11], g: bodyData[offset + 12], b: bodyData[offset + 13] },
|
|
35
|
-
};
|
|
62
|
+
function makeInstanceMaterial(shapeType) {
|
|
63
|
+
return new THREE.MeshStandardMaterial({
|
|
64
|
+
color: 0xffffff,
|
|
65
|
+
roughness: shapeType === RenderShapeType.sphere ? 0.42 : 0.58,
|
|
66
|
+
metalness: 0.03,
|
|
67
|
+
vertexColors: true,
|
|
68
|
+
});
|
|
36
69
|
}
|
|
37
70
|
|
|
38
|
-
function
|
|
39
|
-
let
|
|
40
|
-
|
|
71
|
+
function hideArenaMeshes(fromIndex) {
|
|
72
|
+
for (let i = fromIndex; i < arenaMeshes.length; i += 1) {
|
|
73
|
+
arenaMeshes[i].visible = false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
41
76
|
|
|
77
|
+
function syncArenaMesh(arenaIndex, bodyIndex, record) {
|
|
78
|
+
let mesh = arenaMeshes[arenaIndex];
|
|
42
79
|
if (!mesh) {
|
|
43
|
-
mesh = new THREE.Mesh(
|
|
44
|
-
mesh.castShadow =
|
|
45
|
-
mesh.receiveShadow =
|
|
46
|
-
|
|
80
|
+
mesh = new THREE.Mesh(boxGeometry, makeArenaMaterial(record, bodyIndex));
|
|
81
|
+
mesh.castShadow = false;
|
|
82
|
+
mesh.receiveShadow = false;
|
|
83
|
+
arenaMeshes[arenaIndex] = mesh;
|
|
47
84
|
scene.add(mesh);
|
|
48
|
-
return mesh;
|
|
49
85
|
}
|
|
50
86
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
87
|
+
mesh.visible = true;
|
|
88
|
+
mesh.position.set(record.position.x, record.position.y, record.position.z);
|
|
89
|
+
mesh.quaternion.set(record.quaternion.x, record.quaternion.y, record.quaternion.z, record.quaternion.w);
|
|
90
|
+
mesh.scale.set(record.size.x, record.size.y, record.size.z);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function disposeInstancedMesh(mesh) {
|
|
94
|
+
if (!mesh) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
scene.remove(mesh);
|
|
98
|
+
mesh.material.dispose();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function ensureInstances(kind, required) {
|
|
102
|
+
if (kind === RenderShapeType.sphere) {
|
|
103
|
+
if (sphereInstances && sphereCapacity >= required) {
|
|
104
|
+
return sphereInstances;
|
|
105
|
+
}
|
|
106
|
+
disposeInstancedMesh(sphereInstances);
|
|
107
|
+
sphereCapacity = Math.max(1, required);
|
|
108
|
+
lastSphereColorCount = -1;
|
|
109
|
+
sphereInstances = new THREE.InstancedMesh(sphereGeometry, makeInstanceMaterial(RenderShapeType.sphere), sphereCapacity);
|
|
110
|
+
sphereInstances.castShadow = false;
|
|
111
|
+
sphereInstances.receiveShadow = false;
|
|
112
|
+
sphereInstances.frustumCulled = false;
|
|
113
|
+
scene.add(sphereInstances);
|
|
114
|
+
return sphereInstances;
|
|
55
115
|
}
|
|
56
116
|
|
|
57
|
-
|
|
117
|
+
if (boxInstances && boxCapacity >= required) {
|
|
118
|
+
return boxInstances;
|
|
119
|
+
}
|
|
120
|
+
disposeInstancedMesh(boxInstances);
|
|
121
|
+
boxCapacity = Math.max(1, required);
|
|
122
|
+
lastBoxColorCount = -1;
|
|
123
|
+
boxInstances = new THREE.InstancedMesh(boxGeometry, makeInstanceMaterial(RenderShapeType.box), boxCapacity);
|
|
124
|
+
boxInstances.castShadow = false;
|
|
125
|
+
boxInstances.receiveShadow = false;
|
|
126
|
+
boxInstances.frustumCulled = false;
|
|
127
|
+
scene.add(boxInstances);
|
|
128
|
+
return boxInstances;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function writeInstance(mesh, instanceIndex, bodyData, offset, writeColor) {
|
|
132
|
+
instancePosition.set(bodyData[offset], bodyData[offset + 1], bodyData[offset + 2]);
|
|
133
|
+
instanceQuaternion.set(bodyData[offset + 3], bodyData[offset + 4], bodyData[offset + 5], bodyData[offset + 6]);
|
|
134
|
+
instanceScale.set(bodyData[offset + 7], bodyData[offset + 8], bodyData[offset + 9]);
|
|
135
|
+
instanceMatrix.compose(instancePosition, instanceQuaternion, instanceScale);
|
|
136
|
+
mesh.setMatrixAt(instanceIndex, instanceMatrix);
|
|
137
|
+
|
|
138
|
+
if (writeColor) {
|
|
139
|
+
instanceColor.setRGB(bodyData[offset + 11], bodyData[offset + 12], bodyData[offset + 13]);
|
|
140
|
+
mesh.setColorAt(instanceIndex, instanceColor);
|
|
141
|
+
}
|
|
58
142
|
}
|
|
59
143
|
|
|
60
144
|
return {
|
|
61
|
-
|
|
145
|
+
arenaMeshes,
|
|
146
|
+
get meshes() {
|
|
147
|
+
return [...arenaMeshes, boxInstances, sphereInstances].filter(Boolean);
|
|
148
|
+
},
|
|
62
149
|
sync(physics) {
|
|
63
150
|
const count = physics.getBodyCount();
|
|
64
151
|
const stride = physics.getBodyStride();
|
|
65
152
|
const bodyData = physics.getBodyData();
|
|
153
|
+
let arenaCount = 0;
|
|
154
|
+
let boxCount = 0;
|
|
155
|
+
let sphereCount = 0;
|
|
66
156
|
|
|
67
157
|
for (let i = 0; i < count; i += 1) {
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
158
|
+
const offset = i * stride;
|
|
159
|
+
if (isArenaBoundAt(i, bodyData, offset)) {
|
|
160
|
+
syncArenaMesh(arenaCount, i, getRecordAt(bodyData, offset));
|
|
161
|
+
arenaCount += 1;
|
|
162
|
+
} else if (bodyData[offset + 10] === RenderShapeType.sphere) {
|
|
163
|
+
sphereCount += 1;
|
|
164
|
+
} else {
|
|
165
|
+
boxCount += 1;
|
|
166
|
+
}
|
|
74
167
|
}
|
|
75
168
|
|
|
76
|
-
|
|
77
|
-
|
|
169
|
+
hideArenaMeshes(arenaCount);
|
|
170
|
+
|
|
171
|
+
const boxes = ensureInstances(RenderShapeType.box, boxCount);
|
|
172
|
+
const spheres = ensureInstances(RenderShapeType.sphere, sphereCount);
|
|
173
|
+
let boxIndex = 0;
|
|
174
|
+
let sphereIndex = 0;
|
|
175
|
+
const writeBoxColors = boxCount !== lastBoxColorCount;
|
|
176
|
+
const writeSphereColors = sphereCount !== lastSphereColorCount;
|
|
177
|
+
|
|
178
|
+
for (let i = 0; i < count; i += 1) {
|
|
179
|
+
const offset = i * stride;
|
|
180
|
+
if (isArenaBoundAt(i, bodyData, offset)) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (bodyData[offset + 10] === RenderShapeType.sphere) {
|
|
185
|
+
writeInstance(spheres, sphereIndex, bodyData, offset, writeSphereColors);
|
|
186
|
+
sphereIndex += 1;
|
|
187
|
+
} else {
|
|
188
|
+
writeInstance(boxes, boxIndex, bodyData, offset, writeBoxColors);
|
|
189
|
+
boxIndex += 1;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
boxes.count = boxIndex;
|
|
194
|
+
spheres.count = sphereIndex;
|
|
195
|
+
boxes.instanceMatrix.needsUpdate = true;
|
|
196
|
+
spheres.instanceMatrix.needsUpdate = true;
|
|
197
|
+
if (writeBoxColors && boxes.instanceColor) {
|
|
198
|
+
boxes.instanceColor.needsUpdate = true;
|
|
199
|
+
lastBoxColorCount = boxIndex;
|
|
200
|
+
}
|
|
201
|
+
if (writeSphereColors && spheres.instanceColor) {
|
|
202
|
+
spheres.instanceColor.needsUpdate = true;
|
|
203
|
+
lastSphereColorCount = sphereIndex;
|
|
78
204
|
}
|
|
79
205
|
},
|
|
80
206
|
dispose() {
|
|
81
|
-
for (const mesh of
|
|
207
|
+
for (const mesh of arenaMeshes) {
|
|
82
208
|
scene.remove(mesh);
|
|
83
209
|
mesh.material.dispose();
|
|
84
210
|
}
|
|
211
|
+
disposeInstancedMesh(boxInstances);
|
|
212
|
+
disposeInstancedMesh(sphereInstances);
|
|
85
213
|
boxGeometry.dispose();
|
|
86
214
|
sphereGeometry.dispose();
|
|
87
|
-
|
|
215
|
+
arenaMeshes.length = 0;
|
|
216
|
+
boxInstances = undefined;
|
|
217
|
+
sphereInstances = undefined;
|
|
218
|
+
boxCapacity = 0;
|
|
219
|
+
sphereCapacity = 0;
|
|
220
|
+
lastBoxColorCount = -1;
|
|
221
|
+
lastSphereColorCount = -1;
|
|
88
222
|
},
|
|
89
223
|
};
|
|
90
224
|
}
|
|
91
|
-
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@threecyborgs/wasm-box3d-three",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Three.js helpers for rendering @threecyborgs/wasm-box3d bodies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"prepack": "npm run build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@threecyborgs/wasm-box3d": "0.1.
|
|
32
|
+
"@threecyborgs/wasm-box3d": "0.1.2"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"three": ">=0.160.0"
|