Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

libGDX shader coordinate and camera position

I am working on a platformer with libGDX, Tiled Map and Box2D. I want to apply some shaders.

I want a vignette effect that stick to the hero. For the vignette effect, I used this tutorial. The problem I encounter is: If the camera is fixed, I obtain exactly what I want. The vignette sticks to the hero. But, if the camera moves, which happens in a scrolling platformer game, the vignette effect doesn't stick to the hero.

Here is a video that illustrates my problem

It seems I have to take into account the camera position to calculate the coordinate of the vignette effect, but I have no idea how. Here is the fragment shader I use for the vignette :

varying vec4 v_color;   
varying vec2 v_texCoord0;

uniform vec2 u_resolution;
uniform float u_PosX, u_PosY;
uniform sampler2D u_sampler2D;  

const float outerRadius = 10, innerRadius = 1, intensity = .5;

void main(){
    vec4 color = texture2D(u_sampler2D, v_texCoord0) * v_color;

    vec2 relativePosition = gl_FragCoord.xy / u_resolution - vec2(u_PosX, u_PosY); //Position of the vignette
    relativePosition.x *= u_resolution.x / u_resolution.y;  //The vignette is a circle
    float len = length(relativePosition);
    float vignette = smoothstep(outerRadius, innerRadius, len);
    color.rgb = mix(color.rgb, color.rgb * vignette, intensity);

    gl_FragColor = color;
}

In the game screen, the relevant code is :

public TestScreen(final MyGdxGame gam){    

    camera = new MyCamera(); 
    camera.setToOrtho(false, width, height);
    camera.update();

    vertexShader = Gdx.files.internal("Shaders/vVignette.glsl").readString();
    fragmentShader = Gdx.files.internal("Shaders/fVignette.glsl").readString();
    shaderProgram = new ShaderProgram(vertexShader,fragmentShader);

    shaderProgram.begin();
    shaderProgram.setUniformf("u_resolution", camera.viewportWidth, camera.viewportHeight);
    shaderProgram.end();            
}


public void render(float delta) {
    Gdx.gl.glClearColor(0.1f,0.1f,0.1f,1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    camera.update();

    //calculation of the position of the effect depending on the position of the hero
    posX = (Gdx.graphics.getWidth()/camera.viewportWidth) * hero.bodyHero.getPosition().x/camera.viewportWidth;
    posY = (Gdx.graphics.getHeight()/camera.viewportHeight) * hero.bodyHero.getPosition().y/camera.viewportHeight;  

    shaderProgram.begin();
    shaderProgram.setUniformf("u_PosX", posX);
    shaderProgram.setUniformf("u_PosY", posY);
    shaderProgram.end();
}

As I said, this code works perfectly if the camera doesn't move. But since it doesn't work when the camera moves, I thought the problem was linked to the camera projection and I tried this code, with no better success, in the render() :

Vector3 PosHero = new Vector3();
PosHero.set(hero.bodyHero.getPosition().x, hero.bodyHero.getPosition().y, 0);
camera.unproject(PosHero);

posX = (Gdx.graphics.getWidth()/camera.viewportWidth) * PosHero.x/camera.viewportWidth;
posY = (Gdx.graphics.getHeight()/camera.viewportHeight) * PosHero.y/camera.viewportHeight;

shaderProgram.begin();
shaderProgram.setUniformf("u_PosX", posX);
shaderProgram.setUniformf("u_PosY", posY);
shaderProgram.end();
like image 299
vdlmrc Avatar asked Nov 01 '15 08:11

vdlmrc


1 Answers

OMG... I have been struggling almost 2 weeks on this, and my problem was a simple error:

The problem was, as I thought, linked to the camera projection. In the code I provided at the end of my message, I used camera.unproject(PosHero);, but I need to use camera.project(PosHero); instead !

Finally here is the code I use to give the right coordinates to the fragment shader :

Vector3 PosHero = new Vector3();
PosHero.set(hero.bodyHero.getPosition().x, hero.bodyHero.getPosition().y, 0);
camera.project(PosHero);

posX = PosHero.x/camera.viewportWidth;
posY = PosHero.y/camera.viewportHeight;

shaderProgram.begin();
shaderProgram.setUniformf("u_PosX", posX);
shaderProgram.setUniformf("u_PosY", posY);
shaderProgram.end();
like image 117
vdlmrc Avatar answered Nov 08 '22 00:11

vdlmrc