Spraying Mandelbrotian Graffiti on Euloran Surfaces

March 24th, 2020 by Diana Coman

This past week I got some decent practice with virtual surface vandalisingtexturizing after polygonizing - and that includes some agonising, namely over CrystalSpace's idiotic requirements for texture if it's to do anything at all with it.

Sure, I knew already that CS can't do anything with a texture's procedural specification as such and requires instead the pixel by pixel description of the pretty picture to paint on whatever surface. This much was no surprise indeed. But it turns out that there can be (and therefore is) even worse than that - CS *also* has no idea nor interest to map by itself a given texture to an object, even poorly! Basically it's not enough to feed it all the pixels of the texture - you have to chew them too! And who cares that such chewing further forces the fixing and specifying of "how to paint" in the file that supposedly is instead all about "what shape" this is (aka the mesh description file that has to include also the texture mapping). Eh, such unheard of troubles and scruples that haunt my nights and days around here, let it all rot and fester in one place, what's it to artists anyway and not like anything else matters if it's about pretty pictures on a screen, right?

To put the above in plain terms: CS allows you in principle to apply any texture you want to a mesh (aka polygonized surface) *but* for this to do anything, the mesh's definition has to contain also a fixed mapping of each vertex to a corresponding point of the texture (and no, CS manual doesn't go into such details)! The image that is used as a texture is considered a "texture map" and has a standard "space" going from (0,0) to (1,1), representing the top left corner and bottom right corner of the image, respectively. The mesh definition then has to specify for each vertex, a (u,v) tuple with the u,v values in the above space for direct mapping; negative/ out of range values will result in tiling of the texture or wrapping around (at least in theory, I haven't bothered to fully explore this part as I do not want either tiling or wrapping of the texture).

The above means in practice that, although you can supposedly change the texture on the fly on a mesh, nothing will fit anymore unless the two textures you switch between are *both* made precisely to fit that mesh in the same mapping and all that. And there isn't any sane default for a fit - in my naivety I thought that it would just do some default mapping of the whole texture on the whole surface but practice and this week's dive into the code reveals that there's no such thing attempted, no. Instead, if you don't specify within the mesh any mapping of a not-yet-chosen texture1, it will "apply" the texture aka the 0,0 point of it and nothing else - meaning it's the colour of *that pixel* used... everywhere. For the same money, you can just use a solid colour directly anyway, what the fuck's the point of specifying a texture and loading an image and all that jazz?

The obvious cause of the above insanity is the fact that you are not expected to generate anything at all - you are expected (with a view to force fed already) to "export" everything from one of those crutches for the mathematically challenged (such as Blender). And in there you manually specify some "seams" for a character so that an algorithm unwraps then the skin of the character through a cut along those seams and lays it flat in the texture file, while producing and saving also -generally by means of at least 3 renderings of the thing from different perspectives!- the mapping of vertices to the points in the texture space. What do you need else or more or even less, right?

Anyways, this solved the previous puzzle of those solid-colour surfaces of last week and of Cally's solidly-coloured skin no-matter-what. Cally's meshes do not contain any texture mappings so yes, either you do your own or you paint her directly at runtime or you just make her some solid colour of your choice. And for extra bonus points of wasting time, the darned thing wants all those texture coordinates specified in the xml file as a render buffer with the *precise* name of "texture coordinate" - failing silently, maddeningly and quite characteristically if you do the huge mistake of calling that, for instance, "texture coordinates". As I did, of course, at a cost of a whole morning and assorted cussings in all languages that came to mind. Here, have some pictures of the hyperboloid that silently ignored the texture mapping (the one with spots - the very last pic in this set- is where I added the same mapping to be used for *normals* of the texture and that *worked* because there I got the name right to the letter...) for reason of one 's' too many:

On the bright side, I didn't even try anymore to contemplate the obvious what-the-fuck questions pouring out from the above. Contemplate them on your own time and your own dime if you really have nothing better to do. What I did instead was to update my awk formatting script so that it spits *also* the required texture coordinates for each and every vertex. After all, since it does all sorts to fit CS's love of xml, why not this too? And I kept it short and simple: considering the texture square in size, it just maps the (z,x) coordinates of the shape (considering the actual interval that they spawn for the given surface, so not idiotically from 0 or some such nonsense but between their observed minimum & maximum values) to the full (u,v) space of the texture and that's it. Why the (z,x)? Why not? Sure, there's plenty to play around with there but at this stage I wanted to have something working and working fast, not like there's any clear reason as to how this mapping would even work "best" or what that "best" even means in such context. I did in fact try it at first with mapping (x,y) (hence, ignoring z) but the result looks less interesting to me than the (z,x), so I stuck to the more interesting mapping. Here's how it looks with (x,y) vs (z,x) mapping (the texture is a full Mandelbrot, coloured black inside the set and yellow/blue outside, based on normalized number of iterations, see next paragraph for more on the texture generation itself):

The easy part linked to all the above was to generate *a* Mandelbrot texture. Note the emphasis there because the Maths is easy but the devil in it goes by the name of domain colouring. Essentially the whole thing with a Mandelbrot (or fractal in general) pretty picture is how you pick and apply the colouring scheme (well, ignoring for a moment that you can further zoom in/out if you want to capture some specific bits/parts that might look more interesting than the whole; for any definition of interesting, for any combination of all the various choices, of course). And domain colouring is a whole...domain in itself, you know? Not to mention for that matter that Mandelbrot might be even used as a more general name for fractals and moreover, one could even look at the fractal dimension as the more general approach to procedural generation of anything, from texture to shapes - and get lost in *that* rabbit hole if it's more appealing than the rest of rabbit holes around.

Mandelbrot's pretty fractal aside for a moment, I stepped daintily over the rabbit hole of fractal dimensions and domain colouring at this stage2, simply picking instead *a* colouring scheme by means most undemocratic - because I find it ok to look at. While I don't mind changing it and/or implementing some other specific colouring scheme you might have in mind, at least there is something implemented and visible so far, to start from. Other than this, do tell me if there's a request for further exploration of any of the abundant rabbit holes around (e.g. domain colouring or the fractal dimension as such). Meanwhile, here's what the Mandelbrot texture looks like in a few colouring (starting with grayscales) versions and then how the blue/yellow one looks on some surfaces that I got to play around with:

Using the last texture in the set above, here's how it looks applied to various surfaces I tried out as part of attempting to get a bit of a better understanding of that part too:

With the textures at least figured out as above, I'm currently working on figuring out a way that works for finally setting up a full char made out of meshes "grown" around an arbitrary "skeleton". While implicit surfaces and modelling with them is of course yet another domain by itself, I'm not getting lost in it either, no. I still need though to get a better understanding of what works and what doesn't (e.g. some type of surfaces have the known problem of "bulging" at joints) and how exactly that happens & links to my useful but limited polygonizer because the naive definition bumps into all sorts in practice and there's no substitue that I know of for playing around with actual surfaces and all that. Depending indeed on the type of surface, the "bone" can even work for instance as either medial axis or control points or pretty much anything under the sun. But some concrete pictures will most likely say way more about this than all the half-digested theory can at this point so I'll just go ahead with it, unless requested otherwise.

Based on the above plan, the next write-up will hopefully include even more mandelbrotian graffitti but on attempted meshes-on-a-stick (aka "skeleton") or at least this is what I'm currently aiming for.

  1. I'm practicing laughter, serenity, calm and pure zen. It's not working all that much but that's why I'm ...practicing it, ok? 

  2. Though a 1994 edition of the reference book of Ebert, Musgrave, Peachey, Perlin and Worley made it to my shelf.