Processing Examples : Bouncy balls + Mouse functions examples combine

rajraj
edited October 2017 in Raspberry PI

Hello,

I am working on an simple interactive installation off a PI. This is part of a mobile projection mapping project. Programming question : I want to combine the two processing book examples to overlap. I would like to get your opinion how to approach ? Box2D ? I have basic programming skills. so a direction is very welcome.

  1. the popular Bouncy Balls - here
  2. Mouse Functions : here

Installation : 2m*2m white-board with various differ size 3 mirrors on it. The bouncy ball effects looks on white background. However adding mouse function to aligning the rectangles to the physical mirrors (mapping with mouse) would make it funny. A PIR sensor monitors people's movement and make the bouncing fast/slower.

I read on forums that processing is not best solution for PI, do you suggest alternatives ?

Answers

  • @raj You should be able to take the Bouncy Balls code and run it as it (fullscreened) on a Raspberry Pi with Processing. Not entirely sure what your requirements are with regards to "projection mapping" - but this is not something that Processing does out of the box, and would likely involve rather advanced shader programming. PIR sensor is contingent on how it outputs its data.

  • Thank you for reply @gohai and also thank you for all the work put in for GLVideo and your other work I am yet to cross paths with :).

    Yes I run the bouncy ball example fullscreen - looks good in dark space. I am talking about a simple mapping. In this case where 3 rectangles (as in example 2-above) that can be placed with mouse in certain area of the bouncy ball example fullscreenes. Bouncy-balls now also bounce-off/interact with the static rectangles.

    May this 3 second animation speak 100 words. I call this mapping because I use projector to project output of the sketch on physical surface and adjust the rectangles to the physical mirrors. I use other softwares to do real projection mapping. The whole idea here is use processing+pi+pico projectors to do easy set-up mappings, mostly mobile.

    I am not sure why would shaders come into picture here, not that I know anything about shaders :) ..

  • @raj

    Oh yes, that should definitely work. Just be aware that the the balls themselves won't have their perspective corrected, so they will always appear to be coming from the projector. But simply using geometric shapes to "mask out" parts of the screen in order to make it inaccessible to the simulated balls should be doable!

  • edited October 2017

    Re:

    adjust the rectangles to the physical mirrors. I use other softwares to do real projection mapping.

    So are you also running that software in this setup? If not, P3D renderer + PGraphics + PeasyCam for fast setup interface could give you a quick tilted screen effect for projection -- anything you draw on that PGraphics will be perspective tilted via OpenGL

    Edit: ...ah, I get it. I looked at the examples, and you aren't doing anything with projection on angled surfaces or perspective -- the rectangles are cut-outs.

  • edited October 2017 Answer ✓

    You want to base your bounces on collision detection -- specifically, circle-rect.

    And you want to specify rect geometry with the mouse -- this is the tricky part, as that requires two clicks with switching between mouse states plus saving a selection and deleting bad / old selections.

    The whole thing is hard to test without a physical setup -- so let's create random rectangles that represent mirrors in your physical space. Then we add a list of selections, mouse and keyboard controls for creating and deleting them, and drawing code that shows the list of saved selections and the current active selection.

    Then we add a bouncing ball. Finally, simple collision detection that knows when the ball has crossed over into one of the selections. This demo doesn't actually bounce the ball off the selections -- it just changes color, not direction.

    The real sketch wouldn't have these fake white targets, and it would have an option to hide the selections after they have been set up.

    RectMouseMapping--screenshot

    /**
     * RectMouseMapping -- mapping rectangles with the mouse
     * 2017-10-30 Jeremy Douglass - Processing 3.3.6 
     * forum.processing.org/two/discussion/24762/processing-examples-bouncy-balls-mouse-functions-examples-combine
     */
    ArrayList<Rect> mirrors;
    ArrayList<Rect> selections;
    Rect activeSelection;
    boolean active;
    Ball ball;
    
    void setup() {
      size(400, 400);
      mirrors = new ArrayList<Rect>();
      selections = new ArrayList<Rect>();
      activeSelection = new Rect(0, 0, 0, 0);
      ball = new Ball(random(width), random(height));
      randomRects();
    }
    
    void draw() {
      background(0);
    
      // draw simulated mirrors
      for (Rect r : mirrors) {
        r.render();
      }
    
      // draw selections (bounce barriers)
      pushStyle();
      fill(128, 128, 255, 128);
      for (Rect r : selections) {
        r.render();
      }
      popStyle();
    
      // move bouncing ball
      pushStyle();
      ball.move();
      // check for selection collision
      for (Rect r : selections) {
        if(circleRect(ball.x, ball.y, ball.r, r.x, r.y, r.w, r.h)){
          fill(255,0,0);
        }
      }
      ball.render();
      popStyle();
    
      // draw active mouse selection
      pushStyle();
      fill(255, 128, 128, 128);
      activeSelection.render();
      popStyle();
      instructions();
    }
    
    void instructions(){
      pushStyle();
      fill(255,128);
      rect(0,0,width-1,42);
      translate(4,14);
      fill(0);
      text("Click upper corner, click lower corner, SPACE to add.", 0, 0);
      text("DELETE to cancel selection or remove previous.", 0, 12);
      text("ENTER to shuffle.", 0, 24);
      popStyle();
    }
    
    class Rect {
      float x, y, w, h;
      Rect(float x, float y, float w, float h) {
        this.x=x;
        this.y=y;
        this.w=w;
        this.h=h;
      }
      void render() {
        rect(x, y, w, h);
      }
    }
    
    void randomRects() {
      mirrors.clear();
      int count = (int)random(2, 5)+1;
      for (int i=0; i<count; i++) {
        float x = random(width);
        float y = random(height);
        float w = random(width/6, width/4);
        float h = random(height/6, height/4);
        mirrors.add(new Rect(x, y, w, h));
      }
    }
    
    void keyReleased() {
      if (key == BACKSPACE || key == DELETE) {
        if (active == true) {
          // clear active selection
          activeSelection = new Rect(0, 0, 0, 0);
          active = false;
        } else {
          // remove last selection
          if (selections.size()>0) {
            selections.remove(selections.size() - 1);
          }
        }
      }
      if (key == ' ' && active == true) {
        // save active selection and reset
        selections.add(activeSelection);
        reset();
      }
      if (key == RETURN || key == ENTER) {
        randomRects();
        reset();
      }
    }
    
    void reset() {
      activeSelection = new Rect(0, 0, 0, 0);
      active = false;
    }
    
    void mouseReleased() {
      if (active == false) {
        activeSelection = new Rect(mouseX, mouseY, 20, 20);
        active = true;
      } else {
        activeSelection.w = mouseX - activeSelection.x;
        activeSelection.h = mouseY - activeSelection.y;
      }
    }
    
    // based on processing.org/examples/bounce.html
    class Ball {
      int r = 10;          // Width of the shape
      float x, y;          // Starting position of shape    
      float xspeed = 2.8;  // Speed of the shape
      float yspeed = 2.2;  // Speed of the shape
      int xdirection = 1;  // Left or Right
      int ydirection = 1;  // Top to Bottom
      Ball(float x, float y ){
        this.x = x;
        this.y = y;
      }
      void move(){
        // canvas boundaries
        if (x > width-r || x < r) {
          xdirection *= -1;
        }
        if (y > height-r || y < r) {
          ydirection *= -1;
        }
    
        x = x + ( xspeed * xdirection );
        y = y + ( yspeed * ydirection );
      }
      void render(){
        pushStyle();
        ellipseMode(RADIUS);
        ellipse(x, y, r, r);
        popStyle();
      }
    }
    
    // based on www.jeffreythompson.org/collision-detection/circle-rect.php
    boolean circleRect(float cx, float cy, float radius, float rx, float ry, float rw, float rh) {
    
      // temporary variables to set edges for testing
      float testX = cx;
      float testY = cy;
    
      // which edge is closest?
      if (cx < rx)         testX = rx;      // test left edge
      else if (cx > rx+rw) testX = rx+rw;   // right edge
      if (cy < ry)         testY = ry;      // top edge
      else if (cy > ry+rh) testY = ry+rh;   // bottom edge
    
      // get distance from closest edges
      float distX = cx-testX;
      float distY = cy-testY;
      float distance = sqrt( (distX*distX) + (distY*distY) );
    
      // if the distance is less than the radius, collision!
      if (distance <= radius) {
        return true;
      }
      return false;
    }
    
  • @jeremydouglass - Thank you a lot for going the extra mile and writing the code. I could not have figured this far.

    I ran the code and it words very well. The changing color of the balls when interacting with the box gives a good proxy as how the direction (and speed ) can be changed too. I hopefully understand whats going on :) Thank you indeed for all the comments in the code.

    And also thank you for the reference material from Jeffery Thompson. Yet to go through all the examples but realized my flaw in concepts fromand time to learn.

    best regards Raj

  • @gohai - When I set-up physical space (just colored paper on wall and projected) I notice a perspective problem. Not sure you mean same. The rectangles when projected from projector to physical rectangles (in this case mirrors) does not align properly because of angles of projections. A polygon will be a accurate solution. However its more complex to calculate the polygon collision with bouncy-balls. So for now sticking with rectangles seems to make life little easier :) ..

  • edited October 2017

    Glad it is working. Thompson's tutorials are pure gold, but many focus on overlapping -- not bouncing. In order to bounce, you need to know not just that you are overlapping, but from which direction. With inside-box bounce code (like the ball and the edges of the screen), this is easy -- without outside-box bounce code it is a bit harder (more conditions), but basically the same thing,

    Re: perspective distortion. Yes, that is a problem with quick-and-dirty mapping. There is a four-click version of the code I showed you that will input a closed polygon -- same design, but you click in each point of the rectangle. You can do this with a custom class or with a PShape.

    Still, I would recommend getting everything else working first, then create a second sketch and try to get that working.

    Another alternative approach is to scribble a mask (like drawing with a crayon) and then bounce if the detected pixel is white. That makes complex geometry easy to input, but bouncing is a bit harder to handle.

Sign In or Register to comment.