Why am I getting a blank screen when using shader?

2019-04-16 03:21发布

问题:

I'm using this tutorial to create and draw an outline for my game Sprites. However, all I get is a blank red screen. I'm very new to Shaders so I'm not sure if I'm missing something very trivial. My vertex and fragment shaders were copy-pasted from the above tutorial.

(Commenting on the tutorial doesn't seem to work so I was unable to seek help there.)

My code:

float x = 0, y = 0, height = 256, width = 256, angle = 0, outlineSize = 1f;

@Override
public void create() {
    batch = new SpriteBatch();
    img =new Texture("badlogic.jpg");
    sprite = new Sprite(img);
    loadShader();
    float w = Gdx.graphics.getWidth(); // 640
    float h = Gdx.graphics.getHeight(); // 480
    cam = new OrthographicCamera(h, w);
    cam.update();
}

public void loadShader() {
    String vertexShader;
    String fragmentShader;
    vertexShader = Gdx.files.internal("shaders/outline.vsh").readString();
    fragmentShader = Gdx.files.internal("shaders/outline.fsh").readString();
    shaderOutline = new ShaderProgram(vertexShader, fragmentShader);
    if (!shaderOutline.isCompiled())
        throw new GdxRuntimeException("Couldn't compile shader: "
                + shaderOutline.getLog());
}

@Override
public void render() {
    Gdx.gl.glClearColor(1, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    batch.setProjectionMatrix(cam.combined);
    cam.update();
    shaderOutline.begin();
    shaderOutline.setUniformf("u_viewportInverse", new Vector2(1f / width, 1f / height));
    shaderOutline.setUniformf("u_offset", outlineSize);
    shaderOutline.setUniformf("u_step", Math.min(1f, width / 70f));
    shaderOutline.setUniformf("u_color", new Vector3(0, 0, 1f));
    shaderOutline.end();
    batch.begin();
    batch.setShader(shaderOutline);
    batch.draw(sprite, x, y, width, height, width, height, 1f, 1f, angle);
    batch.end();
    batch.setShader(null);
}

Any Ideas?

回答1:

The problem is that the image you're using, "badlogic.jpg" has no alpha channel. This shader draws an outline within the bounds of the sprite along the border between high alpha and zero alpha. A JPG file has no alpha channel, so there's no border to draw anything on.

By the way, you need to update your camera's width and height in resize, so the view won't be distorted.

That fragment shader from the tutorial could use some optimization. It has multiple dependent texture reads and multiple if statements. if statements should be replaced with calls to clamp. An exhaustive search of nearby pixels is probably unnecessary to detect edges unless the sprite has some super thin areas.