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
- Sort points by x before calling `from_points` and drop exact duplicates
- If cubic interpolation still overshoots backwards between near-equal x values, use denser/more evenly spaced x samples
- 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
- Normalize all curve data through a sort+dedupe step before conversion
- Avoid near-equal x values that make cubic interpolation overshoot backwards
- Reject non-finite x/y values at import time
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
- curve could not be constructed from the given data
- discontinuity found between curve segments
- Unable to generate cubic curve: at least one set of control
- Not enough data to build curve: needed at least {expected} c
- Could not construct an EvenCore
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/f33c0c0708b077cf.
Report an issue: GitHub.