In This Blog-Posting, I wrote that I had installed the FOSS, 3D-graphics application named “Ayam” on my Linux-laptop named ‘Klystron’. This is an application of the sort, where a simplified, diagrammatic preview of a scene is shown to the user by way of his GPU, in real-time, so that he can edit. But then the assumption is that the user will render the higher-quality version of his scene using a software-based, ray-tracer, which is also Renderman-compliant, and which in my case happens to be “Aqsis“.
I recall that an approach which I had used before – years ago with paid-for software – to create a distorted, alien-like head, was to draw a NURBS-curve of the side of a head, to duplicate that at 180⁰, and to draw a NURBS-curve of the front of a head, at 90⁰ to the other two curves, and then to ‘Skin’ these curves into a mesh.
Well that approach still works, and this is what I gave me:
I felt this would be an interesting exercise for testing the stability and the usability of Ayam. It took me a few hours as a rank beginner, to find the necessary tricks to do this.
At first glance, this looks like a piece of cake, especially since the user is not required to make all his selections of combinations of on-screen objects, from the 3D preview panels. Instead, we can hold down the <Ctrl> Key, and select and deselect individual objects in the side-panel, where they are listed in a tree-like, textual form.
But one hindrance which cost me a lot of time, is the fact that when we ‘skin together multiple Curves’, to form a Surface (Patch), we must select the curves in advance, before going into the Create menu and clicking on the correct tool. At that point in time, the Curves that are to be skinned, must be listed in the correct order in the Objects Side-Panel List. Otherwise, predictably distorted and ruined surfaces will be defined.
After working at this for some time however, I noticed that the user may also hold down the <Alt> Key, while one Object is selected, and then click either the Up or the Down arrow of his keyboard, which changes the order of the Objects in the List-View. At that point, the task became much easier for me, to put the curves into the correct order, so that when they were all selected, they did form a meaningful surface.
One fact which impresses me with Ayam, is that when it offers the user NURBS, those are Mathematically-true NURBS, and not just some arbitrary splines. In fact, Ayam distinguishes between ICurves and NCurves, the latter form of which it will gladly initialize into a true circle for us. And also, with NURBS-Patches (surfaces), Ayam will create a NURBS-Sphere.
According to this application,
- An ‘NCurve’ stands for a ‘NURBS-Curve’, in which each Control Point has an equal weight, according to its Knot-Vector, except for the endpoints, for which reason the Curve doesn’t pass through the Control Points.
- An ‘ICurve’ stands for an ‘Interpolation-Curve’, which possesses hidden Control Points that act as ‘Handles’, but more-importantly, the main Control-Points of which the Curve will actually pass through. AFAIK, this ICurve can be converted into a NURBS-Curve by the software, ‘behind the scenes’.
I was able to control ICurves graphically, even though I don’t know enough about the Mathematics of NURBS.
There used to be an application called ‘TrueSpace’ – which no longer exists – but one big drawback of that application was, that it would just randomly convert purported NURBS Surfaces into triangle-meshes, with no warning to the user that it was doing so. Ayam won’t do that.
Another interesting observation about Ayam is, that one of its basic languages for expressing all shapes is – NURBS. Hence, it possess NCurves and NPatches. If we tell it to place a cube into our scene from one of the basic, CSG Primitives, Ayam next makes it difficult for the user to derive shapes from that, other than through CSG.
But, we can tell the application to Convert a given shape into an NPatch, and if given one of its own primitive cubes, doing so will leave us with a combination of 3 NPatches, one corresponding to 4 of the cube’s faces pointed along the X and Z coordinates, one corresponding to the cube’s maximum Y, and one corresponding to the cube’s minimum Y. From there, we can go into:
Tools -> Create -> ExtrNC
Which tells the application to Extract an NCurve from one of the NPatches. If we have set the Attributes of this derivation correctly, we can end up with the ‘top’ face of the original cube, converted into a curve.
But If our intention was to Extrude this curve, then we hit a snag with Ayam: Extrude will always do so, along whichever axis was originally the Z-axis of the curve, since curves are usually defined as 2-dimensional along ‘X’ and ‘Y’. But, the face of the cube I had chosen was ‘maximum Y’, which means that it had a normal-vector aligned with the Y-axis, not the Z. But, Extrude will extract the curve in the direction ‘Z’ anyway. Yet, If we apply a generic transformation after extracting this curve, Then doing so will not affect what the apparent Z-axis of the curve was, since a transformation on any object is applied, after that object is derived from its instance(s).
And so finally, the way around this is to rotate the cube first, 90⁰ on its X-axis using a transformation, so that the corresponding NPatch will follow as facing-Z and not as facing-Y. Then, we can Extract our NCurve from that Npatch, and Extrude the NCurve, finally correctly along ‘Z’.
I suppose it’s better to use explicit CSG-Primitives, for CSG.
Note: Boolean Operations On Meta-balls –
Ayam Can Do It; Aqsis Cannot:
(Edit 08/22/2017 : )
I experimented much more with ‘Ayam’, because to have such an extreme deficiency – to be able to work with NURBS but not Polygonal Meshes – seemed unlikely, or at least, unbefitting of HQ software. And as it happens, we can in fact render the CSG primitives point-editable! We go into a command located at:
Tools -> Surface -> Tesselate
And this will convert almost anything ‘Ayam’ understands, into a PolyMesh.
Further, it is possible to create Subdivision Meshes, if we don’t mind loading another (supplied) plug-in first, by using the Convert Tool on the PolyMesh. BTW, CSG as well as Meta-Objects also required I load plug-ins.
Before I could get the ‘SDMesh’ to work though, I needed to solve another problem. Every time I was asking the program to convert to an SDMesh, the application window would just disappear in an apparent crash.
As it turns out, the programmer used an Assertion, to assert that the Mesh be closed, before proceeding to subdivide it. A failed Assertion will always halt a program. And so, before we can use our PolyMesh to make an SDMesh, we must also perform:
Tools -> PolyMesh -> Optimize
This fixes most Meshes. Then, I found that the Convert Tool did work. Next, we can use the same Convert Tool, to export the Subdivision Mesh back into a regular mesh – with a higher number of vertices and polygons through.
Feeding a Subdivision Mesh to ‘Aqsis’, a rendering engine capable of rendering true spheres etc., is a bit of a down-conversion in some cases. But for other uses, this can provide better compatibility.
Finally, using the Extrude Tool provided by ‘Ayam’, requires understanding that its purpose is somewhat different, from what the Extrude Function does in certain other software.
Instead of being designed to allow simpler shapes to be refined into more complex ones, the Tool provided by Ayam strives to help power-users create new primitives. The online documentation confirms, that this tool will only extrude a 2D curve drawn along ‘X’ and ‘Y’, into the ‘Z’ dimension (before the resulting shape can be used elsewhere).
If the user requires greater flexibility, he should look into using the Sweep Tool, with which he can define a single rail along which to sweep his Curve, that rail possibly being a NURBS Curve with Order 2 and with its minimum of 2 Control Points: A Start and an Endpoint. This will result in a linear interpolation, and the user can direct his Sweep to run along any axis he desires, or along any path not conform to one axis.
The only other advantage which Extrude has, is the ability to add Bevels easily.
I suppose another question which deserves a comment, is ‘To what extent are these tools capable of being used in combination?’ And the answer seems to be, ‘Only to a limited extent.’
It’s not possible to use CSG that starts from Primitives, and to take the Level that defines the Boolean Operation between these Primitives, and to Tessellate that, thereby producing a more-complex PolyMesh. Doing so always results in a Union, where the Level that holds the Meshes together specified a different Boolean Operation. It’s as if the Level data-component was simply listing Meshes, without any Boolean Operation taking place.
But, If Great Care Is Taken, it may succeed to Tessellate each CSG Primitive first, and then to perform the Boolean Operations on them, via the Level data-structure. Effectively then, the first Mesh is rendered, as long as the additional Meshes and / or Primitives don’t negate specific Vertices / Points.
The main problem one encounters, is the fact that any Boolean Operation, besides a Union, will expose the back-side of certain geometries, which according to Mesh-Logic, was never meant to be visible. Negating the other shape from one given Mesh anywhere, even because we are specifying an Intersection, leaves a hole. In such a case, the software does not complete the polygons, across the back opening created in any one of the PolyMeshes, which can result in rendering errors, that are not due to any texture or material treating the back-side of a Mesh incorrectly.
Here, it will be best to choose Polygon-Type: Quad, and Sampling Method: Domain Distance. This way, each Primitive is rasterized into an array of polygons that is (hopefully) aligned with the world.
(Edit 08/23/2017 : )
The above settings deserve some explanation. When we tell this application to Tessellate a 3D object, we are telling it to output a Mesh, but there is no object. The presumed object is thought to consist of a set of NURBS-Patches, each of which is defined as a set of 3D coordinate-points, that arise from 2 parameters, U and V. Presumed objects can exist as more than one Patch, and often do.
If we give the module a CSG-Primitive, that is first Converted into a NURBS-Patch, and then, into a PolyMesh.
The above setting simply tells the application to Tessellate, according to the U and V parameters, in a uniform way, that gave rise to the 3D coordinates.
What can easily happen, for example in the case of a Cube, is that according to Patch 1, the V-parameter consistently correlates with Y, but that U alternates, correlating with X and Z, as this Patch forms 4 faces of the Cube, facing ± X and Z. It would need to be subdivided 4x as many times along U, in order for each of these faces to have as many subdivisions. The other 2 Patches define the maximum and the minimum Y, so that U and V correlate consistently with X and Z.
A presumed sphere, is actually a single Patch, corresponding to a swept half-Circle.
The thing to do next in the exercise above, might be to Copy both the (PolyMesh) Sphere and the (PolyMesh) Cube, to reverse the order of the copies, and then to create another Level, which this time preserves their Intersection… The only problem with that would be, that the 6+6 Meshes won’t align perfectly…
‘Ayam’ also has some sort of built-in support, to render Text, from TrueType Fonts used as a source of 2D curves. This feature is temperamental at best.
When we specify a Font, for an unknown reason, Ayam fails to acquire the orientation of the Curves. The application has a ‘Revert’ button, which causes the Text to display finally. It is best to click on Revert, before the first attempt is made to set up the Text-object.
The developers have already decided someplace else, that Curves are defined in the XY-plane, and that any extrusions or bevels are supposed to be applied along the Z-axis; clicking on ‘Revert’ from the beginning enforces this.
Certain Fonts contain meta-data that the application does not read properly, but which may cause Bevels to form incorrectly, even when ‘Revert’ has been enabled. Yet, most of those Fonts can still be given end-caps without error.
Furthermore, for some reason, this module has decided to insert an exclamation mark after every space. Apparently, text is not supposed to contain any spaces, and every time it does, this module needs to punish the user for it, by putting an exclamation mark in front of the next word. In the correct font.