Yo, Shader* People!

I’ve spent a good portion of the past half-decade reading shaders, and I’ve yet to find anyone using a name for that structure that I’ve considered to be accurate and precise. Most of that time, the shaders I’ve written have been in GLSL, so I didn’t pay this subject much mind, until this year, when I started writing in the Metal shading language. Before diving too deep into the befuddling abyss whence springs the problem, let’s look at some example usage.

Even in Apple’s own sample code, all released within the span of a few months, there’s a good amount of variety, and hardly any consistency! Aside from one other example I’ll get to later in this post, Apple’s sample shaders represent all the kinds of names that I remember that I’ve seen.

The prefixes aren’t necessary, because they’re file-scoped, in files that are named rather well (skybox.metal and environmentMapReflection.metal). The prefixes could be chalked up to educational purposes, but if they’re redundant, wouldn’t that be teaching bad practice?

In theory, this comment would be helpful to some members of the target audience. However, it’s inaccurate, due to not taking the rasterizer into account. I also find “IO” to be confusing. Isn’t VertexOI the correct order, to match up with that comment?

The words are related enough to what’s going on, that I can meaningfully use the structure, but I don’t feel like I know the intent of the author. What did they think was going in, and coming out, of what?

Aside from a transformation matrix multiplication in Textured Quad, data associated with vertexes is coming through unaltered, in these vertex functions, so maybe that’s the IO in question? But, neither vertex function takes a VertexInOut as a parameter, and that concept doesn’t match up with the comment from Image Processing.

The name isn’t completely accurate, because color isn’t the only datum, but we know that position is always going to be in the structure returned from a vertex shader, so Color does describe the unique data.

As for “InOut” in this case, color isn’t based any vertex data input, unlike what we saw in Textured Quad and Vertex Streaming, so either it’s a mistake, I don’t get it, or, as I’m about to argue, nobody does yet.

I have to hypothesize that the same person who wrote the Basic 3D shaders wrote these right afterwards. The name of the structure is identical, but not a single one of these actually contains data that is considered a “color”. Demonstrably, accurate naming doesn’t matter, for desired graphical results. Why don’t we just standardize a generic default, so nobody has to think about the naming? I believe that naming the structure is useless cognitive overload in every case; I’m interested in evidence to the contrary.

Interesting! This is the first time I’ve seen this. Being able to take advantage of function signature matching is a danial boon, but to use the feature only in order to give a struct two names, instead of one, when a single good name would do? I don’t think that’s a worthwhile use case.

Unity’s standard is the term v2f, which actually does a good job of telling the structure’s story (it stands for vertex to fragment). Unfortunately, it isn’t actually a name: the efficiency of using three typed characters doesn’t translate to speech. Vertofrag would be a more practical option, in the same spirit.

Also, I think the sensational spelling of to is an especially poor match for graphics code; “2f” has multiple meaning in this environment (e.g. “2, as a floating point value” or “two floating-point values“). I was initially confused about the name, because of that, and although I’ve now understood it for years, I think there will always be some small, but unnecessary, cognitive load for me, with v2f.

Inputs and Outputs

Vertex function

I used to have the idea that a vertex shader operated on vertexes (along with uniform data), and also returned vertexes as output. OpenGL reinforced this idea, via its concept of vertex attributes: I’d only have access to the data from one vertex, in the shader.

Metal, however, enlightened me that my belief was false. Reading “vertex data” actually involves indexing into an array: the drawPrimitives function allows you to specify what indexes you’ll be supplied, and you can use those numbers, with the [[vertex_id]] parameter, to access any data in that array! Whether that’s actually useful or not, I don’t know, but I now understand that vertexes are not inputs to vertex shaders.

As someone who started off in 3D modeling, before moving onto 3D programming, this is a bit counterintuitive. The first piece of 3D asset creation data is generally a model, which is constructed by creating vertexes, moving them around, and assigning them meaningful properties other than position, such as texture coordinates and colors. The vertex function does use the model’s data, but in the form of reconstruction. What comes out is not the same thing that went in. The stuff that you manually model is actually an ingredient to what a vertex is, not a vertex itself.

Accuracy and Precision

The vertex function is a constructor for a vertex.
The data structure I’ve been talking about in this article is the same data that a vertexcomprises.

…so, is the name for the structure “Vertex”? If this output were the whole story, I’d say yes! But, it rarely is. There may be tessellation and geometry stages, on other platforms, but for now, with Metal, we at least should plan for the

Fragment function

Aside from the special case of blending, I don’t recall having the notion that a fragment shader took a fragment as input, presumably because I never manually constructed fragments. (Had I done more 2D digital art, this might not have been true.) I also don’t recall thinking that they took vertexes as input, but the conventions shown above don’t make it obvious why that wouldn’t be true.

What’s Missing?

The crucial step performed by the rasterizer is not reflected in code that uses a “VertexOutput” or “VertexInOut” as a parameter for a fragment function. Rasterization is not a programmable step that necessitates a function, in your shader file, but it, not the fragment function, is the next process that your vertexes go through, after construction.

Is the only solution, to avoid prevarication, to copypaste a structure, and give it different names for the different things that comprise it, à la Uniform Streaming? I don’t think so.

Rastexes

I propose that, when generating a structure that will be interpolated by a rasterizer, using data from vertexes, we use the word rastex.

While a vertex function does construct a vertex, and the rasterizer interpolates vertexes’ data, the data structure that we actually need will be rasterized/interpolated vertex data. The output of a vertex shader is only useful to the rasterizer; it’s not an “input” to a fragment function. I’ll call that input a rastex, short for “rasterized vertex data”.

Is it accurate to call the output of a vertex function a rastex, if the vertex hasn’t been rasterized? Perhaps not 100%, but I think it’s a big improvement, and a reasonable compromise, without a language feature that could avoid struct duplication.

When we call a vertex a rastex:

It can mean “vertex to be rasterized”.

It’s made of the same data as its rasterized version, under the simplest filtering conditions.

As people sometimes shorten “vertex” to “vert”, I believe we can optionally use “rax”, for short. (“Rast” doesn’t work, because it doesn’t include a syllable from “vertex”.)

Rax, the Eternal Champion of Cyborganic Hemispherical Rasterization

*What Is this “Shading” We’re Doing?

To go with my old belief about vertex shaders taking vertexes as inputs, I believed that the output of a vertex shader represented a “shaded” version of its input. This didn’t translate to fragment shaders; I always had the idea that the fragment shader was a constructor of a fragment. Now that I’m thinking of vertex and fragment both describing outputs, does that mean that “shade” and “construct” are synonyms?…

…I think that it’s possible that they were synonyms for some piece of hardware, in some era, and for whatever reason, the term “shader” stuck, but it has long-outlived any accuracy it might have had:

“Fragment Shader”

Some of the calculations done in forward rendering are not “shading”.

Most of the fragment calculations done in deferred rendering are not “shading”.

“Vertex Shader”

The A7 processor is nearly two years old. “Shading” will only ever again be performed per-vertex as a last resort.

“Compute Shader“, “Tessellation Shader“, “Geometry Shader”

“Shading” very unlikely!

The Swift/Objective-C Metal API doesn’t contain the word “shader”, opting instead for “function”, which might be exactly as general as we need. And yet, Apple hasn’t offered a more accurate name than “Metal shading language”, for the rest of the Metal API. If we do actually need something more than vertex/fragment/geometry constructor, compute/tesselation function, and Metal programming language, then I vote for “doozer” (that can be short for shadoozer, if you want to be sentimental) and “doozing”. And if you’re good with that, and then want to use “fraggle” instead of “rastex”, that will do pigly.