Come caricare PNG con alpha con Cocoa?
-
10-07-2019 - |
Domanda
Sto sviluppando un'applicazione OpenGL per iPhone e devo usare alcune texture con trasparenza. Ho salvato le immagini come PNG. Ho già tutto il codice per caricare i PNG come trame OpenGL e renderli. Funziona bene per tutte le immagini che non hanno trasparenza (tutti i valori alfa sono 1.0). Tuttavia, ora che sto cercando di caricare e utilizzare alcuni PNG che hanno trasparenza (variando i valori alfa), la mia trama è incasinata, come se avesse caricato i dati in modo errato o qualcosa del genere.
Sono abbastanza sicuro che ciò sia dovuto al mio codice di caricamento che utilizza alcune delle API Cocoa. Invierò qui il codice pertinente.
Qual è il modo migliore per caricare PNG o qualsiasi formato di immagine che supporti la trasparenza su OSX / iPhone? Questo metodo sembra rotonda. Renderlo in un CGContext e ottenere i dati sembra strano.
* LOADING *
CGImageRef CGImageRef_load(const char *filename) {
NSString *path = [NSString stringWithFormat:@"%@/%s",
[[NSBundle mainBundle] resourcePath],
filename];
UIImage *img = [UIImage imageWithContentsOfFile:path];
if(img) return [img CGImage];
return NULL;
}
unsigned char* CGImageRef_data(CGImageRef image) {
NSInteger width = CGImageGetWidth(image);
NSInteger height = CGImageGetHeight(image);
unsigned char *data = (unsigned char*)malloc(width*height*4);
CGContextRef context = CGBitmapContextCreate(data,
width, height,
8, width * 4,
CGImageGetColorSpace(image),
kCGImageAlphaPremultipliedLast);
CGContextDrawImage(context,
CGRectMake(0.0, 0.0, (float)width, (float)height),
image);
CGContextRelease(context);
return data;
}
* UPLOADING *
(define (image-opengl-upload data width height)
(let ((tex (alloc-opengl-image)))
(glBindTexture GL_TEXTURE_2D tex)
(glTexEnvi GL_TEXTURE_ENV GL_TEXTURE_ENV_MODE GL_DECAL)
(glTexImage2D GL_TEXTURE_2D
0
GL_RGBA
width
height
0
GL_RGBA
GL_UNSIGNED_BYTE
(->void-array data))
(glTexParameteri GL_TEXTURE_2D
GL_TEXTURE_MIN_FILTER
GL_LINEAR)
(glTexParameteri GL_TEXTURE_2D
GL_TEXTURE_MAG_FILTER
GL_LINEAR)
(glTexParameteri GL_TEXTURE_2D
GL_TEXTURE_WRAP_S
GL_CLAMP_TO_EDGE)
(glTexParameteri GL_TEXTURE_2D
GL_TEXTURE_WRAP_T
GL_CLAMP_TO_EDGE)
(glBindTexture GL_TEXTURE_2D 0)
tex))
Soluzione
La tua superficie grafica principale dovrebbe essere azzerata prima di eseguire il rendering, quindi ti consiglio di usare calloc invece di malloc o di aggiungere un memset dopo il malloc.
Inoltre, non sono sicuro che desideri che TexEnv sia impostato su GL_DECAL . Potresti voler lasciare l'impostazione predefinita ( GL_MODULATE ).
Se desideri evitare Core Graphics per la decodifica delle immagini PNG, ti consiglio di caricare un file PVR. PVR è un formato di file estremamente semplice. Un'app denominata PVRTexTool è inclusa nell'SDK Imagination che semplifica la conversione da PNG a PVR. L'SDK include anche alcuni codici di esempio che mostrano come analizzare il loro formato di file.
Altri suggerimenti
Per essere espliciti ...
Il problema più comune con il caricamento di texture usando Core Image è che insiste nel convertire i dati in formato alfa premoltiplicato. Nel caso di PNG inclusi nel bundle, ciò viene effettivamente eseguito in una fase di preelaborazione del processo di generazione. Non tenerne conto si traduce in bande scure attorno agli oggetti miscelati.
Il modo per tenerne conto è usare glBlendMode (GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
anziché glBlendMode (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
. Se desideri utilizzare i canali alfa per qualcosa di diverso dalla fusione normale, l'unica opzione è passare a un formato e caricatore diversi (come suggerito l'orgoglio, ma per motivi diversi).
ETA: il problema di premoltiplicazione esiste anche in Mac & nbsp; OS & nbsp; X, ma la preelaborazione è specifica per iPhone.
Non so nulla di OpenGL, ma Cocoa estrae questa funzionalità con NSImage / UIImage.
Puoi usare i PVR ma ci saranno alcuni artefatti di compressione, quindi raccomanderei solo quelli per trame di oggetti 3D o trame che non richiedono un certo livello di dettaglio che il PVR non può offrire, specialmente con i gradienti.