# Tex::MipMode::Trilinear vs Aniso: Understanding OpenImageIO Texture Filtering Modes

> Understand Tex::MipMode::Trilinear vs Aniso in OpenImageIO. Learn how anisotropic filtering adapts to texel shape for better quality at oblique angles, compared to trilinear's isotropic blending.

- Repository: [Academy Software Foundation/openimageio](https://github.com/academysoftwarefoundation/openimageio)
- Tags: deep-dive
- Published: 2026-02-23

---

**In OpenImageIO, `Tex::MipMode::Trilinear` performs isotropic filtering by blending two mip levels with equal weighting in all directions, while `Tex::MipMode::Aniso` applies anisotropic filtering that adapts sample distribution to the elongated shape of the texel footprint, providing higher quality for oblique viewing angles at the cost of additional texture samples.**

The `Tex::MipMode` enum in the Academy Software Foundation's OpenImageIO library defines how the texture system samples mip-mapped images. Located in [`src/include/OpenImageIO/texture.h`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/include/OpenImageIO/texture.h) at lines 108-113, this enum includes both `Trilinear` and `Aniso` modes for developers who need to balance rendering quality against performance. Understanding the distinction between these filtering strategies is essential for optimizing texture lookups in production rendering pipelines.

## MipMode Enum Definition

According to the source code in [`src/include/OpenImageIO/texture.h`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/include/OpenImageIO/texture.h), the `MipMode` enum defines the available mip-mapping strategies:

```cpp
enum class MipMode : uint8_t {
    Default,    ///< Default high-quality lookup (same as Aniso)
    NoMIP,      ///< Use only the highest-resolution image
    OneLevel,   ///< Use a single mip level
    Trilinear,  ///< Use two mip levels and linearly blend between them
    Aniso       ///< Use two mip levels with anisotropic filtering
};

```

Both **Trilinear** and **Aniso** select two adjacent mip-map levels and interpolate between them. The critical distinction lies in how the texel footprint is filtered within those levels.

## Key Differences Between Trilinear and Aniso

### Filtering Direction and Footprint Handling

**Trilinear** applies **isotropic** filtering, meaning the same filter size is applied equally in both *u* and *v* directions. This creates a uniform sampling pattern regardless of the texture's orientation on screen.

**Aniso** implements **anisotropic** filtering that adapts to the shape of the projected texel footprint. When a surface is viewed at a grazing angle, the texture footprint becomes elongated. The Aniso mode detects this elongation and applies a longer filter along the dominant axis while maintaining tighter sampling across the narrow axis.

### Visual Quality and Sampling Characteristics

**Trilinear** provides good quality for surfaces facing the camera directly or with moderate texture slopes. However, it may produce visible blur or aliasing when textures are viewed at steep angles or contain high-frequency detail, as the isotropic filter cannot distinguish between the stretched and compressed directions of the footprint.

**Aniso** delivers higher quality for oblique views or stretched textures by taking more samples along the elongated direction. This reduces blur and aliasing on surfaces like ground planes, hair, or architectural elements viewed at grazing angles. The default **anisotropic ratio** is set to **32**, though this can be configured via `TextureOpt::anisotropic`.

### Performance Characteristics

**Trilinear** is faster because it samples a fixed 2×2 (or 4×4 depending on batch width) set of texels per mip level. The predictable memory access pattern and constant sample count make it ideal for performance-critical applications like UI thumbnails or distant geometry.

**Aniso** incurs additional overhead because the number of samples scales with the **anisotropic ratio** and the aspect ratio of the footprint. According to the implementation in [`src/libtexture/texturesys.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/libtexture/texturesys.cpp) at lines 3397-3401, the sample count is determined by `round_to_multiple_of_pow2(2 * options.anisotropic, 4)`. This leads to more texel fetches and increased computation, though the visual improvement often justifies the cost for primary surfaces.

## Implementation Details in OpenImageIO

The architectural distinction between these modes is implemented in [`src/libtexture/texturesys.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/libtexture/texturesys.cpp). While **Aniso** internally calls the same sampling engine as Trilinear, it adds an **anisotropic weighting step** that modifies how samples are distributed across the footprint.

The function `anisotropic_aspect` computes the stretch of the texture footprint, determining how elongated the sampling pattern should be. This calculation directly influences the number of samples taken along the major axis, ensuring that high-frequency detail is preserved even when the texture is stretched across many pixels.

## Practical Code Examples

### C++ Texture System Usage

When using the OpenImageIO C++ API, you configure the mip mode through the `TextureOpt` structure before calling the texture lookup:

```cpp
#include <OpenImageIO/texture.h>

using namespace OIIO;

void demo_trilinear(TextureSystem* ts, const std::string& filename)
{
    TextureOpt opt;
    opt.mipmode = Tex::MipMode::Trilinear;   // two-level linear blend
    // optional: set filter width, wrap mode, etc.
    float result[3];
    bool ok = ts->texture(filename, /*s*/0.5f, /*t*/0.5f,
                           result, 3, TypeDesc::FLOAT, opt);
    // result now holds the filtered RGB values
}
    
void demo_aniso(TextureSystem* ts, const std::string& filename)
{
    TextureOpt opt;
    opt.mipmode = Tex::MipMode::Aniso;       // anisotropic filtering
    opt.anisotropic = 16;                    // request up to 16× anisotropy
    float result[3];
    bool ok = ts->texture(filename, /*s*/0.5f, /*t*/0.5f,
                           result, 3, TypeDesc::FLOAT, opt);
    // Higher-quality result for steep viewing angles
}

```

### Python API Usage

The Python bindings expose the same functionality through the `TextureOpt` class:

```python
import OpenImageIO as oiio

ts = oiio.TextureSystem()
opt = oiio.TextureOpt()
opt.mipmode = "Trilinear"      # or "Aniso"

opt.anisotropic = 8           # only matters for Aniso mode

pixel = ts.texture("myTex.exr", 0.5, 0.5, opt)
print("Filtered color:", pixel)

```

## Summary

- **Tex::MipMode::Trilinear** provides fast, isotropic filtering by blending two mip levels with uniform sampling in all directions, ideal for UI elements and distant geometry where performance is critical.
- **Tex::MipMode::Aniso** delivers higher visual fidelity through anisotropic filtering that adapts to elongated texel footprints, making it essential for ground planes, hair, and architectural surfaces viewed at grazing angles.
- Both modes are defined in [`src/include/OpenImageIO/texture.h`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/include/OpenImageIO/texture.h) and implemented in [`src/libtexture/texturesys.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/libtexture/texturesys.cpp), with Aniso using the `anisotropic_aspect` function to determine sample distribution based on the `anisotropic` option (default 32).
- Aniso incurs higher computational cost because the number of samples scales with the anisotropic ratio using the formula `round_to_multiple_of_pow2(2 * options.anisotropic, 4)`.

## Frequently Asked Questions

### When should I use Trilinear instead of Aniso?

Use **Trilinear** when rendering distant geometry, UI thumbnails, or any surface where the texture is viewed roughly face-on and performance is a higher priority than marginal quality gains. Trilinear requires fewer texture samples per lookup, making it faster for scenes with heavy overdraw or limited memory bandwidth.

### How does the anisotropic ratio affect rendering quality?

The **anisotropic ratio** (controlled via `TextureOpt::anisotropic`) determines the maximum elongation factor the filter will handle. Higher values allow the sampler to take more samples along stretched footprints, reducing blur on surfaces viewed at extreme grazing angles. The default value of **32** provides high quality for most production scenarios, though values up to 16 or 64 are common depending on the renderer's performance constraints.

### Can I change the mip mode at runtime?

Yes, the **mip mode** is specified per texture lookup through the `TextureOpt` structure passed to `TextureSystem::texture()`. This allows different objects or materials in the same scene to use different filtering strategies. For example, background elements might use `Trilinear` while foreground hero assets use `Aniso`, optimizing the trade-off between quality and performance on a per-lookup basis.

### Where is the anisotropic filtering logic implemented?

The anisotropic filtering calculations are implemented in **[`src/libtexture/texturesys.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/libtexture/texturesys.cpp)** around lines 3397-3401. This code calls the `anisotropic_aspect` function to compute the footprint stretch and determines the sample count using `round_to_multiple_of_pow2(2 * options.anisotropic, 4)`. The actual texel fetching reuses the same infrastructure as trilinear filtering but distributes samples anisotropically based on these calculations.