:: BASIC_02_mint_circle_growing

BamgasiJM·2025년 8월 31일

Nannou <BASIC>

목록 보기
15/41
post-thumbnail

📝 Rust Code - Animation

use nannou::prelude::*;

fn main() {
    nannou::app(model).update(update).simple_window(view).size(1000, 500).run();
}

struct Model;

fn model(_app: &App) -> Model {
    Model
}

fn update(_app: &App, _model: &mut Model, _update: Update) {
}

fn ease_in_out(t: f32) -> f32 {
    3.0 * t.powi(2) - 2.0 * t.powi(3)       
}

fn view(app: &App, _model: &Model, frame: Frame) {
    let draw = app.draw();

    draw.background().color(rgba(0.0, 0.0, 0.0, 1.0));
    
    let color = rgb(0.0, 1.0, 0.8);
    let base_radius = 100.0;

    let delay_per_circle = 5.0 / 60.0;

    for (i,x) in [200.0, 400.0, 600.0, 800.0].iter().enumerate() {
        let t = app.time - (i as f32) * delay_per_circle;
        let cycle = t.rem_euclid(4.0) / 4.0;
        let raw = if cycle < 0.5 {
            cycle * 2.0
        } else {
            (1.0 - cycle) * 2.0
        };
        
        let eased = ease_in_out(raw);
        let radius = base_radius * eased;

        draw.ellipse()
            .x_y(x - 500.0, 0.0)
            .radius(radius)
            .color(color);
    }
    draw.to_frame(app, &frame).unwrap();
}

코드 설명

1.

use nannou::prelude::*
  • Rust 문법: use 키워드는 모듈이나 아이템을 현재 스코프로 가져옵니다.
  • nannou: nannou::prelude::*는 nannou에서 자주 쓰이는 타입, 함수, 트레이트 등을 한 번에 가져오는 "사전 설정된 모듈 집합"입니다. 예: App, Draw,Color, Rect, Point2 등이 포함됩니다.
  • 의미: 이 한 줄로 nannou의 핵심 기능들을 간편하게 사용할 수 있게 됩니다.

2.

fn main() {
	nannou::app(Model)
    	.update(update)
        .simple_window(view)
        .size(1000,500)
        .run();
}
  • Rust 문법: fn main()은 프로그램의 진입점입니다.
  • nannou: nannou::app()은 nannou 애플리케이션을 생성하는 시작점입니다. 이후 메서드 체이닝을 통해 앱의 동작을 구성합니다.
    • app(Model): 초기 상태(Model)를 생성하는 함수를 지정.
    • .update(update): 매 프레임마다 호출되는 업데이트 함수 지정.
    • .simple_window(view): 단일 윈도우를 만들고, 그릴 때 view 함수를 사용하도록 설정.
    • .size(1000, 500): 윈도우 크기를 1000×500 픽셀로 설정.
    • .run(): 앱을 실행 (이벤트 루프 시작).
  • 의미: nannou 앱의 구조를 설정하고 실행합니다.

3.

struct Model;
  • Rust 문법: struct는 사용자 정의 데이터 타입을 정의합니다. 여기서는 유닛 구조체(Unit struct)로, 필드가 없습니다.
  • 의미: 앱의 상태를 저장할 Model이라는 타입을 정의했습니다. 현재는 상태가 없기 때문에 비어 있습니다.

4.

