Skip to content

Commit df2ae6f

Browse files
fix(load3d): dispose THREE.Points GPU resources in clearModel() (#11836)
Fixes #11345 ## Summary `clearModel()` in `SceneModelManager` only traversed and disposed `THREE.Mesh` instances, leaving `THREE.Points` objects (created by `handlePLYModeSwitch()` for point-cloud mode) leaking GPU geometry and material memory on repeated point-cloud loads/clears. ## Changes - `SceneModelManager.ts`: extend the dispose traversal in `clearModel()` to also handle `THREE.Points`, mirroring the pattern already used by `removeAllMainModelsFromScene()`. - `SceneModelManager.test.ts`: add regression test verifying `geometry.dispose()` and `material.dispose()` are called for `THREE.Points` children on `clearModel()`. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11836-fix-load3d-dispose-THREE-Points-GPU-resources-in-clearModel-3546d73d365081718338e824bc3e737d) by [Unito](https://www.unito.io)
1 parent 3c77811 commit df2ae6f

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

src/extensions/core/load3d/SceneModelManager.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ function createMeshModel(name = 'TestModel'): THREE.Group {
102102
return group
103103
}
104104

105+
function createPointsModel(name = 'TestModel'): THREE.Group {
106+
const geometry = new THREE.BufferGeometry()
107+
const material = new THREE.PointsMaterial({ color: 0xff0000 })
108+
const points = new THREE.Points(geometry, material)
109+
const group = new THREE.Group()
110+
group.name = name
111+
group.add(points)
112+
return group
113+
}
114+
105115
describe('SceneModelManager', () => {
106116
describe('constructor', () => {
107117
it('initializes default state', () => {
@@ -311,6 +321,20 @@ describe('SceneModelManager', () => {
311321
expect(geoDispose).toHaveBeenCalled()
312322
expect(matDispose).toHaveBeenCalled()
313323
})
324+
325+
it('disposes points geometry and materials', async () => {
326+
const { manager } = createManager()
327+
const model = createPointsModel()
328+
const points = model.children[0] as THREE.Points
329+
const geoDispose = vi.spyOn(points.geometry, 'dispose')
330+
const matDispose = vi.spyOn(points.material as THREE.Material, 'dispose')
331+
332+
await manager.setupModel(model)
333+
manager.clearModel()
334+
335+
expect(geoDispose).toHaveBeenCalled()
336+
expect(matDispose).toHaveBeenCalled()
337+
})
314338
})
315339

316340
describe('reset', () => {

src/extensions/core/load3d/SceneModelManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ export class SceneModelManager implements ModelManagerInterface {
328328
this.scene.remove(obj)
329329

330330
obj.traverse((child) => {
331-
if (child instanceof THREE.Mesh) {
331+
if (child instanceof THREE.Mesh || child instanceof THREE.Points) {
332332
child.geometry?.dispose()
333333
if (Array.isArray(child.material)) {
334334
child.material.forEach((material) => material.dispose())

0 commit comments

Comments
 (0)