Skip to content

Commit

Permalink
fix: improve renderer and object disposal safety
Browse files Browse the repository at this point in the history
  • Loading branch information
alvarosabu committed Feb 4, 2025
1 parent 87da70c commit 431b82e
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 24 deletions.
14 changes: 8 additions & 6 deletions src/components/TresCanvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -158,16 +158,18 @@ const mountCustomRenderer = (context: TresContext, empty = false) => {
const dispose = (context: TresContext, force = false) => {
disposeObject3D(context.scene.value as unknown as TresObject)
if (force) {
context.renderer.value.dispose()
context.renderer.value.renderLists.dispose()
context.renderer.value.forceContextLoss()
// Clear WebGL context
const gl = context.renderer.value.getContext()
// Clear WebGL context first
const gl = context.renderer.value?.getContext()
if (gl) {
const loseContext = gl.getExtension('WEBGL_lose_context')
loseContext?.loseContext()
}
// Then dispose renderer
context.renderer.value?.dispose()
context.renderer.value?.renderLists.dispose()
context.renderer.value?.forceContextLoss()
context.renderer.value = null
}
(scene.value as TresScene).__tres = {
root: context,
Expand Down
2 changes: 1 addition & 1 deletion src/composables/useRaycaster/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const useRaycaster = (
ctx: TresContext,
) => {
// having a separate computed makes useElementBounding work
const canvas = computed(() => ctx.renderer.value.domElement as HTMLCanvasElement)
const canvas = computed(() => ctx.renderer.value?.domElement as HTMLCanvasElement)
const intersects: ShallowRef<Intersection[]> = shallowRef([])
const { x, y } = usePointer({ target: canvas })
let delta = 0
Expand Down
2 changes: 1 addition & 1 deletion src/composables/useTresContextProvider/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export interface TresContext {
camera: ComputedRef<Camera | undefined>
cameras: DeepReadonly<Ref<Camera[]>>
controls: Ref<TresControl | null>
renderer: ShallowRef<WebGLRenderer>
renderer: ShallowRef<WebGLRenderer | null>
raycaster: ShallowRef<Raycaster>
perf: PerformanceState
render: RenderState
Expand Down
2 changes: 1 addition & 1 deletion src/devtools/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export function registerTresDevtools(app: DevtoolsApp, tres: TresContext) {
}),
}

if (instance.isScene) {
if (instance.isScene && tres.renderer.value) {
payload.state.info = {
objects: instance.children.length,
memory: calculateMemoryUsage(instance),
Expand Down
23 changes: 8 additions & 15 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { nodeOps } from 'src/core/nodeOps'
import type { AttachType, LocalState, TresInstance, TresObject, TresPrimitive } from 'src/types'
import type { Material, Object3D, Texture } from 'three'
import { BufferAttribute, BufferGeometry, DoubleSide, InterleavedBufferAttribute, Light, Line, MathUtils, Mesh, MeshBasicMaterial, Points, Scene, Vector3 } from 'three'
import { BufferAttribute, BufferGeometry, DoubleSide, InterleavedBufferAttribute, Line, MathUtils, Mesh, MeshBasicMaterial, Points, Scene, Vector3 } from 'three'
import type { TresContext } from '../composables/useTresContextProvider'
import { HightlightMesh } from '../devtools/highlight'
import * as is from './is'
Expand Down Expand Up @@ -285,7 +285,8 @@ export function disposeMaterial(material: Material): void {
material.dispose()
}

export function disposeObject3D(object: TresObject): void {
export function disposeObject3D(object: TresObject | null): void {
if (!object) { return }
// Clone the children array to safely iterate
const children = [...object.children]
children.forEach(child => disposeObject3D(child))
Expand All @@ -306,13 +307,6 @@ export function disposeObject3D(object: TresObject): void {
}
}

// Handle lights
if (object instanceof Light) {
if (object.shadow?.map) {
object.shadow.map.dispose()
}
}

// Clean up any custom properties
if (object.userData) {
// Clear any custom user data that might hold references
Expand All @@ -336,6 +330,10 @@ export function disposeObject3D(object: TresObject): void {
})
object.attributes = {}
}
// Remove tres state if it exists
if ('__tres' in object) {
delete object.__tres
}

if (object instanceof Scene) {
object.background = null
Expand All @@ -344,13 +342,8 @@ export function disposeObject3D(object: TresObject): void {
if (object.fog) {
object.fog = null
}
}

// Remove tres state
delete object.__tres

if (object.clear) {
object.clear()
object = null
}
}

Expand Down

0 comments on commit 431b82e

Please sign in to comment.