Thursday, January 21, 2021

Genuary 2021 Day 21: "Function"

 


This one was a relatively simple implementation of the prompt, once I decided what the prompt meant to me. The literal prompt on the Genuary page says:

function f(x) { 
    DRAW(x); 
    f(1 * x / 4); 
    f(2 * x / 4); 
    f(3 * x / 4); 
}

Which is easy enough to read, if you're into code, but I wasn't just going to paste that into my code, it required a certain amount of interpretation - what is x? And if x is not a numeric thing, what does it mean to divide or multiply x by numbers?

So, I stepped back a bit and turned the pseudocode above into more human-friendly instructions:
  1. At each step, you will start with a region of the page.
  2. Draw something that fills that region
  3. Then split the region into four sub-regions
  4. For the first three of the four sub-regions, recurse to step 1
Which I think pretty well captures the feeling of the pseudocode, but affords a little more freedom, especially in how the region is split.

My drawing step is just to draw a (colored) rectangle that fills the region. When drawing using my AxiDraw, I just have a single black pen hooked up.

I inset the rectangle to keep edges from overlaying each other.

To split the rectangle, I randomly pick a half split, quarter split, and three-quarters split location along the long axis of the rectangle. I randomly choose whether to output children 1, 2, and 3 or 2, 3, and 4, which might be a stretch from the original code, but I consider it an orientation detail; 2, 3 and 4 is really just 1, 2, and 3 from the other side of the rectangle, so it's fine.





I think this looks a little like a couple server racks, mostly filled.

Or maybe a Rockwell Automation Retro Encabulator:



Tools Used: AxiDraw, Pentel 5mm pen
Languages Used: Python
Development Time: ~30 minutes
Drawing Time: ~5 minutes
What's Generative Here: Each box is subdivided randomly, and colored randomly.



Wednesday, January 20, 2021

Genuary 2021 Day 20: "No Loops"

From Many, One 




This was a pretty easy thing at its base - I generated a set of points using a Bridson Blue Noise Generator, one of my favorites. I then used SciPi's Delaunay to turn these points into a triangular mesh. I then pulled edges at random from that mesh into a spanning tree - visiting each vertex exactly once (no loops).

At this point, the image on screen was complete, but I knew it would draw poorly on the AxiDraw to draw each edge individually, so I wrote a routine to glue edges together into paths, which mostly worked, but I overdrew a few edges (paths with a single edge?) which worked out OK.

Also, some of the edges didn't draw at all, the pen hit a dry spot, which happened a surprising number of times.



Tools Used: AxiDraw, Pentel 5mm pen 

Languages Used: Python

Development Time: ~2 hours

Drawing Time: ~1 hour

What's Generative Here: I started with a generated set of points, I connected the points into a spanning tree by randomly including edges.




Tuesday, January 19, 2021

Genuary 2021 Day 19a : "Randomness Increases (Variant)"




I did the Day 19 prompt last night, letting it run overnight. I woke up around 2:30, and saw the first image coming out, and I was intrigued that the various stacks of cylinders looked like people to me. Some people were purple, and a lot were green. And everybody's feet were a lot bigger than their shoulders.

So, I decided to try a variant, going more deliberately in the direction of representing people. I grabbed some realistic skin tones. I adjusted dimensions to make people's bodies a little more recognizable.

And there were several things that made me uncomfortable and disappointed in the finished drawing. Above, there's an detail clipped from the original which avoids many of the issues. 

  • There's a bug in my renderer (in the octtree code?) that sometimes does not render objects. When the renderer omits a body part, that's uncomfortable.
  • With stacks of shapes that read as humans, a viewer (at least this viewer) starts to read intentionality to things that humans would have control over. There's a clump of darker skinned people on this side, and a different clump of lighter skinned people on this side of the image. What does that mean? At one level, it means nothing. It's just what the dice picked this time around. But viewers will see human patterns, and if I present an image that evokes human patterns, I need to consider that I'm presenting those patterns, they come along.
  • The relative dimensions of "head" and "shirt" reminded me of a turtleneck sweater worn on a cartoon I enjoyed as a kid, and again, that's a connection I'm not entirely comfortable with. I don't enjoy the cartoon now, and the connection to it makes me sad.
  • The rest of my generative artwork is abstract and meaningless. By making this a little less abstract, giving it a little bit of representation of people, it opens up a lot of issues. Kate Compton had some comments about Tracery Grammars and Twitter bots touching on ethnic / social issues, and her message was that if you, as a creator, need to be able say to your audience that ALL of the outputs of your bot are valid and supported - it's not sufficient to shrug and say "well, sure, that's offensive, but that's just what the bot decided to generate".
  • I may be overreacting. I might be underreacting. I did a chunk of the work here on MLK Day, which might increase my sensitivity a little bit. Tomorrow is inauguration day.
  • How much of my reaction is the fact that a majority of the "people" that showed up in my work are brown-skinned? 

Genuary 2021 Day 19: "Increase the randomness along the Y Axis"


This represents a compromise, a fallback, almost a cheat.

I discovered that my work had given me yesterday off as a holiday, and rather than spend it volunteering to help others, or reading a speech or a book by Martin Luther King, Jr., or even reading a book about Unreal Engine C++ code, instead, I spent the day working on my ray marcher, with the hopes of having an island with rolling polygonal hills, and obscure towers rising into the sky.

Which would have been a cheat, in itself, because that image, that I worked almost all of yesterday on, would have been my submission for today's prompt.

