GENCG Working Journal - Day 4 - Drawing Machine


What is a drawing machine? I asked myself that question several times. Basically every sketch we do with p5 is a drawing machine. We give the system some input, define a ruleset by writing conditional structures in code and the program draws something for us.
What makes a drawing machine is the fact that the program manipulates the input we give it in an unpredictable manner. We do have some way of controlling the drawing machine, but since it is a machine, it distorts the input we give and comes up with something we didn't plan upfront.
I decided that I want to create my own input system. I wanted to have some camera input and have it so, that the viewer can draw something by moving infront of the camera. My idea was, that the user could use his smartphone flashlight to draw on the canvas.
Also your PC might struggle on this page because the calculation are quite heavy on your CPU. All sketches are embedded via IFrames and are all loaded and processed simultaneously.
If you encounter too much lag, consider using the provided links to the individual sketches!
Show me!
In the code I search for the brightest pixel in the camera input and draw a circle at that position.
        // the rgba values of each pixel
        let r = camInput.pixels[loc];
        let g = camInput.pixels[loc + 1];
        let b = camInput.pixels[loc + 2];
        let a = camInput.pixels[loc + 3];
        // a color object provided by the p5 library
        let c = color(r, g, b, a);
        // here i check the brightness of the pixel
        let bright = brightness(c);
        // i save a position reference to the brightest pixel
        if (bright > brightestValue) {
          brightestValue = bright;
          brightestPixelIndex = loc;
          xPos = map(x, 0, width / rasterizeDivider, width, 0);
          yPos = map(y, 0, height / rasterizeDivider, 0, height);
        }
      
The problem is, that depending on the lighting conditions there may be other pixels just as bright (255, 255, 255 -> pure white) as the ones coming from the flashlight. Also there is a reflection of the light in the camera lens which is hard to control. The code will simply pick the first completely white pixel and go with that. Not very good...
I decided to use another property than brightness, since this can be quite hard to control. In this example the code will look for the pixel with the highest red value.
You can reset the drawing by clicking on the canvas and then pressing R on your keyboard.
          // RGB values of the pixel
          let r = camInput.pixels[loc];
          let g = camInput.pixels[loc + 1];
          let b = camInput.pixels[loc + 2];
    
          // instead of checking for brightness, I check for the purest red since white also has a red value of 255
          if (r > rMax && g < gMin && b < bMin) {
            rMax = r;
            gMin = g;
            bMin = b;
            xPos = map(x, 0, width / rasterizeDivider, width, 0);
            yPos = map(y, 0, height / rasterizeDivider, 0, height);
          }
      
Show me!
Obviously this aproach suffers from the same problems as the one before, but it's a bit easier to control wheter or not red items are in the view of the camera. Now it's time to come up with some creative ideas on how to draw something better than just green dots. To be honest, what I came up with is not really useful, nor is it aesthetically pleasing. If I find the time, i'll come back to this and try to do something more satisfying. Also here you can reset the drawing by giving focus to the canvas by clicking on it and then pressing R.
Show me!
        
        // draw 10 circles increasing in size by index
        for (let i = 0; i < 10; i++) {
          noFill();

          // decrease the strokeWeight according to the index
          strokeWeight(map(i, 0, 9, 15, 2));
          // map colors and alpha to position and index parameters
          let r = map(random(xPos_target - 100, xPos_target + 100), 0, width, 0, 255);
          let g = map(random(yPos_target - 100, yPos_target + 100), 0, height, 0, 255);
          let b = random(0, 255);
          let alpha = map(i, 0, 9, 100, 10);
          stroke(r, g, b, alpha);
            
          let elipseWidth = map(i, 0, 9, 10, 400);
          ellipse(
            xPos_target,
            yPos_target,
            // create a 3D rotating effect by calculating width and height with sine / cosine
            elipseWidth * sin(millis() / 1000),
            elipseWidth * cos(millis() / 1000)
          );
        }
          
Finally here some pictures I have drawn with my drawing machines.