将OpenGL HQX着色器转换为LibGDX

将OpenGL HQX着色器转换为LibGDX,libgdx,glsl,shader,Libgdx,Glsl,Shader,我正在研究LibGDX的着色器,注意到有些属性只在LibGDX中使用 标准的顶点和片段着色器可以完美地工作,并应用到我的SpriteBatch中 当我尝试使用HQX着色器时,我会遇到很多错误 可能是因为我需要向着色器发送一些LibGDX相关变量,但我无法确定应该发送哪个 我想在有大屏幕的桌面上使用这些着色器,这样游戏在这些屏幕上看起来就一直很棒 我使用以下代码加载着色器: 试试看{ shaderProgram=new shaderProgram(Gdx.files.internal(“verte

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

标准的顶点和片段着色器可以完美地工作,并应用到我的SpriteBatch中

当我尝试使用HQX着色器时,我会遇到很多错误

可能是因为我需要向着色器发送一些LibGDX相关变量,但我无法确定应该发送哪个

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

我使用以下代码加载着色器:

试试看{
shaderProgram=new shaderProgram(Gdx.files.internal(“vertex.glsl”).readString(),Gdx.files.internal(“fragment.glsl”).readString());
shaderProgram.pedantic=false;
System.out.println(“着色器日志:”);
System.out.println(shaderProgram.getLog());
}捕获(例外情况除外){}

着色器日志输出:
无错误。


提前感谢。

这是一个后期处理着色器,因此您的流程应该如下所示:

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();
}
  • 使用SpriteBatch的默认着色器以像素完美分辨率将场景绘制到FBO

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

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

    现在需要一个大小合适的帧缓冲区。它的大小应该适合你的精灵像素完美(一个像素的纹理缩放到一个像素的世界)。大概是这样的:

    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中不可用的内置变量):

    然后在顶点着色器中,将
    gl\u位置
    行更改为

    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_纹理
    ,这是SpriteBatch使用的纹理名称


    我想这就是一切。实际上我没有测试这个,我的内存已经用完了,但希望它能让你接近它。

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

    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();
    }
    
  • 使用SpriteBatch的默认着色器以像素完美分辨率将场景绘制到FBO

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

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

    现在需要一个大小合适的帧缓冲区。它的大小应该适合你的精灵像素完美(一个像素的纹理缩放到一个像素的世界)。大概是这样的:

    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中不可用的内置变量):

    然后在顶点着色器中,将
    gl\u位置
    行更改为

    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_纹理
    ,这是SpriteBatch使用的纹理名称


    我想这就是一切。我并没有实际测试这个,我的记忆也快用完了,但希望它能让你接近它。

    你用它画得怎么样?您是在构建网格还是在使用SpriteBatch?我假设您使用的是帧缓冲区中的纹理?我使用的是
    batch.setShader(shaderProgram)在我的render()方法中,使着色器应用于SpriteBatch,然后我绘制所有的纹理。您如何使用它进行绘制?您是在构建网格还是在使用SpriteBatch?我假设您使用的是帧缓冲区中的纹理?我使用的是
    batch.setShader(shaderProgram)在我的render()方法中,使着色器应用于SpriteBatch,然后我绘制所有纹理谢谢你的帮助,我得到了这样的着色器,不再出现错误,但我得到的只是一个黑屏,你能测试它吗?假设