Lot of shapes with a shader?

edited June 2017 in GLSL / Shaders

I have a for loop that I am running on the CPU to draw thousands of 2D circles per frame, using ellipse(). Could I pass the locations of all of these ellipses to a shader somehow and see a good performance increase?

It seems like this should be easy to do with a frag shader but I am pretty inexperienced and can't find any examples of doing anything similar in processing.

edit: I think the PixelFlow customParticles example has everything, just not very straightforward adapting it

Answers

  • Might not be the answer you wanted, but tested just using FX2D and it runs pretty fast just by doing that.

    void setup(){
    size(600,600,FX2D);
    }
    void draw(){
      background(255);
    
      for (int i=0; i<1000; i++){
        float size = int(random(100));
        fill(size);
        ellipse(random(height),random(width),size,size);
      }
    }
    
  • edited June 2017

    Bit outdated still usefull: https://codeanticode.wordpress.com/2012/08/02/shaders-in-processing-2-0-part/

    See also here: https://github.com/processing/processing/wiki/Advanced-OpenGL

    shader.bind()
    vertLoc = gl.getAttribLocation(Program, "vertex");
    colorLoc = gl.getAttribLocation(Program, "color");
    //   
        ...
        ...
    
    gl.vertexAttribPointer(vertLoc, 3, GL.FLOAT, false, 4 * SIZEOF_FLOAT, 0);
    shader.unbind()
    

    I also learn OpenGL maybe you find something useful:
    ![Processing intern easy to use Attribute ]https://github.com/tolkanabroski/pshader-processing/blob/master/basics/iknowopengl.pde

    ![OpenGL Raw Location Attribute]https://github.com/tolkanabroski/pshader-processing/blob/master/basics/gl4_advancedpoints.pde#L68

  • edited June 2017

    That does really speed things up, is it possible to use FX2D with PGraphics? I have tried a few things and can't use .beginDraw() on a PGraphics set to the FX2D type, I get a NullPointerException.

    Instead of directly drawing to the canvas, I need to draw into a PGraphics container.

    I found PGraphicsFX2D but I don't know what I need to include for processing to be able to see it.

  • image(XYZ,width/2,0);

    also gives me NullPointerException

    reference about createGraphics sais

    renderer String: Either P2D, P3D, or PDF

    So I guess not

    If you need a shader can you show your code that you have now, so I can see exactly what you wan't the shader to do?

  • edited June 2017

    I wasn't going to release this, as it's part of a game I'm working on, but I made a little tech demo of it, enjoy. I'm pretty proud of how well it works.

    I grew very frustrated attempting to implement the various pathfinders already released for processing, and even more so attempting to implement A* myself. I came up with this solution myself, but as usual I just reinvented something that already existed without knowing, called flow field path finding. I just spent some time cleaning it up, but I'd like to get it published into a library.

    https://github.com/lmccandless/Processing3/tree/master/pathFlowing

    The part that is killing it is drawing the lines and ellipses to the pgCollisionMap every frame with P2D. Attempts to move over to FX2D are so far unsuccessful, but tests seem to indicate a dramatic speedup if I can get it to work, or some other solution such as suggested in my OP.

  • edited June 2017 Answer ✓
  • edited June 2017 Answer ✓

    so if you want to let processing tell the shader where to draw the lines you have to use uniform the PShader , and you need to have a fixed number of lines in the shader i belive
    so if you wan't 50 walls i belive you need something like this..
    in shader uniform vec4 lines [50];
    in processing
    float wallSend[200] x,y,z,w,x,y,z,w // a 200 element float array
    and to pass it over use PShader.set("lines" wallsend, 4);

    it can be a bit tricky though, now reading this function and seeing if it can be rewritten somehow to do that instead

    float [] wallSend = new float[200]; 
    void drawCollisionMap() {
    for (int i=0; i<50; i+=4) {
        wallSend[i]=wall.loc.x;
        wallSend[i+1]=wall.loc.y;
        wallSend[i+2]=wall.loc.x - wall.loc2.x;
        wallSend[i+3]=wall.loc.y - wall.loc2.y;
      }
      shader.set("lines",wallSend,4);
    }
    

    might be wrong though

    EDIT: also need thickness
    and seems your code runs fine and fast as is?

  • edited June 2017

    Thanks a ton for the clear examples. I was able to implement your code and use it to draw both the lines and ellipses. It increased my uncapped FPS from ~80 to ~160, well worth the effort!

    This needs to run invisibly in the background of my game and any bit of CPU usage saved is more available for adding features later.

    I am however encountering a problem. I am using a vec2 array for the ellipses, and I have narrowed it down to precisely 924 as the max array size that works. If I increase the size of the array in the shader any higher, I get an unclear error in processing about it. Any idea what could be going on here?

    https://github.com/lmccandless/Processing3/tree/master/pathFlowingFaster

    edit: I was able to get some meaningful errors out of processing like "Constant register limit exceeded; more than 1024 registers needed to compiled program". I guess my shader inexperience is showing, I had no idea of such a limitation. I know there has to be a way around this, like encoding the data into an image and passing that or something, but I'm hoping of an easier way.

  • edited June 2017

    I'm glad you were able to make use of it.
    Didn't know abut the max-array size issue...

    I wrote some more shape code.
    http://thebookofshaders.com/edit.php?log=170611133504 edit
    http://thebookofshaders.com/edit.php?log=170611172212
    Got an idea to make a class that talks to the shader as it's pretty complicated having to build arrays out of everything.
    Might be hard to realise, but I'll give it a try.
    https://github.com/Prince-Polka/Processing-Sketches/tree/master/shaderShapes
    EDIT: got it somewhat working

  • edited June 2017

    Wow, great work, processing would really benefit from a fleshed out version of that, a much faster renderer than P2D, I wonder how it compares to FX2D. You've already implemented many of the main features someone could want. For a good speed comparison we'll need to convert from vec2 arrays for AB/CD to textures to avoid the register limit. Why isn't this already a thing, why is the default renderer technique so slow comparatively?

  • edited June 2017

    The default renderer is doing alot more things and has to be compliant with different of systems and old code.
    Also the goal of processing is teaching, not performance.

    Don't wan't to give any flack on the processing developers
    It's easier, significantly faster than https://clickteam.com/ software, and free

    If you need even more performance , which I don't think is needed...
    openframeworks is worth a look
    And also this new programming language and game developed by Jonathan Blow

  • edited July 2017

    I thought using PShape would be much faster, but I'm only seeing a slight improvement:

        PShape shp;
        void setup() {
          fullScreen(P2D);
          shp = createShape(ELLIPSE, 0, 0, 20, 20);
        }
        void draw() {
          background(140);
          randomSeed(0);
          translate(width/2, height/2);
          rotate(millis() * 0.001);
          for (int i=0; i<3000; i++) {
            // 37 fps with 3000 items
            //ellipse(random(-200, 200), random(-200, 200), 20, 20);
    
            // 42 fps with 3000 items
            pushMatrix();
            translate(random(-200, 200), random(-200, 200));
            shape(shp, 0, 0);
            popMatrix();
          }
          if (frameCount % 60 == 0) {
            println(frameRate);
          }
        }
    

    With PShape you don't pass all the vertices each time to the GPU (as it happens with ellipse). Maybe there's something on the latest version that makes it slower, as I would swear I could draw thousands of shapes at 60 fps.

    BTW, using openFrameworks does not magically make things faster. Processing or openFrameworks can be both the fastest, if you have an idea of how things work behind the scenes (to avoid sending too much data to the graphics card). I've been surprised to port some sketches to C++ and they actually ran slower. Maybe because I know less C++ than Java, or because the way specific drawing functions I used are implemented in Processing and in OF.

    You could look at Examples > Demos > Performance for ideas

Sign In or Register to comment.