Créer dynamiquement du texte 2D en trois.js

J'ai un modèle 3D que j'ai créé en trois.js. Sur la base de certaines données, je veux créer un ensemble de flèches qui est décoré par une petite étiquette de texte. Ces étiquettes doivent être en 2D.

Il semble que j'ai deux alternatives: soit utiliser un élément canvas séparé pour créer une texture qui à son tour est utilisée dans le modèle 3D, soit utiliser du HTML sur l'élément canvas du modèle 3D.

Je me demande comment s'y prendre. Quelle est la façon "correcte" de le faire? Des suggestions et des exemples le code est le bienvenu!

28
demandé sur WestLangley 2013-03-06 17:38:37

7 réponses

Si cela ne vous dérange pas que le texte sera toujours au - dessus (par exemple, si l'objet est bloqué par quelque chose d'autre, son étiquette de texte sera toujours visible et au-dessus de tout le reste), et que le texte ne sera pas affecté par un rendu comme lights/shadow, etc, alors HTML est le moyen le plus simple d'aller

Voici un exemple de 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);

Remplacez 200 dans le style.top et style.variables de gauche pour les coordonnées y et x (respectivement) que vous souhaitez placer le texte. Ils seront valeurs positives où (0,0) est en haut à gauche de la toile. Pour obtenir des conseils sur la façon de projeter du point 3D de votre canevas vers un point 2D en pixels dans la fenêtre de votre navigateur, utilisez un extrait de code comme suit:

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

Assurez-vous que vous avez appelé la caméra.updateMatrixWorld () au préalable.

36
répondu kronuus 2013-03-08 14:51:13

Si vous voulez réellement inclure du texte (ou n'importe quelle image) d'un objet canvas dans votre scène 3D, consultez l'exemple de code à: http://stemkoski.github.com/Three.js/Texture-From-Canvas.html

18
répondu Lee Stemkoski 2013-03-12 21:54:22

Découvrez la démo.

TextGeometry consomme beaucoup de mémoire et vous devez charger une police, qui contient une géométrie pour chaque lettre, que vous utiliserez. Si j'ai plus de 100 maillages de texte dans une scène, mon navigateur se bloque.

Vous pouvez dessiner du texte sur un canevas et l'inclure dans votre scène via un Sprite. Le problème est que vous devez calculer la taille de la police. Si vous avez une caméra mobile, vous devez calculer la taille de la police périodiquement. Sinon, l' le texte deviendra flou, si vous vous rapprochez trop du texte avec l'appareil photo.

J'ai écrit une classe TextSprite {[9] } qui calcule automatiquement la meilleure taille de police possible, en fonction de la distance à la caméra et de la taille de l'élément de rendu. L'astuce consiste à utiliser le callback .onBeforeRender de la classe Object3D, qui reçoit l'appareil photo et le rendu.

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

Vous pouvez également modifier le texte, la taille du texte et la police à la volée.

sprite.textSize = 25;
sprite.material.map.text = 'Hello Stack Overflow!';
sprite.material.map.fontFamily = 'Tahoma, Geneva, sans-serif';
9
répondu SeregPie 2017-09-15 09:02:44

Update : cette méthode est obsolète maintenant et est lourde de CPU, ne l'utilisez pas.

J'ai découvert un autre seulement trois.solution basée sur 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};

Maintenant, pour éditer ce texte dynamiquement,

var textShapes = THREE.FontUtils.generateShapes( text, options );
var text = new THREE.ShapeGeometry( textShapes );
textMesh.geometry = text;
textMesh.geometry.needsUpdate = true;
8
répondu Ishan Sharma 2017-11-21 15:00:24

J'ai publié un module sur NPM qui le fait pour vous: https://github.com/gamestdio/three-text2d

Il vous permet d'avoir un Sprite ou Mesh avec le texte rendu sans traiter le canevas manuellement.

Exemple:

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

var text = new Text2D("Hello world!", { font: '30px Arial', fillStyle: '#000000', antialias: true })
scene.add(text) 
7
répondu Endel 2016-01-23 16:27:04

Vous pouvez créer un canevas 2d et utiliser css pour le positionner en haut de votre canevas webgl. Ensuite, vous pouvez dessiner du texte à l'aide des méthodes ctx.fillText(text,x,y) ou ctx.strokeText(text,x,y) fournies par le contexte de canevas 2d. En utilisant cette méthode, vous pouvez dessiner d'autres choses que du texte, telles que des flèches et des mètres.

Vous pouvez utiliser la méthode suggérée par @kronuus pour convertir un point de 3d en espace 2d.

5
répondu Licson 2013-03-08 15:16:41

La réponse de @LeeStemkoski était très utile. Pourtant, il y a un léger changement qui doit être apporté au code pour que le texte suive vos flèches autour de , c'est-à-dire au cas où la flèche serait déplacée, pivotée, etc.

Voir le code suivant

                        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)

Comme vous pouvez le voir, le truc est d'ajouter le texte (mesh1) à l'shape (votre "flèche") au lieu de l'ajouter à la scène.

J'espère que cela aide.

1
répondu Hugo Nava Kopp 2016-03-30 16:28:27