web-dev-qa-db-fra.com

Tracer une ligne avec three.js dynamiquement

C'est ce que j'aimerais réaliser (un polygone modifiable où les cercles rouges sont des sommets) et je voudrais construire le polygone de manière dynamique.

enter image description here

Lors du lancement de la géométrie

var geometry = new THREE.Geometry();

geometry.vertices.Push(point);
geometry.vertices.Push(point);

var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({}));

cela fonctionne bien jusqu'au deuxième clic, il crée une ligne droite entre 1 et 2 mais n'ajoute pas de troisième ligne quand il est poussé vers le tableau. WebGL semble exiger des points tamponnés.

Lorsque je prédéfinis des sommets comme celui-ci, je peux dessiner deux lignes (troisième clic)

var geometry = new THREE.Geometry();

for (var i = 0; i < 4; i++) {
    geometry.vertices.Push(point);
}

var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({}));

mais ce n'est pas une bonne solution car je ne sais pas combien de sommets l'utilisateur veut ajouter et il est inutile de lui attribuer un grand nombre car je dois le boucler plusieurs fois.

Y a-t-il un moyen de contourner cela?

14
user3960875

Vous pouvez animer une ligne - ou augmenter le nombre de points rendus - très facilement en utilisant BufferGeometry et la méthode setDrawRange(). Vous devez cependant définir un nombre maximum de points.

var MAX_POINTS = 500;

// geometry
var geometry = new THREE.BufferGeometry();

// attributes
var positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );

// draw range
drawCount = 2; // draw the first 2 points, only
geometry.setDrawRange( 0, drawCount );

// material
var material = new THREE.LineBasicMaterial( { color: 0xff0000 } );

// line
line = new THREE.Line( geometry,  material );
scene.add( line );

Vous définissez les données de position à l'aide d'un modèle comme celui-ci:

var positions = line.geometry.attributes.position.array;

var x = y = z = index = 0;

for ( var i = 0, l = MAX_POINTS; i < l; i ++ ) {

    positions[ index ++ ] = x;
    positions[ index ++ ] = y;
    positions[ index ++ ] = z;

    x += ( Math.random() - 0.5 ) * 30;
    y += ( Math.random() - 0.5 ) * 30;
    z += ( Math.random() - 0.5 ) * 30;

}

Si vous souhaitez modifier le nombre de points rendus après le premier rendu, procédez comme suit:

line.geometry.setDrawRange( 0, newValue );

Si vous souhaitez modifier les valeurs de données de position après le premier rendu, vous définissez l'indicateur needsUpdate comme suit:

line.geometry.attributes.position.needsUpdate = true; // required after the first render

Voici un violon montrant une ligne animée que vous pouvez adapter à votre cas d'utilisation.


EDIT: Voir cette réponse pour une technique que vous aimeriez mieux - surtout si la ligne ne comprend que quelques points.

three.js r.84

36
WestLangley

J'ai mis à jour le violon avec des événements de souris et un tableau de vecteurs si vous voulez griffonner à main levée.

https://jsfiddle.net/w67tzfhx/40/

function onMouseDown(evt) {

    if(evt.which == 3) return;


    var x = ( event.clientX / window.innerWidth ) * 2 - 1;
    var y =  - ( event.clientY / window.innerHeight ) * 2 + 1;

    // do not register if right mouse button is pressed.

    var vNow = new THREE.Vector3(x, y, 0);
    vNow.unproject(camera);
    console.log(vNow.x + " " + vNow.y+  " " + vNow.z); 
    splineArray.Push(vNow);

    document.addEventListener("mousemove",onMouseMove,false);
    document.addEventListener("mouseup",onMouseUp,false);
}
7
user3325025

Tracez une ligne en temps réel

Ici un violon mis à jour où j'ai optimisé le code de user3325025 son exemple; Dans ce cas, il n'est absolument pas nécessaire de mettre à jour tous les points de la ligne lors du rendu. La mise à jour est uniquement nécessaire onMouseMove (mise à jour de fin de ligne) et onMouseDown (dessin d'un nouveau point):

// update line
function updateLine() {
  positions[count * 3 - 3] = mouse.x;
  positions[count * 3 - 2] = mouse.y;
  positions[count * 3 - 1] = mouse.z;
  line.geometry.attributes.position.needsUpdate = true;
}

// mouse move handler
function onMouseMove(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  mouse.z = 0;
  mouse.unproject(camera);
  if( count !== 0 ){
    updateLine();
  }
}

// add point
function addPoint(event){
  positions[count * 3 + 0] = mouse.x;
  positions[count * 3 + 1] = mouse.y;
  positions[count * 3 + 2] = mouse.z;
  count++;
  line.geometry.setDrawRange(0, count);
  updateLine();
}
7
Wilt