Browse Source

feat(core): made custom renderer determine whether materials and geometries should be disposed

Tino Koch 2 years ago
parent
commit
36c8cf5ed0

+ 7 - 5
playground/src/components/TheConditional.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { BasicShadowMap, NoToneMapping, sRGBEncoding } from 'three'
+import { BasicShadowMap, MeshToonMaterial, NoToneMapping, sRGBEncoding } from 'three'
 import { reactive } from 'vue'
 import { OrbitControls, useTweakPane } from '@tresjs/cientos'
 import { TresCanvas } from '/@/'
@@ -22,6 +22,8 @@ const { pane } = useTweakPane()
 
 pane.addInput(paneElements, 'boxVisible')
 pane.addInput(paneElements, 'groupVisible')
+
+const material = new MeshToonMaterial({ color: '#ff0000' })
 </script>
 
 <template>
@@ -29,17 +31,17 @@ pane.addInput(paneElements, 'groupVisible')
     <TresPerspectiveCamera :position="[11, 11, 11]" :fov="45" :near="0.1" :far="1000" :look-at="[-8, 3, -3]" />
 
     <TresDirectionalLight :position="[0, 8, 4]" :intensity="0.2" cast-shadow />
-    <TresMesh v-if="paneElements.boxVisible" :position="[0, 0, 0]">
+    <TresMesh v-if="paneElements.boxVisible" :position="[0, 0, 0]" :material="material">
       <TresBoxGeometry :args="[1, 1, 1]" />
-      <TresMeshToonMaterial color="#efefef" />
+      <!-- <TresMeshToonMaterial color="#efefef" /> -->
     </TresMesh>
 
-    <TresGroup v-if="paneElements.groupVisible" :position="[0, -4, -5]">
+    <!-- <TresGroup v-if="paneElements.groupVisible" :position="[0, -4, -5]">
       <TresMesh :position="[0, 0, 0]">
         <TresBoxGeometry :args="[1, 1, 1]" />
         <TresMeshToonMaterial color="#efef11" />
       </TresMesh>
-    </TresGroup>
+    </TresGroup> -->
     <OrbitControls></OrbitControls>
     <TresAmbientLight :intensity="0.5" />
   </TresCanvas>

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

@@ -255,7 +255,7 @@ You could set windowSize=true to force the canvas to be the size of the window.`
     { immediate: true, deep: true },
   )
 
-  setInterval(() => console.log(renderer.value?.info.memory), 3000) // TODO remove
+  setInterval(() => console.log(renderer.value?.info.memory, renderer.value?.info.programs?.length), 3000) // TODO remove
 
   return {
     renderer,

+ 18 - 3
src/core/nodeOps.ts

@@ -1,4 +1,4 @@
-import { BufferAttribute, Mesh } from 'three'
+import { BufferAttribute, Mesh, Object3D } from 'three'
 import { useCamera, useRaycaster, useRenderLoop, useLogger } from '/@/composables'
 import { RendererOptions } from 'vue'
 import { catalogue } from './catalogue'
@@ -23,6 +23,11 @@ function noop(fn: string): any {
 
 let scene: TresObject | null = null
 
+const OBJECT_3D_USER_DATA_KEYS = {
+  GEOMETRY_VIA_PROP: 'tres__geometryViaProp',
+  MATERIAL_VIA_PROP: 'tres__materialViaProp',
+}
+
 export const nodeOps: RendererOptions<TresObject, TresObject> = {
   createElement(tag, _isSVG, _anchor, props) {
     if (tag === 'template') return null
@@ -54,6 +59,13 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
       else if (instance.isBufferGeometry) instance.attach = 'geometry'
     }
 
+    // determine whether the material was passed via prop to
+    // prevent it's disposal when node is removed later in it's lifecycle
+    const { GEOMETRY_VIA_PROP, MATERIAL_VIA_PROP } = OBJECT_3D_USER_DATA_KEYS
+
+    if (props?.material?.isMaterial) (instance as Object3D).userData[MATERIAL_VIA_PROP] = true
+    if (props?.geometry?.isBufferGeometry) (instance as Object3D).userData[GEOMETRY_VIA_PROP] = true
+
     return instance
   },
   insert(child, parent, anchor) {
@@ -122,8 +134,10 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
     node.removeFromParent?.()
 
     // TODO how to handle groups?
-    node.material?.dispose() // TODO probably disposes material also when passed via prop
-    node.geometry?.dispose()
+    const { GEOMETRY_VIA_PROP, MATERIAL_VIA_PROP } = OBJECT_3D_USER_DATA_KEYS
+
+    if (!node.userData[MATERIAL_VIA_PROP]) node.material?.dispose()
+    if (!node.userData[GEOMETRY_VIA_PROP]) node.geometry?.dispose()
 
     //TODO traverse children and dispose them too
 
@@ -156,6 +170,7 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
 
         if (!target?.set) root = chain.reduce((acc, key) => acc[kebabToCamel(key)], root)
       }
+
       let value = nextValue
       if (value === '') value = true
       // Set prop, prefer atomic methods if applicable