I was doing some work on tire dynamics while planning a vehicle physics engine. In the course of that project I wanted to visualize some triangles. Easy right? If you saw my previous post about learning Blender you’d think that would be especially easy for me. But strangely, it was not.

In Blender you can make an equilateral "circle" with 3 sides. You can make an icosahedral sphere (made of triangles) or a triangular fan or a cone made of triangles. You can create triangles out of rectangles with `quads_convert_to_tris()` or `poke()` and then delete the triangles you didn’t want. But simply generating a lone arbitrary triangle is weirdly hard to achieve. It is weird because from a computer science standpoint, 3d computer modeled geometry is composed only of triangles.

How about three 2d lines? Amazingly, no. Blender is also not at all ideal for modeling a simple pair of endpoints connected by a line. Weird, right? I was actually so blown away to learn this that it kicked off an odyssey of heroic software engineering designed to sort this out once and for all. That odyssey is today’s story!

I had been working on learning the arcane art of controlling Blender with Python. That topic was exactly as confusing and muddled as I expected for such a baroque piece of software. But doable. And speaking of baroque, after some experiments with Blender’s Python console, I started to have a dangerously stupid idea…

It turns out that I, Chris Edwards, have written a geometric modeler. It is called GeoGad, short for Geometry Gadget. I started this project in 2004 and until about 2014 it was really only a programming language. Yes, that’s right, a programming language. A delightful Turing complete bad-ass programming language that I’ve used pretty much every day since 2004. I know it’s bad-ass because it was heavily inspired by HP calculator RPL and if you think that was not bad-ass, you’re an idiot.

The GeoGad logo is a triangle. And yes, GeoGad’s mascot is a sloth (Motto — Slow but happy and lovable).

In 2014, I added the geometry model and its functions to the language. In my system, geometry can only consist of simple lines and triangles. The lines are visible and the triangles exist only to provide occlusion reference i.e. allow for hidden line removal. And that hidden line removal was done by a Unix command line rendering engine called `to2d`. That C++ program is the most obscure rendering engine in the world because I wrote that too. While developing the geometry capabilities of GeoGad, I would pipe the raw geometry model to `to2d` and then dump the resulting 2d vectors in a file formatted as SVG. I could have a browser constantly polling and reloading this output and there was a display system. But that was not very user friendly, even for users like me who have different ideas about what friendly means.

At this point in the story:

• I wanted to do some simple geometry that is overly complicated in Blender and which GeoGad is especially good at.

• I was playing around with Blender’s Python interpreter.

• GeoGad is written in Python.

Hmmm…… Could I maybe run GeoGad inside Blender? It turns out, the answer is yes! Check out this screenshot.

This shows how I tell the Blender Python interpreter where GeoGad lives by editing the `sys.path` variable. Now this Blender Python can import the important components of the GeoGad system (you can see these exact components in a similar project, dated 6 years after mine, by Peter Norvig, Google’s Director of Research).

With GeoGad’s code ready to run there was just one problem — the Blender Python interpreter did not implement the Python `input` command. This means I couldn’t just run GeoGad interactively like I normally do. It may be possible to hook up interactive input to some GUI element, but for now I simply define a function `gg()` that takes as input a string of GeoGad code. And it’s ready to use! I start by running the GeoGad `version` command to demonstrate that everything is hooked up.

The next couple of commands import GeoGad’s memory model output code. If I’m running a text only version of GeoGad, I don’t ever need to send the memory model (the geometry) anywhere special. But the real point here is to actually control Blender. So this passes a hint to the output code about where it can use Blender functions.

And finally, I demonstrate a classic programming language test.

``0 1 |[dup2 +::!] 18 repeat``

Can you figure out what that complete GeoGad program does? The answer and a nice comparison to other languages can be found here.

I’ve been making this look easy, but in reality, this has been a real grind. The first obstacle was that Blender, sensibly, uses Python3. In 2004 there was no Python3 and I took this opportunity to convert the entire GeoGad code base from Python2. The next ordeal was figuring out Blender’s interface functions and what might work. Blender uses a list of points and refers to them by their position; I use a dictionary of points and refer to them by numeric ID. My way allows everything to work without changes if some points are removed from the collection. The funny thing is that both ways are the same until some points are removed. I spent quite a while figuring that out while sometimes it would work and sometimes I would get a Blender seg fault.

Once I had added a `blender` command to GeoGad that could reliably put GeoGad’s geometry into Blender, it was time to start writing some stuff in GeoGad to do that. I quickly got sidetracked wishing GeoGad had Vim syntax highlighting. So of course I worked on that. Once I had rough highlighting finished, I was so delighted by it I went through GeoGad and added color to the runtime interpreter. It looks great! I’m loving that new feature but annoyingly, the Blender Python console just makes a mess of it. So I had to go back and make the colors optional. You can see some of that mess on the version string which I haven’t yet fixed.

Here’s an example of a GeoGad program showing off the syntax highlighting.

Even though some of the highlighting is not quite right (`p0` should be white, not mixed colors) it is already a huge improvement for me and immensely helpful.

What does this code do? Since I was frustrated about triangles, I decided to make tetrahedra. So the function (GeoGad thinks of it as a live list stored in the symbol table, but same thing) `tetra` makes a tetrahedron’s geometry. Then there are some functions to randomly rotate and scale something (the tetrahedron presumably). The function `ptsonline` calculates points on a line that are evenly spaced at the interval `_i` (i.e. 0.6 as shown). What this allows me to do is send some lines and replace them with a trail of random tetrahedra.

Another program that I worked on (but won’t bore you with) takes the SVG logo shown above and extracts the geometry (check this HTML page’s source to see it) and builds a GeoGad model with it. By feeding this set of lines to the program shown above, I get the following result.

That is a superb result! I’m delighted with how perfectly GeoGad’s strengths compliment Blender’s. A lot of times when I model something I want a bunch of reference lines that clearly lay out geometric constraints and known geometry that must be designed to. I generally am less concerned with how it looks and more concerned with how it is. GeoGad helps me feed Blender explicit data that adheres to hard constraints. If there’s latitude in other parts of the modeling process to sculpt something to look nice, great, that’s what Blender excels at. Having Blender and GeoGad working together is really the best of both worlds for me.