What the Functor can draw that?

I want to reduce the amount of code I write, and yet increase the power of the core system.

Here are three instances of a Bezier Surface.  What’s different about them?  Their geometry is the same, meaning the exact same control curve was used in all three cases.  Their coloring is obviously different though.

In the first case,  the code looks something like this:

color(“Yellow”)
addshape(lshape3)

I simply use the general purpose ‘color()’ function to give it a nice Crayola Yellow coloring.  Nice and uniform, no fuss no muss.

In the second case, the actual rendering part is exactly the same, but the setup is a bit different.  To setup the surface in the first place, I do the following:


local lshape1 = shape_bicubicsurface.new({
M=cubic_bezier_M(),
UMult=1,
Mesh = mesh,
Thickness = thickness,
USteps = usteps,
WSteps = wsteps,
ColorSampler = colorSampler1,
})
addshape(lshape1)

The various parameters here are all very interesting, but they all have reasonable defaults.  The key here is the ‘ColorSampler = colorSampler1’, so what is colorSampler1?
local colorSampler1 = checkerboard:new({Columns=usteps, Rows=wsteps})

In this case, the checkerboard ‘object’ is a “Functor”, which can procedurally generate a color, at a given point.  It has a function:

rgba GetColor(self, u, v)

This function will be called every time the underlying machinery wants to get a color value.  Those ‘u’ and ‘v’ values will vary from 0 to 1, across the entire surface being rendered.  So, the Checkerboard pattern just needs to determine what value it wants to show, based on the ‘uv’ combination.

This is normally called Procedural Texture Mapping, in the graphics world.  It’s a fairly powerful technique, which will allow you to quickly and easily create all sorts of textures for objects, without having to deal with bitmaps.  At least for textures that can be computed, rather than being static images.  It will get really interesting when the animation system is operative.

In this case, I am using the same checkerboard procedural texture, but it’s setup a bit differently.  I can specify a “HighColor” and a “LowColor”.


torus({Offset=offset,
Size=size,
USteps = usteps,
WSteps = wsteps,
ColorSampler = checkerboard:new({Columns=usteps, Rows=wsteps, LowColor={0,0,1,1}, HighColor={1,1,1,0}})
})

Here, the checkerboard procedural texture is setup with a LowColor == blue, and a HighColor, which is white, but transparent, so nothing shows.  Why would you want to do this?  Well, let’s consider the case where you are trying to print with multiple materials.  You could easily take the exact same mesh, render it twice.  The first instance would have the HighColor set to something, and lowcolor transparent.  The second instance would have things reversed.  Then, as you generate the .stl, you could look at the color, and drop out objects with transparency, or generate a file format that would actually support changing materials like that.

So, what is a function?  It’s just a small object, that typically contains some retained parameters, and can execute a simple function.  In the case of the checkerboard pattern, the retained data is the size of the grid, and the high and low colors.  The function is “GetColor”.

This is great because you can pass this function to a core object, like the BiParametric thing, and it will handily just call your function at the right times.  You don’t have to worry about doing any of the coding to come up with the individual vertices for your mesh.

In this final case, I am using the Image ImageSampler object.  You construct it, supplying a filename, and it will deal with handing out pixels based on the ‘uv’ parameters being passed into its ‘GetColor’ function.  So, great fun.  You could of course implement filters and all manner of things within this sampler.

So, that’s what a functor can do.  Execute a simple function.  When you have a base object like BiParametric, it becomes fairly easy to do everything from determining vertices, to normals, to coloring, using these simple functors.  That makes it extremely fast to experiment and extend without having to really mess with the base class.

 



Leave a comment