124 lines
5.6 KiB
Rust
124 lines
5.6 KiB
Rust
//! GPU time effects (Time Difference, Time Displacement, CC Force Motion Blur, CC Wide Time,
|
|
//! Pixel Motion Blur, Timewarp) vs the CPU effects (the oracle). They fetch other frames through
|
|
//! the effect host: a precomp whose content moves, at a nonzero time, composited at 8 and
|
|
//! 32 bpc (the direct cases have no host and pass the layer through).
|
|
|
|
use effectcraft_color::Label;
|
|
use effectcraft_keyframe::{Keyframe, Value};
|
|
use effectcraft_project::{BitDepth, Comp, ItemKind, LayerSource, build};
|
|
use effectcraft_render::RenderOpts;
|
|
use effectcraft_time::{FrameRate, Tick};
|
|
|
|
use crate::tests::{Scene, check, compare_at, effect_case, n, opts, set, v3};
|
|
|
|
fn e(v: u32) -> Value {
|
|
Value::Enum(v)
|
|
}
|
|
|
|
fn on() -> Value {
|
|
Value::Bool(true)
|
|
}
|
|
|
|
/// `id` with `vals` on a moving precomp; `map` adds a hidden footage layer and sets parameter
|
|
/// `map` to it.
|
|
fn moving(id: &str, vals: &[(&str, Value)], map: Option<&str>) {
|
|
for depth in [BitDepth::Bpc8, BitDepth::Bpc32] {
|
|
let mut s = Scene::new(depth);
|
|
let bg = s.solid([0.15, 0.1, 0.2], 97, 61);
|
|
s.push(bg);
|
|
let mut vals = vals.to_vec();
|
|
if let Some(param) = map {
|
|
let mut m = s.footage(50, 36);
|
|
m.switches.video = false;
|
|
let mid = s.push(m);
|
|
vals.push((param, Value::Layer(Some(mid.0))));
|
|
}
|
|
let inner = Comp::new(60, 40, FrameRate::FPS_30, Tick::from_seconds_f64(2.0));
|
|
let inner_id = s.p.add_item("Inner", Label::Sandstone, None, ItemKind::Comp(inner.into()));
|
|
let mut a = s.footage(30, 24);
|
|
let pos = a.props.prop_mut("transform/position").unwrap();
|
|
pos.keys = vec![Keyframe::new(Tick::ZERO, v3(10.0, 12.0)), Keyframe::new(Tick::from_seconds_f64(1.0), v3(50.0, 30.0))];
|
|
let rot = a.props.prop_mut("transform/rotation").unwrap();
|
|
rot.keys = vec![Keyframe::new(Tick::ZERO, Value::Scalar(0.0)), Keyframe::new(Tick::from_seconds_f64(1.0), Value::Scalar(90.0))];
|
|
s.p.comp_mut(inner_id).unwrap().layers = vec![a];
|
|
let mut l = build::layer(&mut s.p, &s.comp, "Inner", LayerSource::Comp { item: inner_id }, (60, 40), None);
|
|
s.effect(&mut l, id, &vals);
|
|
set(&mut l, "transform/rotation", Value::Scalar(8.0));
|
|
s.push(l);
|
|
let t = Tick::from_seconds_f64(0.4);
|
|
let label = format!("{id} {vals:?} {depth:?}");
|
|
check(&label, compare_at(&s, opts(), t), 0.0);
|
|
check(&format!("{label} half"), compare_at(&s, RenderOpts { scale: 0.5, ..opts() }, t), 0.0);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn without_a_host() {
|
|
for id in
|
|
["ec.time.timedifference", "ec.time.timedisplacement", "ec.time.ccforcemotionblur", "ec.time.ccwidetime", "ec.time.pixelmotionblur", "ec.time.timewarp"]
|
|
{
|
|
effect_case(id, &[]);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn frame_averages() {
|
|
moving("ec.time.ccforcemotionblur", &[], None);
|
|
moving("ec.time.ccforcemotionblur", &[("motionBlurLevels", n(5.0)), ("shutterAngle", n(400.0))], None);
|
|
moving("ec.time.ccwidetime", &[], None);
|
|
moving("ec.time.ccwidetime", &[("forwardSteps", n(1.0)), ("backwardSteps", n(4.0))], None);
|
|
moving("ec.time.pixelmotionblur", &[], None);
|
|
moving("ec.time.pixelmotionblur", &[("shutterControl", e(1)), ("shutterAngle", n(300.0)), ("shutterSamples", n(5.0))], None);
|
|
}
|
|
|
|
#[test]
|
|
fn time_difference() {
|
|
moving("ec.time.timedifference", &[("timeOffset", n(-0.1))], None);
|
|
for alpha in 0..9 {
|
|
moving(
|
|
"ec.time.timedifference",
|
|
&[("timeOffset", n(0.2)), ("contrast", n(40.0)), ("absoluteDifference", Value::Bool(alpha % 2 == 0)), ("alphaChannel", e(alpha))],
|
|
None,
|
|
);
|
|
}
|
|
moving("ec.time.timedifference", &[("timeOffset", n(0.1)), ("alphaChannel", e(2))], Some("targetLayer"));
|
|
}
|
|
|
|
#[test]
|
|
fn time_displacement() {
|
|
moving("ec.time.timedisplacement", &[("maxDisplacementTime", n(0.3)), ("timeResolution", n(10.0))], None);
|
|
moving("ec.time.timedisplacement", &[("maxDisplacementTime", n(0.5)), ("timeResolution", n(30.0))], Some("displacementMapLayer"));
|
|
moving("ec.time.timedisplacement", &[("maxDisplacementTime", n(2.0)), ("stretchMap", Value::Bool(false))], Some("displacementMapLayer"));
|
|
}
|
|
|
|
#[test]
|
|
fn timewarp() {
|
|
for method in 0..3 {
|
|
moving("ec.time.timewarp", &[("method", e(method)), ("speed", n(37.0))], None);
|
|
}
|
|
moving("ec.time.timewarp", &[("method", e(1)), ("adjustTimeBy", e(1)), ("sourceFrame", n(7.4))], None);
|
|
moving("ec.time.timewarp", &[("method", e(2)), ("speed", n(43.0)), ("motionBlur/enableMotionBlur", on()), ("motionBlur/shutterSamples", n(3.0))], None);
|
|
moving(
|
|
"ec.time.timewarp",
|
|
&[
|
|
("speed", n(61.0)),
|
|
("tuning/filtering", e(1)),
|
|
("tuning/errorThreshold", n(30.0)),
|
|
("sourceCrops/leftCrop", n(4.0)),
|
|
("sourceCrops/topCrop", n(3.0)),
|
|
],
|
|
None,
|
|
);
|
|
moving("ec.time.timewarp", &[("speed", n(55.0)), ("tuning/buildFromOneImage", on())], None);
|
|
moving("ec.time.timewarp", &[("speed", n(47.0))], Some("warpLayer"));
|
|
// A Matte Layer: every method and Show, the luminance channels, motion blur.
|
|
for method in 0..3 {
|
|
for show in 0..4 {
|
|
moving("ec.time.timewarp", &[("method", e(method)), ("speed", n(47.0)), ("show", e(show))], Some("matteLayer"));
|
|
}
|
|
}
|
|
moving("ec.time.timewarp", &[("speed", n(39.0)), ("matteChannel", e(2))], Some("matteLayer"));
|
|
moving("ec.time.timewarp", &[("speed", n(43.0)), ("matteChannel", e(1)), ("motionBlur/enableMotionBlur", on())], Some("matteLayer"));
|
|
moving("ec.time.timewarp", &[("method", e(1)), ("speed", n(52.0)), ("tuning/buildFromOneImage", on()), ("show", e(1))], Some("matteLayer"));
|
|
}
|