Three.js: Demande de fonctionnalité : augmenter les performances de détection des collisions raycaster grâce à des arbres de recherche spatiale

Créé le 11 déc. 2017  ·  36Commentaires  ·  Source: mrdoob/three.js

J'ai construit une application VR similaire à WebVR-Vive-Dragging qui permet d'interagir avec de nombreux objets 3D à l'aide de contrôleurs VR. Cela signifie qu'un utilisateur peut saisir un objet avec un contrôleur VR et peut le déplacer ou le redimensionner.

Problème : Lorsqu'il y a des objets 3D complexes dans la scène, c'est-à-dire des objets THREE.Mesh ayant des géométries avec un très grand nombre de sommets, alors le raycasting lors de la détection de collision devient très lent. Par conséquent, le problème est la complexité de la géométrie d'un objet.

Il existe des structures de données arborescentes pour une recherche spatiale rapide, telles que Octree ou R-Tree . J'ai trouvé threeocttree qui permet de diviser une géométrie en plus petits morceaux mais il semble qu'il soit un peu obsolète (Three.js r60).

Autant que je sache, dans la méthode $#$2$ THREE.Mesh l'objet raycast , il y a déjà quelques optimisations de performances (vérification de la boîte englobante et de la sphère avant de faire un raycast réel). Peut-être serait-il judicieux d'avoir une autre étape de vérification de ce type à l'aide d'arbres de recherche spatiale ? ! Qu'est-ce que tu penses?

Sincères amitiés

Enhancement

Commentaire le plus utile

J'ai suggéré que l'index spatial soit inclus dans threejs dans le passé. Il y a eu du travail dans cette direction, et l'exemple d'oct-tree existant en fait partie. En fin de compte, je pense que c'est le manque d'intérêt de la part de la communauté centrale à l'égard d'avoir cette fonctionnalité en tant que citoyen de première classe sur trois.

