如何在 three.js 中使用 2D 文本形状正确切割平面?

How can I cut a plane properly with 2D text shapes in three.js?

许多文本字符都有内部孔(如 a、b、d、e、g、o、p、q、0、4、6、8、9 等)。如果我采用它们的 2D 形状并使用它们在平面形状上切割孔,则只会切割这些形状的轮廓,并且每个角色的中心孔不会保留在平面形状上。

有没有使用文字形状正确切割平面的解决方案? 请注意,我正在寻找具有 2D 文本形状的本机 three.js 解决方案,而不是使用库和挤压 3D 文本,这样效率会低得多。

示例主代码:切割矩形的二维文本形状:

// text shapes
var message = "example";
var textshapes = font.generateShapes( message, 100, 2 );

// rectangle shape
var width = 800, height = 300, x = -130, y = -110;    
var rectShape = new THREE.Shape();
rectShape.moveTo( x, y );
rectShape.lineTo( x, y+height );
rectShape.lineTo( x+width, y+height );
rectShape.lineTo( x+width, y );
rectShape.lineTo( x, y );

//cut rectangle shape with the message's text shapes
var tslen = textshapes.length;
for (i=0; i<tslen; i++){
    rectShape.holes.push( textshapes[i] );
}

var geometry = new THREE.ShapeGeometry(rectShape);

结果:

stemkoski 的三个 csg 模块。不确定为什么要避免 "libraries" 因为三是非常模块化的,并且试图将您所描述的深奥功能保留在其核心之外。嗯!

我最终采用了这种方法,使用 .merge()。我不能说这是最好的解决方案(因为它是刚刚从头开始制作的),但是,至少,它给出了一个可以接受的结果:

var scene = new THREE.Scene();
scene.background = new THREE.TextureLoader().load("https://threejs.org/examples/textures/UV_Grid_Sm.jpg");
var clock = new THREE.Clock();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.set(0, 0, 800);

var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x101010);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

var loader = new THREE.FontLoader();
loader.load('https://threejs.org/examples/fonts/helvetiker_regular.typeface.json', function(font) {
  // text shapes
  var message = "example8";
  var textshapes = font.generateShapes(message, 100, 2);

  // rectangle shape
  var width = 875,
    height = 300,
    x = -130,
    y = -110;
  var rectShape = new THREE.Shape();
  rectShape.moveTo(x, y);
  rectShape.lineTo(x, y + height);
  rectShape.lineTo(x + width, y + height);
  rectShape.lineTo(x + width, y);
  rectShape.lineTo(x, y);

  //cut rectangle shape with the message's text shapes
  var tslen = textshapes.length;
  for (i = 0; i < tslen; i++) {
    rectShape.holes.push(textshapes[i]);
  }

  var geometry = new THREE.ShapeGeometry(rectShape);

  for (let i = 0; i < tslen; i++) {
    let letter = textshapes[i];
    if (letter.holes && letter.holes.length > 0) {
      for (let j = 0; j < letter.holes.length; j++) {
        // here we make geometries from holes and merge them with the main geometry
        let hole = letter.holes[j];
        let pts = hole.getPoints();

        let innerShape = new THREE.Shape(pts);
        let innerGeom = new THREE.ShapeGeometry(innerShape);
        geometry.merge(innerGeom);
      }
    }
  }

  geometry.center();

  var mesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
    color: "aqua",
    side: THREE.DoubleSide
  }));
  scene.add(mesh);
});

function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}

render();
body {
  margin: 0;
  overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/93/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Reference