Próbuję użyć LibGDX, aby stworzyć małą grę w stylu retro, i chciałbym pozwolić graczom wybrać kolory kilku postaci, więc pomyślałem o ładowanie obrazów indeksowanych png i późniejsze aktualizowanie palet ... Jak źle byłem^^ USymulowanie zamieniania palet za pomocą shaderów OpenGL (w LibGDX)
Wygląda na to, że kolorowe palety są czymś w rodzaju przeszłości, a także wydaje się, że najlepszą opcją osiągnięcia podobnego rezultatu jest użycie Shaderów .
Oto obraz wyjaśniający, co usiłuję teraz:
Moim zamiarem jest użycie 2 zdjęcia. Jeden z nich, pixel_guy.png
jest obrazem png z tylko 6 kolorami (te kolory są jego oryginalną paletą). Inny obraz, colortable.png
, byłby png 6x6 pikseli, który zawiera 6 palet po 6 kolorów (każdy wiersz jest inną paletą). Kolory z pierwszego wiersza pikseli colortable.png
pasują do kolorów użytych w pixel_guy.png
, która byłaby pierwszą/oryginalną paletą, a pozostałe wiersze byłyby paletami od 2 do 6. Próbowałem osiągnąć, aby użyć pierwszej palety kolortable do indeksuj kolory pixelguy, a następnie zmień paletę, wysyłając numer (od 2 do 6) do modułu cieniującego.
Po przeprowadzeniu badań znalazłem post in gamedev stackexchange i najwyraźniej właśnie tego szukałem, więc próbowałem go przetestować.
Utworzyłem wierzchołki cieniowania wierzchołków i fragmentów i wczytałem moje tekstury (tę, której paletę chciałem zamienić, i tę, która zawierała kilka palet), ale wynik jest nieoczekiwanym białym obrazem.
My Vertex Shader:
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
My Fragment Shader:
// Fragment shader
// Thanks to Zack The Human https://gamedev.stackexchange.com/questions/43294/creating-a-retro-style-palette-swapping-effect-in-opengl/
uniform sampler2D texture; // Texture to which we'll apply our shader? (should its name be u_texture?)
uniform sampler2D colorTable; // Color table with 6x6 pixels (6 palettes of 6 colors each)
uniform float paletteIndex; // Index that tells the shader which palette to use (passed here from Java)
void main()
{
vec2 pos = gl_TexCoord[0].xy;
vec4 color = texture2D(texture, pos);
vec2 index = vec2(color.r + paletteIndex, 0);
vec4 indexedColor = texture2D(colorTable, index);
gl_FragColor = indexedColor;
}
Kod I wykorzystywane do wiązania tekstury i przekazać numer palety shadera:
package com.test.shaderstest;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
public class ShadersTestMain extends ApplicationAdapter {
SpriteBatch batch;
Texture imgPixelGuy;
Texture colorTable;
private ShaderProgram shader;
private String shaderVertIndexPalette, shaderFragIndexPalette;
@Override
public void create() {
batch = new SpriteBatch();
imgPixelGuy = new Texture("pixel_guy.png"); // Texture to which we'll apply our shader
colorTable = new Texture("colortable.png"); // Color table with 6x6 pixels (6 palettes of 6 colors each)
shaderVertIndexPalette = Gdx.files.internal("shaders/indexpalette.vert").readString();
shaderFragIndexPalette = Gdx.files.internal("shaders/indexpalette.frag").readString();
ShaderProgram.pedantic = false; // important since we aren't using some uniforms and attributes that SpriteBatch expects
shader = new ShaderProgram(shaderVertIndexPalette, shaderFragIndexPalette);
if(!shader.isCompiled()) {
System.out.println("Problem compiling shader :(");
}
else{
batch.setShader(shader);
System.out.println("Shader applied :)");
}
shader.begin();
shader.setUniformi("colorTable", 1); // Set an uniform called "colorTable" with index 1
shader.setUniformf("paletteIndex", 2.0f); // Set a float uniform called "paletteIndex" with a value 2.0f, to select the 2nd palette
shader.end();
colorTable.bind(1); // We bind the texture colorTable to the uniform with index 1 called "colorTable"
}
@Override
public void render() {
Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(imgPixelGuy, 0, 0); // Draw the image with the shader applied
batch.end();
}
}
Nie wiem, czy to jest właściwy sposób przekazania wartości zmiennoprzecinkowej do jednolitego fragmentu. Nie wiem też, jak działa fragment kodu, którego próbowałem użyć.
Edit: Próbowałem zmian sugerowanych przez TenFour04 i działał bez zarzutu :)
Oto wstępnie przetwarzane sprite
I zostały zaktualizowane repozytorium ze zmianami, (Kod Java here, Fragment Shader here), na wypadek, gdyby ktoś był zainteresowany, można go pobrać tutaj: https://bitbucket.org/hcito/libgdxshadertest
Edycja 2: Właśnie dodałem do repozytorium ostatnią optymalizację, którą TenFour04 zalecił (aby przekazać indeks palety do każdego ikonki wewnątrz metody R wywoływania metody sprite.setColor()) i znowu zadziałało idealnie :)
Dlaczego to się kończy głosowaniem? – Tenfour04
Nie mam pojęcia:/Wiem, że mój angielski nie jest bardzo dobry, i że jestem trochę niezgrabny i wszystko, ale naprawdę staram się zrobić tu wszystko najlepiej ^^ Bardzo dziękuję za pomoc, Tenfour :) (Nawiasem mówiąc, potrzebuję 5 punktów więcej w reputacji, aby przegłosować twoją odpowiedź^^ U) – hcito