Fortunately(?) the polygonal mesh dragged my renderer's performance to its knees, so I couldn't meaningfully iterate on my intended image.

Instead, I give you less ornate, less random, but still vaguely tower-ish stacks of primitives. The bottom tier is uniformly medium gray and of identical size, the next tier up has more size variability, and is picked from red, green, or blue. The last cylinder has more size variability, and is picked from a set of 6 colors, and the spheres on top from a continuum of colors.

For a while, I was struggling to reconcile this idea with randomness increasing along Y, because in my renderer, in my mental model, up is +Z, and to pass this off as randomness increasing along Y meant that either I was fudging the prompt, or I was adopting a +Y up model, which I know some people prefer, but for me, the X-Y plane belongs on the horizontal.

But, if you consider that the screen projections of these colorful towers reach upwards along screen Y, then the previous paragraph's concerns mostly fade away. Except that, often, positive screen Y goes down. (Sigh) So, again, we do some gymnastics, and either say that the prompt doesn't specify that randomness increases along the positive Y axis, or we look to the drawing APIs that prefer to have the origin in the lower left corner, to better resemble the diagrams in 7th grade algebra books.

So, we have tower-like stacks of primitives, with their color, and some of their dimensions, increasing in randomness as one goes up. Good enough.

Still a compromise, because it's not the image I had in mind.

Still a cheat of the schedule, because I did my part of the work yesterday, and the rendering completed this morning around 3am.

I look at these towers, which I've been trying to get you to see as stacks of colorful blocks, and I see abstract people. I've kicked off a render of a variation of this inspired in that direction. Maybe that will be less of a cheat, since I'm doing it today.

Also, I don't know what's going on with the red tower in the background, missing a tier. Either a bug in my placement code or a bug in my octtree spatial partition code, which is what I was struggling with all day yesterday.

I did learn a few neat things, and applied them yesterday:

  • I applied scipy's Delaunay triangulator to my Bridson blue noise point grid, and got a nice triangular mesh that I could work with.
  • I tinkered with the way that my python code was organized so I could have my daily Genuary code in one directory, and still "reach up" into my ray tracer's directory, as well as a shared Genuary SVG codebase.
  • I explored cProfile as a way to figure out where all the time was going in my ray marcher
  • I added a flag to my ray marcher to disable the multithreading, which at this point duplicates a bunch of code. But the cProfile seems to not give useful information for code not happening on the main thread, so it's good to begin supporting turning of multithreading.
  • I added progressbar2 support to my ray marcher to give a pretty ASCII display of how much work is complete, and how much remains.

Tools Used: my ray marcher
Languages Used: Python
Development Time: ~1 hours
Drawing Time: ~5 hours
What's Generative Here: Each tower is positioned based on a random assignment within a square around the origin. As you go up the tower, the range of colors, and the dimensions are increasingly drawn from a wider set of options.

Monday, January 18, 2021

Genuary 2021 Day 18: "One Process Grows, Another Process Prunes"

 


This one's a little more of a straightforward interpretation of the prompt than some of the recent ones. I created a hex grid (shout out to Amit's great hex grid resources at https://www.redblobgames.com/grids/hexagons/ of course). I then created two "processes" that would update the grid:

grow - which started on the edge of the grid, moving space to space, placing "food" in the grid, making the cells come "alive". In the raster version, a single process would have a single (random) color, but you can't see that in the plotted version.

prune - which started on the edge of the grid, and moved in longer, straighter, lines, removing the food as it goes. If it reached the end of the map, it terminated.

I ran 100 of each of grow and prune, alternating to produce this pattern.



Tools Used: AxiDraw, Pentel 5mm pen (used up my last one, had to scrounge a second one from around the house) Amit's Hex Grid reference.Languages Used: PythonDevelopment Time: ~2 hoursDrawing Time: ~15 minutesWhat's Generative Here: The individual tiles are turned on and off based on two competing random processes.




Sunday, January 17, 2021

Genuary 2021 Day 17: "Draw a line, pick a new color, move a bit"

 


This is a pretty loose interpretation of the prompt, and it's generative in the "how" of what's being drawn, but not of the "what" of what's being drawn. I went to the Art Institute of Chicago's page, and found a couple impressionist CC0 paintings.

I generated a blue noise point grid, and a flow field for each painting. I generated particles at each point of the point grid, and traced their motion along the flow grid flowing in and out of their designated point.

It looks pretty good as an animated GIF - frames overlay previous frames, so you don't see the gaps between particles, except for at the very beginning.

To contrast, the video on YouTube:


You can totally see the gaps between the particles.


Tools Used: Art Institute of Chicago's web page to download the CC0 source images. Pillow, ImageMagick, ffmpegLanguages Used: PythonDevelopment Time: ~4 hoursDrawing Time: ~15 minutes (and then further processing to make the GIF and MPG animations)What's Generative Here: The flow fields and underlying point grids are random, but that's not where the eye lands. You see the familiar paintings, so I'm not 100% satisfied that this is as generative as it could be. I could generate images to use as my source material, which would be more generative. Or, maybe if you think of the individual particles as having a chunk of data each, on each frame, the particles collaborate to generate the image. Feels like a stretch.


Saturday, January 16, 2021

Genuary 2021 Day 16a "Circles" (extra)

 


Following up from the circle inversion I did earlier today, I decided to draw the Pappas Chain that was in the "Epic Circles" YouTube video.

Not really generative, but still fun, still pretty.