Assumerò che il contenuto dei tag html desiderati sono dati di terze parti come immagine o iframe e non può essere utilizzato con Webgl, quindi deve essere tag html e non può essere sprite.
C'è un libro di cucina per il calcolo della GPU. Ripeti ogni volta che cambia la scena. Mi dispiace, non posso farlo per Three.js (non so il motore).
Fase 1, costruire un'immagine con tag visibilità
Create array (e index) tampone contenente dimensione dei tag html, ID di tag (int numeri da 0) e posizioni tag.
Creare il renderbuffer e il nuovo programma WebGL, che verrà utilizzato per il rendering in esso. Gli shader di questo programma renderanno la scena semplificata includendo le "ombre dei tag". Ora segue l'algoritmo semplificato per lo shader di frammenti: per ogni oggetto viene visualizzato il colore bianco. Tranne che per il tag, renderizza il colore in base all'ID del tag.
Se il tuo programma corrente ha nebbia, oggetti trasparenti, mappe di altezza o qualche logica procedurale, potrebbe essere contenuto anche negli shader (dipende se può coprire o meno tag).
Risultato potrebbe essere la seguente (ma non è importante):
Se il colore è diverso poi bianco, c'è tag. (Supponendo che ho solo 3 i tag, quindi i miei colori sono # 000000, # 010000, # 020000, che tutti guardano come il nero, ma non lo è.)
Piano 2, Raccogliere dati sulla trasparenza circa i tag di immagine
Abbiamo bisogno di un altro programma WebGL e renderbuffer. Renderizzeremo i punti in renderbuffer, ogni punto è grande un pixel ed è uno accanto all'altro. I punti rappresentano i tag. Quindi avremo bisogno di un buffer di array con posizioni di tag (e tag ID, ma questo può essere dedotto nello shader). Inoltre leghiamo la trama dalla fase precedente.
Ora il codice di vertex shader verrà seguito, in base all'attributo tag ID, imposterà la posizione del punto. Poi si calcola la trasparenza con la ricerca di texture, pseudocodice:
attribute vec3 tagPosition;
attribute float tagId;
float calculateTransparency(vec2 tagSize, vec2 tagPosition) {
float transparency = 0;
for(0-tagSize.x+tagPosition.x) {
for(0-tagSize.y+tagPosition.y) {
if(textureLookup == tagId) transparency++; // notice that texture lookup is used only for area where tag could be
}
}
return transparency/totalSize;
}
vec2 tagSize2d = calculateSize(tagPosition);
float transparency = calculateTransparency(tagSize2d, tagPosition.xy);
posizione del punto e la trasparenza entrerà come variabile a FS. FS renderà alcuni colori basati sulla trasparenza (ad esempio, il bianco per il pieno visibile, il nero per l'invisibile e le sfumature di grigio per il visibile parziale).
Il risultato di questa fase è l'immagine, in cui ogni pixel presenta un tag e il colore del pixel è la trasparenza del tag. A seconda del numero di tag che hai, alcuni pixel potrebbero non significare nulla e hanno il valore clearColor. La posizione dei pixel corrisponde al tag ID.
Piano 3, leggere i valori con javascript
Per leggere i dati indietro utilizzano readPixels (o potrebbero utilizzare texImage2D?). Simple way to do it.
Quindi si utilizza forloop basato su ID tag e si scrivono i dati dall'array tipizzato sulla macchina a stati javascript, ad esempio. Ora hai i valori di trasparenza in javascript e puoi modificare i valori CSS.
Idea
Nella fase 1, riducendo le dimensioni del renderbuffer causeranno sensibile incremento delle prestazioni (abbassa anche ricerche trama nello stadio 2) con costi quasi nulli.
Se si utilizza readPixels direttamente dopo la fase 1 e si tenta di leggere i dati dalla schermata con javascript, anche se si utilizza renderbuffer solo 320 * 200px di grandi dimensioni, js deve eseguire il numero di iterazioni della risoluzione. Quindi, nel caso in scena cambierà ogni momento, poi basta forloop vuoto:
var time = Date.now();
for(var i=0;i<320*200*60;i++) { // 64000*60 times per second
}
console.log(Date.now() - time);
tooks ~ 4100ms sulla mia macchina. Ma con lo stage 2, devi fare solo tante iterazioni quante sono le tag nell'area visibile. (Per 50 tag potrebbe essere 3000 * 60).
Il problema più grande che vedo è la complessità dell'implementazione.
Il collo di bottiglia di questa tecnica è readpixel e ricerche di texture. Potresti considerare di non chiamare la fase 3 alla velocità FPS, ma invece di una velocità predefinita più lenta.
È possibile utilizzare un 'THREE.Sprite' invece di un elemento HTML? – WestLangley
@WestLangley Ho bisogno di elementi dinamici generati e interattivi (cliccabili); questo potrebbe essere fatto abbastanza bene con gli sprite? – Frxstrem
Non vedo perché no. Riutilizza i tuoi folletti. Crea un pool di loro. Se superi il numero disponibile nella piscina, aggiungine uno alla piscina. – WestLangley