Просмотр исходного кода

Merge branch 'main' into feature/474-vue-chrome-devtools-plugin

alvarosabu 1 год назад
Родитель
Сommit
849a80428e

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

@@ -85,6 +85,7 @@ export default defineConfig({
       },
       {
         text: 'Examples',
+        collapsed: true,
         items: [
           { text: 'Orbit Controls', link: '/examples/orbit-controls' },
           { text: 'Basic Animations', link: '/examples/basic-animations' },
@@ -96,6 +97,16 @@ export default defineConfig({
           { text: 'Shaders', link: '/examples/shaders' },
         ],
       },
+      {
+        text: 'Directives',
+        collapsed: true,
+        items: [
+          { text: 'v-log', link: '/directives/v-log' },
+          { text: 'v-light-helper', link: '/directives/v-light-helper' },
+          { text: 'v-always-look-at', link: '/directives/v-always-look-at' },
+          { text: 'v-distance-to', link: '/directives/v-distance-to' },
+        ],
+      },
       {
         text: 'Ecosystem',
         items: [

+ 61 - 0
docs/directives/v-always-look-at.md

@@ -0,0 +1,61 @@
+# v-always-look-at 👀
+
+With the new directive v-always-look-at provided by **TresJS**, you can add easily command an [Object3D](https://threejs.org/docs/index.html?q=object#api/en/core/Object3D) to always look at a specific position, this could be passed as a Vector3 or an Array.
+
+## Usage
+
+```vue{3,9}
+<script setup lang="ts">
+import { TresCanvas } from '@tresjs/core'
+import { Box, vAlwaysLookAt } from '@tresjs/cientos'
+</script>
+<template>
+    <TresCanvas >
+      <TresPerspectiveCamera :position="[0, 2, 5]" />
+      <Box
+        v-always-look-at="new Vector3(0, 0, 0)"
+      />
+  </TresCanvas>
+</template>
+```
+No matter where the Box move will always look-at the position [0,0,0]
+
+### Why not use the in built method look-at?
+
+You could ask, this is fine but I can use the `:look-at` method directly in the component, why should I need this?
+
+The answers is that with the method `:look-at` you will indicated to look at that position just once, when the instance is mounted, then if the object changes this will not get updated
+
+### You can look at other instance too!
+
+Another advantage is that you can look at an instance in movement, for example with the camera, like so:
+
+```vue{4,6,20,23}
+<script setup lang="ts">
+import { shallowRef } from 'vue'
+import { TresCanvas, useRenderLoop } from '@tresjs/core'
+import { Box, vAlwaysLookAt } from '@tresjs/cientos'
+
+const sphereRef = shallowRef()
+
+const { onLoop } = useRenderLoop()
+
+// here we update the position of the sphere and the camera will always follow the object
+onLoop(({ elapsed }) => {
+  if (sphereRef.value) {
+    sphereRef.value.value.position.y = Math.sin(elapsed) * 1.5
+  }
+})
+</script>
+<template>
+    <TresCanvas >
+      <TresPerspectiveCamera :position="[0, 2, 5]"
+        v-always-look-at="sphereRef"
+      />
+      <Sphere
+        ref="sphereRef"
+        :scale="0.5"
+      />
+  </TresCanvas>
+</template>
+```

+ 36 - 0
docs/directives/v-distance-to.md

@@ -0,0 +1,36 @@
+# v-distance-to
+
+Have you tried to calculate the distance between two Object3Ds?
+
+With the new directive `v-distance-to` it's easier than ever, you should only indicate the target object to perform the measure and the result will appear in your console.
+
+In addition, an arrow will be created to indicate which objects you're measuring.
+
+```vue{2,8,13}
+<script setup lang="ts">
+import { OrbitControls, Sphere, vLog } from '@tresjs/cientos'
+</script>
+<template>
+  <TresCanvas v-bind="gl">
+    <TresPerspectiveCamera :position="[0, 2, 5]" />
+    <Sphere
+      ref="sphere1Ref"
+      :position="[-2, slider, 0]"
+      :scale="0.5"
+    />
+    <Sphere
+      v-distance-to="sphere1Ref"
+      :position="[2, 0, 0]"
+      :scale="0.5"
+    />
+    <TresGridHelper :args="[10, 10]" />
+    <OrbitControls />
+  </TresCanvas>
+</template>
+```
+
+The use of `v-distance-to` is reactive, so it works perfectly with @tres/leches 🍰.
+
+::: warning
+`v-distance-to` will not measure an object in movement within the renderLoop.
+:::

+ 34 - 0
docs/directives/v-light-helper.md

@@ -0,0 +1,34 @@
+# v-light-helper 🔆
+
+With the new directive v-light-helper provided by **TresJS**, you can add fast the respective helper to your lights with just one line of code 😍.
+
+The following lights are supported:
+- DirectionalLight
+- PointLight
+- SpotLight
+- HemisphereLight
+
+## Usage
+
+```vue{2,8,11,14,17}
+<script setup lang="ts">
+import { OrbitControls, Sphere, vLightHelper } from '@tresjs/cientos'
+</script>
+<template>
+  <TresCanvas >
+    <TresPerspectiveCamera :position="[0, 2, 5]" />
+    <TresDirectionalLight
+      v-light-helper
+    />
+    <TresPointLight
+      v-light-helper
+    />
+    <TresSpotLight
+      v-light-helper
+    />
+    <TresHemisphereLight
+      v-light-helper
+    />
+  </TresCanvas>
+</template>
+```

+ 53 - 0
docs/directives/v-log.md

@@ -0,0 +1,53 @@
+# v-log
+
+### Problem
+
+When you have to log your instance you have to use the template reference and then log them:
+
+```vue
+<script setup lang="ts">
+import { shallowRef, watch } from 'vue'
+
+const sphereRef = shallowRef()
+
+watch(sphereRef, (value) => {
+  console.log(value) // Really for a log?!!! 😫
+})
+</script>
+
+<template>
+  <TresCanvas>
+    <TresPerspectiveCamera :position="[0, 2, 5]" />
+    <Sphere
+      ref="sphereRef"
+      :scale="0.5"
+    />
+    <OrbitControls />
+  </TresCanvas>
+</template>
+```
+
+And is A LOT of code just for a simple log right?
+
+## Usage
+
+With the new directive v-log provided by **TresJS**, you can do this by just adding `v-log` to the instance.
+
+```vue{2,10,12}
+<script setup lang="ts">
+import { OrbitControls, Sphere, vLog } from '@tresjs/cientos'
+</script>
+<template>
+    <TresCanvas >
+    <TresPerspectiveCamera :position="[0, 2, 5]" />
+    <Sphere
+      ref="sphereRef"
+      :scale="0.5"
+      v-log:material  <!-- will print just the material 🎉 -->
+    />
+    <OrbitControls v-log />
+  </TresCanvas>
+</template>
+```
+
+Note that you can pass a modifier with the name of a property, for example `v-log:material`, and will log directly the `material` property 😍

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

@@ -37,7 +37,6 @@ watchEffect(() => {
   <TresCanvas
     v-bind="gl"
     ref="canvas"
-    window-size
     class="awiwi"
     :style="{ background: '#008080' }"
   >

+ 55 - 0
playground/src/pages/lights.vue

@@ -0,0 +1,55 @@
+<script setup lang="ts">
+import type { TresObject } from '@tresjs/core'
+import { TresCanvas, vLightHelper, vAlwaysLookAt, vDistanceTo, vLog } from '@tresjs/core'
+import { BasicShadowMap, SRGBColorSpace, NoToneMapping } from 'three'
+
+import { OrbitControls } from '@tresjs/cientos'
+
+const gl = {
+  clearColor: '#82DBC5',
+  shadows: true,
+  alpha: false,
+  shadowMapType: BasicShadowMap,
+  outputColorSpace: SRGBColorSpace,
+  toneMapping: NoToneMapping,
+}
+
+const planeRef: Ref<TresObject | null> = ref(null)
+</script>
+
+<template>
+  <TresCanvas
+   
+    v-bind="gl"
+  >
+    <TresPerspectiveCamera :position="[3, 3, 3]" />
+    <OrbitControls />
+   
+    <TresDirectionalLight
+      v-light-helper
+      v-always-look-at="[8, 16, 0]"
+      :position="[0, 8, 4]"
+      :intensity="0.7"
+      color="yellow"
+      cast-shadow
+    />
+    <TresMesh
+      ref="planeRef"
+      v-log:material
+      :rotation="[-Math.PI / 2, 0, 0]"
+      receive-shadow
+    >
+      <TresPlaneGeometry :args="[10, 10, 10, 10]" />
+      <TresMeshToonMaterial />
+    </TresMesh>
+    <TresMesh
+      v-distance-to="planeRef"
+      :position="[2, 4, 0]"
+      cast-shadow
+    >
+      <TresSphereGeometry :args="[1, 32, 32]" />
+      <TresMeshToonMaterial color="yellow" />
+    </TresMesh>
+    <TresAmbientLight :intensity="1" />
+  </TresCanvas>
+</template>

+ 6 - 0
playground/src/router.ts

@@ -11,6 +11,11 @@ const routes = [
     name: 'Basic',
     component: () => import('./pages/TheBasic.vue'),
   },
+  {
+    path: '/lights',
+    name: 'lights',
+    component: () => import('./pages/lights.vue'),
+  },
   {
     path: '/groups',
     name: 'Groups',
@@ -81,6 +86,7 @@ const routes = [
     name: 'empty',
     component: () => import('./pages/empty.vue'),
   },
+  
 ]
 export const router = createRouter({
   history: createWebHistory(),

+ 6 - 0
src/directives/index.ts

@@ -0,0 +1,6 @@
+import { vLog } from './vLog'
+import { vLightHelper } from './vLightHelper'
+import { vAlwaysLookAt } from './vAlwaysLookAt'
+import { vDistanceTo } from './vDistanceTo'
+
+export { vLog, vLightHelper, vAlwaysLookAt, vDistanceTo }

+ 21 - 0
src/directives/vAlwaysLookAt.ts

@@ -0,0 +1,21 @@
+import type { Object3D } from 'three'
+import type { Ref } from 'vue'
+import { extractBindingPosition } from '../utils'
+import type { TresVector3 } from '../types'
+import { useLogger, useRenderLoop } from '../composables'
+
+const { logWarning } = useLogger()
+
+export const vAlwaysLookAt = {
+  updated: (el: Object3D, binding: Ref<TresVector3>) => {
+    const observer = extractBindingPosition(binding)
+    if (!observer) {
+      logWarning(`v-always-look-at: problem with binding value: ${binding.value}`)
+      return
+    }
+    const { onLoop } = useRenderLoop()
+    onLoop(() => {
+      el.lookAt(observer)
+    })
+  },
+}

+ 37 - 0
src/directives/vDistanceTo.ts

@@ -0,0 +1,37 @@
+import { ArrowHelper } from 'three'
+import type { Ref } from 'vue'
+import { extractBindingPosition } from '../utils'
+import type { TresObject } from '../types'
+import { useLogger } from '../composables'
+
+const { logWarning } = useLogger()
+
+export const vDistanceTo = {
+  updated: (el: TresObject, binding: Ref<TresObject>) => {
+    const observer = extractBindingPosition(binding)
+    if (!observer) {
+      logWarning(`v-distance-to: problem with binding value: ${binding.value}`)
+      return
+    }
+    if (arrowHelper) {
+      arrowHelper.dispose()
+      el.parent.remove(arrowHelper)
+    }
+    const dir = observer.clone().sub(el.position)
+    dir.normalize()
+    arrowHelper = new ArrowHelper( dir, el.position, el.position.distanceTo(observer), 0xffff00 )
+    el.parent.add( arrowHelper )
+    // eslint-disable-next-line no-console
+    console.table([
+      ['Distance:', el.position.distanceTo(observer)],
+      [`origin: ${el.name || el.type}`, `x:${el.position.x}, y:${el.position.y}, z:${el.position?.z}`],
+      [`Destiny: ${el.name || el.type}`, `x:${observer.x}, y:${observer.y}, z:${observer?.z}`],
+    ],
+    )
+  },
+  unmounted: (el: TresObject) => {
+    arrowHelper?.dispose()
+    el.parent.remove(arrowHelper)
+  },
+}
+let arrowHelper: ArrowHelper | null = null

+ 62 - 0
src/directives/vLightHelper.ts

@@ -0,0 +1,62 @@
+
+import type {
+  Light,
+} from 'three'
+import { 
+  DirectionalLightHelper,
+  PointLightHelper,
+  SpotLightHelper,
+  HemisphereLightHelper,
+} from 'three'
+import { RectAreaLightHelper } from 'three-stdlib'
+import { useLogger } from '../composables'
+import type { TresObject } from '../types'
+
+const { logWarning } = useLogger()
+
+type LightHelper = typeof DirectionalLightHelper 
+| typeof PointLightHelper 
+| typeof SpotLightHelper 
+| typeof HemisphereLightHelper 
+| typeof RectAreaLightHelper
+
+let currentHelper: LightHelper
+let currentInstance: TresObject
+
+const helpers: Record<Light['type'], LightHelper> = {
+  DirectionalLight: DirectionalLightHelper,
+  PointLight: PointLightHelper,
+  SpotLight: SpotLightHelper,
+  HemisphereLight: HemisphereLightHelper,
+  RectAreaLight: RectAreaLightHelper,
+}
+
+export const vLightHelper = {
+  mounted: (el: TresObject) => {
+    if (!el.isLight) {
+      logWarning(`${el.type} is not a light`)
+      return
+    }
+    currentHelper = helpers[el.type]
+    el.parent.add(new currentHelper(el as never, 1, el.color.getHex()))
+  },
+  updated: (el: TresObject) => {
+    currentInstance = el.parent.children.find((child: TresObject) => child instanceof currentHelper)
+    if (currentInstance instanceof RectAreaLightHelper) return
+    currentInstance.update()
+
+  },
+  unmounted: (el: TresObject) => {
+    if (!el.isLight) {
+      logWarning(`${el.type} is not a light`)
+      return
+    }
+    currentInstance = el.parent.children.find((child: TresObject) => child instanceof currentHelper)
+
+    if (currentInstance && currentInstance.dispose) {
+      currentInstance.dispose()
+    }
+    el.parent.remove(currentInstance)
+  },
+}
+

+ 13 - 0
src/directives/vLog.ts

@@ -0,0 +1,13 @@
+import type { TresObject } from '../types'
+
+export const vLog = {
+  mounted: (el: TresObject, binding: { arg: string }) => {
+    if (binding.arg) {
+    // eslint-disable-next-line no-console
+      console.log(`v-log:${binding.arg}`, el[binding.arg])
+      return
+    }
+    // eslint-disable-next-line no-console
+    console.log('v-log', el)
+  },
+}

+ 1 - 0
src/index.ts

@@ -7,6 +7,7 @@ export * from './composables'
 export * from './core/catalogue'
 export * from './components'
 export * from './types'
+export * from './directives'
 
 export interface TresOptions {
   extends?: Record<string, unknown>

+ 11 - 2
src/utils/index.ts

@@ -1,5 +1,5 @@
-import THREE, { MeshBasicMaterial, DoubleSide } from 'three'
-import type { Mesh, type Scene, type Object3D } from 'three'
+import { MeshBasicMaterial, DoubleSide, Vector3 } from 'three'
+import type { Mesh, Scene, Object3D } from 'three'
 import { HightlightMesh } from '../devtools/highlight'
 
 export function toSetMethodName(key: string) {
@@ -226,4 +226,13 @@ export function createHighlightMesh(object: Object3D): Mesh {
   const highlightMesh = new HightlightMesh(object.geometry.clone(), highlightMaterial)
 
   return highlightMesh
+}
+
+export function extractBindingPosition(binding: any): Vector3 {
+  let observer = binding.value
+  if (binding.value && binding.value?.isMesh) {
+    observer = binding.value.position
+  }
+  if (Array.isArray(binding.value)) observer = new Vector3(...observer)
+  return observer
 }