Blender

I’ll admit, using Coldtype in Blender is not a very normal or standard application of Coldtype, but if you’ve ever tried to set text in Blender, you may understand why you’d never want to set text in Blender again using their typography GUI tools. Those tools are… bad. Worse-than-After-Effects bad. (Maybe not even any kerning if I remember correctly?)

Anyway the point is that you can avoid setting text in Blender itself by writing Python scripts that run inside Blender.

That is, the idea here is to work in a more hybrid style. You want a gigantic piece of 3d type that uses the second stylistic set of a font? Blender won’t help you, but Coldtype can: write a short script in Python, using Coldtype to create the vector, and — voila — you have a gigantic piece of 3d type that you can move around and add materials to, etc.

__N.B.__ This means the point of a Coldtype script in Blender is not to return a DATPen or DATPenSet to a renderer, but to work interactively, creating or mutating existing objects available in the Blender data hierarchy in your project file.

Getting it all set up is a bit of a pain, but worth it (if you’re doing anything with typography in Blender).

Installing

Installing packages in Blender requires locating the bundled python binary included with Blender itself. The path to this binary varies based on the version of Blender you have installed, but should look something like this:

/Applications/Blender.app/Contents/Resources/2.90/python/bin/python3.7m

The 2.90 and the 3.7m might be different depending on your installation.

On my computer, I’ve aliased that path to something I call b3d_python, so there’s a line like this in my ~/.bash_profile:

alias b3d_python='/Applications/Blender.app/Contents/Resources/2.90/python/bin/python3.7m'

I also have a line to address the Blender executable itself:

alias b3d='/Applications/Blender.app/Contents/MacOS/blender'

This is useful because when you’re running Python scripts in Blender on Mac, you need to start Blender from the command-line, in order to see errors and logs generated by the Python. If you start Python from the GUI Application in your Applications folder, you’ll be unable to see anything printed or thrown from your script.

Once you have all that out of the way, you can pip install things using that executable, like so:

b3d -m pip install coldtype

Or, if you’re installing a local cloned version of Coldtype (which is what I do):

b3d -m pip install -e ~/path/to/coldtype

However, that probably does not work, because of some C-build requirements in certain Coldtype dependencies. This part is weird & annoying.

We’re going to follow the strategy outlined in this Stack Overflow answer: basically, we need to add some missing files to Blender’s installation, which means you’ll need to download the source of the exact version of Python used in the Blender you have on your machine.

To find that, run b3d_python --version

For Blender 3.9, that’s python 3.7.7 — you can find the source for that here: https://www.python.org/downloads/release/python-377/

Once you’ve downloaded and unzipped the source, copy the Include files from the python 3.7.7 source into the /Applications/Blender.app/Contents/Resources/2.90/python/ (or equivalent), something like:

cp Include/* /Applications/Blender.app/Contents/Resources/2.90/python/include/python3.7m/

Once you’ve done that, you should be able to install coldtype in the normal way described above, with b3d -m pip install coldtype

Running Code in Blender

This code must be run from within Blender itself (see blender/README.md in this repo), using the “Text Editor” window, then run with the play button (aka alt+p):

from coldtype import *
from coldtype.pens.blenderpen import BlenderPen, BPH

BPH.Clear()

r = Rect(0, 0, 1000, 1000)
tc = BPH.Collection("Test")

mutator = Font.Cacheable("~/Goodhertz/coldtype/assets/MutatorSans.ttf")

(DATPen()
    .rect(r)
    .f(hsl(0.9, s=1))
    .tag("Frame")
    .cast(BlenderPen)
    .draw(tc, plane=1))

(StyledString("COLD",
    Style(mutator, 180, wdth=0.5, wght=1))
    .pen()
    .f(hsl(0.65, l=0.5, s=1))
    .align(r)
    .translate(0, 80)
    .tag("COLD")
    .cast(BlenderPen)
    .draw(tc))

(StyledString("TYPE",
    Style(mutator, 210, wdth=0.35, wght=0.25))
    .pen()
    .f(hsl(0.15, s=1))
    .align(r)
    .translate(0, -80)
    .tag("TYPE")
    .cast(BlenderPen)
    .draw(tc))

(StyledString("IN BLENDER",
    Style(mutator, 100, wdth=0.35, wght=0.25))
    .pen()
    .f(hsl(0.95, s=1))
    .align(r)
    .translate(0, -380)
    .tag("Blender")
    .cast(BlenderPen)
    .draw(tc))

Running that code will add some objects to your scene — objects which you can move around and modify as much as you’d like — the goal here is not so much to craft a finished image with code, but to help you quickly and precisely get some good looking typographic vectors in your scene.

So some code like that should result (if you render it via Cycles) in an image similar to this:

../_images/blenderrender.gif

This code is, like DrawBot, not particularly like a standard Coldtype program, because nothing is returned to a renderer. Instead, here we are procedurally building up vectors and manually appending them to Blender. The difference between Blender and normal Coldtype is that rasterization/rendering really only happens very late, when you render your entire Blender composition. So the workflow here is not to create artifacts straight-away, but to aide in building complex vector data with Python, rather than with the poor typography / type tools made available to you in the Blender GUI.