Thursday, November 22, 2012

Fractal adventures: Menger Sponge

I have always found fractals interesting, so recently I decided to start playing around with them a bit as a way to practice my 3D graphics skills. I am using Processing for these experiments. First up is the Menger sponge.

To start I am taking an approach where I build up the geometry of the sponge in an unoptimized way using the "box" primitive. The locations of each cube element will be stored as a PVector in an ArrayList which we will then be able to iterate through when we render. To update the sponge I will iterate through the arraylist, and for each element determine the location for the 20 elements it will be replaced with.

So here is the Sponge class where all of this will happen:

class Sponge{
  //This is a naive implementation of a Menger sponge, using a collection of 
  //cubes to build up the geometry.  
  float size;
  PVector center;
  ArrayList<PVector&rt; elements;
  int MAXLEVEL = 3;
  int level;
  
  Sponge(float size, PVector center){
    this.size = size;
    this.center = center;
    elements = new ArrayList();
    elements.add(center);
    level = 0;
  }
  
  void divide(){
    if (level<MAXLEVEL){
    level++;
    ArrayList<PVector&rt; newElements = new ArrayList();
      float newSize = size/3;
      for(PVector e:elements){
      for(int x=-1; x<2; x++){
        for(int y=-1; y<2; y++){
          for(int z=-1; z<2; z++){
            if(!((x==0&&y==0&&z==0)||
                 (x==-1&&y==0&&z==0)||
                 (x==0&&y==0&&z==-1)||
                 (x==0&&y==0&&z==1)||
                 (x==0&&y==-1&&z==0)||
                 (x==0&&y==1&&z==0)||
                 (x==1&&y==0&&z==0))){
                   newElements.add( 
                     new PVector(e.x+x*newSize,e.y+y*newSize,e.z+z*newSize));
            }
          }
        }
      }
    }
    elements = newElements;
    size = newSize;
    }
  }
  
  
  void draw(){
    for(PVector e:elements){
      pushMatrix();
      noStroke();
      fill(64,85,133);
      translate(e.x, e.y, e.z);
      box(size);
      popMatrix();
    }
  }
}

This class is fairly simple, with only two methods, one divides the sponge so we get the next level of fractal, and the other renders the sponge. In the divide method a new arraylist is created where the locations of all of the new cubes will go. This is then populated by iterating through the current locations, and then for each of those iterating through the possible x, y, and z coordinates where we are subdividing the cube into a 3x3x3 set of cubes. Then the coordinates are checked against the locations we wish to exclude (center cube, and center of each face) and if appropriate add the location to the new arraylist.

One might notice that there is a check in the subdivide class for the maximum level for the sponge. The reason for this is that this is a very inefficient implementation to render. The division is not too bad, however rendering becomes a nightmare since we render 20^level different boxes. A natural optimization of this would be to not render the faces that are hidden from view; where two cubes are next to each other.

Saturday, November 10, 2012

OpenNI on Windows 8

So the other week I upgraded to Windows 8 on my netbook thing where I am doing most of my recent coding. Today I discovered that the code I wrote in Processing using OpenNI was not working, because it couldn't connect to the Kinect. It appears that Windows 8 does not play nicely with unverified drivers following the upgrade. So to fix this I found the following on the google group, which references the Arduino community which has the same issue.

  1. Uninstall openni, nite, and the kinect driver.
  2. Windows key + R to open the run prompt
  3. shutdown.exe /r /o /f /t 00
  4. select troubleshoot
  5. select advanced
  6. select windows startup and then restart
  7. enter the option for Disable Driver Signature
  8. reinstall openni, nite, and the kinect driver


It seems as though this is required each time that you wish to install an unsigned driver. I was initially thinking that this disabled it as a general setting however this does not seem to be the case since last night I had to do this again for the virtual serial driver needed for my 3D printer.

Thoughts on polyglot programming and learning.

The world of computer programming is such a vast and exciting realm with everything from 3d graphics, massive parallel systems, to the tiny embedded systems that make our modern world function. It is thus easy to see the complexity and difficulty in learning all of these different fields in addition to whatever it is we do for work. It feels like such a shame that there is so much to learn about and so little time to learn it all. However I think that is a place where becoming a proficient polyglot programmer can really make a difference.

I have been working a lot with Processing lately to learn about the Kinect. It strikes me how wonderful this language is for learning any graphics related programming. It is important in my view that when learning something it is important to both make rapid progress as well as not be lost in details that are only incidentally related. While I could be doing the same thing in C++ or Java, I think it would slow me down from learning the concepts that are critical to the 3d rendering as well as the Kinect itself. The universal concepts behind what I am doing will be easier to see, and thus I can translate them later to these other platforms.

In this sense I feel that polyglot not only should encompass the use of various languages to tackle problems, but also to extend our ability to rapidly assimilate information. The tools exist to help us both produce better code as well as learn more. We should remember that these languages are creative tools, and sometimes we are best off with the simple tools so we can get closer to what we are actually trying to do.