Early days: oxframe is under very active development. The API is not stable yet and may change from version to version. Pin the exact version in your Cargo.toml and check the changelog before upgrading.

13. Shaders and effects

Water, a wet lens, rings and a rising sea: presets that paint pixels, animated like any other property.

Loading live preview…

Source of learn_13_shaders — edit in the playground
//! Lesson 13 — Shaders and effects.
//!
//! Presets paint pixels with a shader: water as a node, drops on the lens
//! over everything drawn before them, rings on a node, and water rising
//! into the next scene. Their parameters are signals, so you animate them
//! like any other property.

use oxframe::prelude::*;

#[oxframe::scene]
pub async fn sea(view: View) {
    let water = view.add(
        shaders::waves()
            .deep(Accent)
            .foam(Surface)
            .width(pct(100))
            .height(pct(40))
            .to_edge(Edge::Bottom),
    );
    let title = view.add(Txt::new().text("Shaders").display().to_edge(Edge::Top));
    // Added last: it bends everything drawn before it.
    let lens = view.add(shaders::lens_drops().wetness(0.0).fullscreen());

    title.fade_in().await;
    water.amp().to(0.12, 1.0).await;

    // An effect changes one node's own pixels.
    let rings = water.effect(shaders::ripple().strength(0.0));
    rings.strength().to(1.0, 0.4).await;
    rings.strength().to(0.0, 0.8).await;

    lens.wetness().to(1.0, 0.5).await;
    wait_for(0.4).await;
}

#[oxframe::scene]
pub async fn land(view: View) {
    // Added before the transition, so the rising water uncovers it.
    view.add(Txt::new().text("Dry land").display());
    transition(Transition::shader(shaders::water_wipe())).await;
    wait_for(0.6).await;
}

// Try: `.wetness(0.3)` for a light drizzle, or `water_wipe().wave(0.1)`.

pub fn project() -> Project {
    Project::new("shaders").scene(sea()).scene(land())
}

A shader is a node

shaders::waves() paints water inside its box. Place it like a rectangle, with .width(pct(100)), .height(..) and .to_edge(Edge::Bottom). .amp() is the wave height, and it is a signal: water.amp().to(0.12, 1.0) makes the sea grow. .deep(Accent) takes its color from the theme.

Shaders that read the picture

shaders::lens_drops() puts drops on the lens over everything drawn before it, so add it last and make it .fullscreen(). Start dry with .wetness(0.0); a splash is lens.wetness().to(1.0, 0.5).

node.effect(shaders::ripple()) changes one node's own pixels: rings spread from its center. It returns a handle whose .strength() you animate. The colors move and the outline stays, so use it on water, text or an image.

Transition::shader(shaders::water_wipe()) is a transition from lesson 11 painted by a shader: water rises over the frame and the next scene is under it.

Make events signals

A splash at two seconds is a signal change at that moment, not a formula of time. That way the editor shows it on the timeline and oxframe check sees it. A shader can only read finished pixels: inside a fading group or a blur, check reports input_cycle. Rendering video has the details.

Next

Lesson 14 plots functions and data on axes that follow animated ranges.