Html 在three.js中动态创建二维文本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15248872/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dynamically create 2D text in three.js
提问by anders
I have 3D model which I have created in three.js. Based on some data, I want to create a set of arrows which is decorated by a small text label. These labels should be in 2D.
我有我在three.js中创建的3D模型。根据一些数据,我想创建一组由小文本标签装饰的箭头。这些标签应该是二维的。
It seems like I have two alternatives: either use a separate canvas element to create a texture which in its turn is used in the 3D model, or use HTML on top the 3D model's canvas element.
似乎我有两种选择:要么使用单独的画布元素来创建纹理,然后在 3D 模型中使用该纹理,要么在 3D 模型的画布元素顶部使用 HTML。
I'm wondering how to go about this. Which is the "correct" way to do this? Any suggestions and example code is very welcome!
我想知道如何解决这个问题。哪个是“正确”的方法来做到这一点?非常欢迎任何建议和示例代码!
回答by kronuus
If you don't mind that the text will always be on top (e.g. if the object is blocked by something else, its text label will still be visible and on top of everything else), and that the text will not be affected by any rendering like lights/shadow, etc, then HTML is the easiest way to go imho.
如果您不介意文本始终位于顶部(例如,如果对象被其他物体挡住,则其文本标签仍将可见并位于其他所有物体的顶部),并且文本不会受到任何影响渲染像灯光/阴影等,那么 HTML 是最简单的方法。
Here is some sample code:
下面是一些示例代码:
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);
Substitute 200 in the style.top and style.left variables for the y and x coordinates (respectively) you wish to place the text. They will be positive values where (0,0) is the top left of the canvas. For some guidance on how to project from the 3D point in your canvas to a 2D point in pixels in your browser window, use a code snippet like the following:
将 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;
}
Make sure you have called camera.updateMatrixWorld() beforehand.
确保您事先调用了 camera.updateMatrixWorld()。
回答by SeregPie
Check out the demo.
查看 演示。
TextGeometry
consumes a lot of memory and you need to load a font, which contains a geometry for each letter, you will be using. If I have more than 100 text meshes in a scene, my browser crashes.
TextGeometry
消耗大量内存,您需要加载一种字体,其中包含您将使用的每个字母的几何图形。如果场景中有超过 100 个文本网格,我的浏览器就会崩溃。
You can draw text on a canvas and include it in your scene via a Sprite
. The problem with it is that you need to calculate the font size. If you have a moving camera, then you need to calculate the font size periodically. Otherwise the text will get to blurry, if you get too close to the text with the camera.
您可以在画布上绘制文本并通过Sprite
. 它的问题在于您需要计算字体大小。如果你有一个移动的相机,那么你需要定期计算字体大小。否则,如果您用相机离文本太近,文本会变得模糊。
I wrote a class TextSpritewhich automatically calculates the best possible font size, depending on the distance to the camera and the size of the renderer element. The trick is to use the callback .onBeforeRender
of the class Object3D, which receives the camera and the renderer.
我编写了一个TextSprite类,它根据到相机的距离和渲染器元素的大小自动计算可能的最佳字体大小。诀窍是使用Object3D.onBeforeRender
类的回调,它接收相机和渲染器。
let sprite = new THREE.TextSprite({
text: 'Hello World!',
fontFamily: 'Arial, Helvetica, sans-serif',
fontSize: 12,
fillColor: '#ffbbff',
});
scene.add(sprite);
You can also change the text and the font on the fly.
您还可以即时更改文本和字体。
sprite.text = 'Hello Stack Overflow!';
sprite.fontFamily = 'Tahoma, Geneva, sans-serif';
sprite.fontSize = 24;
回答by Lee Stemkoski
If you actually want to include text (or any image) from a canvas object as part of your 3D scene, check out the sample code at: http://stemkoski.github.com/Three.js/Texture-From-Canvas.html
如果您确实想将画布对象中的文本(或任何图像)作为 3D 场景的一部分,请查看以下示例代码:http: //stemkoski.github.com/Three.js/Texture-From-Canvas。 html
回答by Ishan Sharma
Update: This method is Deprecated now and is CPU heavy, don't use it.
更新:此方法现在已弃用,并且占用大量 CPU,请勿使用。
I found out another only three.js based solution,
我发现了另一个仅基于三个.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};
Now to edit this text dynamically,
现在要动态编辑此文本,
var textShapes = THREE.FontUtils.generateShapes( text, options );
var text = new THREE.ShapeGeometry( textShapes );
textMesh.geometry = text;
textMesh.geometry.needsUpdate = true;
回答by Endel
I've published a module on NPM that does that for you: https://github.com/gamestdio/three-text2d
我已经在 NPM 上发布了一个模块,可以为您做到这一点:https: //github.com/gamestdio/three-text2d
It allows you to have an Sprite
or Mesh
with the rendered text without dealing with canvas manually.
它允许您使用Sprite
或Mesh
渲染文本而无需手动处理画布。
Example:
例子:
var Text2D = require('three-text2d').Text2D
var text = new Text2D("Hello world!", { font: '30px Arial', fillStyle: '#000000', antialias: true })
scene.add(text)
回答by Licson
You can create a 2d canvas and use css to position it to the top of your webgl canvas. Then you can draw text on it using the ctx.fillText(text,x,y)
or ctx.strokeText(text,x,y)
methods provided by the 2d canvas context. By using this method you can draw other things besides text, such as arrows and meters.
您可以创建一个 2d 画布并使用 css 将其定位到 webgl 画布的顶部。然后,您可以使用2d 画布上下文提供的ctx.fillText(text,x,y)
或ctx.strokeText(text,x,y)
方法在其上绘制文本。通过使用此方法,您可以绘制除文本之外的其他内容,例如箭头和米。
You can use the method as suggested by @kronuus to convert a point from 3d to 2d space.
您可以使用@kronuus 建议的方法将点从 3d 空间转换为 2d 空间。
回答by Hugo Nava Kopp
The response by @LeeStemkoski was quite useful. Yet there is a slight change that needs to be done to the code in order for the text to follow your arrows aroundi.e. in case the arrow gets moved around, rotated, etc.
@LeeStemkoski 的回复非常有用。然而,需要对代码进行一些细微的更改,以便文本跟随您的箭头,即以防箭头四处移动、旋转等。
See the next code
看下一个代码
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)
As you can see, the trick is to add the text (mesh1
) to the shape
(your "arrow") instead of adding it to the scene.
如您所见,诀窍是将文本 ( mesh1
)添加到shape
(您的“箭头”)而不是将其添加到场景中。
I hope this helps.
我希望这有帮助。
回答by Sylvain Lugez
From the "geometry / text / shape" of Three js : https://threejs.org/examples/?q=text#webgl_geometry_text_shapes
来自三个js的“几何/文本/形状”:https: //threejs.org/examples/?q =text#webgl_geometry_text_shapes
I simplified the code for just have the strict necessary to add a 2D dynamic text :
我简化了代码,只需要添加 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++) {
the method 'generateShapes' permit to create the text in shape
'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);
}
});