Loading...
Logo
Processing Forum
Im rendering the texures fine (ie using parent.image renders them properly over one another preservign transparency)
I need to use GLObject textures though, to layer everything up based on what it is and render them all nice and fast
Ive added noBlend() to the various things (even though the code below doesnt show that) and it doesnt make any difference, the results is shown on the right

Id only need blending for bloomed layers etc, but it seems to be doing some kind of blending all the time

The shots layer is cleared with clear(0f,0f,0f,0f) if filled red the background is visible but everything is tinted red

Any help would be great guys :) thanks!!




Render code:
Copy code
  1.   void render() {
        GLGraphics renderer = (GLGraphics)g;
        GL gl = renderer.gl;
       
        texCoords();
       
        offscreenBuffer.beginDraw();
        offscreenBuffer.beginGL();
          offscreenBuffer.setSize(350,550);
          offscreenBuffer.clear(1.0f,1.0f,1.0f,0.0f);
          for(int i = 0; i < renderList.size(); i++){
            img = renderList.get(i);
            Vec2D pos = renderPos.get(i);
            offscreenBuffer.image(img,pos.x-(img.width*0.5f),pos.y-(img.height*0.5f));//,img.width,img.height);
          }

        offscreenBuffer.endGL();
        offscreenBuffer.endDraw();

          outputPlane.initTextures(2);
          texCoords();
          outputPlane.setTexture(0, testing);
          GLTexture buf = offscreenBuffer.getTexture();
          outputPlane.setTexture(1, buf);
       
        renderer.beginGL(); 
          translate(width/2, height/2,-(width/2)-(height/2)); 
          renderer.model(outputPlane);
        renderer.endGL();

       
        //parent.image(testing,0,0,350,550);
        //parent.image(offscreenBuffer.getTexture(),0,0,350,550);
       
        renderList.clear();
        renderPos.clear();
        initTex();
      }

Replies(6)

A small runnable example of a well-defined problem will increase your chances of solving the problem yourself, people being able to help and in fact getting help.

I have found opengl blending to work less intuitively than one would hope. Sometimes the background impacts the foreground (which is in some way very logical, but not always what you expect). In those cases having a black background darkens the end-result, while a white background lightens it. In other words, try to put something like background(255) before everything.

Another code snippet that has worked for me in the past is this one
Copy code
  1.   ((GLGraphics)g).setBlendMode(REPLACE);
Do you mean GLModel when you say GLObject? noBlend() does not sound like the right setting to me. I believe the default blendMode is BLEND. Did you leave the default setting for the GLModel or used setBlendMode(BLEND)?

Again, a small example of the problem would make it possible for others to run, see and solve it.

Sorry, yes I did mean GLModel (not globject)

The background(255) trick did solve that main problem where the layers below wernt visible, setting the blend mode to replace doesnt appear to have an effect, and adding renderer.background(255) just gives a small white outline to the shots

Although the shots do now appear fairly opaque (where the images actually arnt at all)

Ive upped a version here (700k) and cut out the unneccesary

