Loading...
Logo
Processing Forum
Hi, I guess this question is for Andres. 

Is it possible to update a PGraphics (P2D, P3D) element so that the alpha channel information is ignored and the element is rendered fully opaque (I have tried filter(OPAQUE); but this drives my CPU crazy)? 

For example, when I draw a couple of shapes with a semi-transparent color into a PGraphics3D element I want to retain the semi-transparent alpha behavior when they overlap, but the PGraphics element as a whole should be rendered fully opaque when drawing it onto the screen with image(pg3D, 0 , 0 ); ?


Replies(3)

Perhaps, if you use function set() instead of image(), you may get an opaque result.
When you use bitshifting and the pixel array directly, it doesn't seem to greatly impact the fps.

Code Example
Copy code
  1. // Tested with Processing 2.0b8

  2. PGraphics pg;
  3.  
  4. void setup() {
  5.   size(500, 500, P2D);
  6.   pg = createGraphics(width, height, P2D);
  7.   pg.beginDraw();
  8.   pg.smooth(4);
  9.   pg.noStroke();
  10.   pg.endDraw();
  11.   noStroke();
  12.   fill(0, 255, 0);
  13. }
  14.  
  15. void draw() {
  16.   background(255); // white background
  17.   rect(0, 175, width, 150); // green rectangle
  18.   drawPG();
  19.   if (mousePressed) ignoreAlpha(pg);
  20.   image(pg, 0, 0);
  21.   frame.setTitle(int(frameRate) + " fps");
  22. }
  23.  
  24. void drawPG() {
  25.   pg.beginDraw();
  26.   pg.background(255, 0); // white 'invisible' background (also works with opaque white)
  27.   pg.fill(255, 0, 0); // red opaque ellipse
  28.   pg.ellipse(pg.width/2, pg.height/2, 250, 250);
  29.   pg.fill(0, 0, 255, 125); // blue transparent ellipse
  30.   pg.ellipse(mouseX, mouseY, 200, 200);
  31.   pg.endDraw();
  32. }
  33.  
  34. void ignoreAlpha(PGraphics pg) {
  35.   pg.beginDraw();
  36.   pg.loadPixels();
  37.   for (int i=0; i<pg.pixels.length; i++) {
  38.     color argb = pg.pixels[i];
  39.     int a = (argb >> 24) & 0xFF;
  40.     if (a!=255) {
  41.       int r = (argb >> 16) & 0xFF;
  42.       int g = (argb >> 8) & 0xFF;
  43.       int b = argb & 0xFF;
  44.       pg.pixels[i] = 255<<24 | r<<16 | g<<8 | b;
  45.     }
  46.   }
  47.   pg.updatePixels();
  48.   pg.endDraw();
  49. }
Thanks GoToLoop, amnon.owed. both your solutions do the job. Since I was looking for a GPU solution to avoid using loadPixels, I came up with the following shader which does what I need to the frameBuffer I am using. It also works fine with sending the frameBuffer via Syphon to another application, here the code I use (the shader is at the bottom of the sketch):

Copy code
  1. // import codeanticode.syphon.SyphonServer;

  2. PGraphics tex;

  3. PShader opaque;

  4. //SyphonServer syphonserver;

  5. void setup() {
  6.   size(1024, 768, P3D);

  7.   // syphonserver = new SyphonServer( this, "Continuum Renderer" );

  8.   tex = createGraphics(width, height, P3D );

  9.   opaque = loadShader( "opaque.glsl" );

  10. }

  11. String renderMethod = "";

  12. void draw() {
  13.   background(0);

  14.   if (keyPressed) {
  15.     renderMethod = "image(), rendering texture";
  16.     image(tex, 0, 0 );
  17.   } 
  18.   else {
  19.     renderMethod = "directly drawing shapes to screen";
  20.     drawThings(g);
  21.   }
  22.   
  23.   tex.beginDraw();
  24.   drawThings( tex );
  25.   tex.filter(opaque);
  26.   tex.endDraw();
  27.   
  28.   fill( 255 );
  29.   text( renderMethod , 400 , 40 );
  30.   
  31.   //syphonserver.sendImage( tex );
  32. }

  33. void drawThings(PGraphics g) {
  34.   g.fill(0, mouseX, 0);
  35.   g.rect(0, 0, width, height);
  36.   g.noStroke();
  37.   for (int i=0;i<20;i++) {
  38.     g.fill(255, 0, 0, i * 12.5);
  39.     float c = 150;
  40.     g.ellipse( 200 + (i*100) % 500, 200 + (i/5)*100, c, c );
  41.   }
  42.   for (int i=0;i<10;i++) {
  43.     g.fill(255, i*25);
  44.     float c = 100;
  45.     g.ellipse( i * 100, +i*100, (sin(frameCount*0.1) * 100) + c+i*20, c+i*20 );
  46.   }
  47.   for (int i=0;i<10;i++) {
  48.     g.fill(0, 0, 255, i*25);
  49.     float c = 100;
  50.     g.ellipse( 200 + i * 100, i*100, (sin(frameCount*0.1) * 100) + c+i*20, c+i*20 );
  51.   }
  52.   g.fill(255,255,0,mouseY);
  53.   g.ellipse(100,100,200,200);
  54. }


  55. // opaque.glsl
  56. // A shader to make transparent pixels in a frambuffer opaque. 
  57. // What happanes here:
  58. // - a gl_FragColor's alpha value is set to 1.0.
  59. // - the rgb value is adjusted based on alpha value (one_minus_source_alpha).
  60. // a slight alpha deviation remains in the mid-ranges 
  61. /*

  62. #define PROCESSING_TEXTURE_SHADER

  63. uniform sampler2D texture;
  64. varying vec4 vertTexCoord;

  65. void main(void) {
  66.   vec4 rgba = texture2D(texture, vertTexCoord.st);
  67.   gl_FragColor = vec4(rgba.rgb + ( ( 1.0 - rgba.a ) ) * rgba.rgb, 1.0 );
  68. }

  69. */


andreas schlegel, http://www.sojamo.de