Yesterday (February 13, 2007) I completed a first LARGE painting using an airbrush mounted on my CNC machine to paint 22,000 0.4 inch squares (200 x 110 squares) in four transparent colors on Rives BFK paper. One of 17 simple shapes designed to produce tone in even steps from lightest to darkest was painted in each color over each square in order to produce the image.
I programmed a set of the ‘gestures’ (diamonds, and squares in various sizes and an ‘X’ and a ‘+’) to be painted in order to produce the 17 tones in the painting.
It’s taken the better part of a month to complete and I’ve likely now made most of the possible mistakes which show up quite painfully all over the surface. Gigantic blobs of watercolor leaking from my pigment bottle dripped onto the paper and were then blown all over the place by the air brush as it passed over the painting. Watercolor slowly clogging up the airbrush and leaving vertical ‘light’ areas in stripes. Watercolor spraying out too densely and leaving vertical ‘dark’ areas in stripes. Lines too thick. Lines too thin. Color too rich. Color too lean. The yellow layer offset a column to the left (the other colors were painted after a programming change which calculated the placement differently). Airbrush too close to the paper and too much paint volume resulted in LOTS of color blown out in tiny little splats. Dirty airbrush left broad haloes of color adjacent to lines. Lines unclear and fuzzy-looking.
Here are some details (click for enlargements) of interesting areas of the painting:
movie of painting underway
— Mike
PS… My friend, Jerry, just had a look at this page and phoned to say, “I should just keep my mouth shut… But… You’re totally back-sliding”. After advising me to immediately forward the image to the CIA for their use as ‘proof’ of WMD in Iran (referencing somewhat similar aerial views of Iraq offered up by the White House some years ago), he directed me to Vasarely images familiar from my childhood before (and I’m condensing here) and suggested that I get on to ‘making Art’… Yup… That pretty well sums it up, I think… OK — I’m getting on with it now…
PPS… I’ve consolidated an earlier post below:
My new 17-value airbrush characters seem to be working – now if I can only get my airbrush to not clog up after an hour or 30 minutes or 90 minutes – otherwise it’s gonna require constant supervision which ain’t worth it (and BORING)!
Here’s an image of my spreadsheet calculations of area – I’ve made a set of ‘gestures’ – diamonds, and squares in various sizes and an ‘X’ and a ‘+’:
The ‘X-area’ column is the list of gestures D for Diamond, S for Square, X for diagonals, and P for Plus and the 3-digit number is the area in thousandths that an eighth inch line produces in a 1 inch box.
These are designed to be overpainted in each of red, yellow, blue, and black according to the color and value content of the corresponding area of an image. I’ve got a sample image partially painted in yellow, blue, and red now and it’s pretty much electrically brilliant! There are 17 to the 4th theoretical color possibilities (83,000 plus variations), so PLENTY of variation!
THEN I had to write the program to analyze the image and write the ShopBot code – my code reads an initialization file I wrote in ShopBot code which defines the characters and the subroutines to call them, then the program goes on to analyze each pixel in the image and generate the ShopBot code to position the machine to the pixel and do the painting. The SO,3,1 turns on the airbrush and SO,3,0 turns it off. M2 means Move in 2 dimensions (x,y) – J2 means FAST Jog in 2 dimensions (x,y)
This is actually only the working part of a MUCH longer program – the long program gets input from a screen, checks to make sure it all makes sense, and then calls the appropriate operation, in this case the subroutine above… Here’s what the screen looks like when the program is running (just finished generating the ShopBot code for the color ‘cyan’ for a Jim Winter drawing:
Sub output_sbpcode_for_cmyk() ‘ 1/26/2007 gesture generator… Mike Lyon ‘ THE NEXT TWO LINES ARE FOR CONVENIENCE IN INITIALIZING CURRENT DRAWING LOCATION ‘ IT’D BE A GOOD IDEA TO ENTER THIS LOCATION IN THE FORM ALONG WITH &scale PrintLine(3, “SO,3,0”) PrintLine(3, “J2,8,45”) PrintLine(3, “‘ MRL-generated GESTURE CODE from image”) PrintLine(3, “‘ position bot at top left of drawing first!”) PrintLine(3, “&xstart = %(1) ‘ remember beginning x value”) PrintLine(3, “&ystart = %(2) ‘ remember beginning y value”) PrintLine(3, “&scale = .4 ‘ this is 1=100% of 1 inch, .4 = .4”) PrintLine(3, “&rrr = 0 ‘ initialize rows (Y) variable”) PrintLine(3, “&ccc = 0 ‘ initialize X variable”) skipit = 0 lines_written = 10 ‘ TO ACCOMMODATE TWO LINES ABOVE — NORMALLY SET TO 0 PrintLine(3, “GOTO ROW_1”) While Not EOF(1) ‘ include the gesture subroutines file sbp = LineInput(1) PrintLine(3, sbp |
lines_written += 1 End While For rrr = 0 To rawimage.Height – 1 PrintLine(3, “ROW_” & rrr + 1 & “:”) PrintLine(3, “&rrr = ” & rrr) lines_written += 2 For ccc = 0 To rawimage.Width – 1 ‘ getbrightness returns value from 0 to 1 where 0 is black and 1 is white zz = Math.Round((1 – rawimage.GetPixel(ccc, rrr).GetBrightness) * 16, 0) ‘ 0 is digits to rt of decimal If zz > 0 Then If skipit > 0 Then skipit = 0 End If PrintLine(3, “&ccc = ” & ccc) PrintLine(3, “GOSUB ” & zz.ToString(“00”)) lines_written += 2 |
Else ‘ zz = 0 skipit += 1 End If If Button5.Text = “END” Then Exit Sub Next ccc Label20.Text = “Writing ” & rrr & ” — ” & lines_written ProgressBar1.Value = 100 * rrr / rawimage.Height Call updateform() If Button5.Text = “END” Then Exit Sub Next rrr PrintLine(3, “J2,&xstart,&ystart ‘ back to initial location and ready for next color”) PrintLine(3, “END”) lines_written += 2 End Sub lines_written += 2 End Sub |
COOL, eh? I added the new code onto my existing program so I wouldn’t have to rewrite all the file and form handling – can’t believe it actually works!!!
I’ve defined some subroutines named after each of the 17 possible values (00 through 16 is white through black) which call the gestures I’ve designed to produce the values — – the first routine listed below is for ‘black’ or value 16 – it calls .313” square, .438 square, .234” plus, and .338” diagonals in turn to produce the ‘shading’ in that area.:
Then I defined the movement for each ‘gesture’ – these are shown below as ShopBot subroutines – you can ‘call’ the subroutine (GOSUB D375 calls the .375 square inch diamond, for example) – the starting corner position is assumed to be in the variable “&xstart” and “&ystart” and the scale factor in &scale. Then the row and column indexes are in &rrr and &ccc variables – in a 100 row x 50 column image, for each rrr (1 through 100) I position to each column ccc (1 through 50) and draw the gestures for that position.
Finally, here’s just the very beginning of the completed code to produce 0.4” squares (&scale = .4) for a very STUPIDLY large drawing 200 squares high by 110 squares wide… Next time I’ll start a bit smaller 🙂
SO,3,0 ‘ turn off the airbrush J2,8,45 ‘ jump to the beginning of the drawing – remove this for normal operation – this is for debugging only ‘ position bot at top left of drawing first! &xstart = %(1) ‘ remember beginning x value &ystart = %(2) ‘ remember beginning y value &scale = .4 ‘ this is 1=100% of 1 inch, .4 = .4 &rrr = 0 ‘ initialize rows (Y) variable &ccc = 0 ‘ initialize X variable GOTO ROW_1 ‘ jumps around the gesture subroutines which follow below and get right to the painting! ‘ this is the start of a gesture subroutines file ‘ scaling of &scale = 1 (100%) makes marks in a 1″ square ‘ at &scale = 1 (100%) marks are to be 1/8″ wide ‘ gesture call names are LETTER followed by number nnn ‘ D = diamond shape of .nnn area ‘ S = square shape of .nnn area ‘ X = crossed diagonals of .nnn area ‘ P = ‘plus’ (vertical & horizontal) of .nnn area ‘ main calls are 00 through 16 and represent values (tone or shade) from white to black 16: ‘ this is entry point to produce darkest gesture (value 16) GOSUB S313 GOSUB S438 GOSUB P234 GOSUB X338 RETURN 15: ‘ entry point to produce next to darkest gesture (15) GOSUB S188 GOSUB S438 GOSUB P234 GOSUB X338 RETURN 14: GOSUB S438 GOSUB P234 GOSUB X338 RETURN 13: GOSUB D375 GOSUB S063 GOSUB S438 RETURN 12: GOSUB D375 GOSUB S438 RETURN 11: GOSUB D250 GOSUB S438 RETURN 10: GOSUB D375 GOSUB X338 RETURN 09: GOSUB D250 GOSUB S063 GOSUB X338 RETURN 08: GOSUB D250 GOSUB X338 RETURN 07: GOSUB S188 GOSUB X338 RETURN 06: GOSUB D375 RETURN 05: GOSUB S313 RETURN 04: GOSUB D250 RETURN 03: GOSUB S188 RETURN |
02: GOSUB D125 RETURN 01: ‘ entry point to produce next to lightest gesture GOSUB S063 RETURN 00: ‘ entry point to produce blank (do nothing) RETURN D375: ‘ entry point for 37.5% diamond J2, &xstart + &scale * ( &ccc + 0 ), &ystart – &scale * ( &rrr + 0.5 ) SO,3,1 M2, &xstart + &scale * ( &ccc + 0.5 ), &ystart – &scale * ( &rrr + 1 ) M2, &xstart + &scale * ( &ccc + 1 ), &ystart – &scale * ( &rrr + 0.5 ) M2, &xstart + &scale * ( &ccc + 0.5 ), &ystart – &scale * ( &rrr + 0 ) M2, &xstart + &scale * ( &ccc + 0 ), &ystart – &scale * ( &rrr + 0.5 ) SO,3,0 RETURN D250: ‘ entry point for 25% diamond J2, &xstart + &scale * ( &ccc + 0.125 ), &ystart – &scale * ( &rrr + 0.5 ) SO,3,1 M2, &xstart + &scale * ( &ccc + 0.5 ), &ystart – &scale * ( &rrr + 0.875 ) M2, &xstart + &scale * ( &ccc + 0.875 ), &ystart – &scale * ( &rrr + 0.5 ) M2, &xstart + &scale * ( &ccc + 0.5 ), &ystart – &scale * ( &rrr + 0.125 ) M2, &xstart + &scale * ( &ccc + 0.125 ), &ystart – &scale * ( &rrr + 0.5 ) SO,3,0 RETURN D125: ‘ entry point for 12.5% diamond J2, &xstart + &scale * ( &ccc + 0.375 ), &ystart – &scale * ( &rrr + 0.5 ) SO,3,1 M2, &xstart + &scale * ( &ccc + 0.5 ), &ystart – &scale * ( &rrr + 0.625 ) M2, &xstart + &scale * ( &ccc + 0.625 ), &ystart – &scale * ( &rrr + 0.5 ) M2, &xstart + &scale * ( &ccc + 0.5 ), &ystart – &scale * ( &rrr + 0.375 ) M2, &xstart + &scale * ( &ccc + 0.375 ), &ystart – &scale * ( &rrr + 0.5 ) SO,3,0 RETURN S438: ‘ entry point for 43.8% square J2, &xstart + &scale * ( &ccc + 0.0625 ), &ystart – &scale * ( &rrr + 0.0625 ) SO,3,1 M2, &xstart + &scale * ( &ccc + 0.0625 ), &ystart – &scale * ( &rrr + 0.9375 ) M2, &xstart + &scale * ( &ccc + 0.9375 ), &ystart – &scale * ( &rrr + 0.9375 ) M2, &xstart + &scale * ( &ccc + 0.9375 ), &ystart – &scale * ( &rrr + 0.0625 ) M2, &xstart + &scale * ( &ccc + 0.0625 ), &ystart – &scale * ( &rrr + 0.0625 ) SO,3,0 RETURN S313: ‘entry point for 31.3% square J2, &xstart + &scale * ( &ccc + 0.1875 ), &ystart – &scale * ( &rrr + 0.1875 ) SO,3,1 M2, &xstart + &scale * ( &ccc + 0.1875 ), &ystart – &scale * ( &rrr + 0.8125 ) M2, &xstart + &scale * ( &ccc + 0.8125 ), &ystart – &scale * ( &rrr + 0.8125 ) M2, &xstart + &scale * ( &ccc + 0.8125 ), &ystart – &scale * ( &rrr + 0.1875 ) M2, &xstart + &scale * ( &ccc + 0.1875 ), &ystart – &scale * ( &rrr + 0.1875 ) SO,3,0 RETURN S188: ‘ entry point for 18.8% square J2, &xstart + &scale * ( &ccc + 0.3125 ), &ystart – &scale * ( &rrr + 0.3125 ) SO,3,1 M2, &xstart + &scale * ( &ccc + 0.3125 ), &ystart – &scale * ( &rrr + 0.6875 ) M2, &xstart + &scale * ( &ccc + 0.6875 ), &ystart – &scale * ( &rrr + 0.6875 ) M2, &xstart + &scale * ( &ccc + 0.6875 ), &ystart – &scale * ( &rrr + 0.3125 ) M2, &xstart + &scale * ( &ccc + 0.3125 ), &ystart – &scale * ( &rrr + 0.3125 ) SO,3,0 RETURN S063: ‘ entry point for 6.3% square J2, &xstart + &scale * ( &ccc + 0.4375 ), &ystart – &scale * ( &rrr + 0.4375 ) SO,3,1 M2, &xstart + &scale * ( &ccc + 0.4375 ), &ystart – &scale * ( &rrr + 0.5625 ) M2, &xstart + &scale * ( &ccc + 0.5625 ), &ystart – &scale * ( &rrr + 0.5625 ) M2, &xstart + &scale * ( &ccc + 0.5625 ), &ystart – &scale * ( &rrr + 0.4375 ) M2, &xstart + &scale * ( &ccc + 0.4375 ), &ystart – &scale * ( &rrr + 0.4375 ) SO,3,0 RETURN X338: ‘ entry point for 33.8% ‘X’ J2, &xstart + &scale * ( &ccc + 0 ), &ystart – &scale * ( &rrr + 0 ) SO,3,1 M2, &xstart + &scale * ( &ccc + 1 ), &ystart – &scale * ( &rrr + 1 ) SO,3,0 J2, &xstart + &scale * ( &ccc + 0 ), &ystart – &scale * ( &rrr + 1 ) SO,3,1 M2, &xstart + &scale * ( &ccc + 1 ), &ystart – &scale * ( &rrr + 0 ) SO,3,0 RETURN |
P234: ‘ entry point for 23.4% ‘plus’ J2, &xstart + &scale * ( &ccc + .5 ), &ystart – &scale * ( &rrr + 0 ) SO,3,1 M2, &xstart + &scale * ( &ccc + .5 ), &ystart – &scale * ( &rrr + 1 ) SO,3,0 J2, &xstart + &scale * ( &ccc + 0 ), &ystart – &scale * ( &rrr + 0.5 ) SO,3,1 M2, &xstart + &scale * ( &ccc + 1 ), &ystart – &scale * ( &rrr + 0.5 ) SO,3,0 RETURN ‘ THIS IS THE START OF THE ACTUAL DRAWING routine to produce Jim painting — black layer: ROW_1: ‘nothing in this row &rrr = 0 ROW_2: ‘ nothing in this row &rrr = 1 ROW_3: ‘ nothing in this row &rrr = 2 ROW_4: ‘ nothing in this row &rrr = 3 ROW_5: ‘ column 24 is first area to paint &rrr = 4 &ccc = 24 GOSUB 01 ‘ draw gestures for gray value = 1 of 0-16 ROW_6: &rrr = 5 &ccc = 25 GOSUB 07 ROW_7: &rrr = 6 &ccc = 26 GOSUB 02 &ccc = 144 GOSUB 02 &ccc = 145 GOSUB 04 &ccc = 146 GOSUB 04 &ccc = 147 GOSUB 01 ROW_8: &rrr = 7 &ccc = 26 GOSUB 10 &ccc = 138 GOSUB 05 &ccc = 139 GOSUB 08 &ccc = 140 GOSUB 11 &ccc = 141 GOSUB 11 &ccc = 142 GOSUB 13 &ccc = 143 GOSUB 15 &ccc = 144 GOSUB 15 &ccc = 145 GOSUB 15 &ccc = 146 GOSUB 15 &ccc = 147 GOSUB 15 &ccc = 148 GOSUB 15 &ccc = 149 GOSUB 14 &ccc = 150 GOSUB 13 &ccc = 151 GOSUB 13 &ccc = 152 GOSUB 13 &ccc = 153 GOSUB 12 &ccc = 154 GOSUB 11 &ccc = 155 GOSUB 06 |
ROW_9: &rrr = 8 &ccc = 26 GOSUB 09 &ccc = 27 GOSUB 07 &ccc = 133 GOSUB 02 &ccc = 134 GOSUB 07 &ccc = 135 GOSUB 10 &ccc = 136 GOSUB 13 &ccc = 137 GOSUB 14 &ccc = 138 GOSUB 15 &ccc = 139 GOSUB 14 &ccc = 140 GOSUB 12 &ccc = 141 GOSUB 12 &ccc = 142 GOSUB 10 &ccc = 143 GOSUB 08 &ccc = 144 GOSUB 09 &ccc = 145 GOSUB 09 &ccc = 146 GOSUB 09 &ccc = 147 GOSUB 10 &ccc = 148 GOSUB 11 &ccc = 149 GOSUB 11 &ccc = 150 GOSUB 09 &ccc = 151 GOSUB 12 &ccc = 152 GOSUB 12 &ccc = 153 GOSUB 13 &ccc = 154 GOSUB 13 &ccc = 155 GOSUB 14 &ccc = 156 GOSUB 16 &ccc = 157 GOSUB 12 ROW_10: &rrr = 9 &ccc = 26 GOSUB 02 &ccc = 27 GOSUB 12 &ccc = 131 GOSUB 05 &ccc = 132 GOSUB 13 &ccc = 133 GOSUB 14 &ccc = 134 GOSUB… |
It goes on and on like this – two or three of these commands for each of the 22,000 squares in the drawing – then the next color paints over them, then the next color, and on and on for WEEKS!!!
But it works!!!
— Mike