The renderer code is now looking like this:
Copy code
  1. class rendererglo {
      bulletPatternsP5F home;
      PApplet parent;
      GLModel outputPlane;
      GLGraphicsOffScreen offscreenBuffer, collisionsBuffer;
      GLTexture testing;
      GLTexture img;
      GLTexture bg;
     
      int numPoints = 4;
      int numLayers = 0;
      int w1 = 350;
      int h1 = 550;
     
      ArrayList<GLTexture> renderList;
      ArrayList<Vec2D> renderPos;
     
      rendererglo(PApplet p, bulletPatternsP5F h){
        parent = p;
        home = h;
        offscreenBuffer = new GLGraphicsOffScreen(parent,w1,h1);
        collisionsBuffer = new GLGraphicsOffScreen(parent,w1,h1);
        testing = new GLTexture(parent,w1,h1);
        bg = new GLTexture(parent,"BG00.png");
        outputPlane = new GLModel(parent, numPoints, QUADS, GLModel.STATIC);//DYNAMIC);
        setVertexs();
        initTex();
        texCoords();
        renderList = new ArrayList<GLTexture>();
        renderPos = new ArrayList<Vec2D>();
      }
     
      void setVertexs() {
        // Updating the vertices to their initial positions.
        outputPlane.beginUpdateVertices();
        outputPlane.updateVertex(0, -w1, -h1, 0);
        outputPlane.updateVertex(1, w1, -h1, 0);
        outputPlane.updateVertex(2, w1, h1, 0);
        outputPlane.updateVertex(3, -w1, h1, 0);   
        outputPlane.endUpdateVertices();
      }
     
      void initTex() {
        //testing.clear(0,255,0,255);
        testing = bg;
        // Enabling the use of texturing...
        outputPlane.initTextures(1);
        // ... and loading and setting texture for this model.
        //tex = new GLTexture(this, "milan.jpg");   
        outputPlane.setTexture(0, testing);
      }
     
      void initTex(int num, GLTexture tex) {
        // Enabling the use of texturing...
        outputPlane.initTextures(1+num);
        // ... and loading and setting texture for this model.
        //tex = new GLTexture(this, "milan.jpg");   
        outputPlane.setTexture(0, testing);
        //outputPlane.setTexture(1, offscreenBuffer.getTexture());
      }
     
      void texCoords() {
        for(int i = 0; i < outputPlane.textures.length; i++){
          // Setting the texture coordinates.
          outputPlane.beginUpdateTexCoords(i);
          outputPlane.updateTexCoord(0, 0, 0);
          outputPlane.updateTexCoord(1, 1, 0);   
          outputPlane.updateTexCoord(2, 1, 1);
          outputPlane.updateTexCoord(3, 0, 1);
          outputPlane.endUpdateTexCoords();
        }
      }
     
      void addObject(GLTexture img, Vec2D pos) {
        renderList.add(img);
        renderPos.add(pos);
      }
     
      void collisions(ArrayList<Vec2D> pos){
        collisionsBuffer.beginDraw();
        collisionsBuffer.beginGL();
        collisionsBuffer.setSize(350,550);
        collisionsBuffer.clear(0,255,0,255);
        collisionsBuffer.stroke(255,0,0,255);
        for(int i = 0; i < pos.size(); i++){
          collisionsBuffer.point(pos.get(i).x,pos.get(i).y);
        }
        collisionsBuffer.endGL();
        collisionsBuffer.endDraw();
        //collisionsBuffer.render();
      }
     
      void render() {
        GLGraphics renderer = (GLGraphics)g;
        GL gl = renderer.gl;
        ((GLGraphics)g).setBlendMode(REPLACE);
        //texCoords();
       
        offscreenBuffer.beginDraw();
        offscreenBuffer.beginGL();
          offscreenBuffer.setSize(350,550);
          offscreenBuffer.clear(1.0f,1.0f,1.0f,0.0f);
          offscreenBuffer.background(255);
          for(int i = 0; i < renderList.size(); i++){
            img = renderList.get(i);
            Vec2D pos = renderPos.get(i);         offscreenBuffer.image(img,pos.x-(img.width*0.5f),pos.y-(img.height*0.5f));//,img.width,img.height);
          }
        offscreenBuffer.endGL();
        offscreenBuffer.endDraw();
       
          outputPlane.initTextures(2);
          texCoords();


          outputPlane.setTexture(0, testing);
          GLTexture buf = offscreenBuffer.getTexture();
          outputPlane.setTexture(1, buf);
         
         
        renderer.beginGL();       
          //renderer.background(255);
          translate(width/2, height/2,-(width/2)-(height/2)); 
          renderer.model(outputPlane);
        renderer.endGL();
       
       // parent.image(testing,0,0,350,550);
       //VVV shows bullets how they are meant to appear
       //parent.image(offscreenBuffer.getTexture(),0,0,350,550);
       
        renderList.clear();
        renderPos.clear();
        initTex();
      }
    }
Thanks for your time :) I really appreciate the help with this, its proving a much quicker way to draw alot of stuff and without needing to use the native Image() method

