Javascript Raycaster无法获得正确的网格。3.js
我知道这个问题已经被问了很多次,但我不明白光线投射是如何工作的。我有一个函数,可以从一个geo-json文件创建国家边界,以及填充我想要点击的国家。单击时,应显示有关单击国家/地区的一些信息Javascript Raycaster无法获得正确的网格。3.js,javascript,three.js,raycasting,interaction,Javascript,Three.js,Raycasting,Interaction,我知道这个问题已经被问了很多次,但我不明白光线投射是如何工作的。我有一个函数,可以从一个geo-json文件创建国家边界,以及填充我想要点击的国家。单击时,应显示有关单击国家/地区的一些信息 var borders = new THREE.Group(); function createBorders(dataJSON) { var SIZE_AMPLIFIER = 20; var WIDTH = 2500 * SIZE_AMPLIFIER; var projection = d3.geo
var borders = new THREE.Group();
function createBorders(dataJSON) {
var SIZE_AMPLIFIER = 20;
var WIDTH = 2500 * SIZE_AMPLIFIER;
var projection = d3.geoTransverseMercator().rotate([-10, 0, 0]) //center meridian
.center([10, 52]) //longitude, latitude
.scale(WIDTH * 1.5 - 505); //scale
var path = d3.geoPath().projection(projection);
var svg = d3.select("#Map").append("svg");
svg.selectAll(".country")
.data(dataJSON)
.enter()
.append("path")
.attr("class", ".country")
.attr("d", path);
var svgMarkup = svg.node().outerHTML;
var loader = new SVGLoader();
var svgData = loader.parse(svgMarkup);
svgData.paths.forEach((path, i) => {
var shapes = path.toShapes(true);
shapes.forEach((shape, j) => {
var geomSVG = new THREE.ExtrudeBufferGeometry(shape, {
depth: 50,
bevelEnabled: false
})
//needed for click event!
var materialSVG = new THREE.MeshLambertMaterial({
color: 0xFFFFFF,
transparent: true,
opacity: 0.8,
});
var meshSVG = new THREE.Mesh(geomSVG, materialSVG);
this.borders.add(meshSVG);
//create borders
var borderMaterial = new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 3 })
var borderGeometry = new THREE.EdgesGeometry(geomSVG, 15);
var bordermesh = new THREE.LineSegments(borderGeometry, borderMaterial);
this.borders.add(bordermesh);
})
})
this.borders.rotateX(Math.PI / 2)
this.borders.position.z = -300;
this.borders.position.x = 16300;
this.borders.position.y = 0;
//get only meshes, no linesegments
var countryMeshes = [];
for(let m in this.borders.children){
if(this.borders.children[m] instanceof THREE.Mesh){
countryMeshes.push(this.borders.children[m])
}
}
//add callback for each mesh
for(let c in countryMeshes){
countryMeshes[c].callback = function(){console.log(dataJSON[c].properties.name_long)}
}
this.scene.add(this.state.borders);
svg.remove();
}
然后我制作光线投射功能:
var raycaster = new THREE.Raycaster();
function onMeshClick(event) {
event.preventDefault();
var vector = new THREE.Vector3((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5);
raycaster.setFromCamera(vector, camera);
var intersects = raycaster.intersectObjects(this.borders.children, true);
if (intersects.length > 0) {
intersects[0].object.callback();
}
}
最后,我添加了一个事件侦听器:
window.addEventListener('click', onMeshClick, false);
回调可以工作,但顺序不正确。我必须单击另一个国家或甚至地图之外的国家才能调用其中一些国家。您正在将
线段
与网格
组合在一起。可能在单击时,它捕捉的是一条线而不是网格,因为光线投射器在测量线时的精度阈值为1世界单位,这可能太大了。可以将其视为使用宽笔刷而不是单个像素的光线投射
您有两种选择:
raycaster.params.Line.threshold=0.1
我正在createBorders函数末尾将网格与线段分离。更重要的是,一些国家甚至可以在飞机本身之外或渲染器容器之外单击(想象一下还有其他东西,如输入和其他类型的信息)。尽管如此,我还是尝试了阈值方法,但不幸的是它似乎不起作用。我看到您正在创建一个
CountryMesh
数组,但这不是用于光线投射的方法。您仍在使用intersectObjects(this.borders.children)
,其中包括meshSVG
和borderMesh
对象。但是如果这两个选项都不起作用,那么很抱歉,如果没有一个有效的演示,我将无法帮助您。谢谢您的帮助!在这一点上,我想我别无选择,只有创造一个工作小提琴。
var areas = new THREE.Group();
var borders = new THREE.Group();
scene.add(areas);
scene.add(borders);
svgData.paths.forEach((path, i) => {
// ...
areas.add(meshSVG);
// ...
borders.add(bordermesh);
})
// When raycasting, only test country areas, leaving borders out
var intersects = raycaster.intersectObjects(areas, true);