Skip to content

Commit

Permalink
feat(core): made custom renderer traverse the scene tree to dispose o…
Browse files Browse the repository at this point in the history
…bsolete materials and geometries
  • Loading branch information
Tinoooo committed Apr 6, 2023
1 parent 36c8cf5 commit cae21b1
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 24 deletions.
29 changes: 17 additions & 12 deletions playground/src/components/TheConditional.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { BasicShadowMap, MeshToonMaterial, NoToneMapping, sRGBEncoding } from 'three'
import { BasicShadowMap, MeshPhongMaterial, NoToneMapping, sRGBEncoding } from 'three'
import { reactive } from 'vue'
import { OrbitControls, useTweakPane } from '@tresjs/cientos'
import { TresCanvas } from '/@/'
Expand All @@ -16,32 +16,37 @@ const state = reactive({
const paneElements = reactive({
boxVisible: true,
groupVisible: true,
boxPropMaterialVisible: true,
})
const { pane } = useTweakPane()
pane.addInput(paneElements, 'boxVisible')
pane.addInput(paneElements, 'groupVisible')
pane.addInput(paneElements, 'boxPropMaterialVisible')
const material = new MeshToonMaterial({ color: '#ff0000' })
const material = new MeshPhongMaterial({ color: '#ff0000' })
</script>

<template>
<TresCanvas v-bind="state">
<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]" :material="material">
<TresMesh v-if="paneElements.boxPropMaterialVisible" :position="[0, 0, 0]" :material="material">
<TresBoxGeometry :args="[1, 1, 1]" />
<!-- <TresMeshToonMaterial color="#efefef" /> -->
</TresMesh>

<!-- <TresGroup v-if="paneElements.groupVisible" :position="[0, -4, -5]">
<TresMesh :position="[0, 0, 0]">
<TresBoxGeometry :args="[1, 1, 1]" />
<TresMeshToonMaterial color="#efef11" />
</TresMesh>
</TresGroup> -->
<TresMesh v-if="paneElements.boxVisible" :position="[4, 0, 0]">
<TresBoxGeometry :args="[1, 1, 1]" />
<TresMeshToonMaterial color="#efefef" />
</TresMesh>
<TresGroup v-if="paneElements.groupVisible" :position="[0, -4, -5]">
<TresGroup>
<TresMesh :position="[0, 0, 0]">
<TresBoxGeometry :args="[1, 1, 1]" />
<TresMeshBasicMaterial color="#efef11" />
</TresMesh>
</TresGroup>
</TresGroup>
<OrbitControls></OrbitControls>
<TresAmbientLight :intensity="0.5" />
</TresCanvas>
Expand Down
31 changes: 21 additions & 10 deletions src/core/nodeOps.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BufferAttribute, Mesh, Object3D } from 'three'
import { BufferAttribute, BufferGeometry, Material, Mesh, Object3D } from 'three'
import { useCamera, useRaycaster, useRenderLoop, useLogger } from '/@/composables'
import { RendererOptions } from 'vue'
import { catalogue } from './catalogue'
Expand Down Expand Up @@ -63,8 +63,10 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
// 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
if (instance.isObject3D) {
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
},
Expand Down Expand Up @@ -131,17 +133,26 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
parent.removeChild(node)
}

node.removeFromParent?.()
// remove is only called on the node being removed and not on child nodes.

// TODO how to handle groups?
const { GEOMETRY_VIA_PROP, MATERIAL_VIA_PROP } = OBJECT_3D_USER_DATA_KEYS
if (node.isObject3D) {
const object3D = node as unknown as Object3D

const disposeMaterialsAndGeometries = (object3D: Object3D) => {
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()
if (!object3D.userData[MATERIAL_VIA_PROP]) (object3D as Object3D & { material: Material }).material?.dispose()
if (!object3D.userData[GEOMETRY_VIA_PROP])
(object3D as Object3D & { geometry: BufferGeometry }).geometry?.dispose()
}

object3D.traverse(child => disposeMaterialsAndGeometries(child))

//TODO traverse children and dispose them too
disposeMaterialsAndGeometries(object3D)
}

node.dispose?.()
node.removeFromParent?.()
node.dispose?.() // TODO is dispose ever set?
},
patchProp(node, prop, _prevValue, nextValue) {
if (node) {
Expand Down
4 changes: 2 additions & 2 deletions src/core/nodeOpts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe('nodeOps', () => {
expect(consoleWarnSpy).toHaveBeenCalled()
})

it('createElement should add attach material propety if instance is a material', () => {
it('createElement should add attach material property if instance is a material', () => {
// Setup
const tag = 'TresMeshStandardMaterial'
const props = { args: [] }
Expand All @@ -81,7 +81,7 @@ describe('nodeOps', () => {
expect(instance.attach).toBe('material')
})

it('createElement should add attach geometry propety if instance is a geometry', () => {
it('createElement should add attach geometry property if instance is a geometry', () => {
// Setup
const tag = 'TresTorusGeometry'
const props = { args: [] }
Expand Down

0 comments on commit cae21b1

Please sign in to comment.