1
0
alvarosabu 2 жил өмнө
parent
commit
ab63e14018

+ 2 - 0
playground/components.d.ts

@@ -12,6 +12,7 @@ declare module '@vue/runtime-core' {
     AkuAku: typeof import('./src/components/gltf/AkuAku.vue')['default']
     AnimatedModel: typeof import('./src/components/AnimatedModel.vue')['default']
     FBXModels: typeof import('./src/components/FBXModels.vue')['default']
+    Gltf: typeof import('./src/components/gltf/index.vue')['default']
     MultipleCanvas: typeof import('./src/components/MultipleCanvas.vue')['default']
     PortalJourney: typeof import('./src/components/portal-journey/index.vue')['default']
     Responsiveness: typeof import('./src/components/Responsiveness.vue')['default']
@@ -32,6 +33,7 @@ declare module '@vue/runtime-core' {
     TheFirstScene: typeof import('./src/components/TheFirstScene.vue')['default']
     TheGizmos: typeof import('./src/components/TheGizmos.vue')['default']
     TheGroups: typeof import('./src/components/TheGroups.vue')['default']
+    TheModel: typeof import('./src/components/gltf/TheModel.vue')['default']
     TheParticles: typeof import('./src/components/TheParticles.vue')['default']
     ThePortal: typeof import('./src/components/portal-journey/ThePortal.vue')['default']
     TheSmallExperience: typeof import('./src/components/TheSmallExperience.vue')['default']

+ 1 - 3
playground/src/components/gltf/AkuAku.vue → playground/src/components/gltf/TheModel.vue

@@ -9,8 +9,6 @@ const { scene: model } = await useGLTF(
     draco: true,
   },
 )
-model.position.set(0, 4, 0)
-model.updateMatrixWorld()
 
 const akuAkuRef = ref(null)
 
@@ -20,5 +18,5 @@ watch(akuAkuRef, value => {
 </script>
 
 <template>
-  <TresMesh ref="akuAkuRef" v-bind="model" />
+  <primitive ref="akuAkuRef" :object="model" />
 </template>

+ 6 - 4
playground/src/components/gltf/TheExperiment.vue → playground/src/components/gltf/index.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import { sRGBEncoding, BasicShadowMap, NoToneMapping } from 'three'
 import { TresCanvas } from '/@/'
-import { GLTFModel, OrbitControls } from '@tresjs/cientos'
+import { OrbitControls } from '@tresjs/cientos'
 
 const state = reactive({
   clearColor: '#82DBC5',
@@ -29,12 +29,14 @@ watchEffect(() => {
     <TresAmbientLight :intensity="0.5" />
 
     <Suspense>
-      <GLTFModel
+      <!--  <GLTFModel
         ref="akuAkuRef"
         path="https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/aku-aku/AkuAku.gltf"
         draco
-      />
-      <!--   <AkuAku /> -->
+      /> -->
+      <TresGroup :position="[0, 4, 0]">
+        <TheModel />
+      </TresGroup>
     </Suspense>
     <TresAxesHelper />
     <TresDirectionalLight :position="[0, 2, 4]" :intensity="1" cast-shadow />

+ 1 - 1
playground/src/pages/index.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts"></script>
 <template>
   <Suspense>
-    <VectorSetProps />
+    <Gltf />
   </Suspense>
 </template>

+ 1 - 1
playground/vite.config.ts

@@ -13,7 +13,7 @@ export default defineConfig({
     vue({
       template: {
         compilerOptions: {
-          isCustomElement: tag => tag.startsWith('Tres') && tag !== 'TresCanvas',
+          isCustomElement: tag => (tag.startsWith('Tres') && tag !== 'TresCanvas') || tag === 'primitive',
         },
       },
     }),

+ 35 - 36
src/core/nodeOps.ts

@@ -1,13 +1,11 @@
 import { BufferAttribute } from 'three'
-import { useCamera } from '/@/composables'
+import { useCamera, useLogger } from '/@/composables'
 import { RendererOptions } from 'vue'
 import { catalogue } from './catalogue'
 import { isFunction } from '@vueuse/core'
-import { TresObject } from '../types'
+import { TresInstance, TresObject } from '../types'
 import { isHTMLTag, kebabToCamel } from '../utils'
 
-import type { Object3D, Material, BufferGeometry } from 'three'
-
 const onRE = /^on[^a-z]/
 export const isOn = (key: string) => onRE.test(key)
 
@@ -15,25 +13,33 @@ function noop(fn: string): any {
   fn
 }
 
-let scene: TresObject | null = null
+let fallback: TresObject | null = null
 
-const OBJECT_3D_USER_DATA_KEYS = {
-  GEOMETRY_VIA_PROP: 'tres__geometryViaProp',
-  MATERIAL_VIA_PROP: 'tres__materialViaProp',
-}
+const { logError } = useLogger()
 
 export const nodeOps: RendererOptions<TresObject, TresObject> = {
   createElement(tag, _isSVG, _anchor, props) {
+    if (!props) props = {}
+
+    if (props.args === undefined) {
+      props.args = []
+    }
     if (tag === 'template') return null
     if (isHTMLTag(tag)) return null
+    let name = tag.replace('Tres', '')
     let instance
 
-    if (props === null) props = {}
-
-    if (props?.args) {
-      instance = new catalogue.value[tag.replace('Tres', '')](...props.args)
+    if (tag === 'primitive') {
+      if (props?.object === undefined) logError(`Tres primitives need a prop 'object'`)
+      const object = props.object as TresInstance
+      name = object.type
+      instance = Object.assign(object, { type: name, attach: props.attach, primitive: true })
     } else {
-      instance = new catalogue.value[tag.replace('Tres', '')]()
+      const target = catalogue.value[name]
+      if (!target) {
+        logError(`${name} is not defined on the THREE namespace. Use extend to add it the catalog`)
+      }
+      instance = Object.assign(new target(...props.args), { type: name, attach: props.attach, primitive: true })
     }
 
     if (instance.isCamera) {
@@ -52,28 +58,26 @@ 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 (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
-    }
-
     instance.events = {}
 
     return instance
   },
-  insert(child, parent, anchor) {
-    if (scene === null && parent.isScene) scene = parent
-    if (parent === null) parent = scene as TresObject
+  insert(child, parent) {
+    if (
+      (child?.__vnode.type === 'TresGroup' || child?.__vnode.type === 'TresObject3D') &&
+      parent === null &&
+      !child?.__vnode?.ctx?.asyncResolved
+    ) {
+      fallback = child
+      return
+    }
+
+    if (!parent) parent = fallback as TresObject
+
     //vue core
     /*  parent.insertBefore(child, anchor || null) */
-    if (parent?.isObject3D && child?.isObject3D) {
-      const index = anchor ? parent.children.indexOf(anchor) : 0
-      child.parent = parent
-      parent.children.splice(index, 0, child)
+    if (child?.isObject3D && parent?.isObject3D) {
+      parent.add(child)
       child.dispatchEvent({ type: 'added' })
     } else if (typeof child?.attach === 'string') {
       child.__previousAttach = child[parent?.attach]
@@ -84,7 +88,6 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
   },
   remove(node) {
     if (!node) return
-
     // remove is only called on the node being removed and not on child nodes.
 
     if (node.isObject3D) {
@@ -114,10 +117,6 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
       let finalKey = kebabToCamel(key)
       let target = root?.[finalKey]
 
-      if (!node.parent) {
-        node.parent = scene as TresObject
-      }
-
       if (root.type === 'BufferGeometry') {
         root.setAttribute(
           kebabToCamel(key),
@@ -157,7 +156,6 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
     return node?.parent || null
   },
   createText: () => noop('createText'),
-
   createComment: () => noop('createComment'),
 
   setText: () => noop('setText'),
@@ -169,5 +167,6 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
 
   setScopeId: () => noop('setScopeId'),
   cloneNode: () => noop('cloneNode'),
+
   insertStaticContent: () => noop('insertStaticContent'),
 }