OpenGL ES Pixel Art – Mise à l'échelle

J'ai du mal à afficher de l'art basé sur les pixels (pensez aux carreaux rétro et à l'art) sur OpenGL Es 1.1 sur les iPhones.

Les mosaïques sont représentées en utilisant 8 octets (1 octet pour chaque ligne) avec chaque bit représentant un pixel en cours de définition ou non.

Par exemple une tuile avec le numéro 8:

0 0 0 0 0 0 0 0 -> 0 0 1 1 1 0 0 0 -> xxx 0 1 0 0 0 1 0 0 -> xx 0 1 0 0 0 1 0 0 -> xx 0 0 1 1 1 0 0 0 -> xxx 0 1 0 0 0 1 0 0 -> xx 0 1 0 0 0 1 0 0 -> xx 0 0 1 1 1 0 0 0 -> xxx 

Convertir ceci en OpenGL sur iPhone en utilisant

 glDrawArrays(GL_POINTS, 0, 64); 

Sortie du simulateur à 100%

La logique est correcte, mais le problème est qu'il ne donne pas l'effet rétro. Je cherchais plus d'un style blocky / rétro. J'ai lu que je peux désactiver le lissage des pixels qui entraînerait l'affichage des pixels sous la forme de carrés (je pense que c'était GL_Disable (POINT_SMOOTH), mais je ne sais pas si cela affecte ES car rien n'a changé).

Solutions possibles que j'ai trouvées à des problèmes relatifs:

  1. utilisez un tampon d'image pour get une résolution plus petite, puis agrandissez-le dans le tampon de rendu. Je ne sais pas comment cela se fait ou si ça va marcher.
  2. Créer une image à partir des pixels, créer une texture à partir de cette image et enfin rendre cette texture.

Des solutions possibles j'ai pensé:

  1. Pour chaque pixel, dessinez deux pixels à la fois horizontalement et verticalement.
  2. Dessinez chaque pixel comme un carré en utilisant des sortingangles.
  3. Utiliser GLPointSize – donne un effet correct lorsqu'il est réglé sur 2, mais les coordonnées sont alors foirées. L'alignment devient plus difficile.

En fin de count, j'aimerais que les carreaux soient présentés:

Retro pixels - Numéro 8

C'est plus de moi de comprendre comment fonctionnent OpenGL et pixels, et j'utilise un émulateur gameboy pour résoudre ce problème. Si quelqu'un pense que la manière correcte est de créer les charts manuellement et de les charger en tant que textures, ce n'est pas la réponse possible.

Il y a plusieurs façons de le faire et je suggérerais le premier que vous avez déjà trouvé. Dessinez la scène dans un tampon plus petit, puis redessinez-la.

Ce que vous cherchez ici, c'est un FBO (frame buffer object). Trouvez quelques exemples sur la façon de créer un FBO et y attacher une texture. Cela créera un tampon pour vous avec toutes les dimensions que vous entrerez. Quelques problèmes courants ici sont que vous aurez probablement besoin d'une texture POT (une puissance de 2 dimensions: 2, 4, 8, 16 … Donc 64×128 buffer par exemple) donc pour contrôler une taille différente vous devriez utiliser viewport qui sera alors n'utilisez qu'une partie du tampon dont vous avez besoin.

Donc, à la fin, cela va créer une texture à basse résolution qui peut être utilisée pour dessiner sur la canvas (vue). Comment vous dessinez quelque chose que vous devriez expérimenter. Les points peuvent ne pas être la meilleure solution, même dans le cas d'un tampon j'utiliserais des lignes entre les points que vous avez définis dans votre exemple. À ce stade, vous devez choisir de dessiner avec ou sans l'antialias. Pour l'activer, searchz le multi-échantillonnage sur iOS.

Une fois que vous avez la texture à laquelle la forme est dessinée, vous devrez la redessiner à la vue. Ceci dessine à peu près une texture en plein écran. Encore une fois, vous avez plusieurs façons de le dessiner. L'outil le plus puissant ici sont les parameters de texture: Utiliser le plus proche annulera toutes les interpolations de couleur et les carrés devraient être visibles; l'utilisation linéaire (ou sortinglinéaire) fera une certaine interpolation et le résultat sera probablement plus proche de ce que vous voulez réaliser. Ensuite, vous pouvez à nouveau jouer avec le multi-échantillonnage pour créer un antialiasing et get un meilleur résultat.

Donc, les pouvoirs ici sont:

  • Différentes tailles de buffer FBO
  • Antialiasing sur le FBO
  • Paramètres de texture
  • Antialiasing lors du redessin de la canvas

En ce qui concerne les FBO, c'est l'une des choses les plus faciles à faire:

  • Générer un tampon de trame ( glGenFramebuffers )
  • Lier le tampon d'image ( glBindFramebuffer )
  • Créer une texture ( glGenTextures ) et la lier ( glBindTexture )
  • Définir datatables de texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, twidth, theight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  • Attachez la texture au tampon d'image glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.textureID, 0);
  • Maintenant, lorsque vous dessinez à la texture, vous devez lier le tampon de trame FBO et lorsque vous dessinez dans le tampon principal, il suffit de lier ce tampon de trame.

Puisque c'est une réponse assez large (comme c'est la question) … Si vous allez mettre en œuvre ceci et aura d'autres questions ou problèmes, il vaudra mieux créer des questions distinctes et probablement les relier dans les commentaires.

Bonne chance.

Je ne sais pas si ma question n'était pas claire, mais pour dessiner des pixels à l'écran, vous devez créer une texture et lui transmettre datatables de pixels, puis rendre cette texture sur l'écran. Ce serait l'équivalent de glDrawPixels.

Le code serait:

 #define W 255,255,255 #define G 192,192,192 //8 x 8 tile with 3 bytes for each pixel RGB format GLubyte pixels[8 * 8 * 3] = { W,W,W,W,W,W,W,W, W,W,G,G,G,W,W,W, W,G,W,W,W,G,W,W, W,G,W,W,W,G,W,W, W,W,G,G,G,W,W,W, W,G,W,W,W,G,W,W, W,G,W,W,W,G,W,W, W,W,G,G,G,W,W,W }; 

quelque part dans l'installation:

 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(1, &tex); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 

Puis dessinez la texture comme d'habitude:

 glActiveTexture(GL_TEXTURE0); glUniform1i([program uniformLocation:@"s_texture"], 0); glBindTexture(GL_TEXTURE_2D, tex); glEnableVertexAtsortingbArray(positionAtsortingb); glVertexAtsortingbPointer(positionAtsortingb, 2, GL_FLOAT, GL_FALSE, 0, v); glEnableVertexAtsortingbArray(texAtsortingb); glVertexAtsortingbPointer(texAtsortingb, 2, GL_FLOAT, GL_FALSE, 0, t); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, i);