将 OpenGL HQX 着色器转换为 LibGDX

Convert OpenGL HQX shader to LibGDX

我正在研究 LibGDX 的着色器,并注意到有些属性仅在 LibGDX 中使用。

来自 https://github.com/libgdx/libgdx/wiki/Shaders 的标准顶点和片段着色器工作完美并应用于我的 SpriteBatch。

当我尝试使用像 https://github.com/SupSuper/OpenXcom/blob/master/bin/common/Shaders/HQ2x.OpenGL.shader 这样的 HQX 着色器时,我遇到了很多错误。

可能是因为我需要向着色器发送一些 LibGDX 因变量,但我找不到应该是哪个。

我想在具有大屏幕的桌面上使用这些着色器,以便游戏在这些屏幕上看起来一直很棒。

我使用这段代码来加载着色器:

try { shaderProgram = new ShaderProgram(Gdx.files.internal("vertex.glsl").readString(), Gdx.files.internal("fragment.glsl").readString()); shaderProgram.pedantic = false; System.out.println("Shader Log:"); System.out.println(shaderProgram.getLog()); } catch(Exception ex) { }

着色器日志输出: No errors.

提前致谢。

这是一个 post 处理着色器,因此您的流程应该是这样的:

  1. 使用 SpriteBatch 的默认着色器以像素完美分辨率将场景绘制到 FBO。

  2. 使用放大着色器将 FBO 的纹理绘制到屏幕的帧缓冲区。如果您修改着色器以匹配 SpriteBatch 使用的属性和制服,则可以使用 SpriteBatch 执行此操作。 (您也可以使用着色器期望的属性名称创建一个简单的网格,但 SpriteBatch 可能是最简单的。)

首先,我们没有使用 SpriteBatch 的典型着色器,因此您需要在加载任何内容之前在某处调用 ShaderProgram.pedantic = false;

现在您需要一个大小合适的 FrameBuffer。它的大小应该使您的精灵像素完美(纹理的一个像素缩放到世界的一个像素)。像这样:

public void resize (int width, int height){
    float ratio = (float)width / (float) height;
    int gameWidth = (int)(GAME_HEIGHT / ratio);
    boolean needNewFrameBuffer = false;
    if (frameBuffer != null && (frameBuffer.getWidth() != gameWidth || frameBuffer.getHeight() != GAME_HEIGHT)){
        frameBuffer.dispose();
        needNewFrameBuffer = true;
    }
    if (frameBuffer == null || needNewFrameBuffer)
        frameBuffer = new FrameBuffer(Format.RGBA8888, gameWidth, GAME_HEIGHT);

    camera.viewportWidth = gameWidth;
    camera.viewportHeight = GAME_HEIGHT;
    camera.update();
}

然后您可以像在您的屏幕上一样在帧缓冲区中绘图。然后,将帧缓冲区的纹理绘制到屏幕上。

public void render (){
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    frameBuffer.begin();
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    batch.setProjectionMatrix(camera.combined);
    batch.setShader(null); //use default shader
    batch.begin();
    //draw your game
    batch.end();

    frameBuffer.end();

    batch.setShader(upscaleShader);
    batch.begin();
    upscaleShader.setUniformf("rubyTextureSize", frameBuffer.getWidth(), frameBuffer.getHeight());//this is the uniform in your shader. I assume it's wanting the scene size in pixels
    batch.draw(frameBuffer.getColorBufferTexture(), -1, 1, 2, -2); //full screen quad for no projection matrix, with Y flipped as needed for frame buffer textures
    batch.end();
}

您还需要对着色器进行一些更改,以便它可以与 OpenGL ES 一起使用,并且因为 SpriteBatch 是针对特定属性和统一名称连接的:

在你的顶点着色器的顶部,添加它来定义你的顶点属性和变量(你的链接着色器不需要它,因为它依赖于 GL ES 中不可用的内置变量):

attribute vec4 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord[5];

然后在顶点着色器中,将 gl_Position 行更改为

gl_Position = a_position; //since we can't rely on built-in variables

出于同样的原因,将所有出现的 gl_TexCoord 替换为 v_texCoord

片段着色器中,为了兼容OpenGL ES,需要声明精度。您还需要声明相同的 varying,因此将其添加到顶部:

#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_texCoord[5];

与顶点着色器一样,将所有出现的 gl_TexCoord 替换为 v_texCoord。并将所有出现的 rubyTexture 替换为 u_texture,这是 SpriteBatch 使用的纹理名称。

我想这就是一切。我并没有真正测试过这个,我的记忆已经消失了,但希望它能让你接近。