gradient from the center up and down

edited February 2014 in How To...

hello, I'm newbie

how to make on the display window gradient from the center up and down, and that this gradient is controlled with a variable, mouseY (for example)?.

can you help me to do better, share examples or better I'm doing?

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

    void draw() {
      background(0);

      beginShape();

      fill(0,0,0);
      vertex(0,250-mouseY);

      fill(0,0,0);
      vertex(500,250-mouseY);

      float x1 = map(mouseY, 0, width, 0, 255);
      fill(x1,0,0);
      vertex(500,250);

      float x2 = map(mouseY, 0, width, 0, 255);
      fill(x2,0,0);
      vertex(0,250);

      endShape();

      beginShape();

      float x3 = map(mouseY, 0, width, 0, 255);
      fill(x3,0,0);
      vertex(0,250);

      float x4 = map(mouseY, 0, width, 0, 255);
      fill(x4,0,0);
      vertex(500,250);

      fill(0,0,0);
      vertex(500,250+mouseY);

      fill(0,0,0);
      vertex(0,250+mouseY);

      endShape();
    }
Tagged:

Comments

  • edited February 2014

    Hi lotte,

    it's interesting you did this with shapes and P2D blending, I'd never come up with such a solution. :)

    I don't know if I fully understood your question, but here's a simpler solution to make such a gradient with drawing shrinking rectangles on top of each other for each half of the gradient and interpolating their fill color with the lerpColor() function:

    int h;
    
    void setup() {
      size(400, 400);
      noStroke();
    
      h = height/2; // Height of the two half gradients
    }
    
    void draw() {
      // Map mouseY to gradient intensity
      int cFrom = (int) map(mouseY, 0,height, 0,180);
      int cTo = (int) map(mouseY, 0,height, 80,255);
    
      // Draw a bunch of rectangles on top of each other to simulate gradient
      for (int i=h; i>0; i-=1) {
    
        color from = color(cFrom, 0, 0);
        color to = color(cTo, 0, 0);
    
        // Interpolate the color value from i for upper half
        color inter = lerpColor(from, to, map(i, h, 0, 1.0, 0.0));
        fill(inter);
        rect(0, 0, width, i);
    
        // Reverse-interpolate the color value from i for lower half
        inter = lerpColor(from, to, map(i, h, 0, 0.0, 1.0));
        fill(inter);  
        rect(0, height/2, width, i);
      }
    }
    

    You don't have to use the second "cTo" variable, but it makes the gradient a bit smoother, like in your example.

  • edited February 2014

    @peter_h: lottes solution is pretty much the standard for OpenGL hardware and should be around 200-250 times faster than your approach.

    @lotte: I'm not entirely sure what you are aiming for, but performance wise your code is already pretty good. I optimized it a little bit further, reduced the two draw calls (beginShape()/endShape()) to one, set the shapes type to QUADS (will tell the graphics card how to handle/connect the given vertices), removed unnecessary fill() and map() calls and rotated the gradient by 90° (don't know if that was what you've wanted):

    int halfWidth;
    
    void setup() {
        size(500, 500, P2D);
        halfWidth = width / 2;
        noStroke();
    }
    
    void draw() {
        background(#000000);
        float red = map(mouseY, 0, height, 0, 255);
        float scale = map(mouseY, 0, height, 0, halfWidth);
        beginShape(QUADS);
        fill(#000000);
        vertex(halfWidth - scale, 0);
        vertex(halfWidth - scale, width);
        fill(red, 0, 0);
        vertex(halfWidth, width);
        vertex(halfWidth, 0);
        vertex(halfWidth, 0);
        vertex(halfWidth, width);
        fill(#000000);
        vertex(halfWidth + scale, width);
        vertex(halfWidth + scale, 0);
        endShape();
    }
    
  • edited February 2014

    hi @peter_h & @Poersch, many many thanks,

    I would like to explain better;

    the gradient function as a sunrise, horizontally, from night till noon.

    starting with a total black, the gradient begin in the middle of the display, and would go increase both up and down until the total red (no gradient)

    I have explained a little better? I'm fighting with your sketches, some things still do not understand, thanks...

  • edited February 2014

    This should get you startet:

    int halfHeight;
    
    void setup() {
    
        size(500, 500, P2D);
        noStroke();
    
        halfHeight = height / 2;
    
    }
    
    void draw() {
    
        float factor = (float)mouseY / height; // Basically what the map function does
        float red = 255 * factor;
        float scale = halfHeight * factor;
    
        background(#000000);
    
        beginShape(QUAD_STRIP); // QUAD_STRIP performs even better then QUADS, as you don't have to resend shared vertices
        fill(#000000);
        vertex(width, halfHeight - scale);
        vertex(0, halfHeight - scale);
        fill(red, 0, 0);
        vertex(width, halfHeight);
        vertex(0, halfHeight);
        fill(#000000);
        vertex(width, halfHeight + scale);
        vertex(0, halfHeight + scale);
        endShape();
    
        fill(#ff0000, factor * factor * 255); // An transparent overlay coloring the whole screen (factor * factor gives you a non linear fade)
        rect(0, 0, width, height);
    
    }
    

    And a little bit more advanced:

    int halfHeight;
    
    void setup() {
    
        size(500, 500, P2D);
        noStroke();
    
        halfHeight = height / 2;
    
    }
    
    void draw() {
    
        float factor = (float)mouseY / height; // Basically what the map function does
        float red = 255 * factor;
        float scale = halfHeight * factor;
    
        background(#000000);
    
        renderGradient(#ff0000, height, factor);
        renderGradient(#ffc700, halfHeight, factor);
    
        fill(lerpColor(#ff0000, #ffc700, factor), factor * factor * 255); // An transparent overlay coloring the whole screen (factor * factor gives you a non linear fade)
        rect(0, 0, width, height);
    
        renderGradient(lerpColor(#ffc700, #ffffff, factor), halfHeight / 2, factor);
    
    }
    
    void renderGradient(int gradientColor, float size, float factor) {
        float scale = size * factor;
        beginShape(QUAD_STRIP);
        fill(gradientColor, 0);
        vertex(width, halfHeight - scale);
        vertex(0, halfHeight - scale);
        fill(gradientColor, 255 * factor);
        vertex(width, halfHeight);
        vertex(0, halfHeight);
        fill(gradientColor, 0);
        vertex(width, halfHeight + scale);
        vertex(0, halfHeight + scale);
        endShape();
    }
    
  • edited February 2014

    @Poersch many thanks,

    your second sketch is too much for me...

    I am working with the first; I like the logic that has followed, making those four variables, have you followed any rules?

    I would like to modify it so that the gradient is equal to mine. You could also do it?

    I'm doing reverse engineering to understand how your vertices (you sketch) work, I have reduced your sketch to a minimum and then I deleted the variables,

    this is a sketch to a minimum;

    int halfHeight;
    
    void setup() {
    
        size(200, 200);
        noStroke();
    
        halfHeight = height / 2;
    }
    void draw() {
    
      background(0);
    
      beginShape();
    
      float factor = (float)mouseY / height; 
      float scale = halfHeight * factor;
    
      vertex(0, halfHeight - scale);
      vertex(width, halfHeight - scale);
    
      vertex(width,height);
      vertex(0, height);
    
      endShape(CLOSE);
    }
    

    and here I deleted your variables

        void setup() {
    
          size(200, 200);
          noStroke();
    
        }
    
        void draw() {
    
          background(0);
    
          beginShape();
    
          vertex(0, (height/2)-((height/2)*((float)mouseY/height)));
          vertex(width, (height/2)-((height/2)*((float)mouseY/height)));
    
          vertex(width,height);
          vertex(0, height);
    
          endShape(CLOSE);
        }
    

    I have more simplified preserving the same functionality;

    void setup() {
    
      size(200, 200);
      noStroke();
    
    }
    
    void draw() {
    
      background(0); 
      beginShape();
    
      vertex(0, (height/2)-mouseY);
      vertex(width, (height/2)-mouseY);
    
      vertex(width,height);
      vertex(0, height);
    
      endShape(CLOSE);
    
    }
    

    and I've noticed that your code is smoother, much better, Why? What does "(factor factor * Gives you a non linear fade)"?

  • edited February 2014

    Don't use beginShape() plus endShape(CLOSE) unless you have to. If you don't tell Processing what kind of shapes you are creating it has to tessellate them to triangles by itself. If you are telling Processing, that you will send for example QUADS, it will simply tell the graphics card to tesselate quads, which is much faster. In your case it doesn't really matter (performance wise), but it's always good to know how to improve your code.

    Try not to delete the variables, they are simplifying the code for you, try instead to understand what exactly they do.

    My code is running smoother because I'm using the OpenGL and therefore hardware based renderer P2D. Just replace size(200, 200) with size(200, 200, P2D) to use this renderer.

    The following code should do the same as your first code snippet:

    int halfHeight;
    
    void setup() {
    
        size(500, 500, P2D);
        noStroke();
    
        halfHeight = height / 2;
    
    }
    
    void draw() {
    
        float factor = (float)mouseY / height;
        float red = 255 * factor;
        float scale = mouseY * factor;
    
        background(#000000);
    
        beginShape(QUAD_STRIP);
    
        // The upper edge of the gradient - using height / 2 + mouseY * (mouseY / height)
        fill(#000000);
        vertex(width, halfHeight - scale);
        vertex(0, halfHeight - scale);
    
        // The center of the gradient - using height / 2
        fill(red, 0, 0);
        vertex(width, halfHeight);
        vertex(0, halfHeight);
    
        // The lower edge of the gradient - using height / 2 - mouseY * (mouseY / height)
        fill(#000000);
        vertex(width, halfHeight + scale);
        vertex(0, halfHeight + scale);
    
        endShape();
    
    }
    
  • @Poersch many thanks for your answers and patience...

    if you need anything from Pure Data or MaxMSP tell me.

    I can not understand the variables "factor" and "scale", Do you know of any book or site where this is explained?

    Is it possible to blur(fade out) the longitudinal center line of the gradient?

  • edited February 2014

    No problem. :)

    factor contains the ratio/proportion from mouseY to height, a value from 0.0 to 1.0.

    • Given a window height from 300px and a mouse Y position from 30px, factor would be 0.1.
    • Given a window height from 500px and a mouse Y position from 250px, factor would be 0.5.
    • Given a window height from 200px and a mouse Y position from 200px, factor would be 1.0.

    scale equals mouseY * factor. It's an value with exponential growth (the higher mouseY, the higher factor).

    • Given a window height from 400px and a mouse Y position from 100px, factor would be 0.25, while scale would be 25.
    • Given the same window height and a mouse Y position from 200px, factor would be 0.5, while scale would be 100.
    • Given the same window height and a mouse Y position from 300px, factor would be 0.75, while scale would be 225.

    See, while mouseY and factor grow linear, scale grows exponentially.

    What exactly do you mean by blur (fading out) the center line? Do you want to darken or lighten the vertical line while the mouse moves up or down?

  • @Poersch many thanks for your answer.

    I wonder where you learned those things "factor" and "scale", to understand how it is the process that you follow when programming, and thus to understand how you arrive to the conclusion to use them, Where do I can find more information, are they math, programming?.

    I mean the horizontal line (the center) of the gradient, the problem is that this line is too visible, always stands out, even when the gradient fills the entire screen, could be made less visible?, (I can't find the English word; blur, fade out, diffuse, blear, fuzzy, spread).

  • Years of practice. ;) But of course there are shortcuts, the Processing site offers a nice range of books about programming: http://processing.org/books/

    Anyhow, if your mouse's Y position is >= height, the whole window should be filled in the same color (red). If that's not the case, there is something wrong. Have a look at one of my former examples.

  • I'll get all the books of Processing and look for "factor" and "scale" :)

    yes, everything works well, the screen fills with red,

    but still is a subtle centerline, do not see the same in all my monitors, looks better on my laptop, close, and when I move the screen forward or backward (new MacBook Air)

    would be possible to give a more organic feel, vintage, analog?

Sign In or Register to comment.