当 div 的宽度减小时,用 raycaster 检测不完全准确,three.js(v72)
Detection with raycaster not completely accurate when the width of div is reduced, three.js(v72)
这是我计算交集的代码:
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% 时,对象拾取不正确,即当鼠标离对象很远时拾取对象。
使用下面的代码来改变你的鼠标矢量
Document MouseMove 函数(事件){
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);
}
Instead of using event.clientX - renderer.domElement.offsetLeft
you can just use event.offsetX
我遇到了同样的问题,Brakebein 的回答最适合我的需要。
下面这种获取鼠标相对位置的方式貌似比较准确
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;
在使用 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>
}
}
这是我计算交集的代码:
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% 时,对象拾取不正确,即当鼠标离对象很远时拾取对象。
使用下面的代码来改变你的鼠标矢量
Document MouseMove 函数(事件){
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);
}
Instead of using
event.clientX - renderer.domElement.offsetLeft
you can just useevent.offsetX
我遇到了同样的问题,Brakebein 的回答最适合我的需要。
下面这种获取鼠标相对位置的方式貌似比较准确
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;
在使用 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>
}
}