The other code:
Main (bulletPatternsP5F):
Copy code
  1. import codeanticode.glgraphics.*;
    import processing.opengl.*;
    import javax.media.opengl.*;
    import ddf.minim.*;
    import ddf.minim.signals.*;
    import ddf.minim.analysis.*;
    import ddf.minim.effects.*;

    import toxi.geom.*;


    GLTexture shot0, shot1, shot2, shot3, shot4, shot5, shot6;
    ArrayList<GLTexture> types;
    ArrayList<patternemitter> shooters;

    patternemitter shooter, shooter2;
    float timer = 0.0f;
    rendererglo renderer;

    int numShots = 0;
    boolean sizex2 = false;
    boolean autofire = true;
    PFont pix;

    void setup() {
      size(350,550,GLConstants.GLGRAPHICS);
      frameRate(60);
      pix = loadFont("pixel.vlw");
      textFont(pix,16);
      shooters = new ArrayList<patternemitter>();
      shooter = new patternemitter(this);
      shooters.add(shooter);
      shooter2 = new patternemitter(this);
      shooters.add(shooter2);
      types = new ArrayList<GLTexture>();
      shot0 = new GLTexture(this,"shot00.png");
        types.add(shot0);
      shot1 = new GLTexture(this,"shot01.png");
        types.add(shot1);
      shot2 = new GLTexture(this,"shot02.png");
        types.add(shot2);
      shot3 = new GLTexture(this,"shot03.png");
        types.add(shot3);
      shot4 = new GLTexture(this,"shotMid00.png");
        types.add(shot4);
      shot5 = new GLTexture(this,"shotBig00.png");
        types.add(shot5);
      shot6 = new GLTexture(this,"shotMid01.png");
        types.add(shot6);
        renderer = new rendererglo(this,(bulletPatternsP5F)this);
    }

    void draw() {
     
      timer += 0.01f;
      background(#000000);
      numShots = 0;
      for(patternemitter shoot : shooters){
        shoot.update();
        numShots += shoot.bullets.size();
      }
       
      renderer.render();
      String s = "buffer x2 fix: " + sizex2;
      text(s,10,12);
      s = "frames: " + frameRate;
      text(s,10,24);
      s = "num shots: " + numShots;
      text(s,10,36);
      s = "auto fire (z): " + autofire;
      text(s,10,48);
     
     
        for(patternemitter shoot : shooters){
          if(int(frameRate) >= 60 && autofire == true)
            shoot.fire(int(random(4)),0.0125f,5,15);
        }
        println(frameRate + " " + numShots);
    }

    void mouseReleased() {
        for(patternemitter shoot : shooters){
          shoot.fire(int(random(4)),0.0125f,5,15);
        }
    }

    void keyReleased() {
      if(key != 'z' && key != 'x')
        sizex2 = !sizex2;
      if(key == 'z')
        autofire = !autofire;
    }
Bullet:
Copy code
  1. class bullet {
      float dx;
      float dy;
      float x;
      float y;
      float delta;
     
      int rotSpd = 30;
      int type;
      GLTexture img;
      int rot = 0;
      patternemitter weapon;
     
      bullet(patternemitter p, float xx, float yy, float ddx, float ddy, float spd, int bullettype ) {
        dx = ddx;
        dy = ddy;
        x = xx;
        y = yy;
        delta = spd;
        type = bullettype;
        img = types.get(type);
        weapon = p;
      }
     
      void draw() {
        rot++;
       
        x += (delta * dx) / 1000;
        y += (delta * dy) / 1000;
       
        renderer.addObject(img,new Vec2D(x,y));
        checkPos();
      }
     
     
        void checkPos() {
          if(x > 350 || x < 0 || y > 550 || y < 0){
            weapon.destroybullets.add(weapon.bullets.indexOf(this));
          }
        }
     
    }
PatternEmmitter:
Copy code
  1. class patternemitter {
      ArrayList<bullet> bullets;
      ArrayList<Integer> destroybullets;
      PApplet parent;
      Boolean firing;
      int beat; //0 kick, 1 snare, 2 hat
      Vec2D pos;
      float firetimer = 0.0f;
      float interval;
      int rounds = 0;
      int roundcount = 0;
      int number = 0;
      float rmulti = 0.0f;
     
      patternemitter(PApplet p) {
        parent = p;
        bullets = new ArrayList<bullet>();
        destroybullets = new ArrayList<Integer>();
        firing = false;
      }
     
      void update() {
        pos = new Vec2D(mouseX,mouseY);
        bulletPatternsP5F home = (bulletPatternsP5F)parent;
        if(home.shooters.indexOf(this) == 0) pos = new Vec2D(mouseX-15,mouseY);
        if(home.shooters.indexOf(this) == 1) pos = new Vec2D(mouseX+15,mouseY);
        shooting();
        draw();
        destroy();
      }
     
      void draw() {
        fill(255,0,255);
        rect(pos.x - 5, pos.y - 5, 20, 20);
        fill(255,255,255);
        for(bullet b : bullets){
          b.draw();
        }
      }
     
      void destroy() {
        int dcount = 0;
        for(int b = 0; b < destroybullets.size(); b++){
          int ind = destroybullets.get(b);
          bullets.remove(ind-dcount);
          dcount++;
        }
        destroybullets.clear();
      }
     
      void shooting() {
        if(firing == true && roundcount <= rounds){
          if(timer >= (firetimer + interval)){
            firetimer = timer;
            roundcount++;
            rmulti = 1/(rounds+1);
            float speed = 45;
            int direction = 360;
            float sineVal = 1;

            float sineStep = 1.0f/number;
            for(int i = 1; i < (number+1); i++){
              direction +=  (10*roundcount);       
              bulletPatternsP5F home = (bulletPatternsP5F)parent;
                float dx = speed * cos(radians(((direction / number) + (direction /number)) * (number/i)));
                float dy = speed * sin(radians(((direction / number) + (direction /number)) * (number/i)));
              if(home.shooters.indexOf(this) == 0){
                bullets.add(new bullet(this,pos.x,pos.y,dx,dy,speed,int(random(types.size()-3))));
              }else{
                dx = dx - (dx*2);
                dy = dy - (dy*2);
                bullets.add(new bullet(this,pos.x,pos.y,dx,dy,speed,int(random(types.size()-3))));
              }
            
            }
          }
        }else{
          firing = false;
          rounds = 0;
          number = 0;
          roundcount = 0;
        }
      }
     
      void fire(int b,float interv,int roundss,int num) {
        firetimer = timer;
        interval = interv;
        rounds = 20;//int(random(10)+2);//roundss;
        rmulti = 1/rounds;
        number = 5;//int(random(30)+10);//num;
        firing = true; 
      }
     
     
    }
If this is the way you are using a GLModel, you should not be using it at all. It makes no sense to me to put the offscreen texture in a GLModel.

A GLModel is very good for storing complex geometry and thus can also be used to story many textures. However just putting one existing offscreen texture into it... what's the point?

As you have encountered, you current solution seems to complicate things, which makes it harder to disentangle, predict and control. Your original idea of using several offscreen textures seems sensible. Maybe there are other ways how a GLModel could be used within the context of this project. But using it like this adds very little in my opinion.
its using one offscreen at the moment, im toying between either a) using 1 and when the "layer_type" of a display object is different to the previous one, applying a list of texture filters, setting the new texture, and doing it again for the next type of display objects, or b) having lots of offscreens for each display object type

so a does use one offscreen, but only because the result is then set to the models texture(i) and the buffer cleared for the next lot of stuff, also using this GLM method and monitoring the cpu/gpu usuage, much more gets done on the gpu which is good ;)

the main reason was it massivly improves performance, ive knocked up a sketch with an enemy firing patterns to beats and 400 shots can be on the screen still at 60fps (im using a dated graphcis card but it performing ok for this)

using the glmodel seems to be alot quicker than when i had offscreen buffers and was rendering to them then using image(offscreenbuffer tex) to draw them


I am a strong believer in whatever works.

However I have in the past quite extensively tested GLGraphicsOffScreen + GLModel up to resolutions of 16000 x 1200 for a project. And I wonder how in this case displaying an offscreen texture of 350 x 550 could significantly reduce performance. Perhaps something else was going on.

As you pointed out, the best way to compare alternatives when it comes to performance is to test them in practice. But given the fact that one wrong line of code may cause huge drops in the frameRate, each alternative should have a fair chance under controlled circumstances. Your current sketch is hardly that.