Qual formato de imagem é mais eficiente para economizar memória? PNG, JPEG ou GIF?
graphics
graphics-programming
image
memory-efficiency
Tredecies Nocturne
fonte
fonte
Respostas:
"Memória" e "eficiência" são termos mal utilizados, por isso darei uma resposta para quatro elementos diferentes que podem afetar o desempenho do seu jogo.
Estarei simplificando muitas coisas demais para mantê-lo curto e conciso, mas há toneladas de imprecisões neste texto abaixo; portanto, leve-o com uma pitada de sal. No entanto, os principais conceitos devem ser compreensíveis.
Armazenamento
Esse é o tamanho que suas imagens consomem na sua distribuição de software. Quanto mais espaço seus recursos consumirem, mais longo será o download (como no seu site). Se você estiver distribuindo em mídia física, como CDs ou DVDs, provavelmente precisará fazer algumas otimizações sérias nessa frente.
Em geral, o JPEG compacta melhor para fotografias e imagens sem bordas nítidas. No entanto, suas imagens terão qualidade degradada porque o JPEG usa compactação com perdas (você pode ajustar o nível / degradação da compactação ao exportar imagens como JPEG. Consulte a documentação do software de imagem para obter mais informações sobre isso).
No entanto, por melhor que seja o JPEG, ele não suporta transparência . Isso é crucial se você deseja que as imagens sejam exibidas através de outras pessoas ou se deseja imagens com formas irregulares. O GIF é uma boa opção, mas foi amplamente substituído pelo PNG (há apenas algumas coisas que o GIF suporta que o PNG não suporta, mas elas são irrelevantes na programação de jogos).
O PNG suporta transparência (e semitransparência), compacta dados sem degradar a qualidade (ou seja, usa compactação sem perdas) e compacta razoavelmente bem, mas não tanto quanto JPG.
O problema surge quando você precisa de boa compactação e transparência. Se você não se importa com imagens levemente degradadas, pode usar programas de quantização PNG, como pngquant , que você pode testar on-line no TinyPNG . Lembre-se de que a degradação da imagem realizada por quantização é diferente da do JPEG (que inclui quantização e outras técnicas agressivas), portanto, tente as duas com uma grande variedade de configurações.
Se você quiser minimizar agressivamente o tamanho da sua distribuição, poderá processar manualmente todas as imagens como esta:
Dica: não há problema em armazenar algumas imagens em um formato e outras em outro formato.
Existem outros formatos especializados, como DXT, ETC e PVRTC. Eles suportam compactação e também podem ser carregados compactados na memória, mas são suportados apenas por GPUs específicas, e a maioria dessas GPUs suporta apenas uma delas, portanto, a menos que você saiba as especificações exatas de hardware do hardware de destino (um caso notável é iPhone / iPad, que suporta texturas PVRTC), evite esses formatos.
Memória de programa
Eu incluí aqui, porque é isso que é comumente conhecido por "memória". No entanto, se seu jogo usa aceleração de gráficos (e se você está criando um jogo depois de 1998, provavelmente é), a única coisa que consumirá memória são os descritores de textura (apenas alguns bytes por imagem), que são apenas efetuada pela quantidade de imagens, e não pelo tamanho ou formato (isso tem algumas ressalvas, mas é principalmente irrelevante).
Se sua plataforma não possui memória de vídeo dedicada, não é acelerada por hardware ou outros casos incomuns, a próxima seção sobre VRAM ocorrerá total ou parcialmente na RAM, mas os princípios principais serão os mesmos.
Memória de Vídeo
É aqui que suas imagens serão armazenadas quando o programa estiver em execução. Em geral, o formato em que você os armazenou não fará diferença aqui, pois todas as imagens são descompactadas antes de carregá-las na memória de vídeo.
Agora, a VRAM consumida por suas imagens será aproximadamente
width * height * bitdepth
para cada imagem carregada na VRAM. Há algumas coisas a serem observadas aqui:A largura e a altura em que suas imagens são armazenadas no VRAM não coincidem necessariamente com as da sua imagem original. Algumas GPUs podem lidar apenas com texturas com tamanhos em potências de 2; portanto, sua imagem de 320x240 pode realmente ser armazenada em um espaço de 512x256 na VRAM, com a memória não utilizada efetivamente desperdiçada. Algumas vezes, você nem tem permissão para carregar texturas com tamanhos que não são potências de 2 (como no GLES 1.1).
Portanto, se você deseja minimizar o uso da VRAM, considere atlasar suas imagens e dimensioná-las com potências de 2, o que também terá a vantagem de menos alterações no estado de renderização ao renderizar. Mais sobre isso mais tarde.
A profundidade de bits é muito importante. Normalmente, as texturas são carregadas na VRAM em ARGB de 32 bits ou XRGB de 32 bits, mas se o seu hardware suportar profundidades de 16 bits e você não se importar de ter uma profundidade de bits menor, poderá metade da quantidade de VRAM consumida por cada imagem , o que pode ser algo interessante a considerar.
Mas não importa o que você faça, o fator mais importante ao considerar a quantidade de VRAM usada pelo seu jogo é a quantidade de imagens que você tem na VRAM em um determinado momento. Este é o número que você provavelmente deseja manter o mais baixo possível, se quiser um jogo com bom desempenho. Carregar e descarregar texturas no VRAM é caro, portanto você não pode carregar cada imagem sempre que a usar. Você deve encontrar um equilíbrio entre pré-carregar as imagens que provavelmente usará e descarregá-las quando tiver certeza de que não as usará mais. Fazer esse direito não é trivial, e você deve pensar em sua própria estratégia para o seu jogo em particular.
Velocidade de execução
Mesmo que não seja "memória", está muito relacionado ao desempenho nos jogos. Desenhar imagens é caro e você deseja garantir que sua renderização seja executada o mais rápido possível. Obviamente, aqui, o formato não importa, mas outras coisas fazem:
Tamanho da imagem (na verdade, seria "tamanho de amostra"): quanto maior a região de uma imagem que você vai desenhar, mais tempo levará para desenhá-la. A renderização de uma imagem enorme em uma pequena seção da tela não é muito eficaz; portanto, existe uma técnica chamada mipmapping , que consiste em trocar a VRAM pela velocidade de renderização, armazenando suas imagens várias vezes em várias resoluções e usando a menor que pode oferecer você a qualidade necessária a qualquer momento. O mapeamento de mip pode ser executado quando as imagens são carregadas, o que afetará a velocidade de carregamento e o uso da VRAM, ou no pré-processamento (armazenando manualmente versões diferentes da mesma imagem ou usando um formato que ofereça suporte nativo ao mipmap, como DDS), o que afetará o armazenamento e uso de VRAM, mas terá pouco impacto na velocidade de carregamento.
Renderizar alterações de estado. Você provavelmente desejará desenhar várias imagens diferentes na tela ao mesmo tempo. No entanto, a GPU pode usar apenas uma única imagem de origem a qualquer momento (isso não é verdade, mas tenha paciência comigo aqui). A imagem usada atualmente para renderização é um dos muitos estados de renderização e é cara. Portanto, se você usar a mesma imagem várias vezes (lembra quando mencionei atlas de textura ?), Notará um enorme ganho de desempenho se reutilizar uma imagem o máximo que puder antes de alterar o estado de renderização e começar a usar um imagem diferente (existem outros estados de renderização além disso, e o ajuste fino da ordem em que você desenha suas coisas para minimizar as alterações no estado de renderização é uma atividade muito comum ao aprimorar o desempenho de um jogo)
No entanto , a otimização do uso da imagem é um tópico muito complexo, e o que escrevi aqui é uma visão geral muito ampla e simplificada de alguns dos fatores que você precisará considerar ao escrever um jogo. Por isso, acho que é definitivamente melhor se você simplificar, e otimize apenas quando você realmente precisar. Na maioria das vezes, a otimização prematura é desnecessária (e às vezes até prejudicial), portanto, vá com calma.
fonte
setEnforcePotImages
, desabilita a imposição de poder de texturas de tamanho 2 para o OpenGLES 1.0. Essa não é uma boa ideia, pois nem todo hardware suporta texturas que não sejam de potência 2. O OpenGLES 2.0 requer suporte para texturas que não sejam de potência 2, portanto, se você estiver direcionando para 2.0, poderá usar texturas de qualquer tamanho. Para mais informações, consulte a documentação da libgdx.Depois que uma imagem é carregada do disco e formatada para renderização, ela usa a mesma quantidade de memória, independentemente de a imagem ter sido salva no disco usando PNG, JPEG ou GIF.
Regra geral: JPEG é um formato com perda e diminui a qualidade da imagem para diminuir a imagem no disco. PNG, por outro lado, é um formato de imagem sem perdas e, portanto, normalmente resulta em tamanhos de arquivo maiores no disco. O GIF também é tecnicamente um formato sem perdas, mas suporta apenas um máximo de 256 cores por imagem; portanto, uma imagem de alta cor geralmente gera uma perda de alta qualidade se salva como GIF.
Isso é apenas para a representação em disco, no entanto. Na memória, os dois se expandem para o mesmo formato de textura, usando a mesma quantidade de memória, independentemente de você os ter salvado no disco como PNG, JPEG, JPEG ou GIF.
fonte
Depende.
JPEG é mais eficiente para fotografias. Não é sem perdas, mas os artefatos introduzidos pela compactação são menos visíveis nesse caso de uso.
PNG é sem perdas e mais eficiente para pixel-art com linhas nítidas e poucas cores. Ele também suporta transparência alfa.
O GIF não pode fazer nada O PNG não pode fazer melhor, exceto pela capacidade de armazenar animações. Mas isso é relevante apenas no contexto de aplicativos da web. No desenvolvimento de jogos, você geralmente cria animações usando uma planilha.
Observe que, quando você usa um mecanismo gráfico como o Libgdx, provavelmente descompacta as imagens logo após carregá-las e as mantém na memória como valores RGBA não compactados. Portanto, o formato da imagem importa apenas para a velocidade de carregamento e tinha espaço em disco (ou uso de largura de banda quando você os envia pela rede).
fonte
Eu não sei muito sobre libgdx, mas sobre formatos de imagem e gráficos:
O JPEG é muito bom em casos de fotos do mundo real. Eles estão com perdas, mas você não verá artefatos nas fotos, a menos que tire fotos de bordas nítidas com espaços coloridos simples, como, por exemplo, texto escrito ou quadrinhos. Use-os para grandes gráficos de fundo.
O GIF é obsoleto, só pode armazenar cores paletizadas (até 8 bits por pixel) com uma cor dedicada para total transparência. Permite pequenas animações baseadas em quadros. Uma vez houve uma patente em seu algoritmo de empacotamento para que ele não pudesse ser usado em qualquer lugar legalmente. Por causa dessa patente, o PNG foi desenvolvido.
PNG é mais ou menos um bitmap compactado que pode armazenar RGB + alfa (até 32 bits) e outros formatos de pixel. É especializado para descompactar rapidamente pequenas partes dessa imagem, o que é conveniente para dispositivos muito pequenos e lentos (como um celular de 10 anos), mas as bibliotecas atuais apenas as descompactam em bitmaps quando carregadas.
PNG é melhor que GIF em tamanho, velocidade e recursos, mas se você deseja armazenar bitmaps com eficiência, sugiro: .PNM.BZ2 ([editar] Devido ao método diferente de empacotamento, .PNM.BZ2 nem sempre é mais eficiente que .PNG. [/ editar])
PNM / PBM / PGM / PAM são formatos de bitmap simples com cabeçalhos KISS em texto simples. O uso do gzip nesses arquivos resultará em um tamanho de arquivo semelhante ao PNG; portanto, o bzip2 é a melhor solução para isso. Se você usará bitmaps internamente em seu programa, convém usar bitmaps compactados bzip2 em um contêiner .tar ou .zip. Se você não possui o bzip2, o uso de PNMs em um contêiner zip (zip com compactação máxima) pode ser semelhante ao uso de PNGs. - Portanto, armazenar PNGs em um arquivo ZIP pode ter apenas um benefício pequeno ou nenhum - provavelmente aumentaria o tempo para carregar a imagem.
Além disso, é uma boa opção armazenar vários sprites / fotos em um bitmap, especialmente quando você precisar deles juntos na mesma situação.
fonte
Como formato de armazenamento, o JPEG é provavelmente a melhor escolha para algumas texturas, como grama ou paredes, onde a perda de informações é provavelmente indetectável. Seguido por PNG quando você precisar de transparência ou quando não puder pagar com perda de informações, por exemplo, sprites em um jogo 2D (jogador, inimigos, baú do tesouro), você provavelmente desejará usar PNG para essas imagens.
Quando se fala em custo de memória, o formato usado para armazenar gráficos de jogos no sistema de arquivos não é relevante. Se você armazena buffers de pixel em VRAM ou RAM (renderizador de software), provavelmente os armazena sem compressão, porque os jogos favorecem a leitura rápida de pixels versus memória usada por cada buffer de pixel.
Os dados compactados armazenados na memória não fazem sentido, exceto que você mantém algum tipo de cache para salvar as leituras do disco, mas provavelmente precisará ler esse cache para um estado descompactado para as imagens em uso em um determinado momento do seu jogo.
Os dados de imagem compactada têm um pouco mais de sentido se fosse possível uma rápida decodificação de hardware. Pelo menos no mapeamento normal, lembro-me deste http://en.wikipedia.org/wiki/3Dc . Com isso você pode economizar VRAM. Ainda não estou ciente de outros exemplos de decodificação de hardware.
Em resumo: quaisquer que sejam os formatos usados para o seu jogo para armazenar gráficos em armazenamento persistente, você precisará decodificar e manter uma versão não compactada na memória dinâmica, na memória de vídeo ou em ambas, para poder renderizá-las rapidamente quando necessário.
Finalmente: eu sou um cara da área de trabalho. Quando digo "memória", sempre me refiro à memória dinâmica. Quando digo "disco", "sistema de arquivos" ou "armazenamento persistente", sempre me refiro ao que o seu dispositivo usa como armazenamento persistente, geralmente penso em discos rígidos. Quando você disse "eficiência da memória", aceitei "memória dinâmica" e não "armazenamento persistente". Ultimamente, vejo muitas pessoas usando a palavra "memória" para se referir a "armazenamento persistente" (talvez a terminologia de dispositivos móveis?).
fonte