OpenGL: Dove devo posizionare gli shader?


17

Sto cercando di imparare OpenGL ES 2.0 e mi chiedo quale sia la pratica più comune per "gestire" gli shader.
Sto ponendo questa domanda perché negli esempi che ho trovato (come quello incluso nella demo dell'API fornita con Android SDK), di solito vedo tutto all'interno della classe GLRenderer e preferirei separare le cose in modo che io possa avere, per esempio, un oggetto GLImage che posso riutilizzare ogni volta che voglio disegnare un quad testurizzato (al momento mi sto concentrando sul 2D), proprio come nel mio codice OpenGL ES 1.0. In quasi tutti gli esempi che ho trovato, gli shader sono semplicemente definiti come attributi di classe. Per esempio:

public class Square {

public final String vertexShader =
        "uniform mat4 uMVPMatrix;\n" +
        "attribute vec4 aPosition;\n" +
        "attribute vec4 aColor;\n" +
        "varying vec4 vColor;\n" +
        "void main() {\n" +
        "  gl_Position = uMVPMatrix * aPosition;\n" +
        "  vColor = aColor;\n" +
        "}\n";

public final String fragmentShader =
        "precision mediump float;\n" +
        "varying vec4 vColor;\n" +
        "void main() {\n" +
        "  gl_FragColor = vColor;\n" +
        "}\n";
// ...
}

Mi scuso in anticipo se alcune di queste domande sono stupide, ma non ho mai lavorato con shader prima.

1) Il codice sopra è il modo comune per definire shader (proprietà pubbliche della classe finale)?
2) Dovrei avere una classe Shader separata?
3) Se gli shader vengono definiti al di fuori della classe che li utilizza, come faccio a sapere i nomi dei loro attributi (ad esempio "aColor" nel seguente pezzo di codice) in modo da poterli associare?

colorHandle = GLES20.glGetAttribLocation(program, "aColor");

Risposte:


16

Non ho sempre apprezzato quel modo di definire gli shader (in una stringa). Preferisco fare il mio in un file di testo e leggerlo durante il caricamento. Definirlo in una stringa è fastidioso per il debug e mi sembra solo disordinato. È molto più semplice riuscire a scriverlo e vederlo formattato come dovrebbe essere, anziché all'interno di una stringa.

Ho anche una classe separata che ha funzionalità shader comuni, come leggere in shader e stampare le informazioni di registrazione per il debug degli shader.

Ovunque siano definiti gli shader, puoi accedere ai nomi proprio come fai nel tuo esempio. L'uso del valore letterale stringa è accettabile per gli shader poiché è improbabile che questi valori cambino dopo averli implementati.

Tuttavia, alla fine dipende da te. Il modo in cui lo stai attualmente facendo funziona alla grande, se non ti sta causando problemi.


2
Avere i tuoi shader in file separati significa anche che puoi usare i tuoi editor shader a portata di mano e avere l'evidenziazione completa della sintassi e persino visualizzarli in anteprima prima di testarli nel tuo programma, se lo supporti.
Raceimaztion

6
L'unico vero motivo per avere shader in una stringa è per test rapidi ed esercitazioni .. in cui la gestione dei file aggiunge massa di "codice non necessario".
Jari Komppa l'

2
Puoi anche implementare il hot-ricaricamento sui file shader, consentendoti di eseguire il debug delle modifiche senza riavviare il gioco. Produttività ++
Liosan,

Mi piace l'idea di leggerli da un file e avere una classe Shader separata. Vederli sempre in una stringa mi stava confondendo perché non sapevo se quello era il modo in cui sono generalmente definiti o solo per scopi di apprendimento. Grazie!
miviclin,

8

La gestione dello shader (e quindi del materiale) è un problema piuttosto complicato che si presenta quando il sistema grafico diventa più complesso e si nota una codifica rigida che ogni shader porterebbe a un'enorme duplicazione del codice. Ecco alcuni modi alternativi per risolverlo:

  • Piccoli esempi in cui ci sono solo un paio di shader tendono a codificarli come stringhe per evitare la gestione dei file come ha commentato Jari Komppa
  • È meglio utilizzare file separati in cui è possibile evidenziare la sintassi e una formattazione corretta. Puoi anche codificare un semplice sistema di debug che controlla le modifiche in quei file e applica lo shader modificato al volo mentre il gioco è in esecuzione.
  • Quando il conteggio dei materiali aumenta, un generatore di shader diventa quasi una necessità. Fondamentalmente si definiscono snippet comuni come "frammento di shader normale snippet di mappatura" e si compongono gli shader completi includendo i componenti desiderati.
    • Puoi usare frammenti di stringhe codificati, ma questo diventa molto veloce, quindi i file sono di nuovo una buona idea.
    • O si può avere pezzi di codice in file separati (o lo stesso) o in alternativa utilizzare ubershader / supershader cui si usa il preprocessore (o bandiere uniformi) per abilitare roba / disabilitare.

Per quanto riguarda l'attributo, i nomi uniformi e simili, basta usare una denominazione coerente in tutti gli shader.


Sposterò sicuramente i miei shader in un file separato. Grazie!
miviclin
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.