Raycaster无法获得正确的网格。 Three.js

问题描述 投票:0回答:1

我知道这个问题已经问过很多次了,但我不明白射线广播如何工作。我有一个从geo json文件创建国家边界以及要单击的国家填充的功能。单击后,应显示有关被单击国家的信息。

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);

回调起作用,但顺序不正确。我必须点击另一个国家,甚至是在地图之外才能呼叫某些国家。

javascript three.js raycasting interaction
1个回答
0
投票

您正在将LineSegmentsMesh分组在一起。也许单击时捕获的是直线而不是网格,因为在测量直线时,Raycaster的精度阈值为1世界单位,这可能太大。可以认为它是使用宽笔刷而不是单个像素进行光线投射。

您有2个选项:

  1. 将您所在的国家/地区与边界分开进行分组。
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); 
  1. 降低the threshold of your raycaster,因此边框不会在光线投射器的眼睛中占据太多空间:raycaster.params.Line.threshold = 0.1
© www.soinside.com 2019 - 2024. All rights reserved.