Browse Source

feat: visually highlight element selected

alvarosabu 1 year ago
parent
commit
86476c5a29

+ 1 - 0
plugins/vite-plugin-tres/client/.nuxt/imports.d.ts

@@ -26,6 +26,7 @@ export { computedAsync, asyncComputed, computedEager, eagerComputed, computedInj
 export { createGenericProjection, createProjection, logicAnd, logicNot, logicOr, useAbs, useAverage, useCeil, useClamp, useFloor, useMath, useMax, useMin, usePrecision, useProjection, useRound, useSum, useTrunc } from '@vueuse/math';
 export { injectHead, useHead, useSeoMeta, useHeadSafe, useServerHead, useServerSeoMeta, useServerHeadSafe } from '@unhead/vue';
 export { useDevtoolsHook } from '../composables/useDevtoolsHook';
+export { HightlightMesh } from '../utils/highlightedMesh';
 export { calculateMemoryUsage, bytesToKB, bytesToMB, bytesToGB } from '../utils/perf';
 export { ShortcutConfig, ShortcutsConfig, ShortcutsOptions } from '../../../../node_modules/.pnpm/@nuxt+ui@2.11.1_nuxt@3.9.0_rollup@3.29.4_vite@5.0.10_vue@3.4.3/node_modules/@nuxt/ui/dist/runtime/composables/defineShortcuts.d';
 export { defineShortcuts } from '../../../../node_modules/.pnpm/@nuxt+ui@2.11.1_nuxt@3.9.0_rollup@3.29.4_vite@5.0.10_vue@3.4.3/node_modules/@nuxt/ui/dist/runtime/composables/defineShortcuts';

+ 3 - 0
plugins/vite-plugin-tres/client/.nuxt/types/imports.d.ts

@@ -1,6 +1,7 @@
 // Generated by auto imports
 export {}
 declare global {
+  const HightlightMesh: typeof import('../../utils/highlightedMesh')['HightlightMesh']
   const _useShortcuts: typeof import('../../../../../node_modules/.pnpm/@nuxt+ui@2.11.1_nuxt@3.9.0_rollup@3.29.4_vite@5.0.10_vue@3.4.3/node_modules/@nuxt/ui/dist/runtime/composables/useShortcuts')['_useShortcuts']
   const abortNavigation: typeof import('../../../../../node_modules/.pnpm/nuxt@3.9.0_eslint@8.56.0_rollup@3.29.4_typescript@5.3.3_vite@5.0.10/node_modules/nuxt/dist/app/composables/router')['abortNavigation']
   const addRouteMiddleware: typeof import('../../../../../node_modules/.pnpm/nuxt@3.9.0_eslint@8.56.0_rollup@3.29.4_typescript@5.3.3_vite@5.0.10/node_modules/nuxt/dist/app/composables/router')['addRouteMiddleware']
@@ -401,6 +402,7 @@ declare global {
 import { UnwrapRef } from 'vue'
 declare module 'vue' {
   interface ComponentCustomProperties {
+    readonly HightlightMesh: UnwrapRef<typeof import('../../utils/highlightedMesh')['HightlightMesh']>
     readonly _useShortcuts: UnwrapRef<typeof import('../../../../../node_modules/.pnpm/@nuxt+ui@2.11.1_nuxt@3.9.0_rollup@3.29.4_vite@5.0.10_vue@3.4.3/node_modules/@nuxt/ui/dist/runtime/composables/useShortcuts')['_useShortcuts']>
     readonly abortNavigation: UnwrapRef<typeof import('../../../../../node_modules/.pnpm/nuxt@3.9.0_eslint@8.56.0_rollup@3.29.4_typescript@5.3.3_vite@5.0.10/node_modules/nuxt/dist/app/composables/router')['abortNavigation']>
     readonly addRouteMiddleware: UnwrapRef<typeof import('../../../../../node_modules/.pnpm/nuxt@3.9.0_eslint@8.56.0_rollup@3.29.4_typescript@5.3.3_vite@5.0.10/node_modules/nuxt/dist/app/composables/router')['addRouteMiddleware']>
@@ -791,6 +793,7 @@ declare module 'vue' {
 }
 declare module '@vue/runtime-core' {
   interface ComponentCustomProperties {
+    readonly HightlightMesh: UnwrapRef<typeof import('../../utils/highlightedMesh')['HightlightMesh']>
     readonly _useShortcuts: UnwrapRef<typeof import('../../../../../node_modules/.pnpm/@nuxt+ui@2.11.1_nuxt@3.9.0_rollup@3.29.4_vite@5.0.10_vue@3.4.3/node_modules/@nuxt/ui/dist/runtime/composables/useShortcuts')['_useShortcuts']>
     readonly abortNavigation: UnwrapRef<typeof import('../../../../../node_modules/.pnpm/nuxt@3.9.0_eslint@8.56.0_rollup@3.29.4_typescript@5.3.3_vite@5.0.10/node_modules/nuxt/dist/app/composables/router')['abortNavigation']>
     readonly addRouteMiddleware: UnwrapRef<typeof import('../../../../../node_modules/.pnpm/nuxt@3.9.0_eslint@8.56.0_rollup@3.29.4_typescript@5.3.3_vite@5.0.10/node_modules/nuxt/dist/app/composables/router')['addRouteMiddleware']>

+ 10 - 2
plugins/vite-plugin-tres/client/components/SceneGraphItem.vue

@@ -1,7 +1,8 @@
 <script setup lang="ts">
+import { useDevtoolsHook } from '../composables/useDevtoolsHook'
 import type { SceneGraphObject } from '../types'
 
-withDefaults(defineProps<{
+const props = withDefaults(defineProps<{
   item: SceneGraphObject
   depth?: number
 }>(), {
@@ -10,9 +11,16 @@ withDefaults(defineProps<{
 
 const isExpanded = ref(false)
 
+const { internal, highlightObject } = useDevtoolsHook()
+
 function roundNumber(num: number) {
   return Math.round((num + Number.EPSILON) * 100) / 100
 }
+
+function handleClick() {
+  isExpanded.value = !isExpanded.value
+  highlightObject(props.item)
+}
 </script>
 
 <template>
@@ -21,7 +29,7 @@ function roundNumber(num: number) {
   >
     <div
       class="flex gap-2 items-end cursor-pointer pt2 mb2"
-      @click="isExpanded = !isExpanded"
+      @click="handleClick"
     >
       <span
         v-if="depth > 0"

+ 42 - 1
plugins/vite-plugin-tres/client/composables/useDevtoolsHook.ts

@@ -1,6 +1,9 @@
 import type { TresContext, TresObject } from '@tresjs/core'
-import type { Scene, WebGLRenderer } from 'three'
+import { DoubleSide, MeshBasicMaterial } from 'three'
+import type { Mesh, Object3D, type Scene, type WebGLRenderer } from 'three'
+import { reactive } from 'vue'
 import type { SceneGraphObject } from '../types'
+import { HightlightMesh } from '../utils/highlightedMesh'
 
 interface FPSState {
   value: number
@@ -45,6 +48,7 @@ interface DevtoolsHookReturn {
   fps: FPSState
   memory: MemoryState
   renderer: RendererState
+  highlightObject: (object: TresObject) => void
 }
 
 const scene = reactive<{
@@ -58,6 +62,11 @@ const scene = reactive<{
 })
 
 const gl = {
+  internal: reactive<{}>({
+    selectedObject: null,
+    prevInstance: null,
+    highlightMesh: null,
+  }),
   fps: reactive<FPSState>({
     value: 0,
     accumulator: [],
@@ -108,6 +117,7 @@ const icons: Record<string, string> = {
 
 function createNode(object: TresObject) {
   const node: SceneGraphObject = {
+    uuid: object.uuid,
     name: object.name,
     type: object.type,
     icon: icons[object.type.toLowerCase()] || 'i-carbon-cube',
@@ -170,6 +180,36 @@ function countObjectsInScene(scene: Scene) {
   return count
 }
 
+function createHighlightMesh(object: Object3D): Mesh {
+  const highlightMaterial = new MeshBasicMaterial({
+    color: 0xa7e6d7, // Highlight color, e.g., yellow
+    transparent: true,
+    opacity: 0.2,
+    depthTest: false, // So the highlight is always visible
+    side: DoubleSide, // To e
+  })
+  // Clone the geometry of the object. You might need a more complex approach 
+  // if the object's geometry is not straightforward.
+  const highlightMesh = new HightlightMesh(object.geometry.clone(), highlightMaterial)
+
+  return highlightMesh
+}
+
+function highlightObject(object: TresObject) {
+  const [instance] = scene.value.getObjectsByProperty('uuid', object.uuid)
+  if (gl.internal.prevInstance && gl.internal.highlightMesh && gl.internal.highlightMesh.parent) {
+    gl.internal.prevInstance.remove(gl.internal.highlightMesh)
+  }
+  
+  if (instance.isMesh) {
+    const newHighlightMesh = createHighlightMesh(instance)
+    instance.add(newHighlightMesh)
+
+    gl.internal.highlightMesh = newHighlightMesh
+    gl.internal.prevInstance = instance
+  }
+}
+
 export function useDevtoolsHook(): DevtoolsHookReturn {
   // Connect with Core
   const tresGlobalHook = {
@@ -196,5 +236,6 @@ export function useDevtoolsHook(): DevtoolsHookReturn {
     fps: gl.fps,
     memory: gl.memory,
     renderer: gl.renderer,
+    highlightObject,
   }
 }

+ 24 - 0
plugins/vite-plugin-tres/client/utils/highlightedMesh.ts

@@ -0,0 +1,24 @@
+import * as THREE from 'three'
+
+export class HightlightMesh extends THREE.Mesh {
+  type = 'HightlightMesh'
+  createTime: number
+  constructor(...args: THREE.Mesh['args']) {
+    super(...args)
+    this.createTime = Date.now()
+  }
+
+  onBeforeRender() {
+    const currentTime = Date.now()
+    const time = (currentTime - this.createTime) / 1000
+    // Pulsing effect parameters
+    const scaleAmplitude = 0.07 // Amplitude of the scale pulsation
+    const pulseSpeed = 2.5 // Speed of the pulsation
+
+    // Calculate the scale factor with a sine function for pulsing effect
+    const scaleFactor = 1 + scaleAmplitude * Math.sin(pulseSpeed * time)
+
+    // Apply the scale factor
+    this.scale.set(scaleFactor, scaleFactor, scaleFactor)
+  }
+}