Is it normal for a program with a lot of image arrays to run slow at 300 fps?

I have a very powerful gaming PC, but my program starts to get fps drops at 300 fps. Is it normal for a program with a lot of image arrays (a lot of triggered animations), even for a powerful computer like mine?

I also have animations that have to gain and lose shape when certain things happen in the program, so I scale() the images from the image array in the draw() function. I presume that is very data-deficient, but how else can I achieve this without scaling each image each frame?

Answers

  • Resizing the image shreds quality, so when I resize it to a really small size then back to a reallt big size, the quality turns dismal. Thus, I have to scale it ..

  • starts to get fps drops at 300 fps

    And this is slow? 300 fps is slow?

    You keep posting variants on the same question and people keep telling you that resizing images in draw is expensive.

  • Yes, but nobody’s helping me in figuring out a less costly way to resize an image in the course of a program without having to resize it in draw.

    Say, for example, I want to make a sprite of a bouncing ball smaller every time it hits a wall, and I want its size to reset to original once it gets too small. How do I achieve that without using scale() in draw? Resize() destroys the image once I resize it from small to original size.

  • Yes, but nobody’s helping me in figuring out a less costly way to resize an image in the course of a program without having to resize it in draw.

    which may be because it's impossible?

    how's about textured quads? look into textured quads and move some of the work onto the gpu (which is designed for this stuff)

  • edited September 2017

    Thank you for the suggestion, it was very useful. I am reading up on P2D and trying to utilize the GPU in my sketches. I am still not entirely certain whether it optimizes my sketch the way I'm using it.

    Should I create a new PGraphics with the same width and height as everything else, adding P2D to it, something like "GPUusage = createGraphics(width,height,P2D)" in setup, and then simply enclose the sprite in this PGraphic in draw (GPUusage.beginDraw(); draw sprite; GPUusage.endDraw();) ? Would that move the sprite to the GPU?

    I tried it for myself but apparently for that to work I need to set P2D as the default renderer which makes my whole sketch slow as hell. Am I supposed to call P2D in size, then create two PGraphics - one with P2D and one using the normal renderers, and then call the normal renderer graphics before everything else and the P2D ones just before the sprite? That sounds extremely excruciating. I am interested in making the sketch compatible with android devices and am unsure how to check whether it is. Would the above method improve performance or is there anything more that I need to know?

    I'm sorry for the avalanche of questions, but I'm not very familiar with computers and am trying to pick up on things as best and as fast as possible.

  • The best way to do it would to scale the transformation matrix rather than the image. For instance if you have an image called img and you want to display it at 35% then try something like this

    pushMatrix(); // save the transformation matrix
    scale(0.35); // scale the transformation matrix 
    image(img, x, y); // draw the image at the appropriate sie
    popMatrix(); // restore the transformation matrix
    

    The advantage here is that you never change the actual image so you won't loose detail from shrinking then enlarging the image (because you aren't doing that thus saving time)

    The pushMatrix and popMatrix are used to isolate transformations so they don't affect other drawing commands.

    If you haven't done this before I strongly advise that you create a small sketch with a few images and experiment with this technique. Trying to insert a new technique into an existing application can be difficult to get right, so make sure you are always working with a copy of your code.

  • (i was thinking about the third example here - https://processing.org/reference/vertex_.html . you can use QUADS as an argument to beginShape())

  • @koogs - that is a simpler solution than mine, simply change the vertices to change the size. of the image.

  • edited September 2017

    @koogs Many thanks! I still haven’t had the opportunity to test your solution but it sounds like it would work. Are you suggesting I basically use quad(x,y) instead of vertex(x,y) after beginShape()? Why does it work with quad() and not with vertex()? That’s a way to display an image that I altogether haven’t used.

  • Stupid of me. I tried using, and playing around with, QUADS as an argument to beginShape but it doesn't work. I am simply scaling the matrix now and it seems to work okay. I reckon there is no better option.

  • // floating quads
    // acd 2017
    public static final int SQUARES = 500;
    
    PImage img;
    Square[] square = new Square[SQUARES];
    
    void setup() {
      size(800, 800, P2D);
      img = loadImage("head.png"); // anything 256x256px
      for (int i = 0 ; i < SQUARES ; i++) {
        square[i] = new Square();
      }
      textureMode(NORMAL);
    }
    
    void draw() {
      background(0);
      translate(width / 2, height / 2);
      for (int i = 0 ; i < SQUARES ; i++) {
        square[i].draw();
      }
    }
    
    class Square {
    
      float ax, ay, as;
      float dx, dy, ds;
    
      Square() {
        // initialise
        ax = random(TWO_PI);
        ay = random(TWO_PI);
        dx = random(-.02, .02);
        dy = random(-.02, .02);
        as = random(TWO_PI);
        ds = random(.025);
      }
    
      void draw() {
        // update position
        ax += dx;
        ay += dy;
        float x = (width / 4) * sin(ax);
        float y = (height / 4) * sin(ay);
        // update size
        as += ds;
        float sz = (height / 8) + (height / 16) * sin(as);
        // draw the quad
        beginShape(QUADS);
        texture(img);
        noStroke();
        vertex(x - sz, y - sz, 0, 0);
        vertex(x - sz, y + sz, 0, 1);
        vertex(x + sz, y + sz, 1, 1);
        vertex(x + sz, y - sz, 1, 0);
        endShape();
      }
    }
    

    500 moving, resizing, textured quads. barely registers on my cpu monitor (intel i5, nvidia gtx950m)

  • edited September 2017

    @koogs Apparently this does not register invisible color. It stretches the visible parts of my sprite to the borders of the shape and totally disfigures it, ignoring the 40000 or so invisible pixels.

  • i haven't seen your code and have no idea what you are talking about. the two things may be related.

    i used a transparent png and it looked fine:

    acd

  • edited September 2017

    translate(classx,classy); rotate(-angle-1.5*PI); beginShape(QUADS); texture(sprite[spriteframe]); noStroke(); vertex(-50,-50); vertex(50,-50); vertex(50,50); vertex(-50,50); endShape();

    This is what I used. Image mode is center (sprite is ball-shaped and I need to calculate circle-circle collision so it has to be). It also has to be rotated so I have to use pushMatrix(). spriteframe is the image displayed, dictated by another function that updates it every 200 milliseconds to create the animation. It doesn't work. It distorts the image. This is an image from the image sequence I have.

    Edit: Matter of fact, I just get a red square. Nothing more.

    blob1

  • pushMatrix(); angle = atan2(rotationx,rotationy); translate(translatex,translatey); scale(scalevalue); rotate(-angle-1.5*PI); image(sprite[spriteframe],0,0);

    This, instead of the code above, works properly but affects performance.

  • note the 4 argument vertex() call that i use. read the reference.

    with your first code sample i get this in the console: "No uv texture coordinates supplied with vertex() call"...

    runnable examples please.

  • and trim that image. there's no point in having 100 invisible pixels in every direction.

  • edited September 2017

    Oh my god, I am a complete idiot. Both in your code and in the example there are four arguments, and I keep trying and trying with two...

    I should probably rest a little.

    But I am going to do it the proper way now. Why would your alternative improve performance, though? Isn't the image still recalled each frame?

    I need the extra pixels because in the animation, the ball grows appendages, reaches out towards things in the distance, etc.

  • it's the physical scaling that takes the time. you have to iterate over every pixel deciding where on the destination the source pixel goes. and it's not a linear thing, normally, so it's not a one to one mapping.

    https://en.wikipedia.org/wiki/Bicubic_interpolation

    graphics cards are built for this, do all the resizing in dedicated hardware. and generally keep a local copy of the texture images in high speed memory (and maybe the geometry (if using pshape for instance, vbo's)) so there's no transfer delay.

  • edited September 2017

    Extremely enlightening.

    texture() is not available with this renderer. vertex(x, y, u, v) is not available with this renderer.

    This is the error message that I get when following your example properly, and and the code runs without the image altogether.

    Do I need to use P2D?

    How would that work in my whole code? I need to add P2D in the setup. Do I need to create new PGraphics without the P2D, and draw practically everything else inside them? That would be excruciating.

  • Answer ✓

    if you aren't using p2d then you aren't following my example!

    i know nothing of how you're using pgraphics. i've still not seen a runnable example of your code.

  • The whole code is one thousand lines.

    What I don't understand is - P2D doesn't work unless I call it in the program's void setup. But I notice that if everything is in P2D performance declines majorly. So I need to make it that I have only the things I need in P2D, and the things I don't in the normal renderer. Does that mean that I need to add two renderers in the original setup()? Something like:

    void setup() {
       size(500,500);
       size(500,500,P2D);
    }
    

    And then after that I need to create new PGraphics with P2D, and new PGraphics without P2D, and draw everything under one or the other? That sounds like it would be a pain to do.

  • The whole code is one thousand lines.

    which makes it all the more unreasonable for us to have to guess what you're doing.

  • A huge part of it is unrelated to what I'm asking about here.

    If I try to create a PGraphics with P2D and load the sprite inside them, it says that I need to use P2D as the main renderer in order to have a P2D PGraphics. But if I use P2D as the main renderer, the whole program gets extremely slow. I am so close to getting it right but I just need that final push! :(

  • edited September 2017

    I have successfully incorporated a layer of PGraphics with P2D in the proper places. The thing is, that regardless of whether I use beginShape to draw it, or I just scale() it, P2D improves performance all the same. Does that make sense?

    Edit: The program runs well, but I also get a number of vertical lines across the screen to appear randomly over its course.

Sign In or Register to comment.