J'ai une scène 3D complexe que j'ai besoin d'afficher des éléments HTML au-dessus, en fonction d'une coordonnée 3D. (Je me superpose simplement à une balise code> div code> en haut et positionnez-la avec CSS.) Cependant, j'ai également besoin de le cacher partiellement (par exemple, le rendre transparent) lorsque la coordonnée 3D est masquée par un modèle (ou expressé d'une autre manière, quand ce n'est pas visible dans la caméra). Ces modèles peuvent avoir plusieurs centaines de milliers de visages et j'ai besoin d'un moyen de savoir s'il est masqué que c'est assez rapide pour être couru plusieurs fois par seconde.
Actuellement, j'utilise Raytracer intégré de trois.js, Avec le code suivant: p> Cependant, il s'agit de très em> lents (la fréquence de cadre tombe de 50 FPS à 8 FPS) sur ces modèles complexes. Je cherche de meilleures façons de faire cela, mais je n'ai pas trouvé de ce travail bien dans ce cas. P> Y a-t-il des moyens meilleurs et plus efficaces de déterminer si un point est visible ou obscurci par des modèles dans la scène? p> p>
4 Réponses :
Je ne suis pas au courant d'aucune façon vraiment rapide, mais vous avez quelques options. Je ne sais pas assez sur Three.js pour vous dire comment faire avec cette bibliothèque, mais parler de WebGL en général ...
Si vous pouvez utiliser WebGL 2.0, vous pouvez utiliser les requêtes d'occlusion. Cela revient à p>
var query = gl.createQuery(); gl.beginQuery(gl.ANY_SAMPLES_PASSED, query); // ... draw a small quad at the specified 3d position ... gl.endQuery(gl.ANY_SAMPLES_PASSED); // some time later, typically a few frames later (after a fraction of a second) if (gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE)) { gl.getQueryParameter(query, gl.QUERY_RESULT); }
Merci de votre réponse, WebGL n'est certainement pas une option à ce moment-là (il a essentiellement besoin de prendre en charge tout navigateur pouvant être défini comme "moderne"), mais je vais toujours regarder dans le reste de vos suggestions.
En ce qui concerne le rendu des éléments DOM comme une texture, cela rendra-t-il toujours l'élément cliquable?
Vous pouvez le faire cliquer sur trois.js, mais je soupçonne une solution simple impliquant à nouveau un rayonnaster (je me trompe peut-être). Si c'est la seule chose cliquable dans votre scène, il serait beaucoup plus rapide de rendre l'ensemble de la toile cliquable, de projeter manuellement le quad / sprite à l'écran à l'aide de la matrice de projection de votre modèle, puis vérifiez si les coordonnées de clic sont dans la Sprite's limites.
juste fyi mais vous savez quel code de requête est mauvais? Vous ne pouvez pas garantir la requête que la requête est arrivée à moins que vous demandiez avec GL.GetqueryParameter (requête, GL.Query_Result_Available) Code> et vérifiez qu'il est retourné. En espérant que dans quelques cadres est arrivé est juste demander difficulté. Quelqu'un dirigera un GPU à faible puissance et il faudra plus de cadres ou une autre application / page utilisera le GPU et le temps que vous attendez ne suffira pas. Vérifiez si le résultat est réellement prêt, ne supposez pas que ce sera simplement parce que vous avez attendu un peu de temps
Je supposerai que le contenu des balises HTML souhaitées est des données tierces telles que l'image ou l'iframe, et ne peut pas être utilisée avec WebLL, il doit donc être une balise HTML et ne peut pas être Sprite.
Il y a du livre de cuisine pour le calcul du GPU. Répétez chaque fois que chaque fois la scène change. Désolé, je ne peux pas le faire pour trois.js (je ne connais pas le moteur). P>
Créer une mémoire tampon (et index) contenant la taille des balises HTML, ID de la balise (NUMÉROS INT de 0 ) et des positions d'étiquette. P> Créer un programme Renderbuffer et New WebLL, qui sera utilisé pour le rendre. Les shaders de ce programme rendront une scène simplifiée, notamment des "ombres de tags". Maintenant, l'algoritme simplifié pour le fragment Shader suit: pour tout objet rendu de couleur blanche. À l'exception de la balise, de la couleur de rendu basée sur l'ID de tag. P> Si votre programme actuel contient du brouillard, des objets transparents, des cartes de hauteur ou une certaine logique procédurale, il pourrait également être contenu dans les shaders (dépend s'il peut couvrir la balise ou ne pas). p> résultat pourrait ressembler à ceci (mais ce n'est pas important): p> si la couleur est différente puis blanc, il y a tag. (En supposant que j'ai 3 tags seulement, mes couleurs sont # 000000, # 010000, # 020000, qui ressemblent à un noir, mais non.) P> étage 2, collectez les données de transparence sur les balises Dans l'image forte> p> Nous avons besoin d'un autre programme WebGL et de rendubuffer. Nous allons rendre des points dans Renderbuffer, chaque point est un pixel grand et est à côté de l'autre. Les points représentent des balises. Nous aurons donc besoin de tampon de matrice avec des positions d'étiquette (et des identifiants de balise, mais cela peut être déduit dans Shader). Nous lions également la texture de la scène précédente. P> Le code de Vertex Shader va suivre, basé sur l'attribut ID de balise, il définira la position du point. Ensuite, il calculille la transparence avec la recherche de texture, pseudocode: p> position du point et transparence entrera comme variant à FS. FS rendra une certaine couleur en fonction de la transparence (par exemple, blanche pour tout visible, noir pour invisible et nuances de gris pour partiso-visible). p> résultat de cette étape est l'image, où chaque pixel présente une étiquette et une couleur du pixel est la transparence des balises. Selon le nombre de tags que vous avez, certains pixels risquent de vouloir dire rien et ont une valeur de ClearColor. La position de pixel correspond à l'ID de balise. P> STRAT 3, LIRE Valeurs avec JavaScript STRY> P> Pour lire les données Back Utilisez READPIXELS (ou peut utiliser Teximage2D ?). Un moyen simple de le faire . p> Ensuite, vous utilisez ForLOOOOw basé sur les identifiants de tags et écrivez des données de dactylographiés. Array à votre machine d'état JavaScript par exemple. Vous avez maintenant des valeurs de transparence dans JavaScript et vous pouvez modifier les valeurs CSS. P> Idées forte> p> à l'étape 1, la taille de la taille du rendu entraînera une augmentation significative des performances ( Il abaisse également les recherches de texture dans la phase 2) avec des coûts presque nuls. P> Si vous utilisez des readpixels directement après l'étape 1 et essayez de lire des données à partir de l'écran avec JavaScript, même si vous utilisez Renderbuffer seulement 320 * 200px Large, JS doit faire autant d'itérations que la résolution est. Donc, dans le cas de la scène changera à chaque instant, alors videz simplement FORLOOP: P> var time = Date.now();
for(var i=0;i<320*200*60;i++) { // 64000*60 times per second
}
console.log(Date.now() - time);
En supposant que votre position de div est synchronisée avec la scène 3D sous-jacente, vous devriez pouvoir interroger juste un em> pixel avec réadapixels" sous "Votre div. p>
Enchanté à nouveau que vous maîtrisez la géométrie, cela ne serait-il pas un piratage réalisable pour simplement ajouter une couleur «hors contexte» (ou une valeur alpha) dans la texture où la DIV couvrira et testera-t-elle? < / p>
Dans le cas d'aucune texture, modifiez la géométrie pour "entourer" un sommet un seul sommet dans les limites de la DIV sus-jacente et lui donner une couleur ou une valeur alpha équivalente "hors contexte", pour alimenter le shader de fragment. p>
ici dans cette réponse , vous trouverez un bon exemple en utilisant le Je ne sais pas si cela vous donnera la performance que vous êtes après.
Peut-être que vous pouvez tester pour voir à quel point cela fonctionne et laissez un commentaire avec vos conclusions pour d'autres qui finissent ici à chercher une solution similaire. P> p> trois.frustum code> pour détecter Si des objets sont visibles:
Pouvez-vous utiliser un
trois.sprite code> au lieu d'un élément HTML?
@Westlangley j'ai besoin d'éléments générés et interactifs de manière dynamique (cliquable); cela pourrait-il être fait raisonnablement bien avec des sprites?
Je ne vois pas pourquoi pas. Réutilisez vos sprites. Créer une piscine d'eux. Si vous dépassez le nombre disponible dans la piscine, ajoutez-en un à la piscine.
Votre scène est-elle statique ou dynamique? Si la scène est statique, vous pouvez essayer d'utiliser des tests de rayons basés sur la CPU si vous préparez un maillage spatial avant la main. Il y a probablement une libère pour ça. Probablement une certaine physique lib.
@ Wacławjasper Ma scène est la plupart du temps statique. Si je vous comprends correctement, c'est à peu près ce que je fais maintenant (voir le code dans la question) et c'est juste trop lent sur les grands modèles.
@Frxstrem c'est pas. Trois châtrices JS Ray sont une force très brutale.
S'il y a un objet au point, vous pouvez essayer d'appeler
.traversevisible code> et voir si cela fonctionne pour vous. Référence