Quali tecniche di rendering dovrei usare per disegnare un effetto ombra per le carte in un gioco di carte?


13

Quale tipo di algoritmo di shading potrebbe essere usato per creare ombre come queste? inserisci qui la descrizione dell'immagine

quello che sto realizzando è simile ma è tutto fatto con un'API di disegno 2D basata su OpenGL, quindi non ci sono coordinate Z.

Inoltre, per la mano stessa, mi piacerebbe davvero avere un aspetto ombreggiato come visto qui: inserisci qui la descrizione dell'immagine

Non sono sicuro di come ottenere uno sguardo ombreggiato vicino a quello.

Il numero di carte è destinato a cambiare e le carte vengono gettate sul tavolo, quindi non posso usare alcun tipo di mappa luminosa di sorta.

Quali tipi di algoritmi dovrei esaminare (a parte la sfocatura che so che dovrò fare?)

Grazie

Aggiornare

Sto realizzando un gioco di carte 2D. Voglio aggiungere il dropshadows offset dalle carte, un po 'come:

inserisci qui la descrizione dell'immagine

Il modo in cui sto pensando di farlo è:

  • Mantieni una trama delle stesse dimensioni del backbuffer.
  • Disegna rettangoli scuri come carte improvvisate su quella trama.

  • Sfoca quella trama.

  • Disegna le mie carte su quella trama.
  • Fai ulteriore illuminazione sulle carte.
  • Disegna questa trama sul backbuffer.

Le mie domande sono:

  • È questo il modo giusto per farlo?

  • C'è un modo per farlo senza renderizzare la trama (mantenendo una bitmap
    grande come il backbuffer)?

  • È sicuro supporre che la dimensione massima della trama non sarà
    superata dalla dimensione del backbuffer? (Quello che voglio dire è che se il backbuffer
    è 2000x3000, allora è sicuro dire che posso creare una trama nella
    memoria video di quelle dimensioni?

Grazie


1
Un punto estetico per il tuo secondo numero: ciò non è realmente possibile se in realtà hai in mano quelle carte. Le carte premute l'una accanto all'altra non si ombreggiano sensibilmente l'una con l'altra. A meno che tu non ne abbia molti in mano. Non puoi davvero tenere le carte come sono raffigurate in quell'immagine; quelle carte sembrano separate da alcuni millimetri; non sono piatti l'uno contro l'altro. Non me ne preoccuperei.
Nicol Bolas,

Risposte:


18

Penso che tutti stiano dando soluzioni troppo complicate a questo problema.

inserisci qui la descrizione dell'immagine

Quindi, per prima cosa, abbiamo la carta (o qualunque cosa tu voglia pescare), rappresentata qui da (a). Quindi, ne prendiamo una copia, la riempiamo di nero e eseguiamo una sfocatura gaussiana su di essa (b). Tutto questo accade in Photoshop o qualunque sia il tuo strumento artistico preferito.

Successivamente, nel gioco, quando vogliamo pescare la carta, prima disegna l'immagine nera sfocata con una fusione moltiplicativa (o alfa), scosta un po 'in una direzione, quindi pesca la carta sopra di essa. Ecco.

Per ulteriori trucchi, puoi alternare il rendering delle ombre e delle carte per ottenere l'effetto come (d), oppure prima disegnare tutte le ombre e poi le carte, come in (e) (ho colorato le carte nel caso (e) per mostrare che sei ancora separato =)

È anche meglio non usare il nero puro (o alfa pieno) per l'ombra per creare ombre più sottili e trasparenti.


2
+1 per fare le ombre fuori dal gioco. Potresti anche fare un ulteriore passo avanti e modificare la posizione dell'ombra a se c'è una luce nella scena.
FrenchyNZ,

+1, bella illustrazione. Inoltre, nel caso E puoi usare il rendering di ombre scure sul tavolo e semi-luminose su carte con stencil. Sarà più complicato, ma l'effetto sarà ancora più bello :)
Kromster afferma di sostenere Monica il

2

Il primo non è troppo difficile. Se esegui il rendering di un canale alfa per la tua mano di carte (che potrebbe essere semplice come il nero per un pixel con una carta al suo interno e bianco per il trasparente), puoi eseguire qualsiasi tipo di sfocatura che desideri solo sul canale alfa e quindi spostalo e usalo per controllare l'illuminazione del tavolo. (Presumibilmente, se non hai un buffer Z, dovresti prima renderizzare il canale alfa fuori dallo schermo da qualche parte, quindi fare il tavolo con la maschera, quindi renderizzare le carte reali.)

Il secondo assomiglia un po 'a SSAO (occlusione ambientale spazio-schermo). Quella tecnica richiede una coordinata Z. Tuttavia, se non hai gli angoli variabili tra le carte (che è quello che immagino se non hai un buffer Z), puoi probabilmente fare un'approssimazione abbastanza buona creando un'ombra discendente (come la prima) per ciascuno carta. Le prestazioni potrebbero essere un po 'complicate, però: ogni aereo avrebbe bisogno di un canale alfa sfocato per tutti i piani sopra di esso, e se ci sono un mazzo di carte sul tavolo, questo potrebbe richiedere parecchi passaggi di rendering.


SSAO is overkill =) È molto difficile dire quale tecnica di shadowing viene utilizzata senza vedere l'esempio animato. Se le carte cadono sempre in quell'ordine e si spaziano l'una sull'altra, sarebbe più semplice pre-renderizzare le ombre, ma non sapresti mai senza vedere il gioco in azione.
Patrick Hughes il

