当 div 的宽度减小时,使用 raycaster 进行检测并不完全准确,three.js(v72)

Posted

技术标签:

【中文标题】当 div 的宽度减小时,使用 raycaster 进行检测并不完全准确,three.js(v72)【英文标题】:Detection with raycaster not completely accurate when the width of div is reduced, three.js(v72) 【发布时间】:2016-04-25 20:14:41 【问题描述】:

这是我计算交点的代码:

var wallWidth = 1200;
var wallHeight = 500;
var containerWidth=1200,containerHeight=700; //div 
//camera
camera = new THREE.PerspectiveCamera(60, containerWidth/containerHeight, 1, 10000);
camera.position.set(0, -wallHeight / 2 + 10, wallWidth);

这是我在鼠标移动时与对象相交的函数

function onDocumentMouseMove(event) 

        mouse.x = ( event.clientX / containerWidth ) * 2 - 1;
        mouse.y = -( event.clientY / containerHeight ) * 2 + 1;

        var deltaX = event.clientX - mouseX;
        var deltaY = event.clientY - mouseY;

        raycaster.setFromCamera(mouse, camera);
        var intersects = raycaster.intersectObjects(interactiveObj, true);

        if (intersects.length > 0) 
            //interaction with object
        

        render();
    

它工作正常,即当 div 的宽度为 100% 时,我在 intersects 对象中获取值,但是当我将 div 大小减小到 80% 时,对象没有正确拾取,即它选择了当鼠标离物体很远时,物体。

【问题讨论】:

【参考方案1】:

使用下面的代码来改变你的鼠标矢量

函数 onDocumentMouseMove(事件)

    mouse.x = ( (event.clientX -renderer.domElement.offsetLeft) / renderer.domElement.width ) * 2 - 1;
    mouse.y = -( (event.clientY - renderer.domElement.offsetTop) / renderer.domElement.height ) * 2 + 1;

    var deltaX = event.clientX - mouseX;
    var deltaY = event.clientY - mouseY;

    raycaster.setFromCamera(mouse, camera);
    var intersects = raycaster.intersectObjects(interactiveObj, true);

【讨论】:

不使用event.clientX - renderer.domElement.offsetLeft,你可以使用event.offsetX developer.mozilla.org/en-US/docs/Web/API/MouseEvent/offsetX 您的解决方案也解决了我的光线投射问题;我想在 mousemove 而不是 rendre 上这样做可以确保场景是最新的?如果有人有一些关于为什么它比 Three.js 的示例threejs.org/docs/#api/en/core/Raycaster 更好地工作的附加信息?【参考方案2】:

你可以使用event.offsetX而不是event.clientX - renderer.domElement.offsetLeft

我遇到了同样的问题,Brakebein 的回答最适合我的需要。

【讨论】:

经过 2 天的尝试解决了我的问题【参考方案3】:

以下获取鼠标相对位置的方式似乎更准确。

var rect = renderer.domElement.getBoundingClientRect();
mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1;
mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1;

【讨论】:

【参考方案4】:

在使用 React 长时间搜索此变体后,帮助我提高 raycaster 精度(也许对某人有所帮助):

class Scene extends React.Component 

 componentDidMount() 
  const width = 400;
  const height = 400;

  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(95, width / height, 1, 1000);
  const renderer = new THREE.WebGLRenderer( antialias: true );
  var controls = new OrbitControls(camera);



  const geometry = new THREE.SphereGeometry(2, 100, 100);

  .....

  const material = new THREE.MeshBasicMaterial(
    color: "#00bfff",
    map: canvasTexture
);
  const sphere = new THREE.Mesh(geometry, material);

  camera.position.z = 3;
  scene.add(sphere);
  renderer.setClearColor("#FFF");
  renderer.setSize(width, height);

  this.scene = scene;
  this.camera = camera;
  this.renderer = renderer;
  this.material = material;
  this.sphere = sphere;
  this.geometry = geometry;
  this.mouse = new THREE.Vector2();
  this.raycaster = new THREE.Raycaster();
 

 ...

 clickHandler = event => 

  const mainEl = document.getElementById("mainBlock");
  const rect = mainEl.getBoundingClientRect();

  this.mouse.x = (event.clientX - rect.left) / mainEl.clientWidth * 2 - 1;
  this.mouse.y = -((event.clientY - rect.top) / mainEl.clientHeight) * 2 + 1; 

  this.raycaster.setFromCamera(this.mouse, this.camera);
  const intersects = this.raycaster.intersectObject(this.sphere);


  if (intersects.length !== 0) 
    ...
  
;

render() 
  <div
    id="mainBlock"
    style= width: "400px", height: "400px" 
    ref=mount => 
      this.mount = mount;
    
    onClick=this.clickHandler
  >
     ...
  </div>



【讨论】:

以上是关于当 div 的宽度减小时,使用 raycaster 进行检测并不完全准确,three.js(v72)的主要内容,如果未能解决你的问题,请参考以下文章

当窗体的宽度减小时如何防止控件消失?

当窗口高度减小时,margin-top 百分比不会改变[重复]

如何格式化我的 CSS 和 Bootstrap,以便在页面宽度减小时仅包裹某些元素?

根据容器宽度动态调整文本大小

想用jQuery mobile js 做网页的自适应大小宽度的改变,就是当网页宽度变小时页面还是显示的原来所有内容

android webview控件,当控件宽度较小时,自适应问题