web-dev-qa-db-ja.com

three.jsで2Dテキストを動的に作成する

Three.jsで作成した3Dモデルがあります。いくつかのデータに基づいて、小さなテキストラベルで装飾された矢印のセットを作成します。これらのラベルは2Dである必要があります。

私には2つの選択肢があるようです:3Dモデルで使用されるテクスチャを作成するために個別のキャンバス要素を使用するか、3Dモデルのキャンバス要素の上でHTMLを使用します。

私はこれについてどうするのかと思っています。これを行う「正しい」方法はどれですか?提案やコード例は大歓迎です!

31
anders

テキストが常に一番上にあることを気にしない場合(たとえば、オブジェクトが他の何かによってブロックされている場合、そのテキストラベルは引き続き表示され、他のすべての上に表示されます)、テキストは影響を受けませんライト/シャドウなどのようにレンダリングする場合、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);

テキストを配置するy座標とx座標(それぞれ)をstyle.topおよびstyle.left変数で200に置き換えます。それらは正の値になります。(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()を呼び出していることを確認してください。

39
kronuus

実際にキャンバスオブジェクトのテキスト(または任意の画像)を3Dシーンの一部として含める場合は、次の場所にあるサンプルコードを確認してください。 http://stemkoski.github.com/Three.js/Texture- From-Canvas.html

19
Lee Stemkoski

demo を確認してください。

TextGeometryは大量のメモリを消費し、使用する各文字のジオメトリを含むフォントをロードする必要があります。シーンに100を超えるテキストメッシュがある場合、ブラウザーがクラッシュします。

キャンバスにテキストを描画し、Spriteを介してシーンに含めることができます。問題は、フォントサイズを計算する必要があることです。移動するカメラがある場合は、フォントサイズを定期的に計算する必要があります。そうしないと、カメラでテキストに近づきすぎると、テキストがぼやけてしまいます。

クラスを作成しました TextSprite これは、カメラまでの距離とレンダラー要素のサイズに応じて、最適なフォントサイズを自動的に計算します。コツは、カメラとレンダラーを受け取るクラス Object3D のコールバック.onBeforeRenderを使用することです。

let Sprite = new THREE.TextSprite({
    textSize: 10,
    texture: {
        text: 'Hello World!',
        fontFamily: 'Arial, Helvetica, sans-serif',
    },
    material: {color: 0xffbbff},
});
scene.add(Sprite);

テキスト、テキストサイズ、フォントをその場で変更することもできます。

Sprite.textSize = 25;
Sprite.material.map.text = 'Hello Stack Overflow!';
Sprite.material.map.fontFamily = 'Tahoma, Geneva, sans-serif';
16
SeregPie

更新:このメソッドは非推奨になり、CPUに負荷がかかるため、使用しないでください。

私は別のthree.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;
8
Ishan Sharma

私はあなたのためにそれを行うNPMのモジュールを公開しました: https://github.com/gamestdio/three-text2d

キャンバスを手動で処理することなく、レンダリングされたテキストでSpriteまたはMeshを使用できます。

例:

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

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

2Dキャンバスを作成し、cssを使用してwebglキャンバスの上部に配置できます。次に、2dキャンバスコンテキストで提供されるctx.fillText(text,x,y)またはctx.strokeText(text,x,y)メソッドを使用して、テキストを描画できます。この方法を使用すると、矢印やメーターなど、テキスト以外の他のものを描くことができます。

@kronuusで提案されている方法を使用して、ポイントを3D空間から2D空間に変換できます。

5
Licson

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

ご覧のように、コツはテキスト(mesh1shape(「矢印」)シーンに追加する代わりに

これがお役に立てば幸いです。

1
Hugo Nava Kopp