Fusionner la géométrie / le maillage sans perdre les avantages

11

Dans three.js, nous pouvons simplement fusionner la géométrie pour limiter la quantité d'appels de tirage et ainsi augmenter les performances. Dans un test simple avec un matériau, j'ai pu dessiner 50.000 cubes + ombres @ 60fps sur mon GPU GTX660. Sans fusion de géométrie, 5.000 cubes ont déjà causé un problème.

Je me demande comment conserver les avantages du rendu de chaque maillage de cube par lui-même. Par exemple, comment choisir un maillage de cube lorsque tout est fusionné en une seule géométrie? Par défaut, ce n'est bien sûr pas possible.

Existe-t-il une technique courante pour ce problème? Après tout, j'ai tous les objets maillés non fusionnés même après la fusion. Il doit donc y avoir un moyen de les utiliser pour la cueillette?

Ce que je veux faire en bref

  • SimCity comme un jeu à des fins d'apprentissage
  • Chaque maison est un maillage cube
  • Vous voulez rendre 50 000 maisons et pouvoir ajouter et supprimer des maisons
  • La sélection de la maison via le curseur de la souris (cueillette) doit être possible
user990827
la source
Je ne sais pas si cela vous est utile, mais je le mentionne pour être complet. Simplygon a un modèle de tarification basé sur des redevances pour les développeurs indépendants et peut effectuer une grande partie de cette fusion et partitionnement de maillage au moment de la conception.
steeveeet

Réponses:

11

OK j'ai compris. Après avoir fusionné l'ensemble de la géométrie, j'ai toujours les maillages individuels dans un tableau. Je peux donc simplement utiliser ces maillages pour le raycasting, même s'ils ne sont même pas rendus. Cela m'a pris un certain temps pour réaliser cela.

entrez la description de l'image ici

Pour la cueillette, j'utilise cette implémentation octree: http://threejs.org/examples/#webgl_octree_raycasting

Cela réduit les tests d'intersection par mise à jour de 50 000 à ~ 500. Sans l'octree, les fps diminueront fortement.

La coque de cueillette orange que vous voyez est en fait le maillage maintenant rendu (+1 appel de tirage) avec un matériau changé et une taille modifiée.

entrez la description de l'image ici

Donc je suppose que la prochaine étape consiste à implémenter une sorte de partitionnement de carte. Autrement dit, divisez la géométrie fusionnée en plusieurs parties. La raison en est que la géométrie fusionnée a une grande quantité de sommets. Cela signifie que si je déplace la carte à 99% hors écran, la carte graphique doit toujours traiter tous les sommets car la géométrie est toujours en vue, au moins 1% de celle-ci. Donc, s'il est cassé, seules les pièces en vue doivent être rendues.

user990827
la source
Merci beaucoup pour cet aperçu. J'ai essayé de trouver un moyen de le faire également, et je pense que votre solution ici est la plus excellente! Question rapide cependant: pour votre liste locale d'objets (c'est-à-dire Three.Object3D), quel type de propriétés est requis pour que rayCaster.intersectObjects () fonctionne?
AlvinfromDiaspar
Très bien fait.
ClassicThunder
J'ai un problème similaire, mais je ne parviens pas à obtenir le travail de diffusion de rayons avec le r70. Avez-vous fait quelque chose de spécial lors de la création et de la fusion des boîtes? J'utilise le code suivant ( pastebin.com/PStaAF3P ) pour créer et fusionner les nœuds, mais peut-être qu'il manque quelque chose pour faire fonctionner le raycaster?
fhahn
Question rapide: je fais quelque chose de très similaire à vous (une carte 3D basée sur des données geoJSON). Avec votre méthode, chaque fois que vous faites pivoter la caméra, devez-vous également faire pivoter les maillages de construction préexistants? Ou ajoutez-vous simplement les cases individuelles à la scène mais ne les rendez pas?
Spencer
@Spencer Non, pas besoin de tourner. Je garde les boîtes individuelles dans un tableau global et n'ajoute que la géométrie fusionnée à la scène. Vous pouvez ensuite effectuer une diffusion de rayons avec l'objet dans un tableau global, car le diffuseur de rayons dépend de la matrice de la caméra et de la position de chaque boîte. Ce n'était probablement pas la meilleure façon, c'était juste une preuve de concept pour moi. Ne plus faire de three.js à ce stade.
user990827
1

Pour la sélection, vous pouvez également restituer les ID de chaque cube à une autre cible de rendu et vérifier simplement quelle est la valeur de l'ID au niveau du curseur. L'avantage est que le prélèvement est parfait au pixel près et fonctionne efficacement aussi pour une géométrie plus complexe.

Si tous les objets ont la même géométrie, vous pouvez utiliser le rendu instancié. Un flux définit la géométrie, tandis qu'un autre définit les propriétés par instance (par exemple transformation). Pour l'abattage de troncs, vous devez créer le flux d'instance à chaque image en fonction du test de visibilité. Si vous avez une grande quantité d'objets, vous souhaiterez peut-être placer ces objets dans un octree lâche ou quelque chose pour accélérer l'abattage.

JarkkoL
la source
0

Je ne suis pas sûr des détails de three.js, mais deux porcs de performances possibles me viennent à l'esprit en général OpenGL:

  1. Avez-vous envisagé d'instancier? Vous n'aurez besoin que d'un seul appel et tirez moins de VRAM.
  2. Avez-vous examiné sérieusement l'algorithme de sélection? Si vos cubes ont des volumes englobants dans une liste au lieu d'un arbre par exemple, cela expliquerait une différence de cette ampleur.
bogglez
la source
0

Une autre approche que vous pouvez adopter consiste à créer un attribut de sommet dans votre géométrie et à mettre une logique de surbrillance dans votre shader de fragment. Ceci est extrêmement utile lorsque vous ne voulez pas avoir deux copies de données en mémoire, et vous aurez plus de contrôle sur la façon dont la mise en évidence est implémentée.

HaoCS
la source