Comment mettre à jour les éléments

Par défaut, tous les objets mettent automatiquement à jour leurs matrices s'ils ont été ajoutés à la scène avec

const object = new THREE.Object3D();
scene.add( object );
ou s'ils sont l'enfant d'un autre objet qui a été ajouté à la scène :
const object1 = new THREE.Object3D();
const object2 = new THREE.Object3D();

object1.add( object2 );
scene.add( object1 ); //object1 et object2 mettront automatiquement à jour leurs matrices

Cependant, si vous savez que l'objet sera statique, vous pouvez désactiver cela et mettre à jour la matrice de transformation manuellement uniquement lorsque nécessaire.

object.matrixAutoUpdate = false;
object.updateMatrix();

BufferGeometry

Les BufferGeometries stockent des informations (telles que les positions des sommets, les indices des faces, les normales, les couleurs, les UV et tout attribut personnalisé) dans des tampons d'attributs - c'est-à-dire des [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays tableaux typés]. Cela les rend généralement plus rapides que les Geometries standard, au prix d'être un peu plus difficiles à utiliser.

En ce qui concerne la mise à jour des BufferGeometries, la chose la plus importante à comprendre est que vous ne pouvez pas redimensionner les tampons (c'est très coûteux, c'est fondamentalement l'équivalent de la création d'une nouvelle géométrie). Vous pouvez cependant mettre à jour le contenu des tampons.

Cela signifie que si vous savez qu'un attribut de votre BufferGeometry va croître, par exemple le nombre de sommets, vous devez pré-allouer un tampon suffisamment grand pour contenir tous les nouveaux sommets qui pourraient être créés. Bien sûr, cela signifie également qu'il y aura une taille maximale pour votre BufferGeometry - il n'y a aucun moyen de créer une BufferGeometry qui puisse être étendue efficacement indéfiniment.

Nous utiliserons l'exemple d'une ligne qui s'étend au moment du rendu. Nous allouerons de l'espace dans le tampon pour 500 sommets, mais n'en dessinerons que deux au début, en utilisant `BufferGeometry.drawRange`.

const MAX_POINTS = 500;

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

// attributes
const positions = new Float32Array( MAX_POINTS * 3 ); // 3 floats (x, y et z) par point
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );

// draw range
const drawCount = 2; // dessine seulement les 2 premiers points, seulement
geometry.setDrawRange( 0, drawCount );

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

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

Ensuite, nous ajouterons aléatoirement des points à la ligne en utilisant un modèle comme :

const positionAttribute = line.geometry.getAttribute( 'position' );

let x = 0, y = 0, z = 0;

for ( let i = 0; i < positionAttribute.count; i ++ ) {

    positionAttribute.setXYZ( i, x, y, 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, faites ceci :

line.geometry.setDrawRange( 0, newValue );

Si vous souhaitez modifier les valeurs des données de position après le premier rendu, vous devez définir le drapeau needsUpdate comme suit :

positionAttribute.needsUpdate = true; // requis après le premier rendu

Si vous modifiez les valeurs des données de position après le rendu initial, vous pourriez avoir besoin de recalculer les volumes englobants afin que d'autres fonctionnalités du moteur comme le culling par frustum de vue ou les assistants fonctionnent correctement.

line.geometry.computeBoundingBox();
line.geometry.computeBoundingSphere();

[link:https://jsfiddle.net/t4m85pLr/1/ Voici un fiddle] montrant une ligne animée que vous pouvez adapter à votre cas d'utilisation.

Exemples

[example:webgl_custom_attributes WebGL / personnalisé / attributs]
[example:webgl_buffergeometry_custom_attributes_particles WebGL / buffergeometry / personnalisé / attributs / particules]

Matériaux

Toutes les valeurs des uniforms peuvent être modifiées librement (par exemple couleurs, textures, opacité, etc.), les valeurs sont envoyées au shader à chaque image.

De plus, les paramètres liés à l'état GL peuvent changer à tout moment (depthTest, blending, polygonOffset, etc.).

Les propriétés suivantes ne peuvent pas être facilement modifiées à l'exécution (une fois que le matériau a été rendu au moins une fois) :

  • nombre et types des uniforms
  • présence ou non de
    • texture
    • brouillard
    • couleurs de sommet
    • morphing
    • shadow map
    • test alpha
    • transparent

Les modifications de ces éléments nécessitent la construction d'un nouveau programme de shader. Vous devrez définir

material.needsUpdate = true

Gardez à l'esprit que cela peut être assez lent et provoquer des à-coups dans la cadence d'images (surtout sous Windows, car la compilation des shaders est plus lente en DirectX qu'en OpenGL).

Pour une expérience plus fluide, vous pouvez émuler dans une certaine mesure les modifications de ces fonctionnalités en utilisant des valeurs "factices" comme des lumières d'intensité nulle, des textures blanches ou un brouillard de densité nulle.

Vous pouvez modifier librement le matériau utilisé pour les morceaux de géométrie, cependant, vous ne pouvez pas modifier la façon dont un objet est divisé en morceaux (selon les matériaux des faces).

Si vous avez besoin d'avoir différentes configurations de matériaux pendant l'exécution :

Si le nombre de matériaux / morceaux est faible, vous pouvez pré-diviser l'objet à l'avance (par exemple cheveux / visage / corps / vêtements du haut / pantalon pour un humain, avant / côtés / haut / verre / pneu / intérieur pour une voiture).

Si le nombre est élevé (par exemple, chaque face pourrait être potentiellement différente), envisagez une solution différente, telle que l'utilisation d'attributs / textures pour piloter un aspect différent par face.

Exemples

[example:webgl_materials_car WebGL / matériaux / voiture]
[example:webgl_postprocessing_dof WebGL / webgl_postprocessing / dof]

Textures

Les textures d'image, de canevas, de vidéo et de données doivent avoir le drapeau suivant défini si elles sont modifiées :

texture.needsUpdate = true;

Les cibles de rendu se mettent à jour automatiquement.

Exemples

[example:webgl_materials_video WebGL / matériaux / vidéo]
[example:webgl_rtt WebGL / rtt]

Caméras

La position et la cible d'une caméra sont mises à jour automatiquement. Si vous avez besoin de changer

  • fov
  • aspect
  • near
  • far

alors vous devrez recalculer la matrice de projection :

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

InstancedMesh

InstancedMesh est une classe permettant d'accéder facilement au rendu instancié dans three.js. Certaines fonctionnalités de la bibliothèque comme le culling par frustum de vue ou le ray casting dépendent de volumes englobants à jour (sphère englobante et boîte englobante). En raison de la façon dont InstancedMesh fonctionne, la classe possède ses propres propriétés boundingBox et boundingSphere qui remplacent les volumes englobants au niveau de la géométrie.

Similaire aux géométries, vous devez recalculer la boîte englobante et la sphère chaque fois que vous modifiez les données sous-jacentes. Dans le contexte de InstancedMesh, cela se produit lorsque vous transformez des instances via setMatrixAt(). Vous pouvez utiliser le même modèle qu'avec les géométries.

instancedMesh.computeBoundingBox();
instancedMesh.computeBoundingSphere();

SkinnedMesh

SkinnedMesh suit les mêmes principes que InstancedMesh en ce qui concerne les volumes englobants. Cela signifie que la classe a sa propre version de boundingBox et boundingSphere pour enfermer correctement les maillages animés. Lors de l'appel de computeBoundingBox() et computeBoundingSphere(), la classe calcule les volumes englobants respectifs en fonction de la transformation actuelle des os (ou en d'autres termes, de l'état d'animation actuel).