Browse Source

chore: fix tests and linters, primitive object is now reactive

alvarosabu 1 year ago
parent
commit
8d52f32af1

+ 7 - 6
playground/src/components/DynamicModel.vue

@@ -2,19 +2,20 @@
 import { useControls } from '@tresjs/leches'
 import { useGLTF } from '@tresjs/cientos'
 
-const { scene } = await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/blender-cube.glb', 
-  { draco: true })
+const { nodes } 
+  = await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/blender-cube.glb', 
+    { draco: true })
 
-const { nodes } = await useGLTF(
+const { scene: AkuAku, nodes: akukuNodes } = await useGLTF(
   'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/aku-aku/AkuAku.gltf',
   { draco: true },
 )
-const model = nodes.AkuAku
+
 const { isCube } = useControls({
-  isCube: true,
+  isCube: false,
 })
 </script>
 
 <template>
-  <primitive :object="isCube ? scene : model" />
+  <primitive :object="isCube ? nodes.Cube : AkuAku" />
 </template>

+ 7 - 1
playground/src/components/TheExperience.vue

@@ -3,7 +3,9 @@ import { ref, watchEffect } from 'vue'
 import { BasicShadowMap, SRGBColorSpace, NoToneMapping } from 'three'
 import { TresCanvas } from '@tresjs/core'
 import { OrbitControls } from '@tresjs/cientos'
+import { TresLeches, useControls } from '@tresjs/leches'
 import TheSphere from './TheSphere.vue'
+import '@tresjs/leches/styles'
 
 const gl = {
   clearColor: '#82DBC5',
@@ -15,7 +17,9 @@ const gl = {
 }
 
 const wireframe = ref(true)
-
+const { isVisible } = useControls({
+  isVisible: true,
+})
 const canvas = ref()
 
 watchEffect(() => {
@@ -26,6 +30,7 @@ watchEffect(() => {
 </script>
 
 <template>
+  <TresLeches />
   <TresCanvas
     v-bind="gl"
     ref="canvas"
@@ -51,6 +56,7 @@ watchEffect(() => {
       <TresMeshToonMaterial color="#82DBC5" />
     </TresMesh>
     <TresMesh
+      v-if="isVisible"
       :position="[0, 4, 0]"
       cast-shadow
     >

+ 21 - 9
playground/src/pages/primitives.vue

@@ -1,6 +1,17 @@
 <script setup lang="ts">
 import { ref, watchEffect } from 'vue'
-import { BasicShadowMap, SRGBColorSpace, NoToneMapping, Mesh, TorusGeometry, MeshToonMaterial, TorusKnotGeometry, PlaneGeometry, Group, SphereGeometry } from 'three'
+import { 
+  BasicShadowMap,
+  SRGBColorSpace,
+  NoToneMapping,
+  Mesh,
+  TorusGeometry,
+  MeshToonMaterial,
+  TorusKnotGeometry,
+  PlaneGeometry,
+  Group,
+  SphereGeometry, 
+} from 'three'
 import { TresCanvas } from '@tresjs/core'
 import { OrbitControls } from '@tresjs/cientos'
 import { TresLeches, useControls } from '@tresjs/leches'
@@ -14,14 +25,15 @@ const gl = {
   outputColorSpace: SRGBColorSpace,
   toneMapping: NoToneMapping,
 }
-
-const wireframe = ref(true)
-
 const canvas = ref()
 const meshRef = ref()
 
 const { knot } = useControls({
-  knot: true,
+  knot: false,
+})
+
+const { isVisible } = useControls({
+  isVisible: true,
 })
 
 watchEffect(() => {
@@ -30,7 +42,7 @@ watchEffect(() => {
   }
 })
 
-const torusMesh = new Mesh(
+const torus = new Mesh(
   new TorusGeometry(1, 0.5, 16, 100),
   new MeshToonMaterial({
     color: '#82DBC5',
@@ -52,7 +64,7 @@ const sphere = new Mesh(
 )
 
 const firstGroup = new Group()
-firstGroup.add(torusMesh)
+firstGroup.add(torus)
 firstGroup.add(torusKnot)
 
 const secondGroup = new Group()
@@ -70,12 +82,12 @@ secondGroup.add(sphere)
   >
     <TresPerspectiveCamera
       :position="[7, 7, 7]"
-      :look-at="[0, 4, 0]"
     />
     <OrbitControls />
     <primitive
+      v-if="isVisible"
       :position="[4, 2, 0]"
-      :object="knot ? firstGroup : secondGroup"
+      :object="knot ? firstGroup : sphere"
     />
     <Suspense>
       <DynamicModel />

+ 25 - 20
src/core/nodeOps.ts

@@ -39,7 +39,7 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
       if (props?.object === undefined) logError('Tres primitives need a prop \'object\'')
       const object = props.object as TresObject
       name = object.type
-      instance = Object.assign(object, { type: name })
+      instance = Object.assign(object.clone(), { type: name }) as TresObject
       instance.userData.tres__primitive = true
     }
     else {
@@ -60,8 +60,8 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
     }
 
     if (props?.attach === undefined) {
-      if (instance.isMaterial) instance.userData.tres__attach = 'material'
-      else if (instance.isBufferGeometry) instance.userData.tres__attach = 'geometry'
+      if (instance.isMaterial) instance.attach = 'material'
+      else if (instance.isBufferGeometry) instance.attach = 'geometry'
     }
 
     // determine whether the material was passed via prop to
@@ -112,17 +112,17 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
     else if (child?.isFog) {
       parentObject.fog = child
     }
-    else if (typeof child?.userData.tres__attach === 'string') {
-      child.__previousAttach = child[parentObject?.userData.tres__attach as string]
+    else if (typeof child?.attach === 'string') {
+      child.__previousAttach = child[parentObject?.attach as string]
       if (parentObject) {
-        parentObject[child.userData.tres__attach] = child
+        parentObject[child.attach] = child
       }
     }
   },
   remove(node) {
     if (!node) return
     // remove is only called on the node being removed and not on child nodes.
-
+    node.parent = node.parent || scene
     if (node.isObject3D) {
       const object3D = node as unknown as Object3D
 
@@ -171,6 +171,7 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
       }
 
       node.removeFromParent?.()
+      
       object3D.traverse((child: Object3D) => {
         disposeMaterialsAndGeometries(child)
         deregisterCameraIfRequired(child)
@@ -180,31 +181,35 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
       disposeMaterialsAndGeometries(object3D)
       deregisterCameraIfRequired(object3D)
       deregisterAtPointerEventHandlerIfRequired?.(object3D as TresObject)
+
+      node.dispose?.()
+      
     }
 
-    node.dispose?.()
   },
   patchProp(node, prop, prevValue, nextValue) {
     if (node) {
       let root = node
       let key = prop
       if ( key === 'object' && prevValue !== null) {
-        const parent = node.parent || scene
-        const index = parent?.children.indexOf(prevValue)
-
-        if (index !== undefined && index !== -1) {
-          parent.children.splice(index, 1)
-        }
         const newInstance = nodeOps.createElement('primitive', false, null, { 
           object: nextValue, 
         })
+        const blacklistedKeys = ['uuid', 'position', 'rotation', 'scale', 'quaternion']
+        newInstance.uuid = node.uuid
+        for (const key in newInstance) {
+          if (!blacklistedKeys.includes(key)) {
+            node[key] = newInstance[key]
+          }
+        }
+        if (newInstance.isGroup) {
+          node.geometry = undefined
+          node.material = undefined
+        }
+        else {
+          delete node.isGroup
+        }
 
-        Object.entries(prevValue.userData.tres__memoisedProps).forEach(([key, value]) => {
-          nodeOps.patchProp(newInstance, key, null, value)
-        })
-        
-        nodeOps.insert(newInstance, parent)
-        /* switchInstance(node, nextValue) */
       }
 
       if (node.isObject3D && key === 'blocks-pointer-events') {