Je serais heureux de faire don de mon code BVH au projet, s'il y a suffisamment d'intérêt et d'intention pour l'inclure dans la distribution principale (pas d'exemples).
Mon code se concentre sur 2 aspects :

  • scènes dynamiques

    • insertion rapide

    • suppression rapide

    • réaménagement (possibilité pour les nœuds de changer de forme sans avoir à être réinsérés)

  • vitesse de requête

J'ai 2 implémentations :

  • BinaireBVH

    • très compact, utilisant ByteBuffer

    • mélange de types UintX et FloatX via DataView

    • idéal pour la sérialisation

    • peut être compressé à l'aide d'outils standard tels que la bibliothèque lzma

    • immuable

    • la vitesse de construction est hautement optimisée

    • ne fonctionne que pour BufferGeometry

    • Optimisation SAH

    • requêtes de rayon

  • BVH

    • L'arborescence d'objets, par conséquent, est beaucoup plus grande que l'implémentation binaire

    • mutable

    • insertion en vrac rapide

    • insertion rapide d'un seul article

    • réaménagement

    • implémentations de traversée de pile, récursives et sans pile (différentes caractéristiques de performance)

    • Optimisation SAH

    • Requêtes tronquées

    • Requêtes de rayon

Personnellement, je ne peux pas vivre sans un index spatial, c'est une différence entre les performances n^2 et log(n). Par exemple, dans mon projet actuel, les parties suivantes reposent sur l'index spatial :

  • système de feuillage (arbres, fleurs, buissons, etc.)
  • tous les placements d'objets (personnages et maisons)
  • sélection (utilisé dans les interactions, telles que les clics de souris)

http://server1.lazy-kitty.com/komrade

le terrain a des polygones d'environ 1 m, et placer des milliers d'arbres et exécuter des lancers de rayons en temps réel dessus est tout simplement interdit, en particulier pour les appareils bas de gamme.

Tous les 36 commentaires

Au risque d'énoncer l'évidence, mais avez-vous essayé la version de threeocttree qui se trouve déjà dans le repo( examples/js/Octree.js ) ?

Je ne vote pas pour une utilisation câblée des arbres de recherche spatiale dans three.js . La surcharge/complexité de tels algorithmes compense le gain de performances dans de nombreuses applications.

vérifier d'abord la boîte englobante et la sphère avant de faire un raycast réel

C'est raisonnable et devrait suffire. Si les utilisateurs ont besoin de plus de performances dans le contexte de cas d'utilisation plus avancés, ils peuvent utiliser l'exemple mentionné comme point de départ. Octrees pourrait être un bon choix. Mais je n'ai jamais vu de solution R-Tree dans les applications 3D interactives car son approche est assez sophistiquée (l'algorithme effectue des données au lieu de partitionner l'espace).

Bonjour et merci pour vos réponses,
@ Mugen87 Je reconnais que de nombreux cas d'utilisation ne nécessitent pas de recherches aussi rapides. Cependant, ayant un mécanisme pour interagir avec des objets 3D (et je suppose que c'est le cas pour lequel il est principalement utilisé), l'étape de THREE.Raycaster consiste à vérifier d'abord la boîte englobante/sphère (ce que je suis tout à fait d'accord pour être raisonnable ) dans disons un temps constant à un effort de temps linéaire lorsque le raycast réel est assez important. Je pourrais imaginer une sorte "d'arbre de recherche par géométrie" au lieu d'un arbre de recherche global. Tant que la géométrie ne change pas (souvent, les transformations sont beaucoup plus probables que les changements de géométrie), l'arbre de recherche n'a pas besoin d'être mis à jour.

C'est pourquoi j'ai pensé qu'un tel type d'optimisation utilisant des arbres de recherche spatiale pourrait faire partie intégrante de three.js . Mais je comprends également que cela entraîne une complexité et des frais généraux supplémentaires.

@moraxy Je vais jeter un œil à la version d'exemple. Je voulais juste savoir si une telle fonctionnalité aurait du sens.

Merci encore et cordialement

Peut-être qu'un arbre de recherche plus simple pourrait être intégré dans THREE.BufferGeometry . Par exemple, un appel à computeBoundingBox pourrait également construire une sorte d'arbre de recherche en lecture seule référençant les sommets correspondants. Puisque THREE.BufferGeometry est

mieux adapté aux objets statiques où vous n'avez pas besoin de beaucoup manipuler la géométrie après l'avoir instanciée

cet arbre de recherche n'a pas besoin d'être modifié après l'avoir initialisé. Cela réduirait certains frais généraux pour la mise à jour/suppression. Un Octree serait un bon point de départ ( concept similaire dans BabylonJS ).

mieux adapté aux objets statiques où vous n'avez pas besoin de beaucoup manipuler la géométrie après l'avoir instanciée

FWIW, je ne crois pas que ce soit une déclaration vraie.

@WestLangley Citation de la documentation THREE.BufferGeometry

Documentation THREE.BufferGeometry

Il devrait probablement être supprimé - en tout cas, je ne pense pas qu'il s'agisse d'une déclaration technique, mais plutôt qu'il est plus difficile pour l'utilisateur de manipuler la géométrie après sa création.

Il devrait probablement être supprimé

Très certainement.

Je viens d'implémenter une meilleure méthode de raycasting sur PlaneBufferGeometry. J'utilise le paramètre far et trouve les premières et dernières positions d'index. Cela fonctionne dans planebuffer car le tableau d'index est dans l'ordre x/y. Une fois à l'extérieur de la zone de délimitation x/y, toutes les collisions doivent être à l'extérieur de la plage éloignée. Y a-t-il une volonté de commettre cela quelque part? L'implémentation actuelle est spécifique à mon cas d'utilisation, mais je serais prêt à essayer de rendre plus générique si vous le souhaitez. J'ai pu réduire considérablement mes performances de raycasting sur un grand avionBuffer (2,5 secondes à 10 ms)

@kpetrow Je pense que les exemples octree three.js sont adéquats. Vous êtes bien sûr libre de partager votre code sur GitHub si vous pensez qu'il serait utile à d'autres.

J'ai suggéré que l'index spatial soit inclus dans threejs dans le passé. Il y a eu du travail dans cette direction, et l'exemple d'oct-tree existant en fait partie. En fin de compte, je pense que c'est le manque d'intérêt de la part de la communauté centrale à l'égard d'avoir cette fonctionnalité en tant que citoyen de première classe sur trois.

Je serais heureux de faire don de mon code BVH au projet, s'il y a suffisamment d'intérêt et d'intention pour l'inclure dans la distribution principale (pas d'exemples).
Mon code se concentre sur 2 aspects :

  • scènes dynamiques

    • insertion rapide

    • suppression rapide

    • réaménagement (possibilité pour les nœuds de changer de forme sans avoir à être réinsérés)

  • vitesse de requête

J'ai 2 implémentations :

  • BinaireBVH

    • très compact, utilisant ByteBuffer

    • mélange de types UintX et FloatX via DataView

    • idéal pour la sérialisation

    • peut être compressé à l'aide d'outils standard tels que la bibliothèque lzma

    • immuable

    • la vitesse de construction est hautement optimisée

    • ne fonctionne que pour BufferGeometry

    • Optimisation SAH

    • requêtes de rayon

  • BVH

    • L'arborescence d'objets, par conséquent, est beaucoup plus grande que l'implémentation binaire

    • mutable

    • insertion en vrac rapide

    • insertion rapide d'un seul article

    • réaménagement

    • implémentations de traversée de pile, récursives et sans pile (différentes caractéristiques de performance)

    • Optimisation SAH

    • Requêtes tronquées

    • Requêtes de rayon

Personnellement, je ne peux pas vivre sans un index spatial, c'est une différence entre les performances n^2 et log(n). Par exemple, dans mon projet actuel, les parties suivantes reposent sur l'index spatial :

  • système de feuillage (arbres, fleurs, buissons, etc.)
  • tous les placements d'objets (personnages et maisons)
  • sélection (utilisé dans les interactions, telles que les clics de souris)

http://server1.lazy-kitty.com/komrade

le terrain a des polygones d'environ 1 m, et placer des milliers d'arbres et exécuter des lancers de rayons en temps réel dessus est tout simplement interdit, en particulier pour les appareils bas de gamme.

J'aimerais voir tout ce qui rend Raycast optimisé. Y a-t-il une marge d'optimisation sans ajouter de complexité ? Octree nécessite toute nouvelle bibliothèque, avec tous les nouveaux ajouts et mises à jour, etc.

Une chose que je remarque est qu'une fois qu'une géométrie est convertie en un tableau de tampons indexé, elle n'utilise plus intelligemment les propriétés de la géométrie d'origine. Comme mentionné ci-dessus, les géométries de tampon de plan peuvent être super optimisées en sachant que le arrayBuffer provient d'un PlaneGeometry. Peut-être écraser la méthode MESH.raycast ( raycaster, intersects ) pour qu'elle soit basée sur le type de géométrie ?

Une autre approche consiste à avoir Raycaster en tant que plug-in séparé, tout comme les commandes interactives et les chargeurs. Ensuite, ajouter un raycaster performant similaire à ce que propose @Usnul serait génial.

J'aime l'idée d'avoir des Raycasters enfichables, mais je pense qu'il y a un peu de confusion. Ce que je pense être utile, c'est un index spatial, pas un Raycaster en soi. L'index spatial permet des choses comme :

  • abattage spatial (pensez abattage frustum)
  • effectuer des requêtes de visibilité
  • construire un moteur de rendu de traçage de chemin
  • tri rapide (exploitation de la localité des données)

actuellement, three.js en fait 2 explicitement (tri et élimination) et 1 via des exemples (rendu de lancer de rayons)

le maintien d'un index spatial en interne accélérerait le tri et l'élimination, offrant progressivement plus d'avantages pour les scènes plus grandes au prix de la RAM supplémentaire nécessaire pour stocker l'index.

Pourquoi n'utilisez-vous pas simplement la sélection GPU ? Il y a quelques exemples autour et c'est assez facile à mettre en œuvre. Le spectacle est de jour comme de nuit. Dans nos cas d'utilisation, avec des modèles de plus d'un million de polygones, la sélection est passée de près d'une seconde à une exécution en temps réel à 60 ips tout en faisant glisser des éléments sur le modèle.

https://github.com/brianxu/GPUPicker

@hccampos
La sélection du GPU n'est pas nécessairement plus rapide que de le faire sur le CPU, pour le GPU, vous devez rendre à une résolution proportionnelle à la précision que vous désirez, donc si vous voulez une précision de pixel - vous devez rendre à une résolution d'écran de 1:1. Gardez à l'esprit qu'il s'agit d'une passe de rendu distincte, vous rendez les objets sous forme de couleurs distinctes distinctes. Une passe de rendu supplémentaire signifie une utilisation de la mémoire graphique (typique pour le pipeline différé).
L'utilisation d'un index de partitionnement d'espace binaire vous donne un profil de synchronisation log(n) sur votre sélection, donc pour 1 000 000 de polygones, vous auriez besoin d'environ 14 opérations pour résoudre une requête de rayon. En fonction de votre structure de données, cela prendra probablement quelques microsecondes, ce qui vous permettra d'effectuer des milliers de requêtes avant de commencer à réduire votre budget cadre.

Faisons une comparaison, disons que vous avez un modèle poly de 1 m et que vous souhaitez projeter un rayon depuis l'espace de l'écran directement le long de la direction de la caméra dans la scène (choix du cas d'utilisation). Supposons que vous optiez pour la résolution du bas du baril, "full hd", ou 1920 × 1080. Supposons que vous rendiez RVB uniquement (24 bits par pixel), vous aurez besoin de 6220800 octets (environ 6 Mo) ou RAM graphique pour rendre ce. Si vous utilisez une solution CPU, disons que vous optez pour AABB BVH avec 10 polygones par feuille, cela signifie que vous avez besoin d'environ 200 000 nœuds, disons que chaque nœud est d'environ 6 * 8 octets pour les coordonnées, les nœuds intermédiaires ont 2 * 4 octets supplémentaires pour les pointeurs enfants et les nœuds feuilles ont 10 * 4 octets pour le pointeur de polygone, soit 14 400 000 octets (environ 14 Mo). La principale différence entre en jeu lorsque vous considérez le fait que vos requêtes BVH nécessitent très peu de bande passante RAM, par rapport au cas GPU, et qu'il n'y a qu'une poignée d'opérations impliquées par requête, par rapport au rendu d'une géométrie poly complète de 1 m.
Si vous prenez une résolution plus typique pour les ordinateurs de bureau, comme 2560x1440, vous vous retrouvez avec une cible de rendu de 11059200 octets (11 Mo).

Si vous disposez d'un budget important de bande passante RAM graphique et d'un nombre de cœurs de shader assez décent, bien sûr, c'est une manière simple et directe de choisir.

@Usnul absolument, mais c'est probablement la solution la plus simple à mettre en œuvre. La mise en œuvre et la maintenance des structures de données d'index spatiales seront probablement un fardeau non négligeable pour les mainteneurs des trois JS.

Cela étant dit, j'aimerais absolument avoir une bonne structure de données d'index spatial bien testée et maintenue dans le cadre de trois ou d'un package npm séparé.

J'étais curieux de mettre en œuvre un tel index spatial pour mes géométries utilisées, j'ai donc implémenté un Octree assez simple (création et recherche uniquement) qui divise mon BufferGeomtry. Avec cette solution simple, j'ai obtenu des résultats assez prometteurs : appliqué sur une géométrie avec environ 500 000 vertices, le temps de raycast a été réduit de ~120 ms à ~2,3 ms. La construction de l'arborescence prend actuellement environ 500 ms, mais comme la création de la géométrie et de l'arborescence n'est effectuée qu'une seule fois dans un Web Worker au démarrage de l'application, ce n'est pas un tel problème.

Je suppose que l'algorithme pourrait être assez facilement intégré dans THREE.BufferGeometry et peut-être activé ou désactivé à l'aide d'un indicateur tel que THREE.BufferAttribute 's dynamic . De cette façon, il ne peut être utilisé que lorsque BufferGeometry n'est pas censé changer. Malheureusement, j'ai dû écraser la méthode $#$4$# THREE.Mesh de raycast bien que je n'aie eu besoin que de changer deux lignes (appel de recherche Octree et itération de tableau de position).

Quoi qu'il en soit, dans mon application VR, je dois détecter les collisions objet-contrôleur pendant la boucle de rendu et pas une seule fois lors d'un clic de souris. Ainsi, je dois compter sur ma solution actuelle. Je vais essayer si je peux encore l'améliorer.

MISE À JOUR J'ai fait une erreur en mesurant le temps de raycast. La valeur correcte est ~2,3 ms (au lieu de ~0,3 ms). J'ai modifié la valeur ci-dessus en conséquence.

Je pense qu'il est nécessaire d'avoir un moyen opt-in d'effectuer des recherches spatiales rapides dans la plupart des applications plus complexes construites sur three.js. Par exemple, un éditeur 3D. J'ai joué avec certaines implémentations, mais soit elles ne s'intègrent pas bien, soit elles s'intègrent trop étroitement dans une version spécifique de three.js. Donc, si quelqu'un a la possibilité de le faire sans interrompre le chemin de mise à niveau vers les nouvelles versions de three.js, ce serait formidable.

@matthias-w J'ai essayé le raycaster pour un modèle obj mais le contrôleur ne détecte rien. Les rayons traversent le modèle. Pouvez-vous me dire comment vous avez résolu ce problème

Au sujet de l'index spatial facultatif. Je pense qu'il est suffisamment utile même que le moteur de rendu lui-même (par exemple pour le culling) fasse partie intégrante du moteur. Voici une discussion connexe :

13909

Hé! Cela m'intéressait un peu aussi (bien que j'aie depuis trouvé d'autres solutions pour nos besoins de raycast), mais j'ai pensé que je contribuerais aussi à certaines de mes expériences. C'est un peu dur, mais j'ai mis ça en place il y a quelques mois :

https://github.com/gkjohnson/threejs-fast-raycast

Il ajoute une fonction computeBoundsTree aux TROIS objets géométriques et remplace la fonction raycast pour l'utiliser (et ne renvoie que le premier coup en tant qu'optimisation supplémentaire). Il n'est vraiment bénéfique que pour les maillages statiques très complexes et ne fait rien pour segmenter spatialement la scène. Voici la démo où vous pouvez voir la différence de performances de raycast sur un maillage de 80 000 triangles. Le calcul de l'arbre des limites est un peu lent, mais avec un peu de travail, cela pourrait probablement être plus fluide.

En ce qui concerne mon opinion à ce sujet, je me sens un peu en conflit. Cela ressemble à quelque chose qui peut être assez bien construit comme une extension de TROIS. Et finalement, il ne semble pas que faire des vérifications / collisions / moulages par triangle pour des maillages complexes ou animés soit optimal, de toute façon. Dans des cas simples, cela peut convenir, mais il semble que l'utilisation des représentations typiques plan / cube / sphère / capsule ou des maillages simplifiés serait mieux adaptée pour permettre un raycasting ultra-rapide (ou occlusion-culling, collisions, etc.) dans des cas complexes. Bien sûr, si vous recherchez des moulages au pixel près, cela ne fonctionne pas aussi bien, mais la bonne solution dépend vraiment de votre cas d'utilisation.

@Usnul @matthias-w Vos implémentations octree / BVH sont-elles open source ou disponibles en ligne ? Je serais certainement intéressé à jeter un œil!

@gkjohnson

L'une de vos implémentations octree / BVH est-elle open source ou disponible en ligne ? Je serais certainement intéressé à jeter un œil!

Le code n'est pas open source actuellement. Je pourrais vous fournir les sources si vous me contactez en privé.

Il y a un exemple que j'ai fait pour les maillages instanciés :
http://server1.lazy-kitty.com/tests/instanced-foliage-1mil/
L'exemple ci-dessus comprend les éléments suivants :

  • BVH est mis à jour dynamiquement lorsque de nouvelles instances sont insérées dans l'arborescence
  • Le BVH est optimisé progressivement en utilisant des rotations de profondeur 1-2 à la volée
  • BVH est échantillonné avec une requête frustum dans laquelle les instances doivent être rendues

J'en ai une version en cours d'exécution dans le jeu sur lequel je travaille:
http://server1.lazy-kitty.com/komrade/

En ce qui concerne votre mise en œuvre. Je l'aime bien, le mien est différent de 2 manières principales:

  • Je me concentre sur les performances
  • Je me concentre sur l'empreinte mémoire
  • J'évite le ramassage des ordures dans de nombreux endroits

Quelques points plus spécifiques :

  • J'utilise également un mélange de stratégies de fractionnement de manière transparente, en fonction de ce que vous voulez faire avec le BVH
  • Mon BVH est basé sur AABB
  • Je prends en charge les mises à jour des limites des nœuds via le réaménagement

@Usnul Je ne vois pas votre adresse e-mail ou quoi que ce soit, mais je suis très intéressé par l'étude de votre solution d'indexation spatiale.

Actuellement, je parcours simplement tous les objets de scène pertinents et calcule la distance de la caméra. Pas l'approche la plus optimale.

@titansoftime
c'est
travnick at gmail com
Je n'avais pas réalisé que ce n'était pas accessible au public. Ma faute.

@Usnul Je suis également intéressé par le projet d'un million. Peut-être même 10 ou 20 millions si possible. S'il vous plaît écrivez-moi: kaori.nakamoto. [email protected]

Merci TRÈS cordialement !

Désolé pour la réponse tardive.
@gkjohnson Le code n'est pas open source. De plus, votre solution semble beaucoup plus sophistiquée que la mienne. Ainsi, je suppose qu'il n'y a pas grand-chose à apprendre de ma solution.

@ sid3007 Je ne suis pas sûr de comprendre votre problème. Je peux expliquer ma démarche. Peut-être que c'est utile.

Mon cas d'utilisation est assez simple. Lorsque mon application démarre, les géométries des différents modèles sont chargées. Ces modèles peuvent être transformés par l'utilisateur. Les géométries ne changent pas. Il n'y a pas de déformations géométriques. Par conséquent, j'ai implémenté un Octree très simple qui est construit une fois pour chaque géométrie au démarrage de l'application. L'octree n'est pas dynamique. Il est construit sur la base de la boîte englobante de la géométrie donnée et du tableau de sommets. Au cours de sa construction, il vérifie si un octant contient un sommet ou si la boîte englobante Box3 l'octant coupe un triangle (trois sommets consécutifs dans une géométrie non indexée) et stocke les références du tableau de sommets avec le nœud de l'octree.
L'octree par maillage est ensuite stocké avec le maillage. J'écrase également la méthode raycast mes instances de maillage THREE.Mesh (une seule ligne) afin d'appeler la méthode de test d'intersection octree. Cela renvoie les index des sommets des faces des géométries qui peuvent être utilisés par la logique d'intersection par défaut du maillage.
J'ai fait une optimisation : la création d'octree est effectuée une fois au démarrage de l'application dans un WebWorker (en fait un pool de travailleurs). La raison en est que la création d'arbres pour les grandes géométries prend un certain temps (quelques secondes). Cela bloquerait l'interface utilisateur du navigateur, je l'ai donc déplacé vers un autre fil.
J'espère que ma démarche devient claire.

@matthias-w Cela ressemble à du bon travail ! J'ai indépendamment fait presque la même chose, mais je ne pense pas avoir obtenu une amélioration des performances aussi importante. https://discourse.threejs.org/t/octree-injection-for-faster-raytracing/8291/2 (implémentation octree orientée objet et modifications moins propres de Mesh.raycast)

Serait-il possible pour vous d'ouvrir la source/de contribuer à l'implémentation d'Octree, permettant plus d'expériences par d'autres ?

@EliasHasle Merci. En fait, le gain de performance n'est pas si bon, puisque j'ai fait une erreur dans mes premières mesures. J'ai corrigé la valeur (voir mon message ci-dessus). Les timings ont plus de sens maintenant en ce qui concerne la complexité de la recherche logarithmique d'Octree. Malheureusement, je ne peux pas rendre le code disponible pour le moment, mais peut-être plus tard cette année. Quoi qu'il en soit, ma mise en œuvre est assez simple (et pas si propre d'ailleurs ;)). Je suppose donc qu'il n'y aurait pas d'idées particulières.

