bevyengine/bevy · error · AutoExposureCompensationCurveError

curve is not monotonically increasing on the x-axis

Error message

curve is not monotonically increasing on the x-axis

What it means

While sampling the cubic curve into the compensation LUT, `from_curve` requires the log-luminance axis to be non-decreasing: any sample with `current.x < previous.x` (crates/bevy_post_process/src/auto_exposure/compensation_curve.rs:127) returns `AutoExposureCompensationCurveError::NotMonotonic`. The LUT maps log luminance linearly onto its 256 entries, so a curve that doubles back on x cannot be encoded.

Source

Thrown at crates/bevy_post_process/src/auto_exposure/compensation_curve.rs:52

    /// * `255` maps to `max_compensation`
    ///
    /// The position in the LUT corresponds to the normalized log luminance value.
    /// * `0` maps to `min_log_lum`
    /// * `LUT_SIZE - 1` maps to `max_log_lum`
    lut: [u8; LUT_SIZE],
}

/// Various errors that can occur when constructing an [`AutoExposureCompensationCurve`].
#[derive(Error, Debug)]
pub enum AutoExposureCompensationCurveError {
    /// The curve couldn't be built in the first place.
    #[error("curve could not be constructed from the given data")]
    InvalidCurve,
    /// A discontinuity was found in the curve.
    #[error("discontinuity found between curve segments")]
    DiscontinuityFound,
    /// The curve is not monotonically increasing on the x-axis.
    #[error("curve is not monotonically increasing on the x-axis")]
    NotMonotonic,
}

impl Default for AutoExposureCompensationCurve {
    fn default() -> Self {
        Self {
            min_log_lum: 0.0,
            max_log_lum: 0.0,
            min_compensation: 0.0,
            max_compensation: 0.0,
            lut: [0; LUT_SIZE],
        }
    }
}

impl AutoExposureCompensationCurve {
    const SAMPLES_PER_SEGMENT: usize = 64;

View on GitHub (pinned to 396ca72708)

Solutions

  1. Sort points by x before calling `from_points` and drop exact duplicates
  2. If cubic interpolation still overshoots backwards between near-equal x values, use denser/more evenly spaced x samples
  3. Validate monotonicity of the built curve before registering the asset

Example fix

// before: unsorted x -> NotMonotonic
let pts = [vec2(2.0, 0.5), vec2(-4.0, -2.0), vec2(0.0, 0.0)];

// after: sort by x, remove duplicates
let mut pts: Vec<Vec2> = raw_points.to_vec();
pts.sort_by(|a, b| a.x.partial_cmp(&b.x).unwrap());
pts.dedup_by(|a, b| a.x == b.x);
let curve = AutoExposureCompensationCurve::from_points(pts)?;
Defensive patterns

Strategy: validation

Validate before calling

let mut pts: Vec<Vec2> = raw.to_vec();
pts.sort_by(|a, b| a.x.partial_cmp(&b.x).unwrap());
pts.dedup_by(|a, b| a.x == b.x);
let curve = AutoExposureCompensationCurve::from_points(pts)?;

Try / catch

match AutoExposureCompensationCurve::from_points(pts) {
    Err(AutoExposureCompensationCurveError::NotMonotonic) => {
        warn!("compensation curve x-axis not monotonic; sorting input");
        pts.sort_by(|a, b| a.x.partial_cmp(&b.x).unwrap());
        AutoExposureCompensationCurve::from_points(pts)?
    }
    other => other?,
}

Prevention

When it happens

Trigger: `from_points` with x values out of order, duplicated x values producing local decreases after spline interpolation, or control points that make the cubic overshoot backwards on x even when the raw points are sorted.

Common situations: Artist data pasted in arbitrary order; duplicated rows in a CSV of curve points; spline interpolation overshooting between close x values.

Related errors


AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20). Data as JSON: /api/errors/f33c0c0708b077cf. Report an issue: GitHub.