How to store information in the alpha channel

edited February 2014 in GLSL / Shaders

Hi! For a SSAO effect I'm storing normals on the RGB channel and depth information on the alpha channel, but I'm guessing that due to the transparency the information from objects overlaping is corrupted. Only the normal from the foremost object should prevail no matter the alpha value, instead of blending with the colors/normals from the objects behind.

When I save the normals in one pass and the depth in another one, the effect works nicely, but when using the alpha channel it doesn't work.

I have tried different combinations of gl.glDisable(GL.GL_DEPTH_TEST), gl.glEnable(GL.GL_BLEND) and gl.glBlendFunc() but none of them work as I expect.

Thanks

Answers

  • AFAIK, Processing always mess up w/ the alpha part in order to render a corresponding RGB opaque image.

  • edited February 2014

    As you seem to call OpenGL functions directly, Processing shouldn't interfere with your rendering. Could you show us your shader code?

  • edited February 2014

    I'm using Processing 1 + GLGraphics, rendering from a GLGraphicsOffscreen object. The depth test and blend mode are the only direct OpenGL calls.

    The shader is pretty simple, just storing the information:

    #version 120
    
    uniform float near;
    uniform float far ;
    
    varying vec3 vertNormal;
    
    float linearizeDepth( in float d ) {
         return (2.0 * near) / (far + near - d * (far - near));
    }
    
    void main() {
        gl_FragColor = vec4(vertNormal * .5 + .5, linearizeDepth( gl_FragCoord.z ));
    }
    

    This is pretty standard, but I'm missing something. I tried every combination of depth test, enable/disable GL_BLEND and blend mode, and none of them seem to not blend the colors/normals from objects overlapping.

    Thanks!

  • edited February 2014 Answer ✓

    The following code works fine for me. It stores the screenspace position (X and Y) in the RGB channels and the depth in the alpha channel:

    PShader depthShader;
    PGraphics canvas;
    PImage backImage;
    
    void setup() {
    
        size(600, 600, P2D);
        canvas = createGraphics(width, height, P3D);
        canvas.beginDraw();
        canvas.noStroke();
        canvas.endDraw();
    
        backImage = loadImage("http" + "://upload.wikimedia.org/wikipedia/commons/thumb/5/59/Processing_Logo_Clipped.svg/256px-Processing_Logo_Clipped.svg.png");
    
        String[] vertSource = new String[] {
            "uniform mat4 transform;",
            "attribute vec4 vertex;",
            "attribute vec4 color;",
            "varying vec4 vertColor;",
            "void main() {",
                "gl_Position = transform * vertex;",
                "vertColor = color;",
            "}"
        };
        String[] fragSource = new String[] {
            "#ifdef GL_ES",
            "precision mediump float;",
            "precision mediump int;",
            "#endif",
            "uniform vec4 screen;",
            "varying vec4 vertColor;",
            "void main() {",
                "float depth = smoothstep(screen.z, screen.w, gl_FragCoord.z / gl_FragCoord.w);",
                "gl_FragColor = vec4(gl_FragCoord.x / screen.x, gl_FragCoord.y / screen.y, 1.0, 1.0 - depth);",
            "}"
        };
        depthShader = new PShader(this, vertSource, fragSource);
        depthShader.set("screen", (float)width, (float)height, (float)300, (float)600);
        canvas.shader(depthShader);
    
    }
    
    void draw() {
    
        canvas.beginDraw();
        canvas.blendMode(REPLACE);
    
        canvas.background(#000000, 0);
    
        canvas.translate(width / 2, height / 2);
        canvas.rotate(frameCount / 100.0, 1.0, 0.75, 0.5);
        canvas.box(300);
        canvas.endDraw();
    
        image(backImage, -40, -40, width + 80, height + 80);
        image(canvas, 0, 0);
    
    }
    

    I'm using Processing 2.1, but the example should be downportable.

    Edit: Processing's blendMode(REPLACE); should behave like: gl.glBlendFunc(GL.GL_ONE, GL.GL_ZERO);

  • Thanks Poersch! That solved my problem in Processing 2, only the values of the foremost object is being stored.

    blendMode(REPLACE) was the correct blend mode. I looked in the Processing source and that translates into:

    if (blendMode == REPLACE) {
          if (blendEqSupported) {
            pgl.blendEquation(PGL.FUNC_ADD);
          }
          pgl.blendFunc(PGL.ONE, PGL.ZERO);
    }
    

    I tried that in Processing 1+ GLGraphics as:

    gl.glBlendEquation(GL.GL_FUNC_ADD);
    gl.glBlendFunc(GL.GL_ONE, GL.GL_ZERO);
    

    but didn't work. Maybe this is not available in a GLGraphicsOffscreen @codeanticode?

  • @kosowski: No problem. Did you try yourOffscreenCanvas.setBlendMode(REPLACE)?

  • @Poersch Yes, tried that too with no luck. Anyway, one more reason to move projects to P5 2.

  • Yeah, porting to Processing 2.X is almost always worthwhile. It has a great set of improvements/(new features).

Sign In or Register to comment.