Browse Source

feat(core): extend functionality

Alvaro 2 years ago
parent
commit
c1da08279e

+ 11 - 0
docs/.vitepress/config.ts

@@ -16,6 +16,17 @@ export default defineConfig({
           { text: 'Your first Scene', link: '/guide/your-first-scene' },
         ],
       },
+      /*    {
+        text: 'API',
+      },
+      {
+        text: 'Examples',
+      }, */
+      {
+        text: 'Advanced',
+
+        items: [{ text: 'Extending', link: '/advanced/extending' }],
+      },
     ],
     socialLinks: [
       { icon: 'github', link: 'https://github.com/alvarosabu/tres' },

+ 29 - 0
docs/.vitepress/theme/components/ExtendExample.vue

@@ -0,0 +1,29 @@
+<script setup lang="ts">
+import { useTres } from '@tresjs/core'
+
+const styles = {
+  width: '100%',
+  height: '550px',
+  border: '1px solid #e2e2e2',
+  borderRadius: '8px',
+  overflow: 'hidden',
+}
+
+const { state } = useTres()
+</script>
+<template>
+  <ClientOnly>
+    <TresCanvas shadows clear-color="#fff" :style="styles">
+      <TresPerspectiveCamera :position="[0, 2, 4]" />
+      <TresScene>
+        <TresOrbitControls v-if="state.renderer" :args="[state.camera, state.renderer?.domElement]" />
+
+        <TresDirectionalLight :position="[0, 2, 4]" :intensity="2" cast-shadow />
+        <TresMesh :rotation="[-Math.PI / 4, -Math.PI / 4, Math.PI / 4]">
+          <TresTorusGeometry :args="[1, 0.5, 16, 32]" />
+          <TresMeshToonMaterial color="#FBB03B" />
+        </TresMesh>
+      </TresScene>
+    </TresCanvas>
+  </ClientOnly>
+</template>

+ 1 - 1
docs/.vitepress/theme/components/FirstScene.vue

@@ -3,7 +3,7 @@ import { OrbitControls } from '@tresjs/cientos'
 
 const styles = {
   width: '100%',
-  height: '550px',
+  height: '500px',
   border: '1px solid #e2e2e2',
   borderRadius: '8px',
   overflow: 'hidden',

+ 8 - 2
docs/.vitepress/theme/index.ts

@@ -1,15 +1,21 @@
 import Tres from '@tresjs/core'
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
 // .vitepress/theme/index.ts
 import DefaultTheme from 'vitepress/theme'
 import './config.css'
 import FirstScene from './components/FirstScene.vue'
 import FirstSceneLightToon from './components/FirstSceneLightToon.vue'
-
+import ExtendExample from './components/ExtendExample.vue'
 export default {
   ...DefaultTheme,
   enhanceApp(ctx) {
     ctx.app.component('FirstScene', FirstScene)
     ctx.app.component('FirstSceneLightToon', FirstSceneLightToon)
-    ctx.app.use(Tres)
+    ctx.app.component('ExtendExample', ExtendExample)
+    ctx.app.use(Tres, {
+      extends: {
+        OrbitControls,
+      },
+    })
   },
 }

+ 30 - 0
docs/advanced/extending.md

@@ -0,0 +1,30 @@
+# Extend 🔌
+
+Tres offers bare bones functionality, but it's easy to add third-party elements and extend them into its internal catalogue.
+
+## Adding a third-party element
+
+Most of 3D experience uses `OrbitControls` which is not part of the core library. To add it, you need to import it and add it to the `extends` option when installing the plugin:
+
+```js
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
+
+app.use(plugin, {
+  extends: {
+    OrbitControls,
+  },
+})
+```
+
+This will automatically add a `<TresOrbitControls>` to the catalogue, so you can use it in your templates:
+
+```vue
+<template>
+  <TresCanvas shadows alpha>
+    <TresPerspectiveCamera :position="[5, 5, 5]" />
+    <TresScene>
+      <TresOrbitControls v-if="state.renderer" :args="[state.camera, state.renderer?.domElement]" />
+    </TresScene>
+  </TresCanvas>
+</template>
+```

+ 4 - 0
packages/tres/histoire.setup.ts

@@ -1,9 +1,13 @@
 import { defineSetupVue3 } from '@histoire/plugin-vue'
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
 
 import Tres from './src'
 
 export const setupVue3 = defineSetupVue3(({ app }) => {
   app.use(Tres, {
     prefix: 'Tres',
+    extends: {
+      OrbitControls,
+    },
   })
 })

+ 9 - 8
packages/tres/src/App.vue

@@ -1,22 +1,23 @@
 <script setup lang="ts">
+import { unref } from 'vue'
 import { Color } from 'three'
-import { OrbitControls, useTweakPane } from '@tresjs/cientos'
-/* import TestSphere from '/@/components/TestSphere.vue' */
+import { useTweakPane } from '@tresjs/cientos'
+import { useTres } from './core'
+import TestSphere from '/@/components/TestSphere.vue'
 
-/* import { OrbitControls, useTweakPane } from '@tresjs/cientos' */
-/* import { OrbitControls, useTweakPane } from '../../cientos/src/'
- */
 const colorTeal = new Color('teal')
 useTweakPane()
 
-const meshPosition = [2, 1, 0]
+const { state } = useTres()
+
+const meshPosition = [0, 1, 0]
 </script>
 <template>
   <Suspense>
     <TresCanvas shadows alpha power-preference="high-performance" preserve-drawing-buffer physically-correct-lights>
-      <OrbitControls />
-      <TresPerspectiveCamera :position="[5, 5, 5]" :fov="45" :aspect="1" :near="0.1" :far="1000" />
+      <TresPerspectiveCamera :position="[0, 5, 5]" :fov="45" :near="0.1" :far="1000" />
       <TresScene>
+        <TresOrbitControls v-if="state.renderer" :args="[unref(state), state.renderer?.domElement]" />
         <TresMesh :position="meshPosition" :scale="1">
           <TresSphereGeometry />
           <TresMeshToonMaterial :color="colorTeal" />

+ 3 - 0
packages/tres/src/core/useCamera/index.ts

@@ -1,3 +1,4 @@
+import { useTres } from '/@/core/'
 import { PerspectiveCamera, OrthographicCamera } from 'three'
 
 import { useWindowSize } from '@vueuse/core'
@@ -45,6 +46,7 @@ let camera: Camera
 
 export function useCamera(): UseCameraReturn {
   const { width, height } = useWindowSize()
+  const { setState } = useTres()
 
   function createCamera(
     cameraType = CameraType.Perspective,
@@ -90,6 +92,7 @@ export function useCamera(): UseCameraReturn {
     const currentCamera = inject<Ref<Camera>>('camera')
     if (camera && currentCamera) {
       currentCamera.value = camera
+      setState('camera', currentCamera.value)
     }
     state.cameras.push(camera)
     if (camera instanceof PerspectiveCamera) {

+ 3 - 1
packages/tres/src/core/useInstanceCreator/index.ts

@@ -59,7 +59,9 @@ export function useInstanceCreator(prefix: string) {
               if (name.includes('Camera')) {
                 pushCamera(instance as unknown as PerspectiveCamera)
               }
-              scene?.value.add(instance)
+              if (instance.isObject3D) {
+                scene?.value.add(instance)
+              }
 
               logMessage('Instance added', scene)
 

+ 4 - 1
packages/tres/src/core/useRenderer/index.ts

@@ -17,7 +17,7 @@ import {
   PCFShadowMap,
 } from 'three'
 import type { TextureEncoding, ToneMapping } from 'three'
-import { useRenderLoop } from '/@/core/'
+import { useRenderLoop, useTres } from '/@/core/'
 import { normalizeColor } from '/@/utils/normalize'
 
 export interface UseRendererOptions extends WebGLRendererParameters {
@@ -179,6 +179,9 @@ export function useRenderer(canvas: MaybeElementRef, container: MaybeElementRef,
       premultipliedAlpha,
     })
 
+    const { setState } = useTres()
+    setState('renderer', renderer.value)
+
     updateRendererOptions()
     updateRendererSize()
     resume()

+ 4 - 3
packages/tres/src/examples/Basic.story.vue

@@ -1,16 +1,17 @@
 <script setup lang="ts">
 import { Color } from 'three'
-import { OrbitControls } from '@tresjs/cientos'
+import { useTres } from '/@/core'
 
 const floorTeal = new Color('gray')
+const { state } = useTres()
 </script>
 <template>
   <Story title="Basic">
     <Variant title="playground">
-      <TresCanvas clear-color="#82DBC5" shadows alpha>
+      <TresCanvas clear-color="#82DBC5" shadows alpha preserve-drawing-buffer>
         <TresPerspectiveCamera :position="[11, 11, 11]" />
-        <OrbitControls />
         <TresScene>
+          <TresOrbitControls v-if="state.renderer" :args="[state.camera, state.renderer?.domElement]" />
           <TresMesh :position="[-2, 6, 0]" :rotation="[0, Math.PI, 0]" cast-shadow>
             <TresConeGeometry :args="[1, 1.5, 3]" />
             <TresMeshToonMaterial color="#82DBC5" />

+ 2 - 1
packages/tres/src/index.ts

@@ -7,6 +7,7 @@ export * from './keys'
 
 export interface TresOptions {
   prefix?: string
+  extends?: Record<string, unknown>
 }
 export interface TresPlugin {
   [key: string]: any
@@ -20,7 +21,7 @@ const plugin: TresPlugin = {
     app.component(`${prefix}Scene`, Scene)
     const { catalogue } = useCatalogue()
     const { createComponentInstances } = useInstanceCreator(prefix)
-    const components = createComponentInstances(catalogue)
+    const components = createComponentInstances(options?.extends ? { ...catalogue, ...options.extends } : catalogue)
     components.forEach(([key, cmp]) => {
       app.component(key as string, cmp as Component)
     })

+ 6 - 1
packages/tres/src/main.ts

@@ -1,9 +1,14 @@
 import { createApp } from 'vue'
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
 import App from './App.vue'
 import plugin from '.'
 import './style.css'
 
 export const app = createApp(App)
 
-app.use(plugin)
+app.use(plugin, {
+  extends: {
+    OrbitControls,
+  },
+})
 app.mount('#app')