如何在 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>
许多文本字符都有内部孔(如 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>