335 lines
18 KiB
ReStructuredText
335 lines
18 KiB
ReStructuredText
.. _realtime-compositor:
|
|
|
|
**************
|
|
GPU Compositor
|
|
**************
|
|
|
|
The new GPU accelerated compositor introduced in Blender 3.5 and is
|
|
currently used for :ref:`viewport compositing <viewport-compositing>`. This compositor is currently
|
|
more limited and not all :ref:`Compositor Nodes <compositor-nodes>` are supported, such nodes are
|
|
marked with the :guilabel:`CPU Compositor Only` label along with notes about other limitations.
|
|
Moreover, MacOS is not supported due to missing support for modern OpenGL.
|
|
|
|
Data
|
|
====
|
|
|
|
Dimensionality
|
|
--------------
|
|
|
|
Compositing nodes operate on data that is either an image or a dimensionless single value. For
|
|
instance, the :ref:`Levels node <bpy.types.CompositorNodeLevels>` outputs a single value, while the
|
|
:ref:`Render Layers node <bpy.types.CompositorNodeRLayers>` outputs an image. Node inputs that
|
|
expect a single value assume a default value if an image is given and ignore the image completely,
|
|
for instance, the :ref:`Transform node <bpy.types.CompositorNodeTransform>` expects single values
|
|
for its inputs and will assume default values if images were given to those inputs. The default
|
|
values are those that are considered identity and thus have no effect on the output, so for the
|
|
:ref:`Transform node <bpy.types.CompositorNodeTransform>`, the *X*, *Y*, and *Angle* inputs will
|
|
have a default value of zero, while the *Scale* input will have a default value of one. On the other
|
|
hand, if node inputs that expect an image are given a single value, the single value will be assumed
|
|
to cover the whole compositing space. For instance, the :ref:`Filter node
|
|
<bpy.types.CompositorNodeFilter>` expect its *Factor* input to be an image, but if a single value is
|
|
given, it will be assumed to be the same for all pixels.
|
|
|
|
Type
|
|
----
|
|
|
|
Three types of data exist, all of which are stored in half precision formats:
|
|
|
|
Float
|
|
A signed floating-point number. Integer data is also stored as floats because no integer type
|
|
exist.
|
|
|
|
Vector
|
|
A 4D vector. While it is 4D, it can have different interpretations depending on the node that uses
|
|
it. It can be treated as a 2D vector with the last two components ignored, for instance, the
|
|
*Vector* input of the :ref:`Displace node <bpy.types.CompositorNodeDisplace>` is treated as a 2D
|
|
vector. It can be treated as a 3D vector with the last component ignored, for instance, the
|
|
*Vector* input of the :ref:`Seperate XYZ node <bpy.types.CompositorNodeSeparateXYZ>` is treated as
|
|
a 3D vector. It can be treated as two consecutive 2D vectors. For instance the *Velocity Pass* as
|
|
expected by the :ref:`Vector Blur node <bpy.types.CompositorNodeVecBlur>` is assumed to have the
|
|
*2D Previous Velocity* in the X and Y components of the vector and the *2D Next Velocity* in the
|
|
Z and W components of the vector.
|
|
|
|
Color
|
|
A 4D vector storing the Red, Green, Blue, and Alpha of the color. The color is free form and does
|
|
not conform to a specific color space or alpha storage model, instead, appropriate nodes will have
|
|
settings to control the representation of their output and nodes exist to convert between the
|
|
different representations.
|
|
|
|
Implicit Conversion
|
|
^^^^^^^^^^^^^^^^^^^
|
|
|
|
In case a node input is given data of type other than its own type, the following implicit
|
|
conversions are performed:
|
|
|
|
+---------+---------+-------------------------------------+
|
|
| Source | Target | Conversion |
|
|
+=========+=========+=====================================+
|
|
| Float | Vector | f => Vector(f, f, f, 0) |
|
|
+---------+---------+-------------------------------------+
|
|
| Float | Color | f => Color(f, f, f, 1) |
|
|
+---------+---------+-------------------------------------+
|
|
| Vector | Float | (x, y, z, w) => Average(x, y, z) |
|
|
+---------+---------+-------------------------------------+
|
|
| Vector | Color | (x, y, z, w) => Color(x, y, z, 1) |
|
|
+---------+---------+-------------------------------------+
|
|
| Color | Float | (r, g, b, a) => Average(r, g, b) |
|
|
+---------+---------+-------------------------------------+
|
|
| Color | Vector | (r, g, b, a) => Vector(r, g, b, 0) |
|
|
+---------+---------+-------------------------------------+
|
|
|
|
The following example demonstrates implicit conversion between a color type and a float type, since
|
|
the :ref:`Math node <bpy.types.CompositorNodeMath>` expect float inputs.
|
|
|
|
.. figure:: /images/compositing_realtime-compositor_compositing-space_data_type_implicit_conversion.png
|
|
|
|
An example that demonstrates implicit conversion between a color type and a float type, since the
|
|
*Math* node expects float inputs.
|
|
|
|
Compositing Space
|
|
=================
|
|
|
|
Image Domain
|
|
------------
|
|
|
|
The compositor is designed in such a way as to allow compositing in an infinite compositing space.
|
|
Consequently, images are not only represented by their size, but also by their transformation in
|
|
that space, much like 3D objects have transformations. An identity transformation represents an
|
|
image that is centered in space. The rectangular area occupied by an image in that space as defined
|
|
by its transformation and size is called the *Domain* of the image. The figure below demonstrates
|
|
the domains of two example images.
|
|
|
|
..
|
|
\documentclass[tikz, convert]{standalone}
|
|
\begin{document}
|
|
\begin{tikzpicture}
|
|
% Draw axis and grid.
|
|
\draw[help lines, color = gray, dashed] (-4.9,-3.9) grid (4.9,3.9);
|
|
\draw[->, thick] (-5,0) -- (5,0) node[right] {$x$};
|
|
\draw[->, thick] (0,-4) -- (0,4) node[above] {$y$};
|
|
% Draw bigger domain.
|
|
\draw[ultra thick] (-4, -3) rectangle (4, 3);
|
|
\node[above] at (-2, 3) {800px $\times$ 600px};
|
|
% Draw smaller domain.
|
|
\draw[ultra thick] (1, 1) rectangle (3, 2);
|
|
\node[above] at (2, 2) {800px $\times$ 400px};
|
|
\end{tikzpicture}
|
|
\end{document}
|
|
|
|
.. figure:: /images/compositing_realtime-compositor_compositing-space_image-domain_example.png
|
|
|
|
The domains of two example images are illustrated on the compositing space. One of the images is
|
|
centered in space and the other is scaled down and translated such that it lies in the upper
|
|
right quadrant of the space. Notice that both images have similar sizes in pixels, yet their
|
|
apparent sizes are different.
|
|
|
|
Images can be transformed using nodes like the :ref:`Transform <bpy.types.CompositorNodeTransform>`,
|
|
:ref:`Translate <bpy.types.CompositorNodeTranslate>`, and :ref:`Rotate
|
|
<bpy.types.CompositorNodeRotate>` nodes.
|
|
|
|
Operation Domain
|
|
----------------
|
|
|
|
:ref:`Compositor Nodes <compositor-nodes>` operate on a specific rectangular area of the compositing
|
|
space called the *Operation Domain*. The nodes only consider the area of the input images that
|
|
overlap the operation domain and ignores the rest of the images. If an input image doesn't
|
|
completely overlap the operation domain, the rest of the operation domain for that input will be
|
|
assumed to be a zero value, a zero vector, or a transparent zero color depending on the type. This
|
|
behavior can be changed to an extent, see the section about *Wrapping* below.
|
|
|
|
For instance, the figure below illustrates a case where the operation domain of a node is the large
|
|
blue area and the domain of an input image is the small red area. In that case, the input image
|
|
doesn't completely overlap the operation domain, so the rest of the blue area for that input image
|
|
is assumed to be zero.
|
|
|
|
..
|
|
\documentclass[tikz, convert]{standalone}
|
|
\begin{document}
|
|
\begin{tikzpicture}
|
|
% Draw axis and grid.
|
|
\draw[help lines, color = gray, dashed] (-4.9,-3.9) grid (4.9,3.9);
|
|
\draw[->, thick] (-5,0) -- (5,0) node[right] {$x$};
|
|
\draw[->, thick] (0,-4) -- (0,4) node[above] {$y$};
|
|
% Draw operation domain.
|
|
\fill[opacity = 0.3, blue] (-4, -3) rectangle (4, 3);
|
|
\draw[ultra thick] (-4, -3) rectangle (4, 3);
|
|
% Draw input image domain.
|
|
\fill[fill opacity = 0.3, red] (0, 0) rectangle (3, 2);
|
|
\draw[ultra thick] (0, 0) rectangle (3, 2);
|
|
\end{tikzpicture}
|
|
\end{document}
|
|
|
|
.. figure:: /images/compositing_realtime-compositor_compositing-space_operation-domain_example.png
|
|
|
|
An example case where the operation domain of a node is shown in blue and the domain of an input
|
|
image is shown in red. Since the input image doesn't completely cover the operation domain of the
|
|
node, the rest of the blue area for that input image is assumed to be zero.
|
|
|
|
The previous illustration is a representation of a real world example where one uses the :ref:`Alpha
|
|
Over <bpy.types.CompositorNodeAlphaOver>` node to overlay a small logo on an image, as shown in the
|
|
figure below. In that case, the operation domain covers the entirety of the viewport --- as will later
|
|
be demonstrated, but the logo covers only a small area of it, so the rest of the area is assumed to
|
|
be a zero transparent color, which is convenient for the use case.
|
|
|
|
.. figure:: /images/compositing_realtime-compositor_compositing-space_operation-domain_real-example.png
|
|
|
|
A real world example where the Alpha Over node is used to over a small logo on an image. The logo
|
|
only covers a small area of the operation domain, which is the whole viewport in this case, so
|
|
the rest of the area is assumed to be a zero transparent color.
|
|
|
|
Interpolation
|
|
^^^^^^^^^^^^^
|
|
|
|
If an input image to a node is not perfectly aligned with the operation domain of the node or have a
|
|
different size in pixels, the node would typically need to do a process called Interpolation, where
|
|
the input image is read at the exact positions of the pixels of the operation domain. This can be
|
|
done using different interpolation methods, including Nearest-Neighbor, Bilinear, and Bicubic
|
|
interpolations. Those interpolation methods are demonstrated in the following
|
|
`Wikipedia gallery <https://en.wikipedia.org/wiki/Comparison_gallery_of_image_scaling_algorithms>`__.
|
|
Transformation nodes like the :ref:`Transform <bpy.types.CompositorNodeTransform>` and :ref:`Rotate
|
|
<bpy.types.CompositorNodeRotate>` nodes include an interpolation option to set how they prefer their
|
|
output image to be read and interpolated.
|
|
|
|
Note that the transform nodes don't do any interpolations themselves, they merely record the
|
|
preferred interpolation method for the output image and latter nodes that read that image will be
|
|
the node that does the actual interpolation. It follows that latter transform nodes will overwrite
|
|
the interpolation methods set by former transform nodes if no interpolation took place in-between.
|
|
|
|
Wrapping
|
|
^^^^^^^^
|
|
|
|
While it was previously stated that areas of the input images that do not overlap the operation
|
|
domain are assumed to be zero, this is only the default behavior. The alternative behavior is to
|
|
instruct the compositor to repeat the input image to fill the missing areas along the horizontal
|
|
direction, vertical direction, or both. This can be set in the *Wrap* option of the :ref:`Translate
|
|
node <bpy.types.CompositorNodeTranslate>`. Much like the aforementioned interpolation method, the
|
|
*Translate* node doesn't do any wrapping itself, it merely sets the preferred method of filling
|
|
empty spaces and latter nodes that read the image will be the node that does the actual wrapping.
|
|
|
|
For instance, the previous *Alpha Over* example but with *Both Axis Wrapping* enabled is shown in
|
|
the figure below.
|
|
|
|
.. figure:: /images/compositing_realtime-compositor_compositing-space_operation-domain_wrapping.png
|
|
|
|
The previous example with *Alpha Over* example but with *Both Axis Wrapping* enabled.
|
|
|
|
Determining Operation Domain
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The question remains on how nodes determine their operation domain. Different node types can have
|
|
different mechanisms for determining their operation domain. But generally, three classes of nodes
|
|
exist when it comes to the mechanism of determining the operation domain, each of which is presented
|
|
in one of the following sections.
|
|
|
|
Input Nodes
|
|
"""""""""""
|
|
|
|
The operation domain of input nodes like the :ref:`Image node <bpy.types.CompositorNodeImage>` is a
|
|
domain with an identity transformation and the same size as their outputs, so for the *Image* node,
|
|
the operation domain will be the domain whose size is the size of the image and whose transformation
|
|
is an identity one.
|
|
|
|
Output Nodes
|
|
""""""""""""
|
|
|
|
The operation domain of output nodes like the :ref:`Viewer node <bpy.types.CompositorNodeViewer>` is
|
|
a domain with an identity transformation and the same size as the final compositor output. For
|
|
:ref:`viewport compositing <viewport-compositing>`, that size would be the viewport size, and for
|
|
final render compositing, that size would be the scene render size.
|
|
|
|
Other Nodes
|
|
"""""""""""
|
|
|
|
Unless stated otherwise in their respective documentation pages, all other nodes use the following
|
|
mechanism. One of the inputs of the nodes is designated as the *Domain Input* of the node, and the
|
|
operation domain of the node is identical to the domain of that designated input. For many nodes,
|
|
the domain input can be intuitively identified as the main input of the node, for instance, the
|
|
domain input for the :ref:`Filter node <bpy.types.CompositorNodeFilter>` is the *Image* input. But
|
|
there are some caveats to note, which requires a deeper understanding of the mechanism.
|
|
|
|
Each input in the node has the so called *Domain Priority* property, the operation domain of the
|
|
node is the domain of the non single value input with the highest domain priority. So for instance,
|
|
the :ref:`Filter node <bpy.types.CompositorNodeFilter>` has two inputs, the domain priority of the
|
|
*Image* input is higher than that of the *Factor* input, and there are four possible configurations:
|
|
|
|
* Both the *Image* and factor inputs are connected to images. In this case, the *Image* input is the
|
|
domain input because it has the highest priority and is connected to an image.
|
|
|
|
* The *Image* input is connected to an image, but the *Factor* input isn't. In this case, the
|
|
*Image* input is the domain input because it it is the only input connected to an image regardless
|
|
of its priority.
|
|
|
|
* The *Image* input is not connected to an image but the *Factor* input is. In this case, the
|
|
*Factor* input is the domain input because it is the only input connected to an image regardless
|
|
of its priority.
|
|
|
|
* Neither the *Image* nor the *Factor* inputs are connected to images, in this case, there isn't
|
|
a domain input because the node is evaluated on single values.
|
|
|
|
Considerations
|
|
^^^^^^^^^^^^^^
|
|
|
|
The aforementioned mechanism for determining the operation domain has a number of consequences that
|
|
needs to be considered as they might be undesirable, each of which is presented in one of the
|
|
following sections.
|
|
|
|
Clipping
|
|
""""""""
|
|
|
|
The output of nodes will be intuitively clipped to the operation domain, or rather, the domain of
|
|
the domain input. For instance, if the *Foreground* input is bigger than the *Background* input in
|
|
the :ref:`Alpha Over node <bpy.types.CompositorNodeAlphaOver>`, the output will be clipped to the
|
|
*Background* input because it is the domain input, as shown in the following figure.
|
|
|
|
.. figure:: /images/compositing_realtime-compositor_compositing-space_operation-domain_considerations_clipping.png
|
|
|
|
The *Foreground* input is bigger than the *Background* input in the *Alpha Over* node, so the
|
|
output is intuitively clipped to the *Background* input because it is the domain input.
|
|
|
|
The :ref:`Alpha Over node <bpy.types.CompositorNodeAlphaOver>` currently doe not support changing
|
|
the domain priority for its inputs, so as a workaround, one can use a :ref:`Mix node
|
|
<bpy.types.CompositorNodeMixRGB>` to achieved the desired behavior, noting that the first *Image*
|
|
input in the *Mix* node has the highest domain priority, as shown in the following figure.
|
|
|
|
.. figure:: /images/compositing_realtime-compositor_compositing-space_operation-domain_considerations_clipping-solution.png
|
|
|
|
Working around the clipping behavior of the *Alpha Over* node using a Mix node, noting that the
|
|
first *Image* input in the *Mix* node has the highest domain priority
|
|
|
|
Pixelation
|
|
""""""""""
|
|
|
|
If the domain input of the node is very large, other inputs will look pixelated. That's because the
|
|
resolution of the domain input is the same, while its apparent size is greatly increased, so the
|
|
number of pixels covered by other inputs is much fewer.
|
|
|
|
.. figure:: /images/compositing_realtime-compositor_compositing-space_operation-domain_considerations_pixelation.png
|
|
|
|
An example case where pixelation happens due to very large domain inputs.
|
|
|
|
Pixel Space Operations
|
|
""""""""""""""""""""""
|
|
|
|
Nodes operate on their input images in local pixel space irrespective of their transformation in the
|
|
compositing space. For instance, if an image that is rotated by 90 degrees is blurred along the
|
|
horizontal direction using the :ref:`Blur node <bpy.types.CompositorNodeBlur>`, the blurring will
|
|
apparently take place along the vertical direction instead, because the node is applied in the local
|
|
pixel space of the input.
|
|
|
|
Output
|
|
======
|
|
|
|
The GPU compositor only supports a single active output target, that is, only one of the
|
|
:ref:`Composite nodes <bpy.types.CompositorNodeComposite>`, :ref:`Viewer nodes
|
|
<bpy.types.CompositorNodeViewer>`, or :ref:`Split Viewer nodes
|
|
<bpy.types.CompositorNodeSplitViewer>` in the node tree will be considered active and the rest will
|
|
be ignored. In particular, the compositor searches the *Active Node Tree Context* and falls back to
|
|
the *Root Node Tree Context* if no active output was found in the active node tree context. The
|
|
active node tree context is the node tree of an expanded node group, that is, when the users selects
|
|
a node group node and edits its underlying tree, while the root node tree context is the top level
|
|
node tree without any expanded node groups. The compositor searches for the active *Composite* node,
|
|
if non was found, it searches for the active *Viewer* node, be it a *Viewer* or a *Split Viewer*
|
|
node, if non was found, the compositor doesn't run altogether. Consequently, note that adding a
|
|
*Viewer* node will have no effect if there is a *Composite* node, since the priority is given to
|
|
*Composite* nodes.
|