Libgdx - 将着色器映射到世界

Libgdx - map shader to world

我有一个 2d 关卡,box2d 负责物理。我已经实现了本教程中描述的以下 water effect。我正在使用一个以主角精灵为中心的 OrthographicCamera。相机跟随精灵,当它到达关卡的边缘时,相机停止移动。目前着色器只渲染相机底部的水。我的问题是我将如何沿着关卡底部渲染水,以便当精灵从关卡底部移开时水 "moves" 离开屏幕?

public class GameRenderer {

private ImageProvider imageProvider;
private GameWorld world;
private SpriteBatch spriteBatch;
private OrthographicCamera camera;
Vector2 camPos;
private Player player;
private Sprite itemPointer;
private Sprite playerSprite;
Sprite explosion;
Box2DDebugRenderer debugRenderer = new Box2DDebugRenderer();
private Array<SimpleSpatial> mSpatials; // used for rendering rube images
private static final Vector2 mTmp = new Vector2();
private Map<String, Texture> mTextureMap;
private Map<Texture, TextureRegion> mTextureRegionMap;

//From tutorial
String vertexShader =
        "attribute vec4 a_position;    \n"
                + "attribute vec2 a_texCoord0;\n"
                + "uniform mat4 u_worldView;\n"
                + "varying vec4 v_color;"
                + "varying vec2 v_texCoords;"
                + "void main()                  \n"
                + "{                            \n"
                + "   v_color = vec4(1, 1, 1, 1); \n"
                + "   v_texCoords = a_texCoord0; \n"
                + "   gl_Position =  u_worldView * a_position;  \n"
                + "}                            \n";

String fragmentShader = "#ifdef GL_ES\n"
        + "precision mediump float;\n"
        + "#endif\n"
        + "varying vec4 v_color;\n"
        + "varying vec2 v_texCoords;\n"
        + "uniform sampler2D u_texture;\n"
        + "uniform sampler2D u_texture2;\n"
        + "uniform float timedelta;\n"
        + "void main()                                  \n"
        + "{                                            \n"
        + "  vec2 displacement = texture2D(u_texture2, v_texCoords/6.0).xy;\n" //
        + "  float t=v_texCoords.y +displacement.y*0.1-0.1+  (sin(v_texCoords.x * 60.0+timedelta) * 0.005); \n" //
        + "  gl_FragColor = v_color * texture2D(u_texture, vec2(v_texCoords.x,t));\n"
        + "}";

String fragmentShader2 = "#ifdef GL_ES\n"
        + "precision mediump float;\n"
        + "#endif\n"
        + "varying vec4 v_color;\n"
        + "varying vec2 v_texCoords;\n"
        + "uniform sampler2D u_texture;\n"
        + "void main()                                  \n"
        + "{                                            \n"
        + "  gl_FragColor = v_color * texture2D(u_texture, v_texCoords);\n"
        + "}";


ShaderProgram shader;
ShaderProgram waterShader;

Matrix4 matrix;
float time;

Mesh waterMesh;

private Texture texture2;
private Texture texture3;

FPSLogger fpsLogger = new FPSLogger();


public GameRenderer(GameWorld gameWorld)  {

    imageProvider = GameManager.getInstance().getImageProvider();

    world = gameWorld;
    spriteBatch = new SpriteBatch();
    camPos = new Vector2();

    loadBackgroundTextures();
    loadPlayerTextures();

    explosion = new Sprite(imageProvider.getExplosion());
    explosion.setScale(50  * Constants.WORLD_TO_BOX);

    setupCamera();

    Gdx.input.setCatchBackKey(true);
}

public void show() {

    initGame();
}

private void initGame() {

    player = world.getPlayer();
    playerSprite = new Sprite(playerTexture);
    playerSprite.setScale(15  * Constants.WORLD_TO_BOX, 15  * Constants.WORLD_TO_BOX);

    createSpatialsFromRubeImages(world.getScene());

    initialiseShaders();

}

private void createSpatialsFromRubeImages(RubeScene scene)
{

    Array<RubeImage> images = scene.getImages();
    if ((images != null) && (images.size > 0))
    {
        mSpatials = new Array<>();
        for (int i = 0; i < images.size; i++)
        {
            RubeImage image = images.get(i);
            mTmp.set(image.width, image.height);
            String textureFileName = image.file;
            Texture texture = mTextureMap.get(textureFileName);
            if (texture == null)
            {
                texture = new Texture(textureFileName);
                mTextureMap.put(textureFileName, texture);
            }
            SimpleSpatial spatial = new SimpleSpatial(texture, image.flip, image.body, image.color, mTmp, image.center,
                    image.angleInRads * MathUtils.radiansToDegrees);
            mSpatials.add(spatial);
        }
    }
}

    //From tutorial
public void initialiseShaders() {

    texture2 =new Texture(Gdx.files.internal("gfx/shaders/water.png"));
    texture2.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);

    texture3 = new Texture(Gdx.files.internal("gfx/shaders/waterdisplacement.png"));
    texture3.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
    texture3.bind();
    matrix = new Matrix4();


    ShaderProgram.pedantic=false;

    shader = new ShaderProgram(vertexShader, fragmentShader);

    waterShader = new ShaderProgram(vertexShader, fragmentShader2);
    waterShader.setUniformMatrix("u_projTrans", matrix);

