Skip to content

Commit

Permalink
feat(app): Add a new directive, v-rotate
Browse files Browse the repository at this point in the history
  • Loading branch information
JaimeTorrealba committed Jan 31, 2024
1 parent 0be3969 commit ccf5313
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 11 deletions.
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
],
},
{
Expand Down
8 changes: 4 additions & 4 deletions docs/directives/v-always-look-at.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 >
Expand All @@ -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()
Expand Down
3 changes: 2 additions & 1 deletion docs/directives/v-distance-to.md
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
3 changes: 2 additions & 1 deletion docs/directives/v-light-helper.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 >
Expand Down
3 changes: 2 additions & 1 deletion docs/directives/v-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 >
Expand Down
82 changes: 82 additions & 0 deletions docs/directives/v-rotate.md
Original file line number Diff line number Diff line change
@@ -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_
17 changes: 14 additions & 3 deletions playground/src/pages/lights.vue
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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
Expand All @@ -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
>
Expand Down
3 changes: 2 additions & 1 deletion src/directives/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 61 additions & 0 deletions src/directives/vRotate.ts
Original file line number Diff line number Diff line change
@@ -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)
})
},
}

0 comments on commit ccf5313

Please sign in to comment.