Skip to content

[Feature] Add anisotropic filtering controls to SamplerBuilder #103

@vmarcella

Description

@vmarcella

Overview

Samplers do not expose anisotropy controls, preventing users from enabling anisotropic filtering for improved texture quality at oblique viewing angles. Anisotropic filtering is a quality/performance tradeoff that should be configurable by the user.

Current State

SamplerBuilder` lacks any anisotropy configuration:

// crates/lambda-rs-platform/src/wgpu/texture.rs
pub struct SamplerBuilder {
  label: Option<String>,
  min_filter: FilterMode,
  mag_filter: FilterMode,
  mipmap_filter: FilterMode,
  address_u: AddressMode,
  address_v: AddressMode,
  address_w: AddressMode,
  lod_min: f32,
  lod_max: f32,
  // No anisotropy_clamp field
}

impl SamplerBuilder {
  pub fn new() -> Self {
    return Self {
      label: None,
      min_filter: FilterMode::Nearest,
      mag_filter: FilterMode::Nearest,
      mipmap_filter: FilterMode::Nearest,
      address_u: AddressMode::ClampToEdge,
      address_v: AddressMode::ClampToEdge,
      address_w: AddressMode::ClampToEdge,
      lod_min: 0.0,
      lod_max: 32.0,
      // anisotropy_clamp not set
    };
  }
  // ... no with_anisotropy method ...
}

The wgpu::SamplerDescriptor supports anisotropy_clamp for enabling anisotropic filtering, but this is not exposed through the platform abstraction.

Scope

Goals:

  • Add with_anisotropy_clamp(u16) to SamplerBuilder
  • Plumb the value to wgpu::SamplerDescriptor::anisotropy_clamp
  • Document the quality/performance tradeoffs
  • Validate that the clamp value is within device limits

Non-Goals:

  • Automatic anisotropy level selection based on quality presets
  • Per-texture anisotropy override (handled at sampler level)

Proposed API

// In crates/lambda-rs-platform/src/wgpu/texture.rs
pub struct SamplerBuilder {
  label: Option<String>,
  min_filter: FilterMode,
  mag_filter: FilterMode,
  mipmap_filter: FilterMode,
  address_u: AddressMode,
  address_v: AddressMode,
  address_w: AddressMode,
  lod_min: f32,
  lod_max: f32,
  anisotropy_clamp: u16,  // New field, default 1 (disabled)
}

impl SamplerBuilder {
  /// Set the maximum anisotropic filtering level.
  ///
  /// Valid values are 1 (disabled) through 16. Values outside this range
  /// will be clamped. Higher values improve texture quality at oblique
  /// viewing angles but increase GPU cost.
  ///
  /// Common values:
  /// - 1: Disabled (default)
  /// - 4: Good balance of quality and performance
  /// - 8: High quality
  /// - 16: Maximum quality
  ///
  /// Note: Anisotropic filtering is most effective with linear filtering
  /// and mipmapped textures.
  pub fn with_anisotropy_clamp(mut self, clamp: u16) -> Self {
    self.anisotropy_clamp = clamp.clamp(1, 16);
    return self;
  }
}

Example Usage:

// High-quality sampler for floor/wall textures viewed at angles
let aniso_sampler = SamplerBuilder::new()
  .linear_clamp()
  .with_mip_filter(FilterMode::Linear)
  .with_anisotropy_clamp(8)
  .build(&gpu);

// Default sampler (no anisotropy) for UI textures
let ui_sampler = SamplerBuilder::new()
  .linear_clamp()
  .build(&gpu);

Acceptance Criteria

  • SamplerBuilder has anisotropy_clamp: u16 field defaulting to 1
  • with_anisotropy_clamp(u16) method added
  • Value clamped to valid range (1-16)
  • build() passes anisotropy_clamp to wgpu::SamplerDescriptor
  • Documentation explains anisotropy quality/performance tradeoffs
  • Example updated to demonstrate anisotropic filtering
  • Unit test verifying builder correctly sets anisotropy

Affected Crates

lambda-rs-platform

Notes

  • Anisotropic filtering requires linear filtering to be effective
  • Maximum supported anisotropy varies by GPU (most support 16)
  • Consider a quality preset API in future (e.g., SamplerPreset::HighQuality)
  • Device limits can be queried via wgpu::Limits::max_sampler_anisotropy if validation is needed

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions