Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Comments on Strange change of object lightness and colour in Nannou application

Post

Strange change of object lightness and colour in Nannou application

+6
−0

Building a Nannou App from their template. I want a circle to slowly fade in color and randomly change color when hitting the boundary of the window. But there is something strange going on when updating the colors.

My preamble looks like this:

use nannou::prelude::*;
use rand::Rng;

The model consists of a circle and a boundary.

struct Model {
     // so this is a window id called _window -- I guess.
     _window: window::Id,
    circle: Circle,
    boundary: Boundary,
}

The boundary is just the outline of the application window and the circle has a diameter, position, velocity and color.

struct Boundary {
    x_min: f32,
    x_max: f32,
    y_min: f32,
    y_max: f32,
}
struct Circle {
    d: f32, // diameter
    center: Point2,
    vel: Point2, 
    color: Hsl, 
}

Here is my model function:

fn model(app: &App) -> Model {
    let _window = app.new_window().size(512, 512).view(view).build().unwrap();
    // add the coordinates to a struct and add it to the model
    let circle = Circle {
        d: 50.0,
        center: pt2(-50.0, 167.0),
        vel: pt2(1.3, -0.9),
        color: hsl(154.1, 100.0, 85.0),
    };
    let boundary = Boundary {
        x_min: app.window_rect().x.start,
        x_max: app.window_rect().x.end,
        y_min: app.window_rect().y.start,
        y_max: app.window_rect().y.end,
    };
    Model {
        _window,
        circle,
        boundary,
    }
}

I want three things to happen:

  • The circle to bounce off of the boundary. (This works)
  • The lightness of the color of the circle to slowly reduce at every time step.(Not Working)
  • The color of the circle to randomly change whenever the circle hits the wall(seems to work for a split second)

This is how I update the model:

fn update(_app: &App, _model: &mut Model, _update: Update) {
    // move circle by velocity
    _model.circle.center.x += _model.circle.vel.x;
    _model.circle.center.y += _model.circle.vel.y;
    // update color
    _model.circle.update_color();
    // bounce of the wall
    _model.circle.bounce_wall(&_model.boundary);
}

I created the update_color and bounce_wall functions for my Circle:

impl Circle {
    fn update_color(&mut self) {
        let mut newlight = self.color.lightness - 0.1;
        if newlight < 0.0 {
            newlight = 0.0;
        }
        self.color = hsl(
            self.color.hue.to_positive_degrees(),
            self.color.saturation,
            newlight,
        );
    }
    fn bounce_wall(&mut self, boundary: &Boundary) {
        // all the random number stuff is stolen from
        // https://rust-lang-nursery.github.io/rust-cookbook/algorithms/randomness.html
        let mut rng = rand::thread_rng(); // rng = random number generator
        if self.center.x + 0.5 * self.d > boundary.x_max
            || self.center.x - 0.5 * self.d < boundary.x_min
        {
            self.color = hsl(rng.gen_range(0.0..360.0), rng.gen_range(0.0..100.0), 85.0);
            self.vel.x = -self.vel.x;
        }
        if self.center.y + 0.5 * self.d > boundary.y_max
            || self.center.y - 0.5 * self.d < boundary.y_min
        {
            self.color = hsl(rng.gen_range(0.0..360.0), rng.gen_range(0.0..100.0), 85.0);
            self.vel.y = -self.vel.y;
        }
    }
}

My view function looks like this:

fn view(app: &App, _model: &Model, frame: Frame) {
    let draw = app.draw();
    draw.background().color(GRAY);
    println!(
        "new color lightness is ({})",
        _model.circle.color.into_components().2
    );
    let ellipse = draw.ellipse();
    ellipse
        .color(_model.circle.color)
        .x_y(_model.circle.center.x, _model.circle.center.y)
        .w(_model.circle.d)
        .h(_model.circle.d);
    draw.to_frame(app, &frame).unwrap();
}

Here is what is happening that I do not understand:

  • The lightness of the circle that the view function prints to the command line does go down but the color of the circle does not change at all. Why?
  • When bouncing of a wall, the color of the circle visibly changes for a very brief moment to some random color but then goes back to the initial color. So it works but is reset somehow?
  • When I remove the random color changing from the bounce_wall() function, the color of the circle switches to black once lightness reaches 0. So only changing the color to black is permanent?

Edit: Thanks to comments by elgonzo the solution was quite easy.

hsl expects the first component (hue) to be in [0.0, 1.0] instead of [0.0, 360.0] and the third components (lightness) to be in [0.0, 1.0] instead of [0.0, 100.0].

So providing a lightness value that is slowly reducing from 1.0 is creating the effect I wanted.

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.
Why should this post be closed?

3 comment threads

Please post the answer as an answer (1 comment)
Post title (1 comment)
HSL values in range? (5 comments)
HSL values in range?
elgonzo‭ wrote over 3 years ago · edited over 3 years ago

I have no experience in Nannou. But the doc for the hsl(h, s, l) function (https://docs.rs/nannou/0.17.1/nannou/color/struct.Hsl.html) states that the s and l parameter values should be in the 0.0 to 1.0 range. You are using values that are far larger than the expected max. value of 1.0. (1/2)

elgonzo‭ wrote over 3 years ago · edited over 3 years ago

(2/2) If my (untested) belief is correct, then perhaps setting the values for s and l above the maximum value of 1.0 might still be accepted and stored by the hsl(h,s,l) function, but the out-of-range values might be clamped internally by the Nannou drawing functions to the actual allowed maximum value of 1.0. So, it could be the case that you count down the l value from 100 to 99.9, 99.8, etc... while the drawing routine always clamps it down to 1.0.

elgonzo‭ wrote over 3 years ago · edited over 3 years ago

Again, i want to emphasize: My musings are just based on my belief -- or gut feeling, if you will. I don't have any experience with Nannou, so i might very well just talk bollocks... ;)

Skipping 1 deleted comment.

telefza‭ wrote over 3 years ago

I think you are correct. setting l above 1.0 ends up being just 1.0 in the hsl function. The transition from 1.0 (full lightness) to 0.0 (black) was too quick for me to see in the app. Slowly stepping between 1.0 and 0.0 creates the intended darkening of the circle. Thanks.

elgonzo‭ wrote over 3 years ago · edited over 3 years ago

By the way, you can self-answer your own question, if you like. I mean, in the form of an answer, and not as an edit to the question :-) If i had any prior experience with Nannou, i would answer myself, but due to my complete lack of knowledge about Nannou i fear i might accidentally slip in some unintentional untruth(s) about the workings of Nannou :-(