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();
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.
[example:webgl_custom_attributes WebGL / personnalisé / attributs]
[example:webgl_buffergeometry_custom_attributes_particles WebGL / buffergeometry / personnalisé / attributs / particules]
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) :
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 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.
[example:webgl_materials_car WebGL / matériaux / voiture]
[example:webgl_postprocessing_dof WebGL / webgl_postprocessing / dof]
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.
[example:webgl_materials_video WebGL / matériaux / vidéo]
[example:webgl_rtt WebGL / rtt]
La position et la cible d'une caméra sont mises à jour automatiquement. Si vous avez besoin de changer
alors vous devrez recalculer la matrice de projection :
camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix();
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
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).