fn model(_app: &App) -> Model {
	Model
  • Rust 문법:
    • fn은 함수 정의.
    • _app: &App: App 타입의 참조를 인자로 받지만, _ 접두사는 "사용하지 않음"을 의미하여 경고를 방지.
    • -> Model: 반환 타입이 Model임을 명시.
  • nannou: model 함수는 앱 시작 시 호출되어 초기 상태를 반환합니다.
  • 의미: Model 인스턴스를 생성하여 초기 상태를 제공합니다. 현재는 상태가 없으므로 단순히 Model을 반환.

5.

fn update(_app: &App, _model: &mut Model, _update: Update) {
    // 상태 변화 없음
}
  • Rust 문법:
    • _app: &App: 앱 정보에 대한 참조 (사용 안 함).
    • _model: &mut Model: 상태 Model에 대한 가변 참조 (수정 가능).
    • _update: Update: Update 이벤트 정보 (시간, 델타 타임 등).
    • _ 접두사는 변수를 사용하지 않음을 나타내며, 컴파일러 경고를 피함.
  • nannou: update 함수는 매 프레임마다 호출되며, 상태를 업데이트하는 데 사용됩니다.
  • 의미: 현재는 아무것도 하지 않음. 상태 변화 없음 → 애니메이션은 view에서 시간 기반으로 처리됨.

6.

// ease-in-out 보간 함수 (smoothstep 스타일)
fn ease_in_out(t: f32) -> f32 {
    // t는 [0.0, 1.0] 범위
    3.0 * t.powi(2) - 2.0 * t.powi(3)
}
  • Rust 문법:
    • fn ease_in_out(...) -> f32: f32 타입의 실수를 받아 f32를 반환하는 함수.
    • t.powi(2): t의 제곱 (정수 지수 제곱, powi = power integer).
  • 수학: 이 함수는 smoothstep 함수와 동일한 형태입니다. 입력이 0→1일 때, 출력이 천천히 시작하고 천천히 끝나는 S자 곡선을 만듭니다.
  • 의미: 애니메이션의 움직임을 부드럽게 만들기 위한 이징(easing) 함수.

7.

fn view(app: &App, _model: &Model, frame: Frame) {
  • Rust 문법:
    • app: &App: 앱 정보 참조 (시간, 윈도우 크기 등 접근 가능).
    • _model: &Model: 현재 상태 참조 (읽기 전용).
    • frame: Frame: 현재 프레임 버퍼 (그릴 대상).
  • nannou: view 함수는 매 프레임마다 화면을 그리는 데 사용됩니다.
  • 의미: 시각적 출력을 정의하는 함수.

8.

	let draw = app.draw();
  • nannou: app.draw()Draw 객체를 생성합니다. 이 객체로 도형, 텍스트 등을 그릴 수 있습니다.
  • 의미: 그리기 명령을 모아서 나중에 프레임에 렌더링할 준비를 합니다.

9.

	draw.background().color(BLACK);
  • nannou:
    • draw.background()는 배경 설정.
    • .color(BLACK)으로 검은색 배경을 지정.
    • BLACK은 nannou에서 정의된 상수 색상.
  • 의미: 화면 전체를 검은색으로 채워 이전 프레임을 지우고 깔끔한 시작.

10.

	let mint = rgb(0.0, 1.0, 0.8);
  • Rust/nannou:
    • let mint: 불변 변수 mint 선언.
    • rgb(r, g, b): nannou의 prelude에서 제공하는 함수로, RGB 색상을 생성 (값은 0.0~1.0 사이).
  • 의미: 밝은 청록색(민트색)을 정의합니다.

11.

    let base_radius = 100.0;
    let y = 0.0;
  • Rust: let으로 두 개의 f32 타입 변수를 정의 (Rust는 타입 추론).
  • 의미:
    • base_radius: 원의 기본 반지름.
    • y = 0.0: 모든 원이 같은 y축 위치(가로 기준 중앙)에 있도록 함.

12.

    // 5프레임 지연 (60fps 기준 → 약 0.083초)
    let delay_per_circle = 5.0 / 60.0;
  • 의미: 각 원이 다음 원보다 5프레임 늦게 애니메이션을 시작하도록 지연 시간을 계산.
  • 수학: 60fps 기준 5프레임 = 5/60 ≈ 0.083초.
  • 단위: 초 단위의 지연 시간.

13.

	for (i, x) in [200.0, 400.0, 600.0, 800.0].iter().enumerate() {
  • Rust 문법:
    • [200.0, ...]: 고정 배열.
    • .iter(): 배열의 반복자 생성 (각 원소를 참조).
    • .enumerate(): 인덱스 i와 값 x를 쌍으로 제공.
  • 의미: 네 개의 x 위치에서 각각 원을 그리며, 인덱스 i로 지연 시간을 조절.

14.

        let t = app.time - i as f32 * delay_per_circle;
  • Rust:
    • i as f32: 정수 i를 실수로 변환.
    • * delay_per_circle: i번째 원의 지연 시간 계산.
  • nannou: app.time은 앱이 시작된 후 흐른 시간(초 단위, f32).
  • 의미: 각 원은 i에 따라 점점 더 늦게 애니메이션 시작.

15.

        // 주기 4초 (0~1 구간으로 정규화)
        let cycle = (t.rem_euclid(4.0)) / 4.0;
  • Rust:
    • .rem_euclid(4.0): 양수 나머지 연산 (음수도 처리). 주기를 4초로 반복.
    • / 4.0: 결과를 0.0~1.0 범위로 정규화.
  • 의미: 시간 t를 4초 주기의 0~1 사이 값으로 변환.

16.

        // 0→1→0 삼각파 생성
        let raw = if cycle < 0.5 {
            cycle * 2.0 // 0 ~ 1
        } else {
            (1.0 - cycle) * 2.0 // 1 ~ 0
        };
  • Rust: if 표현식은 값을 반환하므로 let에 바로 할당 가능.
  • 수학: 삼각파(triangle wave) 생성.
    • cycle < 0.5: 0→1로 증가.
    • cycle >= 0.5: 1→0으로 감소.
  • 결과: raw는 0→1→0을 반복하는 값.

17.

        // easing 적용
        let eased = ease_in_out(raw);
  • 의미: 직선적인 삼각파에 ease_in_out 함수를 적용해 부드러운 곡선으로 변형.
  • 결과: 원의 크기가 더 자연스럽게 커졌다가 작아짐.

18.

        let radius = base_radius * eased;
  • 의미: 기본 반지름에 이징된 값을 곱해 현재 반지름을 계산.

19.

        draw.ellipse()
            .x_y(x - 500.0, y)
            .radius(radius)
            .color(mint);
  • nannou:
    • draw.ellipse(): 원(타원) 그리기 명령 시작.
    • .x_y(x - 500.0, y): 위치 설정. x는 원래 좌표지만, x - 500.0은 좌표계를 중앙 기준으로 조정하기 위함.
      • nannou의 기본 좌표계는 윈도우 중심이 (0,0) 이므로, 원래 x=200은 왼쪽에 있으므로 200 - 500 = -300으로 왼쪽으로 이동.
    • .radius(radius): 반지름 설정.
    • .color(mint): 색상 적용.
  • 의미: 현재 프레임에 원을 그릴 명령을 추가 (아직 렌더링되지 않음).

20.

    draw.to_frame(app, &frame).unwrap();
  • nannou:
    • draw.to_frame(...): 지금까지 쌓은 그리기 명령을 실제 프레임 버퍼에 렌더링.
    • &frame: 현재 프레임 (렌더 타겟).
    • .unwrap(): 결과가 Result이므로 성공 시 값을 가져오고, 실패 시 패닉 (간단한 예제에서는 허용).
  • 의미: 화면에 그림을 출력.

📝 Rust Code - 민트 원을 네 개 배치

use nannou::prelude::*;

fn main() {
    nannou::app(model).simple_window(view).size(1000, 500).run();
}

struct Model;

fn model(_app: &App) -> Model {
    Model
}

fn view(app: &App, _model: &Model, frame: Frame) {
    let draw = app.draw();

    // 배경색: 블랙
    draw.background().color(BLACK);

    // 민트색 정의
    let mint = rgb(0.0, 1.0, 0.8);

    // 반지름 200인 원을 네 개 배치
    let radius = 100.0;
    let y = 0.0;
    for x in [200.0, 400.0, 600.0, 800.0] {
        draw.ellipse()
            .x_y(x - 500.0, y) // nannou 좌표는 (0,0)이 화면 중앙
            .radius(radius)
            .color(mint);
    }

    draw.to_frame(app, &frame).unwrap();
}

profile
Coding Art with Blender / oF / Processing / p5.js / nannou

0개의 댓글