You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用TresJS或TroisJS实现3D物体看向鼠标光标?

实现3D物体看向鼠标光标(TresJS 版本)

核心思路

原示例通过顶点着色器计算物体到鼠标的方向,让顶点朝向鼠标。在TresJS中可通过自定义着色器材质实现,关键是传递鼠标坐标、相机投影矩阵等 uniforms 给着色器。

完整实现步骤

1. 基础场景搭建

先创建TresJS基础场景,包含相机、渲染器和轨道控制器(可选)。

<template>
  <TresCanvas shadows>
    <TresPerspectiveCamera :position="[0, 0, 5]" />
    <TresOrbitControls />
    
    <!-- 带交互效果的物体 -->
    <LookAtMouseMesh />
    
    <TresDirectionalLight :position="[5, 5, 5]" castShadow />
    <TresAmbientLight :intensity="0.2" />
  </TresCanvas>
</template>

<script setup>
import { TresCanvas, TresPerspectiveCamera, TresOrbitControls, TresDirectionalLight, TresAmbientLight } from '@tresjs/core'
import LookAtMouseMesh from './LookAtMouseMesh.vue'
</script>

2. 自定义着色器组件(LookAtMouseMesh.vue)

这是核心部分,编写顶点/片段着色器,同时处理鼠标坐标传递。

<template>
  <TresMesh>
    <TresSphereGeometry :radius="1" :segments="32" />
    <TresShaderMaterial
      :vertexShader="vertexShader"
      :fragmentShader="fragmentShader"
      :uniforms="uniforms"
    />
  </TresMesh>
</template>

<script setup>
import { ref, onMounted, watch } from 'vue'
import { TresMesh, TresSphereGeometry, TresShaderMaterial } from '@tresjs/core'
import { useThree } from '@tresjs/core'

const { camera } = useThree()

// 存储鼠标归一化坐标(-1到1范围)
const mouse = ref({ x: 0, y: 0 })

// 着色器 uniforms
const uniforms = ref({
  mouse: { value: [mouse.value.x, mouse.value.y] },
  cameraPosition: { value: camera.value.position },
  projectionMatrix: { value: camera.value.projectionMatrix },
  viewMatrix: { value: camera.value.matrixWorldInverse }
})

// 顶点着色器:计算顶点朝向鼠标的方向
const vertexShader = /* glsl */`
uniform vec2 mouse;
uniform vec3 cameraPosition;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;

varying vec3 vNormal;

void main() {
  vNormal = normal;
  
  // 将鼠标坐标从屏幕空间转换到世界空间
  vec3 mouseWorld = (projectionMatrix * viewMatrix * vec4(mouse, 0.0, 1.0)).xyz;
  mouseWorld = normalize(mouseWorld - cameraPosition);
  
  // 计算顶点朝向鼠标的旋转
  vec3 objectNormal = normalize(normalMatrix * normal);
  vec3 newNormal = normalize(mix(objectNormal, mouseWorld, 0.5)); // 混合系数可调整
  
  // 应用旋转到顶点位置
  vec3 transformed = vec3(position);
  transformed += newNormal * 0.1; // 可选:添加顶点位移效果
  
  gl_Position = projectionMatrix * modelViewMatrix * vec4(transformed, 1.0);
}
`

// 片段着色器:基础漫反射效果
const fragmentShader = /* glsl */`
varying vec3 vNormal;

void main() {
  vec3 lightDirection = normalize(vec3(1.0, 1.0, 1.0));
  float diff = max(dot(vNormal, lightDirection), 0.0);
  gl_FragColor = vec4(diff * vec3(0.8, 0.2, 0.2), 1.0);
}
`

// 监听鼠标移动,更新归一化坐标
const handleMouseMove = (event) => {
  const { clientX, clientY } = event
  const { innerWidth, innerHeight } = window
  
  mouse.value.x = (clientX / innerWidth) * 2 - 1
  mouse.value.y = -(clientY / innerHeight) * 2 + 1
  
  uniforms.value.mouse.value = [mouse.value.x, mouse.value.y]
}

onMounted(() => {
  window.addEventListener('mousemove', handleMouseMove)
})

// 监听相机参数变化,更新uniforms
watch(camera, (newCam) => {
  uniforms.value.cameraPosition.value = newCam.position
  uniforms.value.projectionMatrix.value = newCam.projectionMatrix
  uniforms.value.viewMatrix.value = newCam.matrixWorldInverse
}, { deep: true })
</script>

3. 关键细节说明

  • 鼠标坐标转换:将屏幕坐标转为ThreeJS归一化设备坐标,再通过相机矩阵转成世界空间,才能计算物体到鼠标的方向。
  • uniforms实时更新:需实时传递鼠标坐标、相机位置和矩阵,确保效果随鼠标移动、相机视角变化同步更新。
  • 旋转强度调整:顶点着色器中mix(objectNormal, mouseWorld, 0.5)的0.5可修改,值越大物体朝向鼠标的程度越高。

4. TroisJS 适配提示

如果用TroisJS,核心逻辑一致,仅组件导入路径改为troisjs,示例结构类似:

<template>
  <TroisCanvas>
    <Camera :position="[0, 0, 5]" />
    <OrbitControls />
    <Mesh>
      <SphereGeometry :radius="1" />
      <ShaderMaterial
        :vertexShader="vertexShader"
        :fragmentShader="fragmentShader"
        :uniforms="uniforms"
      />
    </Mesh>
  </TroisCanvas>
</template>

内容的提问来源于stack exchange,提问作者Pedro BARROS PARENTE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 23:13:22