@combos-fun/plugin-renderer-3d-graphics 0.0.45 → 0.0.46
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/agent-skill.md +30 -86
- package/dist/plugin-renderer-3d-graphics.cjs.js +13 -206
- package/dist/plugin-renderer-3d-graphics.cjs.js.map +1 -1
- package/dist/plugin-renderer-3d-graphics.cjs.prod.js +1 -1
- package/dist/plugin-renderer-3d-graphics.d.ts +0 -6
- package/dist/plugin-renderer-3d-graphics.esm.js +15 -208
- package/dist/plugin-renderer-3d-graphics.esm.js.map +1 -1
- package/package.json +4 -4
package/agent-skill.md
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
# `@combos-fun/plugin-renderer-3d-graphics` — Agent notes
|
|
2
2
|
|
|
3
|
-
Procedural
|
|
3
|
+
Procedural primitives and compound primitive groups. Use this for plain or texture-mapped boxes, spheres, cylinders, planes, cones, tori, and capsules.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Read for any procedural primitive: box, sphere, cylinder, plane, cone, torus, capsule, debug placeholders, simple terrain, compound furniture.
|
|
8
|
-
|
|
9
|
-
Read **before** guessing that 3D has no rotation or no per-frame pose — do not wait for a compile error. Pose fields and a chase-camera pattern are below.
|
|
5
|
+
Prerequisite: follow the parent `@combos-fun/plugin-renderer-3d` skill for system order, named resources, pose seeding, hierarchy, and stale-async handling.
|
|
10
6
|
|
|
11
7
|
## Public API
|
|
12
8
|
|
|
13
9
|
```ts
|
|
14
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
Graphics3D,
|
|
12
|
+
Graphics3DSystem,
|
|
13
|
+
type Graphics3DParams,
|
|
14
|
+
type Graphics3DPartParams,
|
|
15
|
+
type Graphics3DMaterialKind,
|
|
16
|
+
type Graphics3DShape,
|
|
17
|
+
} from '@combos-fun/plugin-renderer-3d-graphics';
|
|
15
18
|
```
|
|
16
19
|
|
|
17
|
-
`componentName = 'Graphics3D'
|
|
20
|
+
`componentName = 'Graphics3D'`; `systemName = 'Graphics3DSystem'`.
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
## Parameters
|
|
20
23
|
|
|
21
24
|
| Field | Type | Default |
|
|
22
25
|
|-------|------|---------|
|
|
@@ -26,54 +29,34 @@ import { Graphics3D, Graphics3DSystem, type Graphics3DParams, type Graphics3DPar
|
|
|
26
29
|
| `width` / `height` / `depth` | `number` | `1` |
|
|
27
30
|
| `radius` | `number` | `0.5` |
|
|
28
31
|
| `segments` | `number` | `12` |
|
|
29
|
-
| `tube` | `number` | `0
|
|
30
|
-
| `positionX
|
|
31
|
-
| `rotationX
|
|
32
|
-
| `scaleX
|
|
32
|
+
| `tube` | `number` | `0`; torus resolves it to `0.4 × radius` |
|
|
33
|
+
| `positionX/Y/Z` | `number` | `0` |
|
|
34
|
+
| `rotationX/Y/Z` | `number` | `0` radians |
|
|
35
|
+
| `scaleX/Y/Z` | `number` | `1` |
|
|
33
36
|
| `opacity` | `number` | `1` |
|
|
34
|
-
| `roughness` / `metalness` | `number` | `1` / `0`
|
|
35
|
-
| `emissive` | `number` | `0`
|
|
36
|
-
| `map` | `string` | `''` (
|
|
37
|
+
| `roughness` / `metalness` | `number` | `1` / `0` |
|
|
38
|
+
| `emissive` | `number` | `0` |
|
|
39
|
+
| `map` | `string` | `''` (`IMAGE` resource name) |
|
|
37
40
|
| `doubleSide` | `boolean` | `false` |
|
|
38
41
|
| `material` | `'standard' \| 'basic' \| 'lambert' \| 'toon'` | `'standard'` |
|
|
39
|
-
| `
|
|
40
|
-
| `parts` | `Graphics3DPartParams[]` | — |
|
|
41
|
-
|
|
42
|
-
`parts` replaces the single primitive. Each part can override shape / color / map / local pose. The component pose still moves the whole group.
|
|
43
|
-
|
|
44
|
-
Shape → Three.js geometry: `box → BoxGeometry`, `sphere → SphereGeometry`, `cylinder → CylinderGeometry`, `plane → PlaneGeometry` (uses `segments` as width/height segs), `cone → ConeGeometry`, `torus → TorusGeometry`, `capsule → CapsuleGeometry` (`height` is total height).
|
|
42
|
+
| `parts` | `Graphics3DPartParams[]` | `undefined` |
|
|
45
43
|
|
|
46
|
-
|
|
44
|
+
When non-empty, `parts` replaces the single primitive. Each part inherits component values and may override geometry, appearance, and its local pose; the component pose moves the resulting `Group`.
|
|
47
45
|
|
|
48
|
-
|
|
46
|
+
Geometry mapping is direct to Three.js. Plane segments apply to both axes; capsule `height` is total height. Geometry and materials are reference-counted caches. Creating or rebuilding a mapped primitive is async; stale preparation releases acquired cache entries instead of attaching them.
|
|
49
47
|
|
|
50
|
-
|
|
48
|
+
Non-pose changes rebuild the group. Pose changes are synchronized per frame without rebuilding. A sibling `Material3D` can replace the generated materials.
|
|
51
49
|
|
|
52
|
-
##
|
|
50
|
+
## Package-specific pitfalls
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
| Sync drift with `Physics3D` | Same `GameObject`; `Physics3D.update()` writes positions back |
|
|
60
|
-
| `map` throws `Unknown resource` | Use the engine resource name, not a URL |
|
|
61
|
-
| Compound house as 3 GameObjects | Prefer one `Graphics3D` with `parts`, or `parent.addChild(child)` so the child mesh hangs off the parent |
|
|
62
|
-
| Child does not follow parent | `car.addChild(wheel)` — child `position*` are local. Do not also write world-space pose onto the wheel each frame unless it has its own `Physics3D` |
|
|
52
|
+
- A plane is single-sided unless `doubleSide: true`.
|
|
53
|
+
- A visual `PlaneGeometry` is finite; Cannon `Physics3DType.PLANE` is infinite unless `finite: true`.
|
|
54
|
+
- Lit materials may look dark without enough light; `basic` is unlit.
|
|
55
|
+
- Prefer `parts` for one compound visual. Use child GameObjects when parts need independent components or physics.
|
|
56
|
+
- Physics and graphics should share a GameObject when physics owns its pose.
|
|
63
57
|
|
|
64
58
|
## Minimal example
|
|
65
59
|
|
|
66
|
-
```ts
|
|
67
|
-
const box = new GameObject('box');
|
|
68
|
-
box.addComponent(new Graphics3D({
|
|
69
|
-
shape: 'box',
|
|
70
|
-
width: 1, height: 1, depth: 1,
|
|
71
|
-
color: 0xff0000,
|
|
72
|
-
roughness: 0.8,
|
|
73
|
-
positionX: 0, positionY: 1, positionZ: 0,
|
|
74
|
-
}));
|
|
75
|
-
```
|
|
76
|
-
|
|
77
60
|
```ts
|
|
78
61
|
const house = new GameObject('house');
|
|
79
62
|
house.addComponent(new Graphics3D({
|
|
@@ -82,47 +65,8 @@ house.addComponent(new Graphics3D({
|
|
|
82
65
|
{ shape: 'cone', radius: 1.4, height: 1, color: 0x8b2942, positionY: 1.1 },
|
|
83
66
|
],
|
|
84
67
|
}));
|
|
85
|
-
|
|
86
|
-
const car = new GameObject('car');
|
|
87
|
-
car.addComponent(new Graphics3D({ shape: 'box', width: 2, height: 0.6, depth: 1, color: 0x3366ff }));
|
|
88
|
-
const wheel = new GameObject('wheel');
|
|
89
|
-
wheel.addComponent(new Graphics3D({ shape: 'cylinder', radius: 0.3, height: 0.2, color: 0x222222, rotationZ: Math.PI / 2, positionX: 0.7, positionY: -0.2 }));
|
|
90
|
-
car.addChild(wheel);
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Per-frame pose + chase camera
|
|
94
|
-
|
|
95
|
-
`rotationX/Y/Z` and `positionX/Y/Z` are writable every tick. Use `Component.update` (`deltaTime` is milliseconds). Camera: `this.game.getSystem(Renderer3DSystem).threeContext.camera`. Do not hide `#canvas` or draw a second Canvas 2D game.
|
|
96
|
-
|
|
97
|
-
| Wrong | Correct |
|
|
98
|
-
|-------|---------|
|
|
99
|
-
| Static placemarker cube → “no rotation / don’t know how to change pose each frame” | Assign `graphics.rotationY` / `positionX` / `positionZ` in `update` |
|
|
100
|
-
| Hide WebGL `#canvas` and cover the viewport with Canvas 2D / DOM fake perspective | Keep `#canvas` visible and interactive; keep drawing with `Graphics3D` / `Model3D` |
|
|
101
|
-
| `setInterval` / extra `requestAnimationFrame` to move the mesh | `Component.update` so pause/resume follows `Game.ticker` |
|
|
102
|
-
| 2D `TransformParams` on a 3D GameObject | Pose lives on `Transform3D` (or `Graphics3D` / `Model3D` / `Img3D` fields, which seed `Transform3D`) |
|
|
103
|
-
|
|
104
|
-
```ts
|
|
105
|
-
class ChaseCraft extends Component {
|
|
106
|
-
static componentName = 'ChaseCraft';
|
|
107
|
-
heading = 0;
|
|
108
|
-
update(frame: UpdateParams) {
|
|
109
|
-
const mesh = this.gameObject.getComponent(Graphics3D);
|
|
110
|
-
const camera = this.game.getSystem(Renderer3DSystem).threeContext.camera;
|
|
111
|
-
const dt = frame.deltaTime / 1000;
|
|
112
|
-
this.heading += dt * 0.4;
|
|
113
|
-
mesh.rotationY = this.heading;
|
|
114
|
-
mesh.positionX += Math.sin(this.heading) * 6 * dt;
|
|
115
|
-
mesh.positionZ += Math.cos(this.heading) * 6 * dt;
|
|
116
|
-
camera.position.set(
|
|
117
|
-
mesh.positionX - Math.sin(this.heading) * 8,
|
|
118
|
-
mesh.positionY + 3,
|
|
119
|
-
mesh.positionZ - Math.cos(this.heading) * 8,
|
|
120
|
-
);
|
|
121
|
-
camera.lookAt(mesh.positionX, mesh.positionY, mesh.positionZ);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
68
|
```
|
|
125
69
|
|
|
126
70
|
## Verification
|
|
127
71
|
|
|
128
|
-
`pnpm --filter @combos-fun/plugin-renderer-3d-graphics run build
|
|
72
|
+
`pnpm --filter @combos-fun/plugin-renderer-3d-graphics run build`
|
|
@@ -34,7 +34,7 @@ class Graphics3D extends engine.Component {
|
|
|
34
34
|
this.map = '';
|
|
35
35
|
this.doubleSide = false;
|
|
36
36
|
this.material = 'standard';
|
|
37
|
-
this.
|
|
37
|
+
this.parts = undefined;
|
|
38
38
|
}
|
|
39
39
|
static { this.componentName = 'Graphics3D'; }
|
|
40
40
|
init(obj) {
|
|
@@ -293,140 +293,6 @@ tslib.__decorate([
|
|
|
293
293
|
enumOptions: ['standard', 'basic', 'lambert', 'toon'],
|
|
294
294
|
})
|
|
295
295
|
], Graphics3D.prototype, "material", void 0);
|
|
296
|
-
tslib.__decorate([
|
|
297
|
-
inspectorDecorator.Field({
|
|
298
|
-
type: 'boolean',
|
|
299
|
-
group: 'Graphics3D',
|
|
300
|
-
label: 'instanced',
|
|
301
|
-
description: 'Share an InstancedMesh with identical primitives.',
|
|
302
|
-
editor: 'toggle',
|
|
303
|
-
})
|
|
304
|
-
], Graphics3D.prototype, "instanced", void 0);
|
|
305
|
-
|
|
306
|
-
const _pos = new three.Vector3();
|
|
307
|
-
const _quat = new three.Quaternion();
|
|
308
|
-
const _scale = new three.Vector3();
|
|
309
|
-
const _euler = new three.Euler();
|
|
310
|
-
const _mat = new three.Matrix4();
|
|
311
|
-
const _swap = new three.Matrix4();
|
|
312
|
-
function composePose(px, py, pz, rx, ry, rz, sx, sy, sz, target = _mat) {
|
|
313
|
-
_pos.set(px, py, pz);
|
|
314
|
-
_euler.set(rx, ry, rz);
|
|
315
|
-
_quat.setFromEuler(_euler);
|
|
316
|
-
_scale.set(sx, sy, sz);
|
|
317
|
-
return target.compose(_pos, _quat, _scale);
|
|
318
|
-
}
|
|
319
|
-
class InstanceBuckets {
|
|
320
|
-
constructor(scene, shadows) {
|
|
321
|
-
this.scene = scene;
|
|
322
|
-
this.shadows = shadows;
|
|
323
|
-
this.buckets = new Map();
|
|
324
|
-
}
|
|
325
|
-
add(key, id, geometry, material, matrix) {
|
|
326
|
-
let bucket = this.buckets.get(key);
|
|
327
|
-
if (!bucket) {
|
|
328
|
-
bucket = this.create(key, geometry, material);
|
|
329
|
-
}
|
|
330
|
-
if (bucket.live >= bucket.capacity) {
|
|
331
|
-
this.grow(bucket);
|
|
332
|
-
}
|
|
333
|
-
const index = bucket.live;
|
|
334
|
-
bucket.ids[index] = id;
|
|
335
|
-
bucket.indexOf.set(id, index);
|
|
336
|
-
bucket.mesh.setMatrixAt(index, matrix);
|
|
337
|
-
bucket.live += 1;
|
|
338
|
-
bucket.mesh.count = bucket.live;
|
|
339
|
-
bucket.mesh.instanceMatrix.needsUpdate = true;
|
|
340
|
-
}
|
|
341
|
-
setMatrix(key, id, matrix) {
|
|
342
|
-
const bucket = this.buckets.get(key);
|
|
343
|
-
if (!bucket)
|
|
344
|
-
return;
|
|
345
|
-
const index = bucket.indexOf.get(id);
|
|
346
|
-
if (index == null)
|
|
347
|
-
return;
|
|
348
|
-
bucket.mesh.setMatrixAt(index, matrix);
|
|
349
|
-
bucket.mesh.instanceMatrix.needsUpdate = true;
|
|
350
|
-
}
|
|
351
|
-
remove(key, id) {
|
|
352
|
-
const bucket = this.buckets.get(key);
|
|
353
|
-
if (!bucket)
|
|
354
|
-
return;
|
|
355
|
-
const index = bucket.indexOf.get(id);
|
|
356
|
-
if (index == null)
|
|
357
|
-
return;
|
|
358
|
-
const last = bucket.live - 1;
|
|
359
|
-
if (index !== last) {
|
|
360
|
-
const lastId = bucket.ids[last];
|
|
361
|
-
bucket.mesh.getMatrixAt(last, _swap);
|
|
362
|
-
bucket.mesh.setMatrixAt(index, _swap);
|
|
363
|
-
bucket.ids[index] = lastId;
|
|
364
|
-
if (typeof lastId === 'number') {
|
|
365
|
-
bucket.indexOf.set(lastId, index);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
bucket.ids[last] = undefined;
|
|
369
|
-
bucket.indexOf.delete(id);
|
|
370
|
-
bucket.live -= 1;
|
|
371
|
-
bucket.mesh.count = bucket.live;
|
|
372
|
-
bucket.mesh.instanceMatrix.needsUpdate = true;
|
|
373
|
-
if (bucket.live <= 0) {
|
|
374
|
-
this.scene.remove(bucket.mesh);
|
|
375
|
-
bucket.mesh.dispose();
|
|
376
|
-
this.buckets.delete(key);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
clear() {
|
|
380
|
-
for (const bucket of this.buckets.values()) {
|
|
381
|
-
this.scene.remove(bucket.mesh);
|
|
382
|
-
bucket.mesh.dispose();
|
|
383
|
-
}
|
|
384
|
-
this.buckets.clear();
|
|
385
|
-
}
|
|
386
|
-
create(key, geometry, material) {
|
|
387
|
-
const capacity = 8;
|
|
388
|
-
const mesh = new three.InstancedMesh(geometry, material, capacity);
|
|
389
|
-
mesh.count = 0;
|
|
390
|
-
mesh.frustumCulled = false;
|
|
391
|
-
mesh.castShadow = this.shadows;
|
|
392
|
-
mesh.receiveShadow = this.shadows;
|
|
393
|
-
const ids = new Array(capacity);
|
|
394
|
-
mesh.userData[pluginRenderer3d.COMBOS_INSTANCE_GAME_OBJECT_IDS] = ids;
|
|
395
|
-
this.scene.add(mesh);
|
|
396
|
-
const bucket = {
|
|
397
|
-
mesh,
|
|
398
|
-
ids,
|
|
399
|
-
indexOf: new Map(),
|
|
400
|
-
live: 0,
|
|
401
|
-
capacity,
|
|
402
|
-
geometry,
|
|
403
|
-
material,
|
|
404
|
-
};
|
|
405
|
-
this.buckets.set(key, bucket);
|
|
406
|
-
return bucket;
|
|
407
|
-
}
|
|
408
|
-
grow(bucket) {
|
|
409
|
-
const capacity = bucket.capacity * 2;
|
|
410
|
-
const mesh = new three.InstancedMesh(bucket.geometry, bucket.material, capacity);
|
|
411
|
-
mesh.count = bucket.live;
|
|
412
|
-
mesh.frustumCulled = false;
|
|
413
|
-
mesh.castShadow = this.shadows;
|
|
414
|
-
mesh.receiveShadow = this.shadows;
|
|
415
|
-
const ids = new Array(capacity);
|
|
416
|
-
for (let i = 0; i < bucket.live; i++) {
|
|
417
|
-
bucket.mesh.getMatrixAt(i, _swap);
|
|
418
|
-
mesh.setMatrixAt(i, _swap);
|
|
419
|
-
ids[i] = bucket.ids[i];
|
|
420
|
-
}
|
|
421
|
-
mesh.userData[pluginRenderer3d.COMBOS_INSTANCE_GAME_OBJECT_IDS] = ids;
|
|
422
|
-
this.scene.remove(bucket.mesh);
|
|
423
|
-
bucket.mesh.dispose();
|
|
424
|
-
this.scene.add(mesh);
|
|
425
|
-
bucket.mesh = mesh;
|
|
426
|
-
bucket.ids = ids;
|
|
427
|
-
bucket.capacity = capacity;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
296
|
|
|
431
297
|
function torusTube(radius, tube) {
|
|
432
298
|
return tube && tube > 0 ? tube : radius * 0.4;
|
|
@@ -697,17 +563,15 @@ let Graphics3DSystem = class Graphics3DSystem extends pluginRenderer3d.Renderer3
|
|
|
697
563
|
this.entries = new Map();
|
|
698
564
|
this.geos = new GeometryCache();
|
|
699
565
|
this.mats = new MaterialCache();
|
|
700
|
-
this.buckets = null;
|
|
701
566
|
}
|
|
702
567
|
static { this.systemName = 'Graphics3DSystem'; }
|
|
703
568
|
init() {
|
|
704
569
|
const renderer3DSystem = this.game.getSystem(pluginRenderer3d.Renderer3DSystem);
|
|
705
570
|
renderer3DSystem.rendererManager.register(this);
|
|
706
|
-
this.buckets = new InstanceBuckets(this.threeContext.scene, !!this.threeContext.shadows);
|
|
707
571
|
}
|
|
708
572
|
componentChanged(changed) {
|
|
709
573
|
if (changed.componentName === 'Transform') {
|
|
710
|
-
this.
|
|
574
|
+
this.threeContext.reparentGameObject(changed.gameObject);
|
|
711
575
|
return;
|
|
712
576
|
}
|
|
713
577
|
if (changed.componentName !== 'Graphics3D')
|
|
@@ -738,25 +602,17 @@ let Graphics3DSystem = class Graphics3DSystem extends pluginRenderer3d.Renderer3
|
|
|
738
602
|
const next = poseKey(component.positionX, component.positionY, component.positionZ, component.rotationX, component.rotationY, component.rotationZ, component.scaleX, component.scaleY, component.scaleZ);
|
|
739
603
|
if (!applyVisualPose) {
|
|
740
604
|
entry.lastPose = next;
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
entry.group.scale.set(1, 1, 1);
|
|
745
|
-
}
|
|
605
|
+
entry.group.position.set(0, 0, 0);
|
|
606
|
+
entry.group.rotation.set(0, 0, 0);
|
|
607
|
+
entry.group.scale.set(1, 1, 1);
|
|
746
608
|
return;
|
|
747
609
|
}
|
|
748
610
|
if (entry.lastPose === next)
|
|
749
611
|
return;
|
|
750
612
|
entry.lastPose = next;
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
}
|
|
755
|
-
if (entry.group) {
|
|
756
|
-
entry.group.position.set(component.positionX, component.positionY, component.positionZ);
|
|
757
|
-
entry.group.rotation.set(component.rotationX, component.rotationY, component.rotationZ);
|
|
758
|
-
entry.group.scale.set(component.scaleX, component.scaleY, component.scaleZ);
|
|
759
|
-
}
|
|
613
|
+
entry.group.position.set(component.positionX, component.positionY, component.positionZ);
|
|
614
|
+
entry.group.rotation.set(component.rotationX, component.rotationY, component.rotationZ);
|
|
615
|
+
entry.group.scale.set(component.scaleX, component.scaleY, component.scaleZ);
|
|
760
616
|
}
|
|
761
617
|
async mount(gameObject, component) {
|
|
762
618
|
const asyncId = this.increaseAsyncId(gameObject.id);
|
|
@@ -772,7 +628,7 @@ let Graphics3DSystem = class Graphics3DSystem extends pluginRenderer3d.Renderer3
|
|
|
772
628
|
this.releasePrepared(prepared);
|
|
773
629
|
return;
|
|
774
630
|
}
|
|
775
|
-
this.
|
|
631
|
+
this.attachGroup(gameObject, component, prepared);
|
|
776
632
|
}
|
|
777
633
|
async prepare(component) {
|
|
778
634
|
const specs = this.resolveParts(component);
|
|
@@ -802,50 +658,7 @@ let Graphics3DSystem = class Graphics3DSystem extends pluginRenderer3d.Renderer3
|
|
|
802
658
|
}
|
|
803
659
|
return [resolvePrimitive(component)];
|
|
804
660
|
}
|
|
805
|
-
|
|
806
|
-
const parent = gameObject.parent;
|
|
807
|
-
if (parent && parent !== gameObject.scene) {
|
|
808
|
-
this.ensureGroupMode(parent);
|
|
809
|
-
}
|
|
810
|
-
this.ensureGroupMode(gameObject);
|
|
811
|
-
this.threeContext.reparentGameObject(gameObject);
|
|
812
|
-
}
|
|
813
|
-
ensureGroupMode(gameObject) {
|
|
814
|
-
const entry = this.entries.get(gameObject.id);
|
|
815
|
-
if (!entry || entry.mode !== 'instance')
|
|
816
|
-
return;
|
|
817
|
-
const component = gameObject.getComponent(Graphics3D);
|
|
818
|
-
if (!component)
|
|
819
|
-
return;
|
|
820
|
-
if (entry.bucketKey) {
|
|
821
|
-
this.buckets?.remove(entry.bucketKey, gameObject.id);
|
|
822
|
-
}
|
|
823
|
-
this.attachGroup(gameObject, component, entry.prepared, entry.lastPose);
|
|
824
|
-
}
|
|
825
|
-
attach(gameObject, component, prepared) {
|
|
826
|
-
const useInstance = component.instanced !== false
|
|
827
|
-
&& prepared.length === 1
|
|
828
|
-
&& pluginRenderer3d.is3DSceneParent(gameObject)
|
|
829
|
-
&& !pluginRenderer3d.has3DChildGameObjects(gameObject)
|
|
830
|
-
&& !gameObject.getComponent(pluginRenderer3d.Transform3D)
|
|
831
|
-
&& !this.threeContext.hasTransform3DRoot(gameObject.id);
|
|
832
|
-
const lastPose = poseKey(component.positionX, component.positionY, component.positionZ, component.rotationX, component.rotationY, component.rotationZ, component.scaleX, component.scaleY, component.scaleZ);
|
|
833
|
-
if (useInstance) {
|
|
834
|
-
const part = prepared[0];
|
|
835
|
-
const bucketKey = `${part.geoKey}|${part.matKey}`;
|
|
836
|
-
this.buckets?.add(bucketKey, gameObject.id, part.geometry, part.material, composePose(component.positionX, component.positionY, component.positionZ, component.rotationX, component.rotationY, component.rotationZ, component.scaleX, component.scaleY, component.scaleZ));
|
|
837
|
-
this.entries.set(gameObject.id, {
|
|
838
|
-
mode: 'instance',
|
|
839
|
-
bucketKey,
|
|
840
|
-
prepared,
|
|
841
|
-
lastPose,
|
|
842
|
-
poseBridge: new pluginRenderer3d.VisualPoseBridge(),
|
|
843
|
-
});
|
|
844
|
-
return;
|
|
845
|
-
}
|
|
846
|
-
this.attachGroup(gameObject, component, prepared, lastPose);
|
|
847
|
-
}
|
|
848
|
-
attachGroup(gameObject, component, prepared, lastPose) {
|
|
661
|
+
attachGroup(gameObject, component, prepared) {
|
|
849
662
|
const group = new three.Group();
|
|
850
663
|
const shadows = !!this.threeContext.shadows;
|
|
851
664
|
for (const part of prepared) {
|
|
@@ -871,9 +684,9 @@ let Graphics3DSystem = class Graphics3DSystem extends pluginRenderer3d.Renderer3
|
|
|
871
684
|
group.rotation.set(0, 0, 0);
|
|
872
685
|
group.scale.set(1, 1, 1);
|
|
873
686
|
}
|
|
687
|
+
const lastPose = poseKey(component.positionX, component.positionY, component.positionZ, component.rotationX, component.rotationY, component.rotationZ, component.scaleX, component.scaleY, component.scaleZ);
|
|
874
688
|
this.threeContext.attachVisual(gameObject.id, group, gameObject);
|
|
875
689
|
this.entries.set(gameObject.id, {
|
|
876
|
-
mode: 'group',
|
|
877
690
|
group,
|
|
878
691
|
prepared,
|
|
879
692
|
lastPose,
|
|
@@ -891,12 +704,7 @@ let Graphics3DSystem = class Graphics3DSystem extends pluginRenderer3d.Renderer3
|
|
|
891
704
|
const entry = this.entries.get(id);
|
|
892
705
|
if (!entry)
|
|
893
706
|
return;
|
|
894
|
-
|
|
895
|
-
this.buckets?.remove(entry.bucketKey, id);
|
|
896
|
-
}
|
|
897
|
-
else if (entry.group) {
|
|
898
|
-
this.threeContext.detachVisual(id, entry.group);
|
|
899
|
-
}
|
|
707
|
+
this.threeContext.detachVisual(id, entry.group);
|
|
900
708
|
this.releasePrepared(entry.prepared);
|
|
901
709
|
this.entries.delete(id);
|
|
902
710
|
}
|
|
@@ -905,7 +713,6 @@ let Graphics3DSystem = class Graphics3DSystem extends pluginRenderer3d.Renderer3
|
|
|
905
713
|
this.handleRemove(id);
|
|
906
714
|
}
|
|
907
715
|
this.entries.clear();
|
|
908
|
-
this.buckets?.clear();
|
|
909
716
|
this.geos.clear();
|
|
910
717
|
this.mats.clear();
|
|
911
718
|
}
|
|
@@ -919,7 +726,7 @@ Graphics3DSystem = tslib.__decorate([
|
|
|
919
726
|
'rotationX', 'rotationY', 'rotationZ',
|
|
920
727
|
'scaleX', 'scaleY', 'scaleZ',
|
|
921
728
|
'opacity', 'roughness', 'metalness', 'emissive',
|
|
922
|
-
'map', 'doubleSide', 'material', '
|
|
729
|
+
'map', 'doubleSide', 'material', 'parts',
|
|
923
730
|
],
|
|
924
731
|
Transform: ['_parent'],
|
|
925
732
|
})
|