SpacesDefinitions
From Odwiki
Contents |
Spaces in VEX
First of all, we need to make a subtle but important distinction: VEX, unlike languages like Renderman's Shading Language (RSL), is not just a shading language; it is a generic, multi-context, "vector expression" language. This is great, but some concepts are not equally meaningful across all contexts. For example; what does the phrase "camera space" mean in the CHOP context?
Spaces then, fall into this category of concepts which, while meaningful in some contexts, are either ambiguous or simply not applicable in others. As a result, VEX adopts the convention that there are, at any given time, at least three (and possibly four) spaces predefined for you. And since it would be silly to call them "Space1", "Space2", etc; they decided to label them as follows:
- world
- object
- texture
There are others, and we'll get to what they all mean in a second, but for now, it's important to get used to thinking about these names as simply labels -- they won't necessarily match your idea of what "world space", or "texture space" should mean. This is particularly true if you're coming from RSL, or some other purely shading language.
Spaces in The Shading Contexts
There are four predefined spaces for our use inside shaders, and there are an unlimited number of user-defined spaces that can also be accessed as arbitrary "named spaces" (or at least that's how I like to call them, but that's not an official, SESI-approved name for them ;-) .
What follows is an overview of each one of these. But before we get lost in all the gory details, this is probably a good time to start thinking of these things, more as "space categories", than static things with a single rigid interpretation. The reason is that, as you will see, there isn't really a single "object space", or a single "NDC space".
World Space
- All global variables available to the shading contexts are given in this space. In other words, all the raw materials we are given to play with inside our shader, exist in this so-called world space.
- World space in the shading contexts is defined as the space which has the camera at the origin, and which is oriented such that we're looking down its positive Z axis, with positive Y pointing up, and with positive X to our right. That bit about looking down +Z will become important later on, so try to remember it.
- So world space in the shading contexts is the label given to the space of the camera, or camera space.
Object Space
- This is the space where "the thing that we're shading" lives. The obvious question then, is "what exactly is this thing that we're shading?".
- The answer depends on the type of shader we're writing. Since each type of shader shades a different thing, then the corresponding meaning of object space varies from type to type. All the object space variations however, have the same orientation as world space; that is to say: we're looking down positive Z, with positive X to our right, and positive Y pointing straight up.
- In the case of a surface shader, we are being asked to shade some object's surface, which comes in the form of a single, lowly, surface point: P. For a surface shader then, object space is the space of the geometry object (as in "/obj/some_object") that "owns" the SOPs that define its geometry, and therefore its surface. Note that this is not the space of the SOP inside that object that happens to have its render flag on.
- The definition of object space for displacement shaders, is identical to the one given for surface shaders.
- In the case of a fog shader, we're being asked to shade the line between a surface point P (which has already been shaded by a surface shader by the time we're called), and us (the camera origin: Eye). After shading all these lines which are packed tightly together (actually; they are long, thin volumes, not lines), what we are effectively doing is shading the entire space between us (the camera), and every object in the scene -- so "the thing we're shading" here, is a volume of space; the "atmosphere" that surrounds all objects in the scene -- at least the part of it that stands between us an the objects.
- In Houdini, "atmospheres" are allowed to transform like any geometry object. This is done by giving them the status of a special kind of object: an atmosphere object. There are several reasons why this is a ReallyGoodThing, but for our purposes here, it means that object space for fog shaders is the space of the atmosphere (fog) object which has our shader assigned to it, not the space of the geometry objects being rendered (as is the case with surface/displacement shaders).
- A light shader shades light (or luminance, or radiance). And because this type of shader can only be attached to light objects, it is effectively being asked to shade itself. In this case then, object space is the space of the light object that has our shader attached to it. The only subtlety to note here, is that when we render a shadow map, or any other special data map from the point of view of a light, the light is suddenly also the camera. This means that in that particular case, world space (which is actually "camera space") is identical to object space (the space of the light), since the light is both the camera and the light at the same time. This little detail can trip you up sometimes, so it's good to be aware of it.
- The definition of object space for shadow shaders, is identical to the one given for light shaders.
Texture Space (also called "Shader Space" in the VEX documentation)
- This space is only meaningful for surface and displacement shaders; for all other types of shaders, it is identical to object space as described above, and holds no special significance.
- In Houdini, you can specify any object of your choice as an "extra" space you would like to use for the purposes of shading surfaces and/or displacements. This is done in the object's Shading tab, under Shading Space and Displace Space (see figure 1). This space is refered to as texture space (also shader space in the VEX documentation) within surface and displacement shaders, and a different space can be chosen for each.
- If these spaces are left at their default (set to "This Object"), then they are identical to the already available object space. You can, however, specify any other object in your scene to be the designated texture space. Note that neither light, nor atmosphere objects have these two entries in their respective shading tabs.
NDC Space
- This acronym stands for Normalized Device Coordinates, and represents the 2-dimensional space of the image plane -- specifically, the quadrilateral where it intersects the viewing frustum. The units for the coordinates of this space however, are not given in pixels; rather, they range from 0 to 1 (that's what the normalized part of the acronym stands for) in both the horizontal and vertical directions, regardless of either the resolution, or the aspect ratio of the final image. The origin of this space (the coordinates {0,0}) is at the lower left corner of the image, with the coordinates {1,1} at the top right corner.
- As you've probably guessed, there can't be a concept of an "image" (and therefore, NDC space), without the accompanying concept of a "camera", or "viewer", or, as the acronym implies, some image-capture device. In almost all shading contexts, "the camera" is simply the camera being used to render the final image. Transforming to NDC space then typically means transforming to/from the image plane of the main "render camera".
- However; there are two contexts where things get a little more ambiguous; these are the light and shadow contexts. In both these cases, we are inside a context that contains two cameras: the main render camera (as before), and the light itself, which is also a camera.
- In the case of light and shadow shaders, a transformation to/from NDC space means a transformation to/from the image plane of the light; not of the main render camera. But, as mentioned earlier, all global variables are given to us in world space, which should be taken to mean "the space of the principal rendering camera", not the light.
- The end result of all this is that if we're inside a light/shadow shader, and we need to transform some global variable (say Ps) to NDC space, then we need to first transform Ps from its native world space (the main "render camera" space) to the light's own space (given to us as object space inside light/shadow shaders), before we transform to the light's NDC space. Again, this is because NDC space for light/shadow shaders refers to the NDC space of the light.
- Lurking behind this potential confusion, is that the functions that perform the transformation (toNDC() and fromNDC() and their VOP node equivalents ToNDCVOP and the TransformVOP) are context-sensitive: if called from a surface/displacement shader, they assume you mean the NDC of the camera, and if called from inside a light/shadow shader, they assume you mean the NDC of the light.
Named Spaces
- These are arbitrary spaces that can be acquired by the shader, either explicitly through shader parameters, or by querying other objects and/or shaders currently active at the time of the shader call. They are not part of the "built-in" set of spaces, and they are not manipulated with the same set of tools as with the standard spaces but, as you'll see, can be tremendously useful in many important ways. See <later on in these notes> for details on when and how to use them.
What is a transformation?
This concept of "transforming" between spaces has cropped up a few times already, and we'll see it a lot more as we move on, so perhaps it's a good idea to take a moment and talk about what it means when used in the context of writing shaders.
We're all familiar with what happens when we transform an object in Houdini: the object changes position and/or orientation. But is this also what we mean when we say that we are transforming something from one space to another inside a shader? It is. Mathematically, they are equivalent. Nevertheless, it helps to think about it in a slightly different way when talking about transforming between spaces.
First of all (and just in case), let's disavow ourselves of any notion of "movement" as a result of a transformation. For us to be able to perceive motion there needs to be a passage of time, and time doesn't exist inside a shader -- it's a frozen, static world where things are exactly in one place, and one place only. A few of these frozen slices of time may be averaged together to produce something that resembles motion blur, but that changes nothing -- the fact remains that things do not move inside a shader.
We also intuitively associate a transformation with something changing "outside of us" -- i.e: we are static, then we apply a transformation to an object, and see the object change, not us. But an equivalent way of describing the same thing, is to say that we change and the object stays still. They both describe a change in the relationship between us and the object. The second interpretation however, is, in my opinion, a much better model to use when thinking about transformations between spaces inside shaders.
Using that model then, a transformation from one space to another describes a change in our point of view on a static data set. We see the same objects, but from a different vantage point. We start off at the camera's location looking down its positive-Z, and contemplating the point P, say. But we may choose to "walk over" to where the object we're rendering is, orient ourselves so we look down its positive-Z, and see P from that point of view. In all cases, we are the origin (the location {0,0,0}). Wherever we go, we take the origin along for the ride. It should come as no surprise then, that from our new location and/or orientation, P will have a different set of coordinates than it did from our old position.

Figure 2: The coordinates of a single point, as viewed from four different spaces. The labelled vectors represent the coordinates of P with respect to each space. Note that the vector representing the NDC coordinates is a 2-dimensional vector (unlike all the others, which are 3-dimensional).
In Figure 2, we can see how a single point's position is interpreted from four different spaces. Note that the point P is the same in all cases, we're just "measuring" its position from different locations and orientations, and therefore coming up with different answers in each case -- different coordinates relative to us (the origin) and the local orientation of our system of axes.
In conclusion; whenever we hear the expression "...transform P from world to object space...", we should think to ourselves "...we're currently looking at P from the point of view of the camera, but we should move over to the object's origin, and re-interpret its coordinates from that position instead...". A little verbose, but hopefully you see my point.




