THREEJS的鼠标事件实现(中心旋转,放大缩小等)

本文介绍如何在Three.js项目中通过自定义鼠标事件来控制物体旋转,而非使用默认的TrackballControls.js或OrbitControls.js。这种方法可以确保物体移动到光源下时能够正确显示光照效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近使用threejs自带的TrackballControls.js或者OrbitControls.js发现一个问题:在场景中在一个平行光,当移动物体时,背面始终是黑的,因为没有光照,(本质就是因为使用自带的滚动求,移动的是相机,而不是移动物体)因为效果需要,自己写鼠标事件,控制物体(这样的好处是:当物体移到光照射到的地方,都能实现光亮的效果)

加一束平行光

var directionalLight = new THREE.DirectionalLight(0xFFFFFF);
directionalLight.intensity=1;
directionalLight.position.set( 0, 50,100 );
//把平行光加到场景中
scene.add( directionalLight );
效果图:可以看到,我旋转这个平面后,光照的地方就是一直都是亮的,没有光照的地方,是暗的



实现过程:

document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );//如果运行不出来,也不报错请检查大小写
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );

function render() {
    //渲染场景和相机
    n1.rotation.y+= ( targetRotation - n1.rotation.y ) * 0.05;//n1就是旋转的整体
    renderer.render(scene, camera);

}
function onDocumentTouchMove( event ) {

    if ( event.touches.length == 1 ) {
        event.preventDefault();
        mouseX = event.touches[ 0 ].pageX - windowHalfX;
        targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;

    }

}
function onDocumentTouchStart( event ) {

    
    if ( event.touches.length === 1 ) {
        event.preventDefault();
        mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
        targetRotationOnMouseDown = targetRotation;
    }
}
function onDocumentMouseMove( event ) {

    //旋转
    mouseX = event.clientX - windowHalfX;
    mouseY = event.clientY - windowHalfY;
    targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
   

}
function onDocumentMouseUp( event ) {

    document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
    document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
    document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentMouseOut( event ) {

    document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
    document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
    document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentMouseDown( event ) {

    event.preventDefault();
    document.addEventListener( 'mousemove', onDocumentMouseMove, false );
    document.addEventListener( 'mouseup', onDocumentMouseUp, false );
    document.addEventListener( 'mouseout', onDocumentMouseOut, false );

    mouseXOnMouseDown = event.clientX - windowHalfX;
    targetRotationOnMouseDown = targetRotation;

 

}
//放大缩小的功能实现,主要是通过鼠标的滚轮事件,改变的是carema的fov
function onDocumentMouseWheel(event){
    event.preventDefault();
    //event.stopPropagation();
      if (event.wheelDelta)
          {  //判断浏览器IE,谷歌滑轮事件
              if (event.wheelDelta > 0)
              {   //当滑轮向上滚动时
                  fov -= (near < fov ? 1 : 0);
              }
              else
              {   //当滑轮向下滚动时
                  fov += (fov < far ? 1 : 0);
              }
      }
      //console.info('camera.fov:'+camera.fov);
      //改变fov值,并更新场景的渲染
      camera.fov = fov;
      camera.updateProjectionMatrix();
      renderer.render(scene, camera);
}
注意:1.初始化camera
var  fov = 45,//拍摄距离  视野角值越大,场景中的物体越小
    near = 1,//最小范围
    far = 1000;//最大范围

camera = new THREE.PerspectiveCamera(fov, window.innerWidth / window.innerHeight, near, far);
camera.position.x = 0;
camera.position.y = 100;
camera.position.z =150;
camera.lookAt(new THREE.Vector3(0,0,0));
2,其他初始化
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0,mouseY = 0;
var mouseXOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

<think>好的,我现在需要帮助用户在Vue3中使用Three.js的OrbitControls实现鼠标位置为中心的缩放功能。首先,我需要回顾一下OrbitControls的基本原理。根据引用[2],OrbitControls通过控制摄像机与模型的距离来实现旋转、缩放等功能。通常,默认的缩放可能以画布中心中心,但用户希望以鼠标位置为中心缩放,这需要调整摄像机的位置和观察点。 接下来,我应该考虑如何修改OrbitControls的默认缩放行为。OrbitControls本身可能没有直接提供以鼠标中心缩放的选项,因此需要手动干预缩放过程。根据引用[1]中的例子,鼠标位置可以通过事件监听获取,比如event.pageX和event.pageY。但需要注意,Three.js中的坐标系统与屏幕坐标可能不同,需要进行转换。 然后,我需要确定缩放时如何调整摄像机的位置。以鼠标位置为中心缩放意味着在缩放时,摄像机需要朝着鼠标所在的三维点移动,而不仅仅是向场景中心移动。这涉及到将鼠标的屏幕坐标转换为场景中的三维坐标,可能需要使用射线投射(Raycaster)来获取鼠标指向的三维点。 另外,引用[3]提到了在animate函数中设置camera.lookAt,这可能对保持观察方向有帮助。在缩放过程中,可能需要动态调整摄像机的位置,同时保持看向某个点,以确保视角正确。 可能的步骤包括: 1. 监听鼠标滚轮事件,获取鼠标在屏幕上的位置。 2. 将鼠标位置转换为Three.js的三维坐标,找到鼠标指向的场景中的点。 3. 根据缩放方向(放大缩小),计算摄像机需要移动的距离。 4. 调整摄像机的位置,使其朝向鼠标点移动,同时保持观察目标。 5. 更新OrbitControls的目标点,可能需要禁用自动旋转或其他默认行为。 需要注意的是,直接修改OrbitControls的内部方法可能会比较困难,因此可能需要覆盖或扩展其缩放处理逻辑。此外,在Vue3中集成时,要确保正确管理事件监听器和Three.js对象的生命周期,避免内存泄漏。 最后,测试实现的效果,确保缩放平滑且以鼠标位置为中心,同时处理可能的边缘情况,比如鼠标在画布边缘时的坐标转换问题。</think>在Vue3中实现Three.js的OrbitControls以鼠标位置为中心的缩放功能,需要重写缩放逻辑并处理坐标转换。具体步骤如下: --- ### 1. 禁用默认缩放行为 首先禁用OrbitControls的默认缩放响应: ```javascript import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' const controls = new OrbitControls(camera, renderer.domElement) controls.enableZoom = true // 保持缩放功能启用 controls.mouseButtons.LEFT = null // 禁用左键旋转 ``` --- ### 2. 监听鼠标滚轮事件 通过自定义滚轮事件实现精准控制: ```javascript let targetZoom = 1 // 当前缩放系数 const ZOOM_SPEED = 0.1 renderer.domElement.addEventListener('wheel', (event) => { event.preventDefault() // 获取标准化鼠标位置(范围[-1,1]) const mouse = new THREE.Vector2() mouse.x = (event.offsetX / window.innerWidth) * 2 - 1 mouse.y = -(event.offsetY / window.innerHeight) * 2 + 1 // 计算缩放方向 const delta = event.deltaY > 0 ? 1 : -1 targetZoom *= Math.pow(0.95, delta * ZOOM_SPEED) // 执行自定义缩放 handleZoom(mouse, delta) }) ``` --- ### 3. 实现坐标转换与缩放 核心算法通过射线投射获取三维空间坐标点: ```javascript const raycaster = new THREE.Raycaster() const targetPoint = new THREE.Vector3() function handleZoom(mouse, delta) { // 获取鼠标指向的三维坐标 raycaster.setFromCamera(mouse, camera) const intersects = raycaster.intersectObjects(scene.children) if (intersects.length > 0) { targetPoint.copy(intersects[0].point) } else { // 当未选中物体时,使用默认场景中心点 targetPoint.set(0, 0, 0) } // 计算摄像机位移方向 const direction = new THREE.Vector3() direction.subVectors(camera.position, targetPoint).normalize() // 计算新摄像机位置 const newPosition = new THREE.Vector3() const moveDistance = direction.multiplyScalar(delta * ZOOM_SPEED) newPosition.copy(camera.position).add(moveDistance) // 更新摄像机 camera.position.copy(newPosition) controls.target.copy(targetPoint) // 关键:更新控制器的目标点[^2] controls.update() } ``` --- ### 4. 在Vue组件中的集成 在Vue3组件中管理Three.js生命周期: ```vue <script setup> import { onMounted, onUnmounted } from 'vue' let controls, renderer, camera onMounted(() => { // 初始化Three.js场景 initScene() // 初始化轨道控制器 controls = new OrbitControls(camera, renderer.domElement) controls.minDistance = 2 controls.maxDistance = 50 }) onUnmounted(() => { // 清理事件监听器 renderer.domElement.removeEventListener('wheel', handleWheel) }) </script> ``` --- ### 实现原理 1. **坐标转换**:通过`Raycaster`将2D屏幕坐标转换为3D场景坐标[^1] 2. **摄像机移动**:根据鼠标指向点计算摄像机位移方向,保持观察焦点始终在目标点[^2] 3. **控制器同步**:每次缩放后强制更新`controls.target`确保控制器状态同步[^3] ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值