浏览代码

feat: add directives to core, add color support to light helper

alvarosabu 1 年之前
父节点
当前提交
df28b8cff3

+ 3 - 5
playground/src/components/TheExperience.vue

@@ -27,15 +27,13 @@ watchEffect(() => {
 
 <template>
   <div>
-    <button @click="wireframe = !wireframe">
-      Click
-    </button>
+    <RouterLink to="/multiple">
+      Multiple
+    </RouterLink>
   </div>
-  <pre>{{ wireframe }}</pre>
   <TresCanvas
     v-bind="gl"
     ref="canvas"
-    window-size
     class="awiwi"
     :style="{ background: '#008080' }"
   >

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

@@ -0,0 +1,45 @@
+<script setup lang="ts">
+import { TresCanvas, vLightHelper } 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,
+}
+</script>
+
+<template>
+  <TresCanvas v-bind="gl">
+    <TresPerspectiveCamera :position="[3, 3, 3]" />
+    <OrbitControls />
+
+    <TresMesh
+      :position="[0, 4, 0]"
+      cast-shadow
+    >
+      <TresSphereGeometry :args="[1, 32, 32]" />
+      <TresMeshToonMaterial color="yellow" />
+    </TresMesh>
+    <TresDirectionalLight
+      v-light-helper
+      :position="[0, 8, 4]"
+      :intensity="0.7"
+      color="yellow"
+      cast-shadow
+    />
+    <TresMesh
+      :rotation="[-Math.PI / 2, 0, 0]"
+      receive-shadow
+    >
+      <TresPlaneGeometry :args="[10, 10, 10, 10]" />
+      <TresMeshToonMaterial />
+    </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 }

+ 19 - 0
src/directives/vAlwaysLookAt.ts

@@ -0,0 +1,19 @@
+import { useRenderLoop, useLogger } from '@tresjs/core'
+import type { Object3D } from 'three'
+import { extractBindingPosition } from '../utils'
+
+const { logWarning } = useLogger()
+
+export const vAlwaysLookAt = {
+  updated: (el: Object3D, binding: any) => {
+    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)
+    })
+  },
+}

+ 35 - 0
src/directives/vDistanceTo.ts

@@ -0,0 +1,35 @@
+import { useLogger } from '@tresjs/core'
+import { ArrowHelper } from 'three'
+import { extractBindingPosition } from '../utils'
+
+const { logWarning } = useLogger()
+
+export const vDistanceTo = {
+  updated: (el: any, binding: any) => {
+    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) / 1.5, 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: any) => {
+    arrowHelper?.dispose()
+    el.parent.remove(arrowHelper)
+  },
+}
+let arrowHelper: ArrowHelper | null = null

+ 61 - 0
src/directives/vLightHelper.ts

@@ -0,0 +1,61 @@
+import { useLogger } from '@tresjs/core'
+import type {
+  Light,
+} from 'three'
+import { 
+  DirectionalLightHelper,
+  PointLightHelper,
+  SpotLightHelper,
+  HemisphereLightHelper,
+} from 'three'
+import { RectAreaLightHelper } from 'three-stdlib'
+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)
+  },
+}
+

+ 11 - 0
src/directives/vLog.ts

@@ -0,0 +1,11 @@
+export const vLog = {
+  mounted: (el: any, binding: any) => {
+    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 - 0
src/utils/index.ts

@@ -1,3 +1,5 @@
+import { Vector3 } from 'three'
+
 export function toSetMethodName(key: string) {
   return `set${key[0].toUpperCase()}${key.slice(1)}`
 }
@@ -127,3 +129,12 @@ export function deepArrayEqual(arr1: any[], arr2: any[]): boolean {
  * TypeSafe version of Array.isArray
  */
 export const isArray = Array.isArray as (a: any) => a is any[] | readonly any[]
+
+export function extractBindingPosition(binding: any): Vector3 {
+  let observer = binding.value
+  if (binding.value && binding.value?.value?.isMesh) {
+    observer = binding.value.value.position
+  }
+  if (Array.isArray(binding.value)) observer = new Vector3(...observer)
+  return observer
+}