2011-10-12 7 views
18

Sto cercando di convertire il mio codice di rendering OpenGL per sfruttare alcune funzionalità di GLKit (ovvero il caricamento di texture asincrone e l'automazione fornita da GLKView/Controller). Tuttavia, sembra che le classi siano progettate principalmente per ospitare persone che eseguono il rendering utilizzando un ciclo di animazione, mentre io sto lavorando con il rendering on-demand. Inoltre, parte del rendering è per una texture piuttosto che per il framebuffer di GLKView, quindi dovrei cercare di creare una sottoclasse di GLKView e aggiungere altri FBO?Rendering OpenGL ES su richiesta con GLKit

Esiste un approccio consigliato per questo tipo di installazione? Mi sarei aspettato qualcosa sulla falsariga di:

  • Impostare il controller della vista preferredFramesPerSecond-0, o semplicemente mettere in pausa gli aggiornamenti del telaio?
  • Ignorare i metodi glkViewControllerUpdate o glkView:drawInRect: e disegnare solo ciò di cui ho bisogno, quando ne ho bisogno.
  • Uso della visualizzazione setNeedsDisplay come con un normale UIView al fine per visualizzare il fotogramma (ho bisogno di chiamare bindDrawable dato che io verrà eseguito il rendering di una texture come bene?).

Forse non vale la pena se questo non è ciò per cui è progettata la nuova API? Vorrei che la documentazione fosse un po 'più approfondita di quanto non sia. Forse saranno forniti più campioni quando l'API ha 'maturato' un po '...

Grazie

+0

è possibile eseguire il rendering su FBO secondario insieme a GLKit. http://mickyd.wordpress.com/2012/05/20/creating-render-to-texture-secondary-framebuffer-objects-on-ios-using-opengl-es-2/ – MickyD

risposta

22

L'approccio che ho utilizzato è stato quello di non preoccuparsi di GLKViewController, ma di utilizzare semplicemente GLKView direttamente sotto una sottoclasse UIViewController.

Chiaramente, lo GLKViewController è destinato all'uso da parte di utenti che necessitano di un ciclo di rendering coerente per app come i giochi. Senza di essa, il disegno su GLKView è semplice come chiamare [glkView setNeedsDisplay]. Assicurati di impostare enableSetNeedsDisplay su YES per abilitare questo comportamento.

Se avete ancora voglia di fare uso di un GLKViewController, è possibile disattivare il ciclo di rendering dell'animazione in viewWillAppear in questo modo:

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; // setPaused automatically set to NO in super's implementation 

    [self setPaused:YES]; 
} 

Inoltre, impostare resumeOnDidBecomeActive-NO per evitare che il controller della vista di riprendere di nuovo automaticamente .

L'utilizzo di un semplice UIViewController con un GLKView è perfettamente accettabile tuttavia, e ho visto consigliato da un ingegnere Apple come un modo appropriato per eseguire il disegno su richiesta.

+0

Sarebbe utile chiarire in quali metodi enableSetNeedsDisplay e resumeOnDidBecomeActive devono essere impostati come menzionato, poiché non li hai messi in viewWillAppear (BOOL) animato. Grazie. –

+0

Impostare queste proprietà quando si crea il controller vista/vista. Ad esempio, se crei il tuo 'GLKViewController' nel codice, forse lo imposti sulla riga dopo il tuo' alloc'/'init'. Se lo crei in Interface Builder, implementare il metodo '-awakeFromNib' nel tuo controller di visualizzazione potrebbe essere un buon posto per farlo. In generale, proprietà come questa dovrebbero essere impostate dopo/come l'oggetto viene creato ma prima che venga utilizzato. – Stuart

+0

Hai a disposizione un codice sorgente aperto che mostri un esempio di questo? Grazie – aehlke

3

Ho appena convertito il mio codice di utilizzare un gestore EAGLContext mi sono rotolato a utilizzare le classi GLKit.

Si consiglia di "..individuare i metodi .. glkView:drawInRect: e disegnare ciò di cui [si] ha bisogno, quando ne ho bisogno". Questa sembra un'opzione ragionevole per quanto riguarda le prestazioni; Presumo (anche se non ho provato) se semplicemente non si specifica GLKViewGLKView con la sua drawInRect: definita, quindi non si verificherà alcun rendering del ciclo di animazione. Hai provato questo?

L'alternativa sarebbe quella di creare semplicemente qualche @property (assign, nonatomic) BOOL shouldUpdate; nella classe MyController : GLKViewController <GLKViewDelegate> che aggiornerà solo se c'è qualcosa da fare:

[self setDelegate:self]; // in init or awakeFromNib or other.. 

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect { 
    if ([self shouldUpdate]) { ... 

Sono sicuro che si ottiene l'idea, non è certo complicato.

Una cosa degna di nota: i documenti API ufficiali indicano che viewDidLoad deve essere utilizzato nel proprio GLKViewController per l'installazione iniziale GL. Ho avuto problemi con questo; per qualche ragione le mie chiamate glCreateShader hanno sempre restituito zero. Ciò potrebbe essere dovuto al fatto che ho impostato la post-inizializzazione EAGLContext; Non ho potuto passarlo come parametro init da quando ho creato il controller in Storyboard. Tuttavia, non c'era nulla di logicamente sbagliato nel codice, quindi offro questo avviso amichevole nel caso in cui incontri problemi simili. La mia soluzione è semplicemente quello di avere la seguente nel mio drawInRect:

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect { 
    if ([self initialGLSetupDone] == NO) { 
     [self beforeFirstRender]; 
     [self setInitialGLSetupDone:YES]; 
    } 
    // .. rest of render code goes here. 
} 

Ovviamente non è l'ideale per avere un IF in là inutilmente, ma era una soluzione facile.

Fammi sapere come va se provi ad aggiornare per utilizzare GLKit.

+0

Per quanto riguarda 'viewDidLoad' problema, il tuo 'EAGLContext' deve essere impostato prima di creare i tuoi shader, come hai notato tu stesso. Non c'è nulla di male nel fare ciò anche in 'viewDidLoad', direttamente prima di configurare il resto del codice GL. Dai un'occhiata al progetto del modello 'OpenGL Game' in Xcode per un buon esempio di come eseguire questa configurazione. – Stuart

+0

Grazie per il suggerimento del chiavistello. Molto più facile che tentare di disegnare manualmente il CAEAGLLayer o altre soluzioni alternative. –

1

Dopo aver creato GLKView, aggiungere questa riga:

glkView.enableSetNeedsDisplay = TRUE;

(A causa di questo, nessuno potrà ridisegnare la vista automaticamente)

quando si vuole ridisegnare, inserire questa riga:

[glkView setNeedsDisplay]; 

... quindi la routine drawInRect verrà chiamata una sola volta.

Spero che aiuti.

+1

-1. Questo non è corretto - l'impostazione 'enableSetNeedsDisplay' su' NO' ** disabilita ** il metodo '' SetNeedsDisplay' di 'GLKView'. Questa proprietà viene automaticamente impostata su "NO" quando si usa un "GLKViewController', e quindi è, di fatto, richiesto che lo si imposta manualmente su" SÌ "quando si disegna in" Modalità "setNeedsDisplay. – Stuart

+1

È stata corretta questa risposta ... – rodamn