0

Non potresti fare una mappa ombra? Rende la scena su un fbo. Salvare solo i valori di profondità ed eseguire il normale controllo dei valori di profondità nello shader per vedere se un'ombra deve essere resa o meno.


Non sto usando un buffer Z, non c'è "profondità".
jmasterx,

0

Il seguente processo non richiede un target di rendering off-screen. Tuttavia, così facendo, ottiene il requisito che la tabella venga disegnata per prima . O almeno, non viene disegnato nulla sui pixel che la tabella coprirà prima che la tabella venga disegnata. Richiede anche che il tavolo stesso sia un pezzo unico, non sovrapposto: un'immagine.

Inoltre, il tuo framebuffer necessita di un componente alfa.

  1. Ottieni un'immagine in scala di grigi di una carta. Renderlo sfocato attorno ai bordi, eventualmente espandendo le sue dimensioni. Questa è l'immagine della tua carta ombra. Si noti che questa è un'immagine a canale singolo. Quando accedi a questa trama nel tuo shader, dovresti assicurarti di inserire il singolo valore nel componente alfa. Questo può essere fatto nel tuo shader o da qualche altra parte.

    Un valore di 0,0 nell'immagine significa che non c'è ombra. Un valore di 1,0 nell'immagine indica l'ombra totale . Cioè, completamente nero pece. Probabilmente vuoi un valore di circa 0,5 come il tuo colore più scuro.

  2. Cancella lo schermo in modo che l'alfa sia impostata su zero .

  3. Prima di eseguire il rendering di qualsiasi cosa (o almeno di tutto ciò che verrà reso "sotto" il tavolo), per ogni carta, rendere la trama sfocata, sfalsata dalla posizione effettiva della carta (ma con lo stesso orientamento). Il colore in uscita dallo shader dovrebbe essere La configurazione della fusione per questo dovrebbe essere (in linguaggio OpenGL):

    glBlendEquation(GL_MAX);

    Questa modalità di fusione viene utilizzata per impedire alle ombre sovrapposte di diventare sempre più scure o più chiare. Prende semplicemente il valore più scuro scritto su quel pixel. Dovrebbe avere un bell'aspetto.

    È inoltre necessario utilizzare la maschera di scrittura a colori per disattivare le scritture a colori.

  4. Rendi il tavolo. Nel fare ciò, la fusione dovrebbe essere impostata come segue:

    glBlendEquation(GL_ADD);
    glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO);