    waterMesh = createQuad();

    time=1f;
}

//From tutorial
public Mesh createQuad() {
    float[] verts = new float[20];
    int i = 0;

    verts[i++] = -1; // x1
    verts[i++] = -1; // y1
    verts[i++] = 0;
    verts[i++] = 1f; // u1
    verts[i++] = 1f; // v1 //

    verts[i++] = 1f; // x2
    verts[i++] = -1; // y2
    verts[i++] = 0;
    verts[i++] = 0f; // u2
    verts[i++] = 1f; // v2 //

    verts[i++] = 1; // x3
    verts[i++] = -0.3f; // y2
    verts[i++] = 0;
    verts[i++] = 0f; // u3
    verts[i++] = 0f; // v3

    verts[i++] = -1; // x4
    verts[i++] = -0.3f; // y4
    verts[i++] = 0;
    verts[i++] = 1f; // u4
    verts[i++] = 0f; // v4

    Mesh mesh = new Mesh(true, 4, 0, // static mesh with 4 vertices and no
            // indices
            new VertexAttribute(VertexAttributes.Usage.Position, 3,
                    ShaderProgram.POSITION_ATTRIBUTE), new VertexAttribute(
            VertexAttributes.Usage.TextureCoordinates, 2,
            ShaderProgram.TEXCOORD_ATTRIBUTE + "0"));

    mesh.setVertices(verts);
    return mesh;

}

private void setupCamera() {

    camera = new OrthographicCamera(imageProvider.getScreenWidth(), imageProvider.getScreenHeight());
    camera.position.x = 500;
    camera.position.y = 500;

    camera.zoom = Constants.ZOOM_FACTOR;
    camera.update();
}

public void render(float delta) {

    spriteBatch.flush();

    Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
    fpsLogger.log();


    Gdx.gl.glScissor(0, 0, (int)Constants.SCREEN_WIDTH, (int)Constants.SCREEN_HEIGHT);
    Gdx.gl.glDisable(GL20.GL_SCISSOR_TEST);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    Gdx.gl.glEnable(GL20.GL_SCISSOR_TEST);

    camera.update();
    spriteBatch.setProjectionMatrix(camera.combined);

    drawBackground();
    updateCameraPosition();
    drawRest(delta);
    drawPlayer(delta);

    //Render water shader
    drawWater();

    debugRenderer.render(world.getRubeWorld(), camera.combined);
}

public void drawWater() {

    spriteBatch.setProjectionMatrix(camera.combined);

    float dt = Gdx.graphics.getDeltaTime();
    time += dt;
    float angle = time * (2 * MathUtils.PI);
    if (angle > (2 * MathUtils.PI))
        angle -= (2 * MathUtils.PI);

    //RENDER WATER
    Gdx.gl20.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
    Gdx.gl20.glEnable(GL20.GL_BLEND);


    texture2.bind(1);
    texture3.bind(2);
    shader.begin();
    shader.setUniformMatrix("u_worldView",  matrix);
    shader.setUniformi("u_texture", 1);
    shader.setUniformi("u_texture2", 2);
    shader.setUniformf("timedelta", -angle);
    shader.setUniformf("v_texCoords.y", -10f );

    waterMesh.render(shader, GL20.GL_TRIANGLE_FAN);
    shader.end();

    Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
    //Gdx.gl20.glDisable(GL20.GL_BLEND);


}
public void drawBackground() {

    spriteBatch.begin();
    spriteBatch.setProjectionMatrix(parallaxCamera.combined);
    spriteBatch.draw(backgroundImage, parallaxCamera.position.x - 400, parallaxCamera.position.y - 240);
    spriteBatch.end();

}

public void drawRest(float delta) {

    camera.update();
    spriteBatch.setProjectionMatrix(camera.combined);

    spriteBatch.begin();

    //Renders Box2d world
    for (int i = 0; i < mSpatials.size; i++)
    {
        mSpatials.get(i).render(spriteBatch, 0);
    }

    spriteBatch.end();
}

public void drawPlayer(float delta) {

    if (!world.isGameOver()) {

        spriteBatch.begin();

        playerSprite.setOrigin(playerSprite.getWidth() / 2, playerSprite.getHeight() / 2);
        playerSprite.setPosition(world.getPlayer().getPosition().x - playerSprite.getWidth() / 2, world.getPlayer().getPosition().y - playerSprite.getHeight() / 2);
        playerSprite.setRotation(world.getPlayer().getDirection() - 90);
        playerSprite.draw(spriteBatch);

        spriteBatch.end();
    }
    else {

        spriteBatch.begin();
        explosion.draw(spriteBatch);
        spriteBatch.end();

    }
}

private void updateCameraPosition() {

    camPos.lerp(world.getPlayer().getPosition(), 1.5f);

    if (camPos.x * Constants.WORLD_TO_BOX < LEVELWIDTH && camPos.x  * Constants.WORLD_TO_BOX > 0) {

        camera.position.x = camPos.x;
    }

    if (camPos.y  * Constants.WORLD_TO_BOX < LEVELHEIGHT && camPos.y  * Constants.WORLD_TO_BOX > 0.75) {

        camera.position.y = camPos.y;
    }
}

}

您是否将 camera.combined 矩阵发送到 u_worldView?

shader.setUniformMatrix("u_worldView", cam.combined);

如果您有一些代码片段会很有帮助。