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

bbmckpt7  于 2023-06-20  发布在  Java
关注(0)|答案(8)|浏览(274)

我在three.js中创建了3D模型。基于一些数据,我想创建一组箭头,由一个小文本标签装饰。这些标签应该是二维的。
看来我有两个选择:或者使用单独的canvas元素来创建纹理,该纹理又在3D模型中使用,或者在3D模型的canvas元素之上使用HTML。
我不知道该怎么办。哪一种是“正确”的方法?任何建议和示例代码都非常欢迎!

olmpazwi

olmpazwi1#

如果你不介意文本总是在顶部(例如:如果对象被其他东西挡住了,它的文本标签仍然可见,并且在其他所有东西的顶部),并且文本不会受到任何渲染(如灯光/阴影等)的影响,那么HTML是最简单的方法。
下面是一些示例代码:

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

在style.top和style.left变量中分别替换200作为您希望放置文本的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;
}

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

vsikbqxv

vsikbqxv2#

看看demo
TextGeometry消耗大量内存,您需要加载字体,其中包含每个字母的几何形状,您将使用。如果场景中的文本网格超过100个,浏览器就会崩溃。
您可以在画布上绘制文本,并通过Sprite将其包含在场景中。它的问题是你需要计算字体大小。如果你有一个移动的相机,那么你需要定期计算字体大小。否则文本会变得模糊,如果你用相机太接近文本。
我写了一个类TextSprite,它根据到相机的距离和渲染器元素的大小自动计算最佳字体大小。技巧是使用Object3D类的回调.onBeforeRender,它接收相机和渲染器。

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

您还可以动态更改文本和字体。

sprite.text = 'Hello Stack Overflow!';
sprite.fontFamily = 'Tahoma, Geneva, sans-serif';
sprite.fontSize = 24;
cgvd09ve

cgvd09ve3#

如果你真的想将画布对象中的文本(或任何图像)作为3D场景的一部分,请查看以下位置的示例代码:http://stemkoski.github.com/Three.js/Texture-From-Canvas.html

inkz8wg9

inkz8wg94#

更新:这个方法现在已经被废弃了,而且CPU很重,不要使用它。

我发现了另一个基于三个. js的解决方案,

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

现在要动态编辑此文本,

var textShapes = THREE.FontUtils.generateShapes( text, options );
var text = new THREE.ShapeGeometry( textShapes );
textMesh.geometry = text;
textMesh.geometry.needsUpdate = true;
oipij1gg

oipij1gg5#

我已经发布了一个关于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)
y1aodyip

y1aodyip6#

你可以创建一个2d画布,并使用css将其放置在webgl画布的顶部。然后,您可以使用2d canvas上下文提供的ctx.fillText(text,x,y)ctx.strokeText(text,x,y)方法在其上绘制文本。通过使用此方法,您可以绘制除文本之外的其他内容,例如箭头和 Jmeter 。
您可以使用@kronuus建议的方法将点从3d空间转换为2d空间。

xzlaal3s

xzlaal3s7#

@LeeStemkoski的回应非常有用。然而,需要对代码做一个轻微的更改**,以便文本跟随您的箭头**,即。以防箭头被移动、旋转等。
看下一段代码

var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
context1.font = "Bold 10px Arial";
context1.fillStyle = "rgba(255,0,0,1)";
context1.fillText('Hello, world!', 0, 60);

// canvas contents will be used for a texture
var texture1 = new THREE.Texture(canvas1)
texture1.needsUpdate = true;

var material1 = new THREE.MeshBasicMaterial({
    map: texture1,
    side: THREE.DoubleSide
});
material1.transparent = true;

var mesh1 = new THREE.Mesh(
    new THREE.PlaneGeometry(50, 10),
    material1
);
mesh1.position.set(25, 5, -5);
mesh1.rotation.x = -0.9;
shape.add(mesh1);
// Note that mesh1 gets added to the shape and not to the scene

scene.add(shape)

正如你所看到的,诀窍是将文本(mesh1添加到shape(你的“箭头”),而不是将它添加到场景
希望这能帮上忙。

zi8p0yeb

zi8p0yeb8#

从“几何/文字/形状”的三个js:https://threejs.org/examples/?q=text#webgl_geometry_text_shapes
我简化了代码,只需要添加一个2D动态文本:

var loader = new THREE.FontLoader();
loader.load( 'assets/fonts/helvetiker_regular.typeface.json', function ( font ) {   
    var textPositions = [[1, 1, 1],
                         [2, 2, 2]];

    var textMessages = ['Text 1', 'Text 2'];

    var textSizes = [0.1, 0.2];

    var textName = ['text1', 'text2'];

    var textsNumber = textPositions.length;     

    for (var i = 0; i < textsNumber; i++) {

方法'generateShapes'允许在形状中创建文本

var textsShapes = font.generateShapes( textMessages[i], textSizes[i] );
        var textsGeometry = new THREE.ShapeBufferGeometry( textsShapes );    
        var textsMaterial = new THREE.MeshBasicMaterial({color: 0xeeeeee});

        var text = new THREE.Mesh(textsGeometry, textsMaterial);
        text.position.set(textPositions[i][0], textPositions[i][1], textPositions[i][2]);
        text.name = textName[i]; 

        scene.add(text);
    }

});

相关问题