Я разрабатываю программу для 2D-просмотра чертежей САПР с использованием библиотеки three.js, и для этого проекта мне нужно иметь возможность щелкать объекты на сцене, чтобы выполнять некоторые операции.
Используя орфографическую камеру, рейкастинг three.js не точен, как я ожидаю.
Вот код и рабочий пример, которая точно показывает, что я имею в виду https://jsfiddle.net/toriphes/a0o7td1u/
var camera, scene, renderer, square, raycaster;
init();
animate();
function init() {
output = document.getElementById('output');
raycaster = new THREE.Raycaster();
// Renderer.
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
var aspect = window.innerWidth / window.innerHeight;
var d = 20;
camera = new THREE.OrthographicCamera(-window.innerWidth / 2, window.innerWidth / 2, window.innerHeight / 2, -window.innerHeight / 2, 1, 1000);
camera.position.z = 10;
camera.position.x = 25;
camera.position.y = 25;
camera.zoom = 10
camera.updateProjectionMatrix()
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableRotate = false
controls.target.x = camera.position.x;
controls.target.y = camera.position.y;
controls.update();
// Create scene.
scene = new THREE.Scene();
var points = [
new THREE.Vector2(10, 10),
new THREE.Vector2(40, 10),
new THREE.Vector2(40, 40),
new THREE.Vector2(10, 40),
new THREE.Vector2(10, 10)
]
var shape = new THREE.Shape(points);
var geometry = new THREE.Geometry().setFromPoints(points);
var square = new THREE.Line(geometry, new THREE.LineBasicMaterial({
color: 0xFF0000
}));
scene.add(square)
document.addEventListener('mousemove', findIntersections, false);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
function updateMousePosition(event) {
return new THREE.Vector3(
(event.clientX - renderer.domElement.offsetLeft) /
renderer.domElement.clientWidth *
2 -
1,
-(
(event.clientY - renderer.domElement.offsetTop) /
renderer.domElement.clientHeight
) *
2 +
1,
0
);
}
function findIntersections(e) {
var mouseposition = updateMousePosition(e);
raycaster.setFromCamera(mouseposition, camera);
const intersects = raycaster.intersectObjects(scene.children);
output.innerHTML = intersects.length > 0 ?
'Intersect: TRUE' :
'Intersect: FALSE';
}
Если вы проведете мышь рядом с красным квадратом, вы увидите, что пересечение срабатывает до наведения на край.
Что я делаю неправильно?
Обнаружение пересечения линий зависит от свойства .linePrecision
Raycaster
.
например
raycaster.linePrecision = 0.1;
const intersects = raycaster.intersectObjects(scene.children);
Параметр должен быть установлен в зависимости от масштаба сцены. Значение 0,1 является эмпирическим значением, которое дает хорошие результаты для вашего примера. К сожалению, в документации нет дополнительной информации (возможно, я что-то пропустил, но не нашел).
Отличный совет. Я использую значение 0,01, которое дает мне точность, которую я хочу. Но, по-видимому, это означает, что raycaster должен выполнять в 10x10=100 раз больше работы, чем при использовании значения 0,1. |Верно, свойство linePrecision не упоминается в официальные документы. Но упоминается объект params
, внутри которого threshold
— это точность лучакастера при пересечении различных объектов в мировых единицах. Это объясняет, почему иногда было трудно выбрать объекты-сетки, когда для линейных объектов порог по умолчанию был равен 1.
linePrecision = 0.1
кажется, работает в моем проекте. было бы полезно иметь немного больше документации об этом.