OpenGL ottiene la struttura di più oggetti sovrapposti


10

Ho appena avuto un'idea per il mio gioco in corso realizzato con Opengl in c ++: mi piacerebbe avere un grande contorno (5-6 pixel) su più oggetti sovrapposti quando il giocatore vince qualcosa.

Ho pensato che il modo migliore fosse usare il buffer di stencil ma sono poche ore che sto cercando di eseguire un rendering off-screen del buffer di stencil e non riesco a ottenere alcun tipo di risultato così probab. ci sono altre tecniche!

Questo è quello che voglio ottenere:

inserisci qui la descrizione dell'immagine

Qualche idea?


Utilizzare un filtro per il rilevamento dei bordi, riempire i bordi con linee colorate spesse, quindi estrarre le immagini renderizzate delle forme e sovrapporre sopra il livello delle linee colorate?
Fucile Ninja

cosa intendi con un filtro edge-detect? uno shader? un filtro per l'elaborazione delle immagini? come opencv (renderizza alla trama, applica il filtro alla trama, respinge la trama modificata)?
nkint,

Non ne ho idea; Per cominciare, non sono molto esperto nel rendering 3D.
Fucile Ninja

hai qualche esempio di un buffer di stencil come questo? Penso che usare il buffer di stencil sarebbe il modo più pulito, ma non sono in grado di far funzionare alcun buffer di stencil
nkint

Risposte:


4
  1. Abilita e cancella il buffer dello stencil.
  2. Disegna gli oggetti, impostando il buffer dello stencil. Gli oggetti possono essere semi-trasparenti ecc.
  3. Ora imposta la modalità stencil per scrivere solo i pixel in cui lo stencil non è impostato.
  4. E disegna nuovamente ogni oggetto, leggermente ingrandito, nel colore del bordo desiderato e senza trame.
  5. Disabilita il buffer dello stencil.

Ecco il codice adattato da alcuni codici stencil webGL che sto lavorando:

// drawing will set stencil stencil
    gl.enable(gl.STENCIL_TEST);
    gl.stencilFunc(gl.ALWAYS,1,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE);
    gl.stencilMask(1);
    gl.clearStencil(0);
    gl.clear(gl.STENCIL_BUFFER_BIT);
// draw objects
for(var object in objects)
  objects[object].draw();
// set stencil mode to only draw those not previous drawn
    gl.stencilFunc(gl.EQUAL,0,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
    gl.stencilMask(0x00);
// draw object halo
for(var object in objects)
  objects[object].drawHalo(1.1,red); // each mesh should be individually scaled e.g. by 1.1
// done
    gl.disable(gl.STENCIL_TEST);

Penso di aver usato questo approccio nei giochi RTS per disegnare aloni attorno ad unità selezionate, ma è stato molto tempo fa e non ricordo se ci sono gotcha e tutte le sfumature.


hai qualche esempio di un buffer di stencil come questo? Penso che usare il buffer di stencil sarebbe il modo più pulito ma non sono in grado di far funzionare alcun buffer di stencil
nkint

7
Si noti che il rendering di oggetti leggermente ingranditi non comporterà uno spessore di linea uniforme. I bordi più lontani saranno più sottili. Se si tiene conto di ciò quando si ridimensionano gli oggetti, gli oggetti lunghi che si allungano in lontananza avranno uno spessore non uniforme. C'è un po 'di più in questo effetto per rendere le linee belle e uniformi.
Sean Middleditch,

2
Meglio semplicemente ridimensionare gli oggetti è scrivere uno shader di vertici che compensi ogni vertice a breve distanza lungo il suo normale. Funziona abbastanza bene per oggetti lisci, ma genererà crepe su bordi duri. Potresti provare a costruire la mesh con un insieme alternativo di normali che vengono levigati ovunque e vedi dove ti porta.
Nathan Reed,

2

Inizia trovando tutti i gruppi di oggetti, in cui un gruppo di oggetti è una raccolta di oggetti che si sovrappongono. Il rilevamento di collisioni standard dovrebbe fare il lavoro. Assegna a ciascun gruppo un colore unico. Qualsiasi colore farebbe.

Rendi tutti i tuoi oggetti come colori solidi, usando il colore di gruppo, su una trama.

Crea una nuova trama di contorno con le stesse dimensioni della destinazione di rendering. Effettua la scansione di ciascun texel del target di rendering e determina se ha un colore diverso da qualsiasi texel circostante. In tal caso, modifica il texel corrispondente nella trama del contorno con il colore della linea desiderato.

Infine, prendi questa trama del contorno e rendila sopra la parte superiore dell'immagine che vuoi disegnare sullo schermo (puoi ovviamente farlo contemporaneamente al rilevamento dei bordi in uno shader di frammenti ed evitare di creare la trama dei bordi nel primo posto).

Se esegui questo passaggio sulla CPU usando un ciclo for per passare attraverso i tex del target di rendering, questo sarà piuttosto lento, ma probabilmente abbastanza buono da testare e persino usarlo in alcuni casi. Per usarlo in tempo reale, sarebbe meglio gestirlo in uno shader.

Uno shader di frammenti per eseguire questo rilevamento dei bordi potrebbe assomigliare a questo;

precision mediump float;

uniform sampler2D s_texture;

varying vec2 v_texCoord;

void main()
{
    gl_FragColor = vec4(0.0);

    vec4 baseColor = texture2D(s_texture, v_texCoord);
    gl_FragColor += baseColor - texture2D(s_texture, top);
    gl_FragColor += baseColor - texture2D(s_texture, topRight);
    gl_FragColor += baseColor - texture2D(s_texture, right);
    gl_FragColor += baseColor - texture2D(s_texture, bottomRight);
    gl_FragColor += baseColor - texture2D(s_texture, bottom);
    gl_FragColor += baseColor - texture2D(s_texture, bottomLeft);
    gl_FragColor += baseColor - texture2D(s_texture, left);
    gl_FragColor += baseColor - texture2D(s_texture, topLeft);
}

Dove il secondo valore nella texture2D cerca è una coordinata 2d relativa a v_texCoord. Dovresti applicarlo eseguendo il rendering del primo target di rendering come trama su un quad a schermo intero. Questo è simile a come si applicano gli effetti di sfocatura a schermo intero come una sfocatura guassiana.

Il motivo per utilizzare il primo target di rendering con colori solidi è semplicemente quello di assicurarsi che non vi sia alcun margine percepito tra oggetti diversi che si sovrappongono. Se si eseguisse semplicemente il rilevamento dei bordi sull'immagine dello schermo, probabilmente si scoprirà che rileva anche i bordi in corrispondenza delle sovrapposizioni (supponendo che gli oggetti abbiano colori / trame / illuminazione diversi).


2
scusa ma cosa intendi con "Scansiona ogni texel"? un ciclo for comunque ogni pixel? nella cpu? quindi è qualcosa di simile: renderizzare con un colore solido su una trama, trasferire l'immagine sulla CPU, fare la scansione, rimetterli nella trama? o farlo in uno shader?
nkint,

Preferibilmente farlo in uno shader eseguendo il rendering di un quad a schermo intero usando il rendering come texture, in modo simile a un effetto di sfocatura post-processo, ma puoi farlo funzionare prima sulla cpu con un ciclo for, solo per vedere se funziona abbastanza bene.
OriginalDaemon,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.