.. Copyright Contributors to the OpenImageIO project. SPDX-License-Identifier: CC-BY-4.0 .. _chap-texturesystem: Texture Access: TextureSystem ############################# .. |br| raw:: html
.. _sec-texturesys-intro: Texture System Introduction and Theory of Operation ================================================================== Coming soon. FIXME .. _sec-texturesys-helperclasses: Helper Classes ================================================================== Imath ------------------------------------------------- The texture functionality of OpenImageIO uses the excellent open source ``Imath`` types when it requires 3D vectors and transformation matrixes. Specifically, we use ``Imath::V3f`` for 3D positions and directions, and ``Imath::M44f`` for 4x4 transformation matrices. To use these yourself, we recommend that you:: // If using Imath 3.x: #include #include // OR, if using OpenEXR 2.x, before Imath split off: #include #include Please refer to the ``Imath`` documentation and header files for more complete information about use of these types in your own application. However, note that you are not strictly required to use these classes in your application --- ``Imath::V3f`` has a memory layout identical to ``float[3]`` and ``Imath::M44f`` has a memory layout identical to ``float[16]``, so as long as your own internal vectors and matrices have the same memory layout, it's ok to just cast pointers to them when passing as arguments to TextureSystem methods. .. _sec-textureopt: TextureOpt ------------------------------------------------- TextureOpt is a structure that holds many options controlling single-point texture lookups. Because each texture lookup API call takes a reference to a TextureOpt, the call signatures remain uncluttered rather than having an ever-growing list of parameters, most of which will never vary from their defaults. Here is a brief description of the data members of a TextureOpt structure: - `int firstchannel` : The beginning channel for the lookup. For example, to retrieve just the blue channel, you should have `firstchannel` = 2 while passing `nchannels` = 1 to the appropriate texture function. - `int subimage, ustring subimagename` : Specifies the subimage or face within the file to use for the texture lookup. If `subimagename` is set (it defaults to the empty string), it will try to use the subimage that had a matching metadata `"oiio:subimagename"`, otherwise the integer `subimage` will be used (which defaults to 0, i.e., the first/default subimage). Nonzero subimage indices only make sense for a texture file that supports subimages (like TIFF or multi-part OpenEXR) or separate images per face (such as Ptex). This will be ignored if the file does not have multiple subimages or separate per-face textures. - `Tex::Wrap swrap, twrap` : Specify the *wrap mode* for 2D texture lookups (and 3D volume texture lookups, using the additional `rwrap` field). These fields are ignored for shadow and environment lookups. These specify what happens when texture coordinates are found to be outside the usual [0,1] range over which the texture is defined. `Wrap` is an enumerated type that may take on any of the following values: - `Wrap::Black` : The texture is black outside the [0,1] range. - `Wrap::Clamp` : The texture coordinates will be clamped to [0,1], i.e., the value outside [0,1] will be the same as the color at the nearest point on the border. - `Wrap::Periodic` : The texture is periodic, i.e., wraps back to 0 after going past 1. - `Wrap::Mirror` : The texture presents a mirror image at the edges, i.e., the coordinates go from 0 to 1, then back down to 0, then back up to 1, etc. - `Wrap::Default` : Use whatever wrap might be specified in the texture file itself, or some other suitable default (caveat emptor). The wrap mode does not need to be identical in the `s` and `t` directions. - `float swidth, twidth` : For each direction, gives a multiplier for the derivatives. Note that a width of 0 indicates a point sampled lookup (assuming that blur is also zero). The default width is 1, indicating that the derivatives should guide the amount of blur applied to the texture filtering (not counting any additional *blur* specified). - `float sblur, tblur` : For each direction, specifies an additional amount of pre-blur to apply to the texture (*after* derivatives are taken into account), expressed as a portion of the width of the texture. In other words, blur = 0.1 means that the texture lookup should act as if the texture was pre-blurred with a filter kernel with a width 1/10 the size of the full image. The default blur amount is 0, indicating a sharp texture lookup. - `float fill` : Specifies the value that will be used for any color channels that are requested but not found in the file. For example, if you perform a 4-channel lookup on a 3-channel texture, the last channel will get the fill value. (Note: this behavior is affected by the `"gray_to_rgb"` attribute described in the Section about TextureSystem attributes. - `const float* missingcolor` : If not NULL, indicates that a missing or broken texture should *not* be treated as an error, but rather will simply return the supplied color as the texture lookup color and `texture()` will return `true`. If the `missingcolor` field is left at its default (a NULL pointer), a missing or broken texture will be treated as an error and `texture()` will return `false`. Note: When not NULL, the data must point to `nchannels` contiguous floats. - `Tex::Wrap rwrap, float rblur, rwidth` : Specifies wrap, blur, and width for the third component of 3D volume texture lookups. These are not used for 2D texture or environment lookups. - `Tex::MipMode mipmode` : Determines if/how MIP-maps are used. The enum value are: - `MipMode::Default` : The default high-quality lookup (same as Aniso). - `MipMode::NoMIP` : Just use highest-res image, no MIP mapping - `MipMode::OneLevel` : Use just one mipmap level - `MipMode::Trilinear` : Use two MIPmap levels (trilinear) - `MipMode::Aniso` : Use two MIPmap levels w/ anisotropic - `Tex::InterpMode interpmode` : Determines how we sample within a mipmap level: - `InterpMode::Closest` : Force closest texel. - `InterpMode::Bilinear` : Force bilinear lookup within a mip level. - `InterpMode::Bicubic` : Force cubic lookup within a mip level. - `InterpMode::SmartBicubic` : Bicubic when maxifying, else bilinear (default). - `uint16_t anisotropic` : Maximum anisotropic ratio (default: 32). - `bool conservative_filter` : When true (the default), filters conservatively in a way that chooses to sometimes over-blur rather than alias. - `int colortransformid` : If non-zero, specifies a color transformation to apply to the texels, a handle to a transform retrieved `TextureSystem::get_colortransform_id()`. .. _sec-texturesys-api: TextureSystem API ================================================================== .. doxygenclass:: OIIO::TextureSystem :members: .. _sec-texturesys-udim: UDIM texture atlases ==================== Texture lookups --------------- The `texture()` call supports virtual filenames that expand per lookup for UDIM tiled texture atlases. The substitutions will occur if the texture filename initially passed to `texture()` does not exist as a concrete file and contains one or more of the following substrings: ========== ======================== ================================= Pattern Numbering scheme Example expansion if u=0.5, v=2.5 ========== ======================== ================================= `` 1001 + utile + vtile*10 `1021` `` utile `u0` `` vtile `v2` `` utile + 1 `u1` `` vtile + 1 `v3` `` equivalent to `_` `u0_v2` `` equivalent to `_` `u1_v3` `_u##v##` utile, vtile `_u00v02` `%(UDIM)d` synonym for `` `1021` ========== ======================== ================================= where the tile numbers are derived from the input u,v texture coordinates as follows:: // Each unit square of texture is a different tile utile = max (0, int(u)); vtile = max (0, int(v)); // Re-adjust the texture coordinates to the offsets within the tile u = u - utile; v = v - vtile; Example:: ustring filename ("paint..tif"); float s = 1.4, t = 3.8; texsys->texture (filename, s, t, ...); will retrieve from file :file:`paint.1032.tif` at coordinates (0.4,0.8). Handles of udim files --------------------- Calls to `get_texture_handle()`, when passing a UDIM pattern filename, will always succeed. But without knowing a specific u and v, it has no way to know that the concrete file you will eventually ask for would not succeed, so this handle is for the overall "virtual" texture atlas. You can retrieve the handle of a specific "tile" of the UDIM set by using .. cpp:function:: TextureHandle* resolve_udim(ustring udimpattern, float s, float t) TextureHandle* resolve_udim(TextureHandle* udimfile, Perthread* thread_info, float s, float t) Note: these will return `nullptr` if the UDIM tile for those coordinates is unpopulated. Note also that the `is_udim()` method can be used to ask whether a filename or handle corresponds to a UDIM pattern (the whole set of atlas tiles): .. cpp:function:: bool is_udim(ustring filename) bool is_udim(TextureHandle* udimfile) Retrieving metadata from UDIM sets and tiles -------------------------------------------- Calls to `get_texture_info()` on UDIM file pattern will succeed if the metadata is found and has the same value in all of the populated "tiles" of a UDIM. If not all populated tile files have the same value for that attribute, the call will fail. If you want to know the metadata at a specific texture coordinate, you can use a combination of `resolve_udim()` to find the handle for the corresponding concrete texture file for that "tile," and then `get_texture_info()` to retrieve the metadata for the concrete file. Full inventory of a UDIM set ---------------------------- You can get the range in u and v of the UDIM texture atlas, and the list of all of the concrete filenames of the corresponding tiles with this method: .. cpp:function:: void inventory_udim(ustring udimpattern, std::vector& filenames, int& nutiles, int& nvtiles) void inventory_udim(TextureHandle* udimfile, Perthread* thread_info, std::vector& filenames, int& nutiles, int& nvtiles) The indexing scheme is that `filenames[u + v * nvtiles]` is the name of the tile with integer indices `(u,v)`, where 0 is the first index of each row or column. The combination of `inventory_udim()` and `get_texture_handle()` of the listed filenames can be used to generate the corresponding handles for each UDIM tile. .. _sec-texturesys-api-batched: Batched Texture Lookups ================================================================== On CPU architectures with SIMD processing, texturing entire batches of samples at once may provide a large speedup compared to texturing each sample point individually. The batch size is fixed (for any build of OpenImageIO) and may be accessed with the following constant: .. doxygenvariable:: OIIO::Tex::BatchWidth .. doxygentypedef:: OIIO::Tex::FloatWide .. doxygentypedef:: OIIO::Tex::IntWide All of the batched calls take a *run mask*, which describes which subset of "lanes" should be computed by the batched lookup: .. doxygentypedef:: RunMask .. cpp:enumerator:: RunMaskOn The defined constant `RunMaskOn` contains the value with all bits `0..BatchWidth-1` set to 1. Batched Options --------------- TextureOptBatch is a structure that holds the options for doing an entire batch of lookups from the same texture at once. The members of TextureOptBatch correspond to the similarly named members of the single-point TextureOpt, so we refer you to Section :ref:`sec-textureopt` for detailed explanations, and this section will only explain the differences between batched and single-point options. Members include: - `int firstchannel` : - `int subimage, ustring subimagename` : - `Wrap swrap, twrap, rwrap` : - `float fill` : - `const float* missingcolor` : - `MipMode mipmode` : - `InterpMode interpmode` : - `int anisotropic` : - `bool conservative_filter` : These fields are all scalars --- a single value for each TextureOptBatch --- which means that the value of these options must be the same for every texture sample point within a batch. If you have a number of texture lookups to perform for the same texture, but they have (for example) differing wrap modes or subimages from point to point, then you must split them into separate batch calls. - `float sblur[Tex::BatchWidth]` : - `float tblur[Tex::BatchWidth]` : - `float rblur[Tex::BatchWidth]` : These arrays hold the `s`, and `t` blur amounts, for each sample in the batch, respectively. (And the `r` blur amount, used only for volumetric `texture3d()` lookups.) - `float swidth[Tex::BatchWidth]` : - `float twidth[Tex::BatchWidth]` : - `float rwidth[Tex::BatchWidth]` : These arrays hold the `s`, and `t` filtering width multiplier for derivatives, for each sample in the batch, respectively. (And the `r` multiplier, used only for volumetric `texture3d()` lookups.) Batched Texture Lookup Calls ---------------------------- .. cpp:function:: bool TextureSystem::texture (ustring filename, TextureOptBatch &options, Tex::RunMask mask, const float *s, const float *t, const float *dsdx, const float *dtdx, const float *dsdy, const float *dtdy, int nchannels, float *result, float *dresultds=nullptr, float *dresultdt=nullptr) bool TextureSystem::texture (TextureHandle *texture_handle, Perthread *thread_info, TextureOptBatch &options, Tex::RunMask mask, const float *s, const float *t, const float *dsdx, const float *dtdx, const float *dsdy, const float *dtdy, int nchannels, float *result, float *dresultds=nullptr, float *dresultdt=nullptr) Perform filtered 2D texture lookups on a batch of positions from the same texture, all at once. The parameters `s`, `t`, `dsdx`, `dtdx`, and `dsdy`, `dtdy` are each a pointer to `[BatchWidth]` values. The `mask` determines which of those array elements to actually compute. The various results are arranged as arrays that behave as if they were declared:: float result[channels][BatchWidth] In other words, all the batch values for channel 0 are adjacent, followed by all the batch values for channel 1, etc. (This is "SOA" order.) This function returns `true` upon success, or `false` if the file was not found or could not be opened by any available ImageIO plugin. .. cpp:function:: bool texture3d (ustring filename, TextureOptBatch &options, Tex::RunMask mask, const float *P, const float *dPdx, const float *dPdy, const float *dPdz, int nchannels, float *result, float *dresultds=nullptr, float *dresultdt=nullptr,float *dresultdr=nullptr) bool texture3d (TextureHandle *texture_handle, Perthread *thread_info, TextureOptBatch &options, Tex::RunMask mask, const float *P, const float *dPdx, const float *dPdy, const float *dPdz, int nchannels, float *result, float *dresultds=nullptr, float *dresultdt=nullptr, float *dresultdr=nullptr) Perform filtered 3D volumetric texture lookups on a batch of positions from the same texture, all at once. The "point-like" parameters `P`, `dPdx`, `dPdy`, and `dPdz` are each a pointers to arrays of `float value[3][BatchWidth]`. That is, each one points to all the *x* values for the batch, immediately followed by all the *y* values, followed by the *z* values. The various results arrays are also arranged as arrays that behave as if they were declared `float result[channels][BatchWidth]`, where all the batch values for channel 0 are adjacent, followed by all the batch values for channel 1, etc. This function returns `true` upon success, or `false` if the file was not found or could not be opened by any available ImageIO plugin. .. cpp:function:: bool environment (ustring filename, TextureOptBatch &options, Tex::RunMask mask, const float *R, const float *dRdx, const float *dRdy, int nchannels, float *result, float *dresultds=nullptr, float *dresultdt=nullptr) bool environment (TextureHandle *texture_handle, Perthread *thread_info, TextureOptBatch &options, Tex::RunMask mask, const float *R, const float *dRdx, const float *dRdy, int nchannels, float *result, float *dresultds=nullptr, float *dresultdt=nullptr) Perform filtered directional environment map lookups on a batch of positions from the same texture, all at once. The "point-like" parameters `R`, `dRdx`, and `dRdy` are each a pointers to arrays of `float value[3][BatchWidth]`. That is, each one points to all the *x* values for the batch, immediately followed by all the *y* values, followed by the *z* values. Perform filtered directional environment map lookups on a collection of directions all at once, which may be much more efficient than repeatedly calling the single-point version of `environment()`. The parameters `R`, `dRdx`, and `dRdy` are now VaryingRef's that may refer to either a single or an array of values, as are many the fields in the `options`. The various results arrays are also arranged as arrays that behave as if they were declared `float result[channels][BatchWidth]`, where all the batch values for channel 0 are adjacent, followed by all the batch values for channel 1, etc. This function returns `true` upon success, or `false` if the file was not found or could not be opened by any available ImageIO plugin.