ThreeJs中的可交互网格

时间:2018-07-16 11:38:51

标签: javascript three.js

我需要绘制一个矩形(不是二次方)的“支撑”网格:用户可以将鼠标悬停在该网格的图块上,然后在其中放置特定的对象。例如。我将鼠标悬停在(x:0 y:15)上,然后单击,我在(x:0 y:15)处得到一个对象。

enter image description here

此网格是使用PlaneGeometry完成的,并绘制为线框(在r58中)。

new THREE.PlaneGeometry(x,y,16, 9);
var mat = new THREE.MeshBasicMaterial({
    color: 0x004488,
    wireframe: true
});
mat.color.r = r;
mat.color.g = g;
mat.color.b = b;

在将代码库更新为r94之后,对于平面的不同图块,现在得到的是三角形而不是正方形。

我尝试了以下操作:

画线:在查看GridHelper的源代码之后,我创建了一个矩形版本。看起来非常不错,但是磁贴的命中检测已关闭。命中检测是通过Raycaster实现的。我认为问题是,只有当鼠标实际上在一条线上时,才能检测到这些线。使用PlaneGeometry,鼠标可以位于图块内部,并且可以正确检测到该几何形状。

使用纹理绘制PlaneGeometry 接下来我想尝试的是使用具有自定义纹理的PlaneGeometry,如下所示:

let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
canvas.height = 32;
canvas.width = 32;
context.beginPath();
context.rect(0, 0, 32, 32);
context.lineWidth = 2;
context.strokeStyle = color.getStyle();
context.stroke();

// canvas contents will be used for a texture
let texture = new THREE.Texture(canvas);

texture.needsUpdate = true;

let material = new THREE.MeshBasicMaterial();
// let material = new THREE.LineBasicMaterial();
material.map = texture;
material.flatShading = true;
material.fog = false;
material.lights = false;
material.side = THREE.DoubleSide;
material.transparent = true;

return material;

现在,命中检测就像r54一样具有魅力,但是如果视角是平坦的,现在看起来非常难看:

enter image description here

我的想法不多了,因此,我希望能获得一些提示或如何绘制漂亮的网格的方法,该网格是一种几何图形,因此可以使用当前的点击检测系统。

TL; DR; 我需要一个网格,其行为类似于PlaneGeometry(命中检测),但仅绘制正方形而不是三角形。

1 个答案:

答案 0 :(得分:2)

您可以有一个由线构成的网格。为此,您可以创建THREE.PlaneBufferGeometry()并更改其.index属性。然后将此几何与THREE.LineSegments()一起使用。

enter image description here

Reference

以及用于更改索引的源代码:

  Object.assign(THREE.PlaneBufferGeometry.prototype, {
    toGrid: function() {
      let segmentsX = this.parameters.widthSegments || 1;
      let segmentsY = this.parameters.heightSegments || 1;
      let indices = [];
      for (let i = 0; i < segmentsY + 1; i++) {
        let index11 = 0;
        let index12 = 0;
        for (let j = 0; j < segmentsX; j++) {
          index11 = (segmentsX + 1) * i + j;
          index12 = index11 + 1;
          let index21 = index11;
          let index22 = index11 + (segmentsX + 1);
          indices.push(index11, index12);
          if (index22 < ((segmentsX + 1) * (segmentsY + 1) - 1)) {
            indices.push(index21, index22);
          }
        }
        if ((index12 + segmentsX + 1) <= ((segmentsX + 1) * (segmentsY + 1) - 1)) {
          indices.push(index12, index12 + segmentsX + 1);
        }
      }
      this.setIndex(indices);
      return this;
    }
  });

使用:

var planeGeom = new THREE.PlaneBufferGeometry(10, 5, 10, 5).toGrid();
var gridPlane = new THREE.LineSegments(planeGeom, new THREE.LineBasicMaterial({color: "yellow"}));