Arbitrary Attributes
====================

Katana provides the ability to export arbitrary attributes to renderers. This
information takes on a renderer-specific form at render time, such as
*user data* for Arnold and *primvars* for RenderMan.

In its simplest form, an arbitrary attribute can be defined through its scope
and value, as shown in the following :kat:node:`OpScript` code snippet:

.. code-block:: lua

   Interface.SetAttr("geometry.arbitrary.myFloat.scope", StringAttribute("primitive"))
   Interface.SetAttr("geometry.arbitrary.myFloat.value", FloatAttribute(1.0))

In the following example, a single ``float`` is converted to a ``color3`` data
type:

.. code-block:: lua

   Interface.SetAttr("geometry.arbitrary.myFloatToColor3.scope", StringAttribute("primitive"))
   Interface.SetAttr("geometry.arbitrary.myFloatToColor3.value", FloatAttribute(0.1))
   Interface.SetAttr("geometry.arbitrary.myFloatToColor3.outputType", StringAttribute("color3"))

In this example, two colors are defined and then converted to
``uniform color[2]`` when rendering with RenderMan:

.. code-block:: lua

   Interface.SetAttr("geometry.arbitrary.myColorArray.scope", StringAttribute("primitive"))
   Interface.SetAttr("geometry.arbitrary.myColorArray.value", FloatAttribute({0.1, 0.2, 0.3, 0.4, 0.5, 0.6}))
   Interface.SetAttr("geometry.arbitrary.myColorArray.inputType", StringAttribute("color3"))
   Interface.SetAttr("geometry.arbitrary.myColorArray.elementSize", IntAttribute(3))

A simple example with each face of a cube assigned an alternating texture using
an indexed array:

.. code-block:: lua

   Interface.SetAttr("geometry.arbitrary.myIndexedArray.scope", StringAttribute("face"))
   Interface.SetAttr("geometry.arbitrary.myIndexedArray.indexedValue", StringAttribute({"textureA.tx", "textureB.tx"}))
   Interface.SetAttr("geometry.arbitrary.myIndexedArray.index", IntAttribute({0, 1, 0, 1, 0, 1}))

.. list-table::
    :header-rows: 1
    :widths: 5 20 75

    - * Type
      * Attribute
      * Description

    - * :kat:type:`string`
      * :kat:attr:`geometry.arbitrary.<group>.scope`
      * The scope of the attribute. Valid values are:

        ``primitive``
          Constant.
        ``face``
          Uniform.
        ``point``
          Varying and vertex. For curves, this matches vertex.
        ``vertex``
          Face varying. For curves, this matches Face varying and varying.

        Support for the different scope types depends on the renderer's
        capabilities. Therefore, not all of these are supported in every
        renderer.

    - * :kat:type:`string`
      * :kat:attr:`geometry.arbitrary.<group>.inputType`
      * Types of values in :kat:attr:`value` or :kat:attr:`indexedValue`. It's
        important to note that the specified :kat:attr:`inputType` must match
        the footprint of the data as described.

        Valid values are:

        - ``float``
        - ``double``
        - ``int``
        - ``string``
        - ``color3``
        - ``color4``
        - ``normal2``
        - ``normal3``
        - ``vector2``
        - ``vector3``
        - ``vector4``
        - ``point2``
        - ``point3``
        - ``point4``
        - ``matrix9``
        - ``matrix16``

        Support for different input types depends on the renderer's
        capabilities. Therefore, not all of these are supported in every
        renderer.

    - * :kat:type:`string`
      * :kat:attr:`geometry.arbitrary.<group>.outputType`
      * Output type for the arbitrary attribute can be specified, if the
        intended output type (and footprint) differs from the input type but
        can be reasonably converted. Examples of reasonable conversions
        include: ``float`` -> ``color3``, ``color3`` -> ``color4``.

    - * :kat:type:`any`
      * :kat:attr:`geometry.arbitrary.<group>.value`
      * Attribute containing the value. The type is dependent on the type
        specified. The type of the value can be ``int``, ``float``, ``double``,
        or ``string``.

        The value can also be specified as an indexed list using the
        :kat:attr:`index` and :kat:attr:`indexedValue` attributes (see below).

    - * :kat:type:`int`
      * :kat:attr:`geometry.arbitrary.<group>.index`
      * List of indices. If no index is present, the index is implicitly
        defined by the scope.

    - * :kat:type:`any`
      * :kat:attr:`geometry.arbitrary.<group>.indexedValue`
      * List of values. The types of values in the list can be ``int``,
        ``float``, ``double``, or ``string``.

    - * :kat:type:`int`
      * :kat:attr:`geometry.arbitrary.<group>.elementSize`
      * This optional attribute determines the array length of each scoped
        element. This is used by some renderers, for example, RenderMan maps
        this to the ``[n]`` portion of a RenderMan type declaration:
        ``uniform color[2]``.

    - * :kat:type:`int`
      * :kat:attr:`geometry.arbitrary.<group>.isArray`
      * This optional attribute informs the renderer plug-in that the
        arbitrary attribute should be declared as an array (when set to ``1``)
        or a scalar (when set to ``0``). When this attribute is not set, the
        renderer plug-in typically infers this information from the length of
        the arbitrary attribute value.