@matthias-w Je pense que 2,3 ms contre 120 ms pour un raycast sur un maillage de sommets de 500k est toujours une amélioration significative, qui, par exemple, permet une résolution en temps réel des balles tirées dans les jeux (à une assez grande partie du calcul budget par image).

As-tu aussi essayé le raytracing ?

Votre implémentation est-elle basée sur une arborescence d'objets JS ? Objets littéraux ou instances d'un prototype ? Le mien est entièrement auto-similaire, de sorte que chaque nœud est un octree, avec des méthodes et tout.

@EliasHasle

Si vous êtes intéressé par le raycasting contre la géométrie statique, moi et d'autres avons déployé des efforts considérables sur three-mesh-bvh , qui utilise un BVH pour indexer les triangles et permet un raycasting haute performance ainsi qu'une détection d'intersection contre une géométrie complexe statique. Le processus de construction de l'arborescence est plus complexe, il prend donc un peu plus de temps, mais réduit le raycasting à moins d'une milliseconde et souvent à moins de 0,1 ms lors du raycasting contre une géométrie avec des centaines de milliers de triangles.

Le temps de construction pourrait être amélioré de différentes manières, mais cela a été suffisant pour ce que je voulais en faire – l'amélioration de cela est cependant sur la liste.

J'aimerais créer un octree dynamique basé sur la scène pour permettre une meilleure détection de rayons et de collision pour les scènes avec beaucoup de maillages, mais je n'ai pas eu moi-même un bon cas d'utilisation. Peut-être un jour!

@EliasHasle Mon implémentation est un arbre d'objets de classe JS (j'utilise des classes ES6, c'est-à-dire des instances prototypes). Fondamentalement, un nœud est un arbre dans mon implémentation. Cependant, j'ai une classe Octree supplémentaire qui contient le nœud racine et fournit des méthodes pour construire et rechercher (ainsi que du débogage et de la visualisation) dans l'arborescence.

Je n'ai pas beaucoup expérimenté les valeurs du niveau de nœud d'arbre maximal et du nombre maximal de sommets par nœud de feuille. Il y a peut-être une meilleure combinaison.
J'utilise également une hiérarchie de volumes englobants pour accélérer les tests d'intersection. Je teste donc la sphère englobante et la boîte englobante du maillage avant de vérifier l'octree de la géométrie du maillage.

Je peux recommander un livre qui est une très belle collection d'approches de détection de collision : C. Ericson, Real-Time Collision Detection, CRC Press, 2004

@gkjohnson Ça a l'air génial ! Les performances sont impressionnantes. Quel type de BVH utilisez-vous?

@matthias-w Merci !

Il existe quelques options de stratégie de division, mais diviser les nœuds BVH au centre du côté le plus long construit l'arbre le plus rapidement. Les triangles sont divisés en côtés en fonction du centre de leurs limites et les nœuds de l'arbre sont développés pour contenir entièrement les triangles enfants (il y a donc une petite quantité de chevauchement des nœuds de l'arbre).

@gkjohnson Alors, l'implémentation BVH est une sorte d'arbre Kd déséquilibré avec une sélection d'axe dépendant de la forme de la boîte, n'est-ce pas? Si c'est le cas, je pensais faire quelque chose comme ça pour les cas où la racine BB était trop éloignée d'un cube, puis utiliser des octrees après le fractionnement conditionnel. Cela s'appliquerait vraisemblablement bien à des cas tels que le monde de la carte de @ Usnul , où le fractionnement initial se ferait dans les deux dimensions de la "carte" et le fractionnement ultérieur se déroulerait en 3D. Je pense que c'est une bien meilleure solution que la mienne, qui consiste à étendre la racine BB à un cube englobant avec le même centre, puis à utiliser la division octree jusqu'au bout.

Je viens d'implémenter une meilleure méthode de raycasting sur PlaneBufferGeometry.

@kpetrow Je pense que l'optimisation des raycasts sur PlaneBufferGeometry , l'hypothèse que les positions des sommets ne seront pas modifiées ne sera très probablement pas valable pour les géométries haute résolution où une recherche linéaire est insuffisante. Pour autant que je sache, l'utilisation principale de la haute résolution PlaneBufferGeometry est de la remodeler en déplaçant les sommets, tout en conservant la topologie, par exemple pour construire un terrain.

Clôture en faveur de #13909.

Cette page vous a été utile?
0 / 5 - 0 notes