将OpenGL HQX着色器转换为LibGDX

时间:2016-04-15 20:44:06

标签: libgdx glsl shader

我进入了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.

提前致谢。

1 个答案:

答案 0 :(得分:0)

这是一个后处理着色器,所以你的流程应该是这样的:

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

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

  3. 首先,我们没有使用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兼容,您需要声明精度。您还需要声明相同的变化,因此将其添加到顶部:

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

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

    我认为这就是一切。我实际上并没有对此进行测试,而且我会记忆犹新,但希望它可以让你接近。