Przeglądaj źródła

fix: improve renderer and object disposal safety

alvarosabu 5 miesięcy temu
rodzic
commit
431b82eabc

+ 8 - 6
src/components/TresCanvas.vue

@@ -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,

+ 1 - 1
src/composables/useRaycaster/index.ts

@@ -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

+ 1 - 1
src/composables/useTresContextProvider/index.ts

@@ -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

+ 1 - 1
src/devtools/plugin.ts

@@ -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),

+ 8 - 15
src/utils/index.ts

@@ -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'
@@ -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))
@@ -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
@@ -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
@@ -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
   }
 }