mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-30 13:08:07 -06:00
Test that an Environment light visibly lights the scene (#2436)
End-to-end regression tests for the issue's report, through the real command path (what the Light Settings dialog runs) and the real viewer: adding an Environment light to a Classic 3D comp switches it to Advanced 3D and changes the viewer's pixels — a red light at full intensity, the default white light, and the same on the GPU compositor (skips without an adapter, like ui_gpu).
This commit is contained in:
@@ -20,6 +20,8 @@ mod ui_drag_drop;
|
||||
mod ui_effect_controls;
|
||||
mod ui_effect_drop_highlight;
|
||||
mod ui_effect_names;
|
||||
mod ui_env_light_gpu;
|
||||
mod ui_env_light_repro;
|
||||
mod ui_font_search;
|
||||
mod ui_form_fit;
|
||||
mod ui_frame_step;
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
//! The Environment light through the app's GPU compositor (egui_kittest with wgpu): adding one
|
||||
//! visibly changes the viewer's GPU frames (#2436). Skips without a GPU adapter (CI).
|
||||
|
||||
use effectcraft_engine::Session;
|
||||
use effectcraft_engine::project::Renderer;
|
||||
use effectcraft_ui_egui::EffectcraftApp;
|
||||
use egui_kittest::Harness;
|
||||
use serde_json::json;
|
||||
|
||||
fn settle(h: &mut Harness<'_, EffectcraftApp>) {
|
||||
for _ in 0..600 {
|
||||
h.step();
|
||||
if h.state().frames.inflight() == 0 && h.state().frames.last_ms.lock().map(|v| *v > 0.0).unwrap_or(false) {
|
||||
break;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(20));
|
||||
}
|
||||
for _ in 0..4 {
|
||||
h.step();
|
||||
}
|
||||
}
|
||||
|
||||
/// egui_kittest's wgpu setup on the adapter the headless compositor picked, so the viewer's GPU
|
||||
/// compositor attaches (see ui_gpu.rs).
|
||||
fn same_adapter(name: String) -> eframe::egui_wgpu::WgpuSetup {
|
||||
let mut setup = egui_kittest::wgpu::default_wgpu_setup();
|
||||
if let eframe::egui_wgpu::WgpuSetup::CreateNew(c) = &mut setup {
|
||||
let fallback = c.native_adapter_selector.take();
|
||||
c.native_adapter_selector = Some(std::sync::Arc::new(move |adapters, surface| {
|
||||
let named = |a: &&eframe::wgpu::Adapter| format!("{} ({:?})", a.get_info().name, a.get_info().backend) == name;
|
||||
match (adapters.iter().find(named), &fallback) {
|
||||
(Some(a), _) => Ok(a.clone()),
|
||||
(None, Some(f)) => f(adapters, surface),
|
||||
(None, None) => adapters.first().cloned().ok_or_else(|| "No adapter found".to_owned()),
|
||||
}
|
||||
}));
|
||||
}
|
||||
setup
|
||||
}
|
||||
|
||||
/// A red Environment light at full intensity lights the scene on the GPU compositor too: the
|
||||
/// viewer's GPU frames change when the light is added.
|
||||
#[test]
|
||||
fn environment_light_lights_the_scene_on_the_gpu() {
|
||||
let Some(probe) = effectcraft_gpu::Gpu::headless() else {
|
||||
eprintln!("no GPU adapter: skipping");
|
||||
return;
|
||||
};
|
||||
let adapter = effectcraft_engine::render::Accelerator::name(&probe);
|
||||
eprintln!("headless compositor adapter: {adapter}");
|
||||
let gl = adapter.ends_with("(Gl)");
|
||||
drop(probe);
|
||||
let mut s = Session::default();
|
||||
s.execute("file.openDemoProject", json!({})).unwrap();
|
||||
s.execute("comp.open", json!({"comp": "3D Showcase"})).unwrap();
|
||||
s.execute("time.set", json!({"time": 5.0})).unwrap();
|
||||
s.execute("comp.settings", json!({"renderer": "classic3D"})).unwrap();
|
||||
let mut h = Harness::builder()
|
||||
.with_size(egui::vec2(1400.0, 900.0))
|
||||
.with_pixels_per_point(1.0)
|
||||
.wgpu_setup(same_adapter(adapter))
|
||||
.build_eframe(|_| EffectcraftApp::new(s));
|
||||
settle(&mut h);
|
||||
if gl && h.state().gpu_adapter().is_none() {
|
||||
eprintln!("egui-wgpu's GL device has WebGL2 limits: the viewer stays on the CPU, skipping");
|
||||
return;
|
||||
}
|
||||
assert!(h.state().gpu_adapter().is_some(), "GPU compositor on egui-wgpu's device");
|
||||
let before = h.state_mut().viewer_pixels().expect("GPU frame before adding the light").pixels.clone();
|
||||
|
||||
h.state_mut().session.execute("layer.newLight", json!({"kind": "Environment", "color": [1.0, 0.0, 0.0], "intensity": 100.0})).unwrap();
|
||||
assert_eq!(h.state().session.active_comp().unwrap().renderer, Renderer::Advanced3D);
|
||||
settle(&mut h);
|
||||
let after = h.state_mut().viewer_pixels().expect("GPU frame after adding the light").pixels.clone();
|
||||
|
||||
assert_eq!(before.len(), after.len());
|
||||
let diff = before.iter().zip(&after).filter(|(a, b)| a != b).count();
|
||||
assert!(diff > 500, "a red Environment light at 100 % changed only {diff} GPU pixels");
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//! Reproduction of issue #2436's report: an Environment light added through the real command
|
||||
//! path (what the Light Settings dialog runs) must visibly light the scene in the viewer.
|
||||
|
||||
use effectcraft_engine::Session;
|
||||
use effectcraft_engine::project::Renderer;
|
||||
use effectcraft_ui_egui::EffectcraftApp;
|
||||
use egui_kittest::Harness;
|
||||
use serde_json::json;
|
||||
|
||||
fn app() -> EffectcraftApp {
|
||||
let mut s = Session::default();
|
||||
s.execute("file.openDemoProject", json!({})).unwrap();
|
||||
s.execute("comp.open", json!({"comp": "3D Showcase"})).unwrap();
|
||||
s.execute("time.set", json!({"time": 5.0})).unwrap();
|
||||
EffectcraftApp::new(s)
|
||||
}
|
||||
|
||||
/// Step the UI until background frame renders have landed.
|
||||
fn settle(h: &mut Harness<'_, EffectcraftApp>) {
|
||||
for _ in 0..600 {
|
||||
h.step();
|
||||
if h.state().frames.inflight() == 0 && h.state().frames.last_ms.lock().map(|v| *v > 0.0).unwrap_or(false) {
|
||||
break;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(20));
|
||||
}
|
||||
for _ in 0..4 {
|
||||
h.step();
|
||||
}
|
||||
}
|
||||
|
||||
fn changed_pixels(before: &[egui::Color32], after: &[egui::Color32]) -> usize {
|
||||
before.iter().zip(after).filter(|(a, b)| a != b).count()
|
||||
}
|
||||
|
||||
/// An Environment light (red, full intensity, no source: the flat default environment) added to
|
||||
/// a Classic 3D comp switches it to Advanced 3D and visibly changes the viewer's pixels.
|
||||
#[test]
|
||||
fn environment_light_lights_the_scene() {
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1600.0, 1000.0)).build_eframe(|_| app());
|
||||
h.state_mut().session.execute("comp.settings", json!({"renderer": "classic3D"})).unwrap();
|
||||
h.run_steps(3);
|
||||
settle(&mut h);
|
||||
let before = h.state_mut().viewer_pixels().expect("frame before adding the light").pixels.clone();
|
||||
|
||||
h.state_mut().session.execute("layer.newLight", json!({"kind": "Environment", "color": [1.0, 0.0, 0.0], "intensity": 100.0})).unwrap();
|
||||
|
||||
assert_eq!(h.state().session.active_comp().unwrap().renderer, Renderer::Advanced3D, "the comp switched to Advanced 3D");
|
||||
settle(&mut h);
|
||||
let after = h.state_mut().viewer_pixels().expect("frame after adding the light").pixels.clone();
|
||||
assert_eq!(before.len(), after.len());
|
||||
let diff = changed_pixels(&before, &after);
|
||||
assert!(diff > 500, "a red Environment light at 100 % changed only {diff} pixels");
|
||||
}
|
||||
|
||||
/// The literal action from the issue: default white Environment light, defaults everywhere —
|
||||
/// even then the lighting model changes (Advanced 3D IBL instead of unlit/Classic), so pixels
|
||||
/// must change somewhere in the comp frame.
|
||||
#[test]
|
||||
fn default_environment_light_changes_the_scene() {
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1600.0, 1000.0)).build_eframe(|_| app());
|
||||
h.state_mut().session.execute("comp.settings", json!({"renderer": "classic3D"})).unwrap();
|
||||
h.run_steps(3);
|
||||
settle(&mut h);
|
||||
let before = h.state_mut().viewer_pixels().expect("frame before adding the light").pixels.clone();
|
||||
|
||||
h.state_mut().session.execute("layer.newLight", json!({"kind": "Environment"})).unwrap();
|
||||
|
||||
assert_eq!(h.state().session.active_comp().unwrap().renderer, Renderer::Advanced3D);
|
||||
settle(&mut h);
|
||||
let after = h.state_mut().viewer_pixels().expect("frame after adding the light").pixels.clone();
|
||||
assert_eq!(before.len(), after.len());
|
||||
let diff = changed_pixels(&before, &after);
|
||||
assert!(diff > 500, "a default white Environment light changed only {diff} pixels");
|
||||
}
|
||||
Reference in New Issue
Block a user