User Guide Cancel

Paths Format Specifications | Substance 3D Designer

Paths Format Specifications

This page describes the Paths format and provides guidance for manipulating data in that format using functions included in the Paths tools.

In this page


Format specifications

This section explains how a Paths document (or image) is encoded:

A Paths document is a list of paths, each of which describes a list of segments, encoded in a 32bit floating-point color texture.

The texture is split into 'top' ($pos.y < 0.5) and 'bottom' ($pos.y > 0.5) parts.

Any data in a pixel in the 'top' part is semantically closely related to the matching pixel in the 'bottom' part, and vice-versa.

Paths Polygon encoded data

Note:

Paths data require 32-bit precision and using lower bitdepth will produce incorrect results.

Therefore, make sure to set the 'Ouptut Format' parameter of nodes generating Paths data to 'HDR High Precision (32F)'.

Let `uv_pos` be a 2D address (such as $pos) of a pixel of the 'top' part.

In the rest of this document:

  • top[uv_pos].XYZW will be referring to the 4 floats stored in the pixel of the top part.
    top[uv_pos] == sample_color(paths, uv_pos)
  • bottom[uv_pos].XYZW will be referring to the 4 floats stored in the matching pixel of the bottom part.
    bottom[uv_pos] == sample_color(paths, uv_pos + Float2(0, 0.5))

top[uv_pos] and bottom[uv_pos] together are forming a semantic unit U[uv_pos] of the document, composed of 8 floats.

Document header

Every Paths document starts with a document header. It is the very first semantic unit U[(0,0)]:

Path headers

The document header is immediately followed by number-of-paths = top[(0,0)].X path-headers, one by semantic unit.
E.g. if there are 3 paths in the document, they will be stored in U[(0,1)*pixel_size], U[(0,2)*pixel_size] and U[(0,3)*pixel_size] (with pixel_size = top[(0,0)].YZ).

If there are more paths than what one line of pixel can contains, the remaining path-headers are written one the next line(s), in scanline order.
It is allowed to have null path-headers (`top[...].XYZW = Float4(0,0,0,0)`); such path still could as one empty path.

The path-header of the Nth path will be defined at address `path_addr` will be defined as:

Note:

You can compute `path_addr` from N using the function `Utils/pixel_index_to_position` in paths_tools.sbs: `path_addr = pixel_index_to_position(N+1)`

Vertices information

Vertices can be found anywhere in the image after the headers (document or path headers). Vertices can be of various "types" (Start, Mid or End) and they are explicitly linked together using 2 address pointers ("links").

Start and End vertices are special in this respect: To allow the representation of closed paths or of an arbitrary network of paths linked together, one of the link is actually used to form a circular forward linked list of all the other Start or End vertices that represent the same vertex. Such vertices matching each others are called "siblings". [Illustration welcomed]

Formally, each vertex at address `vert_addr` is defined like this:


Reading and writing Paths information

If you want to make your own Paths-processing nodes, you have several tools.

The basics are provided by the Paths Vertex Processor and Paths Vertex Processor Simple nodes, which can basically be used the same way as a Pixel Processor.

If you need features beyond what the Paths Vertex Processor nodes offers (more input textures, or more previous or next vertices), copying the implementation of this graph might be good starting point (assuming you replace the Get("%perVertex") node with you custom processing).

But in case you want to do something more alien than applying a per-vertex function, here is a detailed explanation of the tools you can use. These are usually small helper functions that can be found in the same package as the other Paths nodes (paths_tools.sbs). (These functions are not exposed in the Library and Node menu.)

'Read' functions

Under the `Read` folder, you can find several of these, useful to gather information about the Paths:

Some can give you information about a given pixel. They all take the sampled Float4 value in the *top* part as input. If you look at their implementation, they are super-simple. Their point is to convey more meaning than just atomic nodes:

'Write' functions

Under the `Write` folder, you will find small helpers that builds a Float4 ready to be written by an Fx-Map.

Indeed, the Fx-Map multiplies RGB by Alpha before drawing, so the actual values are un-premultiplied to compensate for that. If you want to use these function e.g. in a Pixel Processor, we recommend that you apply the premultiplication yourself again, or that you write a custom version (more optimized for your use case and easier to use).

There is no bottom-part builder for path headers nor vertices: both encode two links to the top part, so this function would essentially be a Vector Float4 constructor from two Float2. Don't forget to divide XYZ by W if you are writing using an Fx-Map (W being the Y of an address, it should never be null).

You will find a pertinent example of how to use these functions in the paths_polygon.sbs package hosting the Paths Polygon node.

Methods for processing paths

You will likely use either a Pixel Processor or an Fx-Map to implement your custom processing, each of which has its strength and weaknesses:

Get help faster and easier

New user?