在three.js中动态创建2D文本

and*_*ers 31 html javascript three.js

我有三个模型,我在three.js创建.基于一些数据,我想创建一组由小文本标签装饰的箭头.这些标签应为2D.

看起来我有两种选择:使用单独的canvas元素来创建纹理,然后在3D模型中使用它,或者在3D模型的canvas元素上使用HTML.

我想知道如何解决这个问题.这是"正确"的方法吗?任何建议和示例代码都非常欢迎!

kro*_*uus 39

如果您不介意文本将始终位于顶部(例如,如果对象被其他内容阻止,则其文本标签仍然可见并且在其他所有内容之上),并且文本不会受到任何影响渲染像灯光/阴影等,然后HTML是最简单的方式去imho.

以下是一些示例代码:

var text2 = document.createElement('div');
text2.style.position = 'absolute';
//text2.style.zIndex = 1;    // if you still don't see the label, try uncommenting this
text2.style.width = 100;
text2.style.height = 100;
text2.style.backgroundColor = "blue";
text2.innerHTML = "hi there!";
text2.style.top = 200 + 'px';
text2.style.left = 200 + 'px';
document.body.appendChild(text2);
Run Code Online (Sandbox Code Playgroud)

在style.top和style.left变量中替换为您希望放置文本的y和x坐标(分别).它们将是正值,其中(0,0)是画布的左上角.有关如何从画布中的3D点投影到浏览器窗口中的2D点(像素点)的一些指导,请使用如下代码段:

function toXYCoords (pos) {
        var vector = projector.projectVector(pos.clone(), camera);
        vector.x = (vector.x + 1)/2 * window.innerWidth;
        vector.y = -(vector.y - 1)/2 * window.innerHeight;
        return vector;
}
Run Code Online (Sandbox Code Playgroud)

确保您事先调用了camera.updateMatrixWorld().


Lee*_*ski 19

如果您确实想要将画布对象中的文本(或任何图像)作为3D场景的一部分包含在内,请查看示例代码:http: //stemkoski.github.com/Three.js/Texture-From-Canvas. HTML

  • 模糊文本似乎(主要)发生,因为three.js将精灵渲染为方形,即使画布可能比它更宽.如果你将精灵缩放到与画布相同的比例,它应该看起来更好. (2认同)

Ser*_*Pie 17

看看 演示.

TextGeometry消耗大量内存,您需要加载一个字体,其中包含您将使用的每个字母的几何.如果场景中有超过100个文本网格,我的浏览器会崩溃.

您可以在画布上绘制文本并通过a将其包含在场景中Sprite.它的问题是你需要计算字体大小.如果您有移动相机,则需要定期计算字体大小.否则,如果您使用相机太靠近文本,文本将变得模糊.

我写了一个类TextSprite,它根据相机的距离和渲染器元素的大小自动计算出最佳的字体大小.诀窍是使用Object3D.onBeforeRender类的回调,它接收相机和渲染器.

let sprite = new THREE.TextSprite({
  text: 'Hello World!',
  fontFamily: 'Arial, Helvetica, sans-serif',
  fontSize: 12,
  fillColor: '#ffbbff',
});
scene.add(sprite);
Run Code Online (Sandbox Code Playgroud)

您还可以动态更改文本,文本大小和字体.

sprite.text = 'Hello Stack Overflow!';
sprite.fontFamily = 'Tahoma, Geneva, sans-serif';
sprite.fontSize = 24;
Run Code Online (Sandbox Code Playgroud)


Ish*_*rma 8

更新:此方法现在已弃用并且CPU很重,请勿使用它.

我发现另一个只有三个基于解决方案的解决方案,

var textShapes = THREE.FontUtils.generateShapes( text, options );
var text = new THREE.ShapeGeometry( textShapes );
var textMesh = new THREE.Mesh( text, new THREE.MeshBasicMaterial( { color: 0xff0000 } ) ) ;
scene.add(textMesh);
// Example text options : {'font' : 'helvetiker','weight' : 'normal', 'style' : 'normal','size' : 100,'curveSegments' : 300};
Run Code Online (Sandbox Code Playgroud)

现在动态编辑此文本,

var textShapes = THREE.FontUtils.generateShapes( text, options );
var text = new THREE.ShapeGeometry( textShapes );
textMesh.geometry = text;
textMesh.geometry.needsUpdate = true;
Run Code Online (Sandbox Code Playgroud)

  • 应该注意的是,这是用于创建2D文本的非常昂贵的方法.如果您正在考虑显示标准2D文本,则在画布中使用HTML会更加明智. (3认同)
  • 现在不推荐使用,只有FontLoader有效 (2认同)

End*_*del 7

我已经在NPM上发布了一个模块,可以帮助你:https://github.com/gamestdio/three-text2d

它允许您拥有SpriteMesh使用渲染文本而无需手动处理画布.

例:

var Text2D = require('three-text2d').Text2D

var text = new Text2D("Hello world!", { font: '30px Arial', fillStyle: '#000000', antialias: true })
scene.add(text) 
Run Code Online (Sandbox Code Playgroud)

  • 你能举例说明如何使用你的模块吗?我刚刚开始使用ThreeJS,所以我只有ThreeJS hello-world示例.我相信我不能在其中要求('three-text2d'),所以我应该使用像browserify这样的软件包来编译你的包使用ThreeJS吗?谢谢! (4认同)

Lic*_*son 5

您可以创建2D画布并使用css将其定位到webgl画布的顶部.然后,您可以使用2d画布上下文提供的ctx.fillText(text,x,y)ctx.strokeText(text,x,y)方法在其上绘制文本.通过使用此方法,您可以绘制除文本之外的其他内容,例如箭头和米.

您可以使用@kronuus建议的方法将点从3d转换为2d空间.