libdgx - Mesh Shader Blending Errors

Hi, I just don’t get why the blue triangle is rendered, I think that Blend isn’t enabled but I don’t know what I could do to fix it.
You can just compile and test it on your own if you want to, the code is “working”, the shaders not ::slight_smile:
What I got:

-a blue triangle
What I expected:
-a red triangle, because the opacity from the blue one is 0


import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;

public class ErrorShader implements ApplicationListener {
    MeshHelper meshHelper;

    public static void main(String[] args) {
		LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
		cfg.title = "Error";
		cfg.useGL20 = true;
		cfg.width = 500;
		cfg.height = 500;
		cfg.resizable = false;
		new LwjglApplication(new ErrorShader(), cfg);
	}
    
    
    @Override
    public void create() {
        meshHelper = new MeshHelper();
        meshHelper.createMesh(new float[] { -1.0f, -1.0f, Color.toFloatBits(0, 0, 255, 0),
				0.0f, 1f, Color.toFloatBits(0, 0, 255, 0),
				1f, -1.0f, Color.toFloatBits(0, 0, 255, 0) });
    }
    
    

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void render() {
        Gdx.graphics.getGL20().glClearColor(0.2f, 0.2f, 0.2f, 1);
        Gdx.graphics.getGL20().glClear(GL10.GL_COLOR_BUFFER_BIT);
        Gdx.graphics.getGL20().glEnable(GL20.GL_BLEND);
        Gdx.gl.glBlendFunc(GL10.GL_ONE_MINUS_SRC_ALPHA, GL10.GL_SRC_ALPHA);
        meshHelper.drawMesh();
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }

    @Override
    public void dispose() {
        meshHelper.dispose();
    }
}

class MeshHelper {
    private Mesh mesh;
    private ShaderProgram redShader;
    private ShaderProgram blueShader;

    public MeshHelper() {
        createShader();
    }

    public void createMesh(float[] vertices) {
    	mesh = new Mesh(true, vertices.length, 0,
    	        new VertexAttribute(Usage.Position, 2, "a_position"),
    	        new VertexAttribute(Usage.ColorPacked, 4, "a_color"));
        mesh.setVertices(vertices);
    }

    public void drawMesh() {
        if (mesh == null)
            throw new IllegalStateException("drawMesh called before a mesh has been created.");
        
        redShader.begin();
        mesh.render(redShader, GL20.GL_TRIANGLES);
        redShader.end();
        blueShader.begin();
        mesh.render(blueShader, GL20.GL_TRIANGLES);
        blueShader.end();
    }

    private void createShader() {
    	String vertexShader = "attribute vec4 a_position;    \n"
                + "attribute vec4 a_color;       \n"
                + "varying vec4 v_color;         \n"
                + "void main()                   \n"
                + "{                             \n"
                + "   v_color = a_color;         \n"
                + "   gl_Position = a_position;  \n"
                + "}                             \n";           
    	

    	String fragmentBLUEShader = 
    			//GL ES specific stuff
    			  "#ifdef GL_ES\n" //
    			+ "#define LOWP lowp\n" //
    			+ "precision mediump float;\n" //
    			+ "#else\n" //
    			+ "#define LOWP \n" //
    			+ "#endif\n" + //
    			"\n" + 
    			"void main() {\n" + 
    			"	gl_FragColor = vec4(0.0,0.0,1.0, 0.0);\n" +  //Why is that rendered?
    			"}";
        blueShader = new ShaderProgram(vertexShader, fragmentBLUEShader);
        if (blueShader.isCompiled() == false)
            throw new IllegalStateException(blueShader.getLog());
    
        String fragmentREDShader = 
    			//GL ES specific stuff
    			  "#ifdef GL_ES\n" //
    			+ "#define LOWP lowp\n" //
    			+ "precision mediump float;\n" //
    			+ "#else\n" //
    			+ "#define LOWP \n" //
    			+ "#endif\n" + //
    			"\n" + 
    			"void main() {\n" +
    			"	gl_FragColor = vec4(1,0,0,1);\n" + 
    			"}"; 
        redShader = new ShaderProgram(vertexShader, fragmentREDShader);
        if (redShader.isCompiled() == false)
            throw new IllegalStateException(redShader.getLog());
    }
    public void dispose() {
        mesh.dispose();
        blueShader.dispose();
        redShader.dispose();
    }

}

edit:
Got it, if I use

Gdx.gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

it works,
but I don’t understand why the other one doesn’t work. It would be great if someone could explain it
The text is german but the pictures are nice: http://wiki.delphigl.com/index.php/glBlendFunc#Beispiele

thx for help,
best regards

Aha, I hadn’t noticed you had it reversed when I first saw the pastebin.

[icode]glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)[/icode] is the standard function for transparency blending for non-premultiplied alpha (the first arg is [icode]GL_ONE[/icode] if it is premultiplied).

The way you interpret glBlendFunc is that the first arg is the factor you multiply the source color by (the color coming out of your shader or fixed function draw call), and the second is the factor you multiply the destination color by (the color already in the buffer). The default blend equation is to then add them together to get the final color, which becomes the new destination color (you can change that equation with glBlendEquation but it’s far less common).

So in the case above, it says to multiply the color of the source by its own alpha, and multiply the color of the destination by the inverse of the source’s alpha, after which they’ll be added together. This means the more opaque a source color is (higher alpha) the more its color dominates and the less the destination color does.

Reversing the args effectively reverses the meaning of alpha, making 0.0 opaque and 1.0 fully transparent. This is weird to say the least, so it’s not a blend mode you see very often.

Two minor suggestions:

It’s better practice to use Gdx.gl or Gdx.graphics.getGLCommon() for common GL functions like glClear, glClearColor, glEnable, etc. You can use GL10 or GL20 for constants.

And instead of using two shaders, you only need one. Pass the “a_color” attribute to the fragment shader in order to color your mesh. This is much more efficient as it allows you to batch the red and blue geometry in a single draw call, reduces state changes, and will speed up loading time.

thx, got it :slight_smile:
best regards