Se le restrizioni sono troppo restrittive per te, allora devi usare una destinazione di rendering. Questo viene fatto come segue:

  1. Crea l'immagine della scheda ombra come prima.

  2. Innanzitutto, renderizza le ombre. Associa il framebuffer ombra (che deve essere solo un'immagine a canale singolo, se l'hardware può eseguire il rendering a uno di questi). Cancella il suo valore a zero.

  3. Per ogni carta, renderizza l'immagine della carta ombra, sfalsandola come prima. Lo shader dovrebbe scrivere lo stesso valore su tutti e quattro i componenti del colore di output. La modalità di fusione dovrebbe essere di nuovo glBlendEquation(GL_MAX).

  4. Torna al framebuffer normale. Disegna tutto ciò che vuoi essere ombreggiato.

  5. Ora disegna un quad a schermo intero con l'immagine ombra che abbiamo reso. Lo shader dovrebbe archiviare il texel recuperato dall'immagine ombra nell'alfa dell'output; l'RGB è irrilevante. La modalità di fusione dovrebbe essere:

    glBlendEquation(GL_ADD);
    glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);

Nel primo metodo, penso che hai dimenticato il passaggio 5: disabilitare la fusione e il rendering delle carte. Inoltre, vale la pena notare che il primo metodo non consente di ottenere ombre inter-card come mostrato nel secondo screenshot del PO.
Nathan Reed l'

@NathanReed: ho pensato che sapesse come spegnere le cose da solo. Inoltre, le "ombre inter-card" non hanno alcun senso, come ho sottolineato nel mio commento sotto la domanda.
Nicol Bolas,

1
Potrebbe non rappresentare realisticamente come avresti effettivamente le carte, ma sembra bello! In realtà non ha "senso" che le carte galleggino sopra il tavolo come nel primo tiro, sia ...
Nathan Reed,

0

Userei il buffer di stencil. Deselezionalo su 1 (preferibilmente contemporaneamente alla profondità), disegna il tuo tavolo. Quindi abilita il test dello stencil, disegna le ombre usando una trama rettangolare sfocata, incrementando se lo stencil e la profondità passano, non facendo nulla se lo stencil fallisce, nulla se la profondità fallisce e imposta la funzione dello stencil su GL_EQUAL (rif 1, maschera 0xff), disabilita il test dello stencil . (Non l'ho ancora testato completamente, ma è derivato da un codice che funziona in modo simile e dovrebbe funzionare bene; potrebbe essere necessario modificare i parametri). Quindi disegna tutto il resto.

Le chiamate sarebbero:

glEnable (GL_STENCIL_TEST);
glStencilFunc (GL_EQUAL, 1, 2);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);

// draw shadow textures

glDisable (GL_STENCIL_TEST);

L'unica volta che ciò può causare problemi è se hai due bordi sfocati che si sovrappongono leggermente; altrimenti non ha bisogno di nulla di speciale oltre a ciò che offre OpenGL 1.1 di base e funzionerà su tutto l'hardware (aspettatevi forse vecchie schede 3DFX, che presumo non sia davvero preoccupato per il supporto ...)

Una seconda alternativa, che dovrebbe funzionare molto bene in un gioco non critico per le prestazioni, è glCopyTexSubImage2D. Funzionerà con una trama più piccola del backbuffer ed è anche supportato bene su tutto l'hardware (fa parte di OpenGL 1.1 e Doom 3 lo ha usato, quindi puoi aspettarti che il supporto sia molto buono).

L'impostazione di base dovrebbe essere così:

  • Colore chiaro al nero.
  • Disabilita la scrittura di profondità (sebbene questo metodo non abbia bisogno di un buffer di profondità, quindi puoi ignorare quella parte poiché non ne stai usando una).
  • Imposta una finestra con le stesse dimensioni della trama.
  • Disegna le carte come geometria riempita di bianco.
  • glCopyTexSubImage2D alla tua trama.
  • Riporta la finestra alla dimensione intera della finestra.
  • Disegna la tabella normalmente.
  • Disegna la trama come un quad a schermo intero, usando uno shader per sfocarlo e invertire il colore.
  • Disegna tutto il resto.

Dovrebbe anche funzionare molto bene, è un po 'più intensivo per la GPU rispetto al metodo del buffer di stencil ma gestisce correttamente il caso di sovrapposizione e - come ho detto - penso che un gioco come il tuo avrà il potere della GPU da bruciare, anche su una fascia bassa carta.

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.