소스 검색

feat(app): Add a new directive, v-rotate

Jaime Torrealba 1 년 전
부모
커밋
ccf53135a8

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

@@ -105,6 +105,7 @@ export default defineConfig({
           { 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: 'v-rotate', link: '/directives/v-rotate' },
         ],
       },
       {

+ 4 - 4
docs/directives/v-always-look-at.md

@@ -6,8 +6,8 @@ With the new directive v-always-look-at provided by **TresJS**, you can add easi
 
 ```vue{3,9}
 <script setup lang="ts">
-import { TresCanvas } from '@tresjs/core'
-import { Box, vAlwaysLookAt } from '@tresjs/cientos'
+import { TresCanvas, vAlwaysLookAt } from '@tresjs/core'
+import { Box } from '@tresjs/cientos'
 </script>
 <template>
     <TresCanvas >
@@ -33,8 +33,8 @@ Another advantage is that you can look at an instance in movement, for example w
 ```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'
+import { TresCanvas, useRenderLoop, vAlwaysLookAt } from '@tresjs/core'
+import { Box } from '@tresjs/cientos'
 
 const sphereRef = shallowRef()
 

+ 2 - 1
docs/directives/v-distance-to.md

@@ -8,7 +8,8 @@ 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'
+import { vDistanceTo } from '@tresjs/core'
+import { OrbitControls, Sphere } from '@tresjs/cientos'
 </script>
 <template>
   <TresCanvas v-bind="gl">

+ 2 - 1
docs/directives/v-light-helper.md

@@ -12,7 +12,8 @@ The following lights are supported:
 
 ```vue{2,8,11,14,17}
 <script setup lang="ts">
-import { OrbitControls, Sphere, vLightHelper } from '@tresjs/cientos'
+import { vLightHelper } from '@tresjs/core'
+import { OrbitControls, Sphere,  } from '@tresjs/cientos'
 </script>
 <template>
   <TresCanvas >

+ 2 - 1
docs/directives/v-log.md

@@ -35,7 +35,8 @@ With the new directive v-log provided by **TresJS**, you can do this by just add
 
 ```vue{2,10,12}
 <script setup lang="ts">
-import { OrbitControls, Sphere, vLog } from '@tresjs/cientos'
+import { vLog } from '@tresjs/core'
+import { OrbitControls, Sphere } from '@tresjs/cientos'
 </script>
 <template>
     <TresCanvas >

+ 82 - 0
docs/directives/v-rotate.md

@@ -0,0 +1,82 @@
+# v-rotate
+
+## Problem
+
+When you want to simply add rotation to your mesh, you have to use the template reference, [useRenderLoop](/api/composables#userenderloop) and then assign the axis and the speed, but before check if you mesh is already available:
+
+```vue
+<script setup lang="ts">
+import { shallowRef, watch } from 'vue'
+import { useRenderLoop } from '@tresjs/core'
+
+const boxRef = shallowRef()
+
+const { onLoop } = useRenderLoop()
+
+onLoop(({ elapsed }) => {
+  if (boxRef.value) {
+    boxRef.value.rotation.x = elapsed
+  }
+})
+</script>
+
+<template>
+  <TresCanvas>
+    <TresPerspectiveCamera :position="[0, 2, 5]" />
+    <TresMesh
+      ref="boxRef"
+      :scale="0.5"
+    >
+      <TresBoxGeometry />
+      <TresMesh>
+        <OrbitControls />
+      </TresMesh>
+    </TresMesh>
+  </TresCanvas>
+</template>
+```
+
+And is A LOT of code just for a simple rotation right? Normally we need something fast to see if something is working
+
+## Usage
+
+With the new directive v-rotate provided by **TresJS**, you can do this by just adding `v-rotate` to the instance.
+
+```vue{2,8}
+<script setup lang="ts">
+import { vRotate } from '@tresjs/core'
+</script>
+<template>
+    <TresCanvas >
+    <TresPerspectiveCamera :position="[0, 2, 5]" />
+    <TresMesh
+      v-rotate // 😍
+    >
+      <TresBoxGeometry />
+    </TresMesh>
+  </TresCanvas>
+</template>
+```
+By default `v-rotate` uses [Quaternions](https://threejs.org/docs/index.html?q=quater#api/en/math/Quaternion) so you don't have to worry by [Gimbal Lock](https://en.wikipedia.org/wiki/Gimbal_lock), or check if you mesh is available in the first frames.
+
+## Modifiers
+
+You can control the axis and the rotation speed by adding modifiers
+
+```vue{2,8}
+<script setup lang="ts">
+import { vRotate } from '@tresjs/core'
+</script>
+<template>
+    <TresCanvas >
+    <TresPerspectiveCamera :position="[0, 2, 5]" />
+    <TresMesh
+      v-rotate:x.y="0.1" // the axis will be x and y with a speed of 0.1
+    >
+      <TresBoxGeometry />
+    </TresMesh>
+  </TresCanvas>
+</template>
+```
+
+_Note default speed is 0.01_

+ 14 - 3
playground/src/pages/lights.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts">
 import type { TresObject } from '@tresjs/core'
-import { TresCanvas, vLightHelper, vAlwaysLookAt, vDistanceTo, vLog } from '@tresjs/core'
+import { TresCanvas, vLightHelper, vAlwaysLookAt, vDistanceTo, vLog, vRotate } from '@tresjs/core'
 import { BasicShadowMap, SRGBColorSpace, NoToneMapping } from 'three'
 
 import { OrbitControls } from '@tresjs/cientos'
@@ -22,7 +22,11 @@ const planeRef: Ref<TresObject | null> = ref(null)
    
     v-bind="gl"
   >
-    <TresPerspectiveCamera :position="[3, 3, 3]" />
+    <TresPerspectiveCamera
+      v-distance-to="planeRef"
+      v-rotate
+      :position="[3, 3, 3]"
+    />
     <OrbitControls />
    
     <TresDirectionalLight
@@ -43,7 +47,14 @@ const planeRef: Ref<TresObject | null> = ref(null)
       <TresMeshToonMaterial />
     </TresMesh>
     <TresMesh
-      v-distance-to="planeRef"
+      v-rotate="0.01"
+      :position="[-2, 2, 0]"
+    >
+      <TresBoxGeometry :args="[1, 1, 1]" />
+      <TresMeshToonMaterial color="red" />
+    </TresMesh>
+    <TresMesh
+      
       :position="[2, 4, 0]"
       cast-shadow
     >

+ 2 - 1
src/directives/index.ts

@@ -2,5 +2,6 @@ import { vLog } from './vLog'
 import { vLightHelper } from './vLightHelper'
 import { vAlwaysLookAt } from './vAlwaysLookAt'
 import { vDistanceTo } from './vDistanceTo'
+import { vRotate } from './vRotate'
 
-export { vLog, vLightHelper, vAlwaysLookAt, vDistanceTo }
+export { vLog, vLightHelper, vAlwaysLookAt, vDistanceTo, vRotate }

+ 61 - 0
src/directives/vRotate.ts

@@ -0,0 +1,61 @@
+import { shallowRef } from 'vue'
+import { Quaternion, Vector3 } from 'three'
+import type { TresObject } from '../types'
+import { useLogger, useRenderLoop } from '../composables'
+
+const { logWarning } = useLogger()
+
+export const vRotate = {
+  mounted: (
+    el: TresObject,
+    binding: {
+      arg: 'x' | 'y' | 'z'
+      value: number
+      modifiers: Partial<{ x: boolean; y: boolean; z: boolean }>
+    },
+  ) => {
+    if (el.isCamera) {
+      logWarning(`Rotate the ${el.type} is not a good idea`)
+      return
+    }
+    const speed = binding.value ?? 0.01
+    const defaultQuaternion = new Quaternion()
+    const quaternionX = shallowRef(
+      binding.modifiers.x || binding.arg === 'x'
+        ? new Quaternion().setFromAxisAngle(new Vector3(1, 0, 0), speed)
+        : defaultQuaternion,
+    )
+    const quaternionY = shallowRef(
+      binding.modifiers.y || binding.arg === 'y'
+        ? new Quaternion().setFromAxisAngle(new Vector3(0, 1, 0), speed)
+        : defaultQuaternion,
+    )
+    const quaternionZ = shallowRef(
+      binding.modifiers.z || binding.arg === 'z'
+        ? new Quaternion().setFromAxisAngle(new Vector3(0, 0, 1), speed)
+        : defaultQuaternion,
+    )
+    if (
+      quaternionX.value === defaultQuaternion
+      && quaternionY.value === defaultQuaternion
+      && quaternionZ.value === defaultQuaternion
+    ) {
+      quaternionZ.value = new Quaternion().setFromAxisAngle(
+        new Vector3(0, 0, 1),
+        speed,
+      )
+      quaternionY.value = new Quaternion().setFromAxisAngle(
+        new Vector3(0, 1, 0),
+        speed,
+      )
+    }
+
+    const { onLoop } = useRenderLoop()
+
+    onLoop(() => {
+      el.applyQuaternion(quaternionX.value)
+      el.applyQuaternion(quaternionY.value)
+      el.applyQuaternion(quaternionZ.value)
+    })
+  },
+}