From 3fa847225e2262500069b68182efa22f71cbac62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Mon, 19 Oct 2026 09:43:57 -0700 Subject: [PATCH 1/3] Camera fixes. --- Cargo.lock | 168 +++++------ .../examples/Basics/Camera/move_eye.py | 4 +- .../examples/Basics/Camera/orthographic.py | 3 +- .../examples/Basics/Camera/perspective.py | 3 +- .../examples/Basics/Form/primitives_3d.py | 2 +- .../examples/Basics/Lights/directional.py | 3 +- .../examples/Basics/Lights/mixture.py | 9 +- .../examples/Basics/Lights/mixture_grid.py | 11 +- .../examples/Basics/Lights/on_off.py | 3 +- .../examples/Basics/Lights/spot.py | 17 +- .../examples/Basics/Shape/load_display_obj.py | 2 +- .../examples/Demos/Graphics/planets.py | 4 +- .../dynamic_particles_immediate.py | 6 +- .../Performance/dynamic_particles_retained.py | 6 +- .../examples/Demos/Tests/multiple_windows.py | 12 +- .../examples/Demos/Tests/redraw_test.py | 2 +- .../examples/Topics/Geometry/space_junk.py | 7 +- .../examples/Topics/Geometry/vertices.py | 21 +- .../Topics/Image Processing/explode.py | 2 +- .../Topics/Image Processing/extrusion.py | 2 +- .../examples/Topics/Image Processing/zoom.py | 6 +- .../Topics/Shaders/glossy_fish_eye.py | 6 +- .../examples/Topics/Shaders/toon_shading.py | 5 +- .../Topics/Textures/texture_cylinder.py | 14 +- .../examples/Topics/Textures/texture_quad.py | 14 +- .../Topics/Textures/texture_sphere.py | 14 +- .../Topics/Textures/texture_triangle.py | 9 +- crates/processing_render/src/geometry/mod.rs | 6 + crates/processing_render/src/graphics.rs | 275 ++++++++++++------ crates/processing_render/src/image.rs | 111 ++++++- .../processing_render/src/material/custom.rs | 18 +- crates/processing_render/src/material/mod.rs | 8 + .../src/particles/material.rs | 1 + .../src/particles/point_render.rs | 1 + .../processing_render/src/render/material.rs | 43 ++- crates/processing_render/src/render/mod.rs | 197 ++++++------- 36 files changed, 602 insertions(+), 413 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41d209c1..1b7105ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -562,7 +562,7 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bevy" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_internal", ] @@ -570,7 +570,7 @@ dependencies = [ [[package]] name = "bevy_a11y" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "accesskit", "bevy_app", @@ -582,7 +582,7 @@ dependencies = [ [[package]] name = "bevy_android" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "android-activity", ] @@ -590,7 +590,7 @@ dependencies = [ [[package]] name = "bevy_animation" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_animation_macros", "bevy_app", @@ -622,7 +622,7 @@ dependencies = [ [[package]] name = "bevy_animation_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_macro_utils 0.19.0", "quote", @@ -632,7 +632,7 @@ dependencies = [ [[package]] name = "bevy_anti_alias" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -653,7 +653,7 @@ dependencies = [ [[package]] name = "bevy_app" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_derive", "bevy_ecs", @@ -674,7 +674,7 @@ dependencies = [ [[package]] name = "bevy_asset" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "async-broadcast", "async-channel", @@ -717,7 +717,7 @@ dependencies = [ [[package]] name = "bevy_asset_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_macro_utils 0.19.0", "proc-macro2", @@ -728,7 +728,7 @@ dependencies = [ [[package]] name = "bevy_audio" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -743,7 +743,7 @@ dependencies = [ [[package]] name = "bevy_camera" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -768,7 +768,7 @@ dependencies = [ [[package]] name = "bevy_camera_controller" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_camera", @@ -785,7 +785,7 @@ dependencies = [ [[package]] name = "bevy_clipboard" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_ecs", @@ -799,7 +799,7 @@ dependencies = [ [[package]] name = "bevy_color" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_math", "bevy_reflect", @@ -814,7 +814,7 @@ dependencies = [ [[package]] name = "bevy_core_pipeline" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -856,7 +856,7 @@ dependencies = [ [[package]] name = "bevy_derive" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_macro_utils 0.19.0", "quote", @@ -866,7 +866,7 @@ dependencies = [ [[package]] name = "bevy_dev_tools" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -897,7 +897,7 @@ dependencies = [ [[package]] name = "bevy_diagnostic" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "atomic-waker", "bevy_app", @@ -914,7 +914,7 @@ dependencies = [ [[package]] name = "bevy_ecs" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "arrayvec", "bevy_ecs_macros", @@ -941,7 +941,7 @@ dependencies = [ [[package]] name = "bevy_ecs_macro_logic" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_macro_utils 0.19.0", "proc-macro2", @@ -952,7 +952,7 @@ dependencies = [ [[package]] name = "bevy_ecs_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_ecs_macro_logic", "bevy_macro_utils 0.19.0", @@ -964,7 +964,7 @@ dependencies = [ [[package]] name = "bevy_encase_derive" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_macro_utils 0.19.0", "encase_derive_impl", @@ -973,7 +973,7 @@ dependencies = [ [[package]] name = "bevy_feathers" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "accesskit", "bevy_a11y", @@ -1004,7 +1004,7 @@ dependencies = [ [[package]] name = "bevy_gilrs" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_ecs", @@ -1019,7 +1019,7 @@ dependencies = [ [[package]] name = "bevy_gizmos" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1041,7 +1041,7 @@ dependencies = [ [[package]] name = "bevy_gizmos_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_macro_utils 0.19.0", "quote", @@ -1051,7 +1051,7 @@ dependencies = [ [[package]] name = "bevy_gizmos_render" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1079,7 +1079,7 @@ dependencies = [ [[package]] name = "bevy_gltf" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "async-lock", "base64", @@ -1114,7 +1114,7 @@ dependencies = [ [[package]] name = "bevy_image" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1142,7 +1142,7 @@ dependencies = [ [[package]] name = "bevy_input" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_ecs", @@ -1158,7 +1158,7 @@ dependencies = [ [[package]] name = "bevy_input_focus" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_ecs", @@ -1174,7 +1174,7 @@ dependencies = [ [[package]] name = "bevy_internal" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_a11y", "bevy_android", @@ -1233,7 +1233,7 @@ dependencies = [ [[package]] name = "bevy_light" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1258,7 +1258,7 @@ dependencies = [ [[package]] name = "bevy_log" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "android_log-sys", "bevy_app", @@ -1275,7 +1275,7 @@ dependencies = [ [[package]] name = "bevy_macro_utils" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "proc-macro2", "quote", @@ -1298,7 +1298,7 @@ dependencies = [ [[package]] name = "bevy_material" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_asset", "bevy_derive", @@ -1320,7 +1320,7 @@ dependencies = [ [[package]] name = "bevy_material_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_macro_utils 0.19.0", "quote", @@ -1330,7 +1330,7 @@ dependencies = [ [[package]] name = "bevy_math" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "approx", "arrayvec", @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "bevy_mesh" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1391,7 +1391,7 @@ dependencies = [ [[package]] name = "bevy_pbr" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "arrayvec", "bevy_app", @@ -1433,7 +1433,7 @@ dependencies = [ [[package]] name = "bevy_picking" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1456,7 +1456,7 @@ dependencies = [ [[package]] name = "bevy_platform" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "critical-section", "foldhash 0.2.0", @@ -1477,7 +1477,7 @@ dependencies = [ [[package]] name = "bevy_post_process" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1501,12 +1501,12 @@ dependencies = [ [[package]] name = "bevy_ptr" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" [[package]] name = "bevy_reflect" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "assert_type_match", "bevy_platform", @@ -1534,7 +1534,7 @@ dependencies = [ [[package]] name = "bevy_reflect_derive" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_macro_utils 0.19.0", "indexmap", @@ -1547,7 +1547,7 @@ dependencies = [ [[package]] name = "bevy_render" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "async-channel", "bevy_app", @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "bevy_render_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_macro_utils 0.19.0", "proc-macro2", @@ -1611,7 +1611,7 @@ dependencies = [ [[package]] name = "bevy_scene" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1631,7 +1631,7 @@ dependencies = [ [[package]] name = "bevy_scene_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_ecs_macro_logic", "bevy_macro_utils 0.19.0", @@ -1680,7 +1680,7 @@ dependencies = [ [[package]] name = "bevy_shader" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_asset", "bevy_platform", @@ -1699,7 +1699,7 @@ dependencies = [ [[package]] name = "bevy_sprite" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1724,7 +1724,7 @@ dependencies = [ [[package]] name = "bevy_sprite_render" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1756,7 +1756,7 @@ dependencies = [ [[package]] name = "bevy_state" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_ecs", @@ -1771,7 +1771,7 @@ dependencies = [ [[package]] name = "bevy_state_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_macro_utils 0.19.0", "quote", @@ -1781,7 +1781,7 @@ dependencies = [ [[package]] name = "bevy_tasks" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "async-channel", "async-executor", @@ -1799,7 +1799,7 @@ dependencies = [ [[package]] name = "bevy_text" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1827,7 +1827,7 @@ dependencies = [ [[package]] name = "bevy_time" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_ecs", @@ -1841,7 +1841,7 @@ dependencies = [ [[package]] name = "bevy_transform" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_ecs", @@ -1857,7 +1857,7 @@ dependencies = [ [[package]] name = "bevy_ui" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "accesskit", "bevy_a11y", @@ -1894,7 +1894,7 @@ dependencies = [ [[package]] name = "bevy_ui_render" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1926,7 +1926,7 @@ dependencies = [ [[package]] name = "bevy_ui_widgets" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "accesskit", "bevy_a11y", @@ -1949,7 +1949,7 @@ dependencies = [ [[package]] name = "bevy_utils" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "async-channel", "bevy_platform", @@ -1961,7 +1961,7 @@ dependencies = [ [[package]] name = "bevy_window" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -1979,7 +1979,7 @@ dependencies = [ [[package]] name = "bevy_winit" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "accesskit", "accesskit_winit", @@ -2011,7 +2011,7 @@ dependencies = [ [[package]] name = "bevy_world_serialization" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#9da7c6250114ee8613ae54ab3ad7bb7e43a2f91b" +source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" dependencies = [ "bevy_app", "bevy_asset", @@ -3389,15 +3389,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "font-types" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75382bc7392ef10aad10935f92fc3db36d2d4dad0e5d96d8d65e04f89a07ec39" -dependencies = [ - "bytemuck", -] - [[package]] name = "fontique" version = "0.7.0" @@ -3665,7 +3656,7 @@ dependencies = [ "vec_map", "wasm-bindgen", "web-sys", - "windows 0.62.2", + "windows 0.58.0", ] [[package]] @@ -3819,7 +3810,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.20", - "windows 0.62.2", + "windows 0.58.0", ] [[package]] @@ -6612,17 +6603,6 @@ dependencies = [ "font-types 0.11.3", ] -[[package]] -name = "read-fonts" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046a7d674daf459825b32f5062056d6882db0d2f5a479fbd76ccfc870ac18709" -dependencies = [ - "bytemuck", - "font-types 0.12.3", - "once_cell", -] - [[package]] name = "realfft" version = "3.5.0" @@ -7095,16 +7075,6 @@ dependencies = [ "read-fonts 0.39.2", ] -[[package]] -name = "skrifa" -version = "0.44.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819ab7d62b1d3e72d9d9dea5650bac30424f9111364bb94928dbf5ecad1baa68" -dependencies = [ - "bytemuck", - "read-fonts 0.41.0", -] - [[package]] name = "slab" version = "0.4.12" @@ -7250,7 +7220,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c2499c2d826531388872b2268718aed907a39bd785ab0dcfe57fab26283f92e" dependencies = [ - "skrifa 0.44.0", + "skrifa 0.37.0", "yazi", "zeno", ] diff --git a/crates/processing_pyo3/examples/Basics/Camera/move_eye.py b/crates/processing_pyo3/examples/Basics/Camera/move_eye.py index c4e481ab..45affc27 100644 --- a/crates/processing_pyo3/examples/Basics/Camera/move_eye.py +++ b/crates/processing_pyo3/examples/Basics/Camera/move_eye.py @@ -19,8 +19,8 @@ def setup(): def draw(): background(0.0) - # Change height of the camera with mouseY (the world is y-up) - camera(30.0, -mouse_y, 220.0, # eyeX, eyeY, eyeZ + # Change height of the camera with mouseY + camera(30.0, mouse_y, 220.0, # eyeX, eyeY, eyeZ 0.0, 0.0, 0.0, # centerX, centerY, centerZ 0.0, 1.0, 0.0) # upX, upY, upZ diff --git a/crates/processing_pyo3/examples/Basics/Camera/orthographic.py b/crates/processing_pyo3/examples/Basics/Camera/orthographic.py index fc3dd7dd..896f7e89 100644 --- a/crates/processing_pyo3/examples/Basics/Camera/orthographic.py +++ b/crates/processing_pyo3/examples/Basics/Camera/orthographic.py @@ -30,8 +30,7 @@ def draw(): perspective(PI / 3.0, width / height, 10, far) else: ortho(-width / 2.0, width / 2.0, -height / 2.0, height / 2.0, 10, far) - # Rotations about x run the other way in the y-up world - rotate_x(PI / 6) + rotate_x(-PI / 6) rotate_y(PI / 3) box(180) diff --git a/crates/processing_pyo3/examples/Basics/Camera/perspective.py b/crates/processing_pyo3/examples/Basics/Camera/perspective.py index c8bb57d3..72861494 100644 --- a/crates/processing_pyo3/examples/Basics/Camera/perspective.py +++ b/crates/processing_pyo3/examples/Basics/Camera/perspective.py @@ -37,8 +37,7 @@ def draw(): perspective(fov, aspect, camera_z / 10.0, camera_z * 10.0) translate(30, 0, 0) - # Rotations about x run the other way in the y-up world - rotate_x(PI / 6) + rotate_x(-PI / 6) rotate_y(PI / 3 + mouse_y / height * PI) box(45) translate(0, 0, -50) diff --git a/crates/processing_pyo3/examples/Basics/Form/primitives_3d.py b/crates/processing_pyo3/examples/Basics/Form/primitives_3d.py index d452c6aa..e01ac35a 100644 --- a/crates/processing_pyo3/examples/Basics/Form/primitives_3d.py +++ b/crates/processing_pyo3/examples/Basics/Form/primitives_3d.py @@ -30,7 +30,7 @@ def draw(): no_fill() stroke(1.0) push_matrix() - translate(500 - width / 2, height / 2 - height * 0.35, -200) + translate(500 - width / 2, height * 0.35 - height / 2, -200) sphere(280) pop_matrix() diff --git a/crates/processing_pyo3/examples/Basics/Lights/directional.py b/crates/processing_pyo3/examples/Basics/Lights/directional.py index a9dd41ae..ae7fe5d5 100644 --- a/crates/processing_pyo3/examples/Basics/Lights/directional.py +++ b/crates/processing_pyo3/examples/Basics/Lights/directional.py @@ -26,8 +26,7 @@ def draw(): background(0.0) dir_y = (mouse_y / height - 0.5) * 2 dir_x = (mouse_x / width - 0.5) * 2 - # The world is y-up, so the vertical direction is flipped - light.look_at(-dir_x, dir_y, -1) + light.look_at(-dir_x, -dir_y, -1) translate(-100, 0, 0) sphere(80) translate(200, 0, 0) diff --git a/crates/processing_pyo3/examples/Basics/Lights/mixture.py b/crates/processing_pyo3/examples/Basics/Lights/mixture.py index 033790fa..b4b30a13 100644 --- a/crates/processing_pyo3/examples/Basics/Lights/mixture.py +++ b/crates/processing_pyo3/examples/Basics/Lights/mixture.py @@ -15,11 +15,10 @@ def setup(): mode_3d() no_stroke() - # Lights are created once; the world is y-up, so the y of every - # position and direction is flipped + # Lights are created once # Orange point light on the right point = point_light((0.59, 0.39, 0.0), 3000000000.0, 600.0, 1.0, # Color - position=(200, 150, 0)) # Position + position=(200, -150, 0)) # Position # Blue directional light from the left directional = directional_light((0.0, 0.4, 1.0), 4000.0, # Color @@ -28,8 +27,8 @@ def setup(): # Yellow spotlight from the front spot = spot_light((1.0, 1.0, 0.43), 2000000000.0, 600.0, 1.0, # Color PI / 4, PI / 2, # Angle, concentration - position=(0, -40, 200), # Position - look_at=(0, -40 + 0.5, 200 - 0.5)) # Direction + position=(0, 40, 200), # Position + look_at=(0, 40 - 0.5, 200 - 0.5)) # Direction roughness(0.6) diff --git a/crates/processing_pyo3/examples/Basics/Lights/mixture_grid.py b/crates/processing_pyo3/examples/Basics/Lights/mixture_grid.py index 21a0497d..1a5d1362 100644 --- a/crates/processing_pyo3/examples/Basics/Lights/mixture_grid.py +++ b/crates/processing_pyo3/examples/Basics/Lights/mixture_grid.py @@ -22,7 +22,7 @@ def draw(): for x in range(0, width + 1, 60): for y in range(0, height + 1, 60): push_matrix() - translate(x - width / 2, height / 2 - y, 0) + translate(x - width / 2, y - height / 2, 0) rotate_y(remap(mouse_x, 0, width, 0, PI)) rotate_x(remap(mouse_y, 0, height, 0, PI)) box(90) @@ -31,11 +31,10 @@ def draw(): def define_lights(): global point, directional, spot - # The lights are created once, placed relative to the top-left corner - # as in the original (the world is centered and y-up) + # The lights are created once, in the original's top-left coordinates # Orange point light on the right point = point_light((0.59, 0.39, 0.0), 3000000000.0, 600.0, 1.0, # Color - position=(200 - width / 2, height / 2 + 150, 0)) # Position + position=(200 - width / 2, -150 - height / 2, 0)) # Position # Blue directional light from the left directional = directional_light((0.0, 0.4, 1.0), 4000.0, # Color @@ -44,8 +43,8 @@ def define_lights(): # Yellow spotlight from the front spot = spot_light((1.0, 1.0, 0.43), 2000000000.0, 600.0, 1.0, # Color PI / 4, PI / 2, # Angle, concentration - position=(-width / 2, height / 2 - 40, 200), # Position - look_at=(-width / 2, height / 2 - 40 + 0.5, 200 - 0.5)) # Direction + position=(-width / 2, 40 - height / 2, 200), # Position + look_at=(-width / 2, 40 - height / 2 - 0.5, 200 - 0.5)) # Direction roughness(0.6) diff --git a/crates/processing_pyo3/examples/Basics/Lights/on_off.py b/crates/processing_pyo3/examples/Basics/Lights/on_off.py index 56aa1f3b..45532551 100644 --- a/crates/processing_pyo3/examples/Basics/Lights/on_off.py +++ b/crates/processing_pyo3/examples/Basics/Lights/on_off.py @@ -30,8 +30,7 @@ def draw(): spin += 0.01 push_matrix() - # Rotations about x run the other way in the y-up world - rotate_x(-PI / 9) + rotate_x(PI / 9) rotate_y(PI / 5 + spin) box(150) pop_matrix() diff --git a/crates/processing_pyo3/examples/Basics/Lights/spot.py b/crates/processing_pyo3/examples/Basics/Lights/spot.py index 3801f589..bca85c15 100644 --- a/crates/processing_pyo3/examples/Basics/Lights/spot.py +++ b/crates/processing_pyo3/examples/Basics/Lights/spot.py @@ -16,28 +16,27 @@ def setup(): no_stroke() fill(0.8) - # Lights are created once and positioned relative to the top-left corner - # as in the original (the world is centered and y-up) + # Lights are created once, in the original's top-left coordinates # Light the bottom of the sphere - bottom = directional_light((0.2, 0.4, 0.49), 4000.0, look_at=(0, 1, 0)) + bottom = directional_light((0.2, 0.4, 0.49), 4000.0, look_at=(0, -1, 0)) # Orange light on the upper-right of the sphere orange = spot_light((0.8, 0.6, 0.0), 10000000000.0, 1200.0, 1.0, 0.0, PI / 12, - position=(360 - width / 2, height / 2 - 160, 600), - look_at=(360 - width / 2, height / 2 - 160, 0)) + position=(360 - width / 2, 160 - height / 2, 600), + look_at=(360 - width / 2, 160 - height / 2, 0)) # Moving spotlight that follows the mouse blue = spot_light((0.4, 0.6, 0.8), 10000000000.0, 1200.0, 1.0, 0.0, PI / 12, - position=(360 - width / 2, height / 2, 600), - look_at=(360 - width / 2, height / 2, 0)) + position=(360 - width / 2, -height / 2, 600), + look_at=(360 - width / 2, -height / 2, 0)) roughness(0.6) def draw(): background(0.0) - blue.position(360 - width / 2, height / 2 - mouse_y, 600) - blue.look_at(360 - width / 2, height / 2 - mouse_y, 0) + blue.position(360 - width / 2, mouse_y - height / 2, 600) + blue.look_at(360 - width / 2, mouse_y - height / 2, 0) sphere(120, 60, 60) diff --git a/crates/processing_pyo3/examples/Basics/Shape/load_display_obj.py b/crates/processing_pyo3/examples/Basics/Shape/load_display_obj.py index 4d8b5820..1ce3dc5b 100644 --- a/crates/processing_pyo3/examples/Basics/Shape/load_display_obj.py +++ b/crates/processing_pyo3/examples/Basics/Shape/load_display_obj.py @@ -22,7 +22,7 @@ def draw(): global ry background(0.0) - translate(0, -100, -200) + translate(0, 100, -200) rotate_z(PI) rotate_y(ry) shape(rocket) # GAP: shape(model) draws a loaded model diff --git a/crates/processing_pyo3/examples/Demos/Graphics/planets.py b/crates/processing_pyo3/examples/Demos/Graphics/planets.py index 17340ba0..b58a7b37 100644 --- a/crates/processing_pyo3/examples/Demos/Graphics/planets.py +++ b/crates/processing_pyo3/examples/Demos/Graphics/planets.py @@ -35,7 +35,7 @@ def setup(): # pointLight(255, 255, 255, 0, 0, 0) at the sun's position, and # pointLight(255, 255, 255, 0, 0, -150) at the screen corner for planet1 sun_light = point_light((1.0, 1.0, 1.0), 1000000.0, 1200.0, 1.0, position=(0, 0, -300)) - planet_light = point_light((1.0, 1.0, 1.0), 1000000.0, 1200.0, 1.0, position=(-width / 2, height / 2, -150)) + planet_light = point_light((1.0, 1.0, 1.0), 1000000.0, 1200.0, 1.0, position=(-width / 2, -height / 2, -150)) def draw(): @@ -64,7 +64,7 @@ def draw(): pop_matrix() - translate(0.25 * width, -0.1 * height, 50) + translate(0.25 * width, 0.1 * height, 50) texture(surftex1) sphere(150, 40, 40) no_texture() diff --git a/crates/processing_pyo3/examples/Demos/Performance/dynamic_particles_immediate.py b/crates/processing_pyo3/examples/Demos/Performance/dynamic_particles_immediate.py index 030e0d22..ab16a118 100644 --- a/crates/processing_pyo3/examples/Demos/Performance/dynamic_particles_immediate.py +++ b/crates/processing_pyo3/examples/Demos/Performance/dynamic_particles_immediate.py @@ -50,9 +50,9 @@ def draw(): opacity = 1.0 - lifetimes[n] / part_lifetime if lifetimes[n] == 0: - # Re-spawn dead particle (the 3D origin is the canvas center, y up) + # Re-spawn dead particle (the 3D origin is the canvas center) positions[n].x = mouse_x - width / 2 - positions[n].y = height / 2 - mouse_y + positions[n].y = mouse_y - height / 2 angle = random(0, TWO_PI) s = random(0.5 * speed, 0.5 * speed) @@ -62,7 +62,7 @@ def draw(): positions[n].x += velocities[n].x positions[n].y += velocities[n].y - velocities[n].y -= gravity + velocities[n].y += gravity draw_particle(positions[n], opacity) fcount += 1 diff --git a/crates/processing_pyo3/examples/Demos/Performance/dynamic_particles_retained.py b/crates/processing_pyo3/examples/Demos/Performance/dynamic_particles_retained.py index d92f85a6..9c659893 100644 --- a/crates/processing_pyo3/examples/Demos/Performance/dynamic_particles_retained.py +++ b/crates/processing_pyo3/examples/Demos/Performance/dynamic_particles_retained.py @@ -73,8 +73,8 @@ def draw(): tints[n] = [1.0, 1.0, 1.0, opacity] if lifetimes[n] == 0: - # Re-spawn dead particle (the 3D origin is the canvas center, y up) - positions[n] = [mouse_x - width / 2, height / 2 - mouse_y, 0.0] + # Re-spawn dead particle (the 3D origin is the canvas center) + positions[n] = [mouse_x - width / 2, mouse_y - height / 2, 0.0] angle = random(0, TWO_PI) s = random(0.5 * speed, 0.5 * speed) velocities[n].x = s * cos(angle) @@ -82,7 +82,7 @@ def draw(): else: positions[n][0] += velocities[n].x positions[n][1] += velocities[n].y - velocities[n].y -= gravity + velocities[n].y += gravity else: tints[n] = [0.0, 0.0, 0.0, 0.0] diff --git a/crates/processing_pyo3/examples/Demos/Tests/multiple_windows.py b/crates/processing_pyo3/examples/Demos/Tests/multiple_windows.py index 78f88f54..5d2cd567 100644 --- a/crates/processing_pyo3/examples/Demos/Tests/multiple_windows.py +++ b/crates/processing_pyo3/examples/Demos/Tests/multiple_windows.py @@ -27,9 +27,9 @@ def draw(): arcball.run() if mouse_is_pressed: fill(0.0) - text("Mouse pressed on parent.", 10 - width / 2, height / 2 - 10) + text("Mouse pressed on parent.", 10 - width / 2, 10 - height / 2) fill(0.0, 0.94, 0.0) - ellipse(mouse_x - width / 2, height / 2 - mouse_y, 60, 60) + ellipse(mouse_x - width / 2, mouse_y - height / 2, 60, 60) mouse_pressed_on_parent = True else: fill(0.08) @@ -37,7 +37,7 @@ def draw(): mouse_pressed_on_parent = False box(100) if child.g.mouse_is_pressed: - text("Mouse pressed on child.", 10 - width / 2, height / 2 - 30) + text("Mouse pressed on child.", 10 - width / 2, 30 - height / 2) child.draw() @@ -69,9 +69,9 @@ def draw(self): arcball2.run() if g.mouse_is_pressed: g.fill(0.94, 0.0, 0.0) - g.ellipse(g.mouse_x - g.width / 2, g.height / 2 - g.mouse_y, 20, 20) + g.ellipse(g.mouse_x - g.width / 2, g.mouse_y - g.height / 2, 20, 20) g.fill(1.0) - g.text("Mouse pressed on child.", 10 - g.width / 2, g.height / 2 - 30) + g.text("Mouse pressed on child.", 10 - g.width / 2, 30 - g.height / 2) else: g.fill(1.0) g.ellipse(0, 0, 20, 20) @@ -79,7 +79,7 @@ def draw(self): g.draw_box(100, 200, 100) if mouse_pressed_on_parent: g.fill(1.0) - g.text("Mouse pressed on parent", 20 - g.width / 2, g.height / 2 - 20) + g.text("Mouse pressed on parent", 20 - g.width / 2, 20 - g.height / 2) # Ariel and V3ga's arcball class with a couple tiny mods by Robert Hodgin diff --git a/crates/processing_pyo3/examples/Demos/Tests/redraw_test.py b/crates/processing_pyo3/examples/Demos/Tests/redraw_test.py index 8530bdc6..d77e3d87 100644 --- a/crates/processing_pyo3/examples/Demos/Tests/redraw_test.py +++ b/crates/processing_pyo3/examples/Demos/Tests/redraw_test.py @@ -13,7 +13,7 @@ def setup(): def draw(): background(1.0, 0.0, 0.0) - ellipse(mouse_x - width / 2, height / 2 - mouse_y, 100, 50) + ellipse(mouse_x - width / 2, mouse_y - height / 2, 100, 50) print("draw") diff --git a/crates/processing_pyo3/examples/Topics/Geometry/space_junk.py b/crates/processing_pyo3/examples/Topics/Geometry/space_junk.py index c3dfc95d..d324621f 100644 --- a/crates/processing_pyo3/examples/Topics/Geometry/space_junk.py +++ b/crates/processing_pyo3/examples/Topics/Geometry/space_junk.py @@ -32,12 +32,11 @@ def setup(): int(random(-10, 10)), int(random(-140, 140)), int(random(-140, 140)), int(random(-140, 140)))) - # Set up some different colored lights, placed relative to the top-left - # corner as in the original (the world is centered and y-up) + # Set up some different colored lights, in the original's top-left coordinates blue_light = point_light((0.2, 0.4, 1.0), 3000000000.0, 600.0, 1.0, - position=(65 - width / 2, height / 2 - 60, 100)) + position=(65 - width / 2, 60 - height / 2, 100)) red_light = point_light((0.78, 0.16, 0.24), 3000000000.0, 600.0, 1.0, - position=(-65 - width / 2, height / 2 + 60, -150)) + position=(-65 - width / 2, -60 - height / 2, -150)) # Raise overall light in scene ambient_light(0.27, 0.27, 0.04) # GAP: ambient_light() diff --git a/crates/processing_pyo3/examples/Topics/Geometry/vertices.py b/crates/processing_pyo3/examples/Topics/Geometry/vertices.py index a3a24ef7..fc780091 100644 --- a/crates/processing_pyo3/examples/Topics/Geometry/vertices.py +++ b/crates/processing_pyo3/examples/Topics/Geometry/vertices.py @@ -28,8 +28,7 @@ def draw(): rotate_z(remap(mouse_y, 0, height, 0, -PI)) no_stroke() fill(1.0, 1.0, 1.0) - # The world is y-up: the cylinder hangs down from y=40 - translate(0, 40, 0) + translate(0, -40, 0) draw_geometry(cylinder) @@ -52,15 +51,15 @@ def build_cylinder(top_radius, bottom_radius, tall, sides): g = create_geometry(topology=TRIANGLES) angle = 0 angle_increment = TWO_PI / sides - # The sides: one quad per step around the axis (going down to y=-tall) + # The sides: one quad per step around the axis (going down to y=tall) for i in range(sides): a0 = angle a1 = angle + angle_increment add_quad(g, Vec3(top_radius * cos(a0), 0, top_radius * sin(a0)), - Vec3(top_radius * cos(a1), 0, top_radius * sin(a1)), - Vec3(bottom_radius * cos(a1), -tall, bottom_radius * sin(a1)), - Vec3(bottom_radius * cos(a0), -tall, bottom_radius * sin(a0))) + Vec3(bottom_radius * cos(a0), tall, bottom_radius * sin(a0)), + Vec3(bottom_radius * cos(a1), tall, bottom_radius * sin(a1)), + Vec3(top_radius * cos(a1), 0, top_radius * sin(a1))) angle += angle_increment # If it is not a cone, draw the circular top cap as a fan around the center @@ -69,18 +68,18 @@ def build_cylinder(top_radius, bottom_radius, tall, sides): center = Vec3(0, 0, 0) for i in range(sides): add_triangle(g, center, - Vec3(top_radius * cos(angle + angle_increment), 0, top_radius * sin(angle + angle_increment)), - Vec3(top_radius * cos(angle), 0, top_radius * sin(angle))) + Vec3(top_radius * cos(angle), 0, top_radius * sin(angle)), + Vec3(top_radius * cos(angle + angle_increment), 0, top_radius * sin(angle + angle_increment))) angle += angle_increment # If it is not a cone, draw the circular bottom cap if bottom_radius != 0: angle = 0 - center = Vec3(0, -tall, 0) + center = Vec3(0, tall, 0) for i in range(sides): add_triangle(g, center, - Vec3(bottom_radius * cos(angle), -tall, bottom_radius * sin(angle)), - Vec3(bottom_radius * cos(angle + angle_increment), -tall, bottom_radius * sin(angle + angle_increment))) + Vec3(bottom_radius * cos(angle + angle_increment), tall, bottom_radius * sin(angle + angle_increment)), + Vec3(bottom_radius * cos(angle), tall, bottom_radius * sin(angle))) angle += angle_increment return g diff --git a/crates/processing_pyo3/examples/Topics/Image Processing/explode.py b/crates/processing_pyo3/examples/Topics/Image Processing/explode.py index d326a42a..9f7eb224 100644 --- a/crates/processing_pyo3/examples/Topics/Image Processing/explode.py +++ b/crates/processing_pyo3/examples/Topics/Image Processing/explode.py @@ -37,7 +37,7 @@ def draw(): z = (mouse_x / width) * brightness(px[loc]) * 255 - 20.0 # Translate to the location, set fill and stroke, and draw the rect push_matrix() - translate(x + 200 - width / 2, height / 2 - (y + 100), z) + translate(x + 200 - width / 2, y + 100 - height / 2, z) fill(c.with_alpha(0.8)) no_stroke() rect_mode(CENTER) diff --git a/crates/processing_pyo3/examples/Topics/Image Processing/extrusion.py b/crates/processing_pyo3/examples/Topics/Image Processing/extrusion.py index 35bdaeab..94d7b79a 100644 --- a/crates/processing_pyo3/examples/Topics/Image Processing/extrusion.py +++ b/crates/processing_pyo3/examples/Topics/Image Processing/extrusion.py @@ -46,7 +46,7 @@ def draw(): for i in range(0, a.height, 4): for j in range(0, a.width, 4): stroke(values[j][i] / 255, 1.0) - line(j - a.width / 2, a.height / 2 - i, -values[j][i], j - a.width / 2, a.height / 2 - i, -values[j][i] - 10) # GAP: 3D line(x1, y1, z1, x2, y2, z2) + line(j - a.width / 2, i - a.height / 2, -values[j][i], j - a.width / 2, i - a.height / 2, -values[j][i] - 10) # GAP: 3D line(x1, y1, z1, x2, y2, z2) run() diff --git a/crates/processing_pyo3/examples/Topics/Image Processing/zoom.py b/crates/processing_pyo3/examples/Topics/Image Processing/zoom.py index c62d5304..61579e1f 100644 --- a/crates/processing_pyo3/examples/Topics/Image Processing/zoom.py +++ b/crates/processing_pyo3/examples/Topics/Image Processing/zoom.py @@ -42,13 +42,13 @@ def draw(): sval = constrain(sval, 1.0, 2.0) - translate(nmx * sval - 100, -(nmy * sval - 100), -50) + translate(nmx * sval - 100, nmy * sval - 100, -50) scale(sval) rotate_z(PI / 9 - sval + 1.0) rotate_x(PI / sval / 8 - 0.125) rotate_y(sval / 8 - 0.125) - translate(-width / 2, height / 2, 0) + translate(-width / 2, -height / 2, 0) for i in range(0, img.height, res): for j in range(0, img.width, res): @@ -57,7 +57,7 @@ def draw(): bb = img_pixels[j][i].b tt = (rr + gg + bb) * 255 stroke(rr, gg, gg) - line(i, -j, tt / 10 - 20, i, -j, tt / 10) # GAP: 3D line(x1, y1, z1, x2, y2, z2) + line(i, j, tt / 10 - 20, i, j, tt / 10) # GAP: 3D line(x1, y1, z1, x2, y2, z2) run() diff --git a/crates/processing_pyo3/examples/Topics/Shaders/glossy_fish_eye.py b/crates/processing_pyo3/examples/Topics/Shaders/glossy_fish_eye.py index 20bef1fe..dbcdd205 100644 --- a/crates/processing_pyo3/examples/Topics/Shaders/glossy_fish_eye.py +++ b/crates/processing_pyo3/examples/Topics/Shaders/glossy_fish_eye.py @@ -44,12 +44,12 @@ def draw(): canvas.no_stroke() canvas.background(0.0) # pointLight(204, 204, 204, 1000, 1000, 1000) under rotateY(frameCount * 0.01), - # converted from Processing's corner-origin, y-down space to the centered y-up world + # in the original's top-left coordinates angle = frame_count * 0.01 lx = 1000 * cos(angle) + 1000 * sin(angle) ly = 1000 lz = -1000 * sin(angle) + 1000 * cos(angle) - glossy.set(light_position=(lx - canvas.width / 2, canvas.height / 2 - ly, lz)) + glossy.set(light_position=(lx - canvas.width / 2, ly - canvas.height / 2, lz)) canvas.material(glossy) x = 0 while x < canvas.width + 100: @@ -58,7 +58,7 @@ def draw(): z = 0 while z < 400: canvas.push_matrix() - canvas.translate(x - canvas.width / 2, canvas.height / 2 - y, -z) + canvas.translate(x - canvas.width / 2, y - canvas.height / 2, -z) canvas.draw_geometry(ball) canvas.pop_matrix() z += 100 diff --git a/crates/processing_pyo3/examples/Topics/Shaders/toon_shading.py b/crates/processing_pyo3/examples/Topics/Shaders/toon_shading.py index 6e93e539..0360c1a4 100644 --- a/crates/processing_pyo3/examples/Topics/Shaders/toon_shading.py +++ b/crates/processing_pyo3/examples/Topics/Shaders/toon_shading.py @@ -29,12 +29,11 @@ def draw(): background(0.0) dir_y = (mouse_y / height - 0.5) * 2 dir_x = (mouse_x / width - 0.5) * 2 - # directionalLight(204, 204, 204, -dirX, -dirY, -1), y flipped for the y-up world - light.look_at(-dir_x, dir_y, -1) + light.look_at(-dir_x, -dir_y, -1) if shader_enabled: # the custom material does not see the scene lights: pass the # direction toward the light as a uniform - toon.set(light_dir=(dir_x, -dir_y, 1.0)) + toon.set(light_dir=(dir_x, dir_y, 1.0)) material(toon) else: material(plain) # GAP: no reset_shader()/no_material() to return to the default material diff --git a/crates/processing_pyo3/examples/Topics/Textures/texture_cylinder.py b/crates/processing_pyo3/examples/Topics/Textures/texture_cylinder.py index 6726fd5c..7dc6126b 100644 --- a/crates/processing_pyo3/examples/Topics/Textures/texture_cylinder.py +++ b/crates/processing_pyo3/examples/Topics/Textures/texture_cylinder.py @@ -23,26 +23,26 @@ def setup(): no_stroke() # The meshes are built once; uv coordinates are the image coordinates - # divided by the image size, and the world is y-up (the top edge is +100) + # divided by the image size tube = create_geometry(topology=TRIANGLE_STRIP) for i in range(tube_res): x = tube_x[i] * 100 z = tube_y[i] * 100 u = (img.width // tube_res * i) / img.width tube.uv(u, 0) - tube.vertex(x, 100, z) - tube.uv(u, 1) tube.vertex(x, -100, z) + tube.uv(u, 1) + tube.vertex(x, 100, z) quad = create_geometry(topology=TRIANGLES) quad.uv(0, 0) - quad.vertex(0, 100, 0) + quad.vertex(0, -100, 0) quad.uv(100 / img.width, 0) - quad.vertex(100, 100, 0) - quad.uv(100 / img.width, 100 / img.height) quad.vertex(100, -100, 0) + quad.uv(100 / img.width, 100 / img.height) + quad.vertex(100, 100, 0) quad.uv(0, 100 / img.height) - quad.vertex(0, -100, 0) + quad.vertex(0, 100, 0) for i in (0, 1, 2, 0, 2, 3): quad.index(i) diff --git a/crates/processing_pyo3/examples/Topics/Textures/texture_quad.py b/crates/processing_pyo3/examples/Topics/Textures/texture_quad.py index 3a52d9f5..7bac514a 100644 --- a/crates/processing_pyo3/examples/Topics/Textures/texture_quad.py +++ b/crates/processing_pyo3/examples/Topics/Textures/texture_quad.py @@ -15,17 +15,16 @@ def setup(): img = load_image("data/berlin-1.jpg") no_stroke() - # uv coordinates are the image coordinates divided by the image size, - # and the world is y-up (the top edge is +100) + # uv coordinates are the image coordinates divided by the image size quad = create_geometry(topology=TRIANGLES) quad.uv(0, 0) - quad.vertex(-100, 100, 0) + quad.vertex(-100, -100, 0) quad.uv(1, 0) - quad.vertex(100, 100, 0) - quad.uv(1, 1) quad.vertex(100, -100, 0) + quad.uv(1, 1) + quad.vertex(100, 100, 0) quad.uv(0, 1) - quad.vertex(-100, -100, 0) + quad.vertex(-100, 100, 0) for i in (0, 1, 2, 0, 2, 3): quad.index(i) @@ -33,8 +32,7 @@ def setup(): def draw(): background(0.0) rotate_y(remap(mouse_x, 0, width, -PI, PI)) - # Rotations about z run the other way in the y-up world - rotate_z(-PI / 6) + rotate_z(PI / 6) unlit() texture(img) draw_geometry(quad) diff --git a/crates/processing_pyo3/examples/Topics/Textures/texture_sphere.py b/crates/processing_pyo3/examples/Topics/Textures/texture_sphere.py index e43ffe41..d162469b 100644 --- a/crates/processing_pyo3/examples/Topics/Textures/texture_sphere.py +++ b/crates/processing_pyo3/examples/Topics/Textures/texture_sphere.py @@ -62,10 +62,9 @@ def key_pressed(): def draw(): background(0.0) - # The world is centered and y-up, so the eye and center lose the - # width/2, height/2 offsets and flip their y + # The origin is centered: the eye and center lose the width/2, height/2 offsets camera(remap(mouse_x, 0, width, -2 * width, 2 * width), - -remap(mouse_y, 0, height, -height, height), + remap(mouse_y, 0, height, -height, height), height / 2 / tan(PI * 30.0 / 180.0), width / 2, 0, 0, 0, 1, 0) @@ -118,7 +117,6 @@ def texture_sphere(rx, ry, rz, t): u = 0 # Width variable for the texture v = 0 # Height variable for the texture - # The world is y-up, so the y of every vertex and normal is flipped g = create_geometry(topology=TRIANGLE_STRIP) for i in range(num_points_h - 1): # For all the rings but top and bottom # Goes into the array here instead of loop to save time @@ -129,12 +127,12 @@ def texture_sphere(rx, ry, rz, t): multxz_plus = mult_xz[i + 1] for j in range(num_points_w): # For all the pts in the ring - g.normal(-coor_x[j] * multxz, coory, -coor_z[j] * multxz) + g.normal(-coor_x[j] * multxz, -coory, -coor_z[j] * multxz) g.uv(u, v) - g.vertex(coor_x[j] * multxz * rx, -coory * ry, coor_z[j] * multxz * rz) - g.normal(-coor_x[j] * multxz_plus, coory_plus, -coor_z[j] * multxz_plus) + g.vertex(coor_x[j] * multxz * rx, coory * ry, coor_z[j] * multxz * rz) + g.normal(-coor_x[j] * multxz_plus, -coory_plus, -coor_z[j] * multxz_plus) g.uv(u, v + change_v) - g.vertex(coor_x[j] * multxz_plus * rx, -coory_plus * ry, coor_z[j] * multxz_plus * rz) + g.vertex(coor_x[j] * multxz_plus * rx, coory_plus * ry, coor_z[j] * multxz_plus * rz) u += change_u v += change_v u = 0 diff --git a/crates/processing_pyo3/examples/Topics/Textures/texture_triangle.py b/crates/processing_pyo3/examples/Topics/Textures/texture_triangle.py index 75f46053..a32cc2c0 100644 --- a/crates/processing_pyo3/examples/Topics/Textures/texture_triangle.py +++ b/crates/processing_pyo3/examples/Topics/Textures/texture_triangle.py @@ -14,15 +14,14 @@ def setup(): img = load_image("data/berlin-1.jpg") no_stroke() - # uv coordinates are the image coordinates divided by the image size, - # and the world is y-up (the top edge is +100) + # uv coordinates are the image coordinates divided by the image size tri = create_geometry(topology=TRIANGLES) tri.uv(0, 0) - tri.vertex(-100, 100, 0) + tri.vertex(-100, -100, 0) tri.uv(300 / img.width, 120 / img.height) - tri.vertex(100, 40, 0) + tri.vertex(100, -40, 0) tri.uv(200 / img.width, 400 / img.height) - tri.vertex(0, -100, 0) + tri.vertex(0, 100, 0) def draw(): diff --git a/crates/processing_render/src/geometry/mod.rs b/crates/processing_render/src/geometry/mod.rs index 0ed13339..ec4b4d47 100644 --- a/crates/processing_render/src/geometry/mod.rs +++ b/crates/processing_render/src/geometry/mod.rs @@ -83,6 +83,8 @@ pub struct Geometry { pub current_color: [f32; 4], pub current_uv: [f32; 2], pub custom_current: HashMap, + /// set once a color with alpha below one is used; never cleared + pub translucent: bool, } impl Geometry { @@ -94,6 +96,7 @@ impl Geometry { current_color: [1.0, 1.0, 1.0, 1.0], current_uv: [0.0, 0.0], custom_current: HashMap::new(), + translucent: false, } } } @@ -259,6 +262,9 @@ pub fn color(world: &mut World, entity: Entity, color: Vec4) -> Result<()> { .get_mut::(entity) .ok_or(ProcessingError::GeometryNotFound)?; geometry.current_color = color.to_array(); + if color.w < 1.0 { + geometry.translucent = true; + } Ok(()) } diff --git a/crates/processing_render/src/graphics.rs b/crates/processing_render/src/graphics.rs index c8005e79..183046ec 100644 --- a/crates/processing_render/src/graphics.rs +++ b/crates/processing_render/src/graphics.rs @@ -10,7 +10,7 @@ use bevy::{ }, core_pipeline::tonemapping::Tonemapping, ecs::query::QueryEntityError, - math::{Mat4, Vec3A}, + math::{Mat4, Vec3A, Vec4}, prelude::*, render::{ RenderApp, @@ -44,6 +44,7 @@ pub struct GraphicsPlugin; impl Plugin for GraphicsPlugin { fn build(&self, app: &mut App) { app.init_resource::() + .add_systems(First, crate::image::clear_background_blits) .add_systems(PostUpdate, sync_to_surface); } } @@ -77,49 +78,75 @@ macro_rules! graphics_mut { #[derive(Component)] pub struct SurfaceSize(pub u32, pub u32); -/// Custom orthographic projection for Processing's coordinate system. -/// Origin at top-left, Y-axis down, in pixel units (aka screen space). +/// Screen-space y flip applied after projection, so the world is y-down (origin top-left in 2D, +/// canvas center in 3D) like Processing's and p5.js WEBGL's, with transforms, cameras and lights +/// left untouched. The reflection mirrors triangle winding; every pipeline compensates with +/// `material::apply_processing_winding`. +pub(crate) const Y_FLIP: Mat4 = Mat4::from_cols( + Vec4::new(1.0, 0.0, 0.0, 0.0), + Vec4::new(0.0, -1.0, 0.0, 0.0), + Vec4::new(0.0, 0.0, 1.0, 0.0), + Vec4::new(0.0, 0.0, 0.0, 1.0), +); + +/// Orthographic projection over a y-down world: `bottom` is the smallest visible y (screen +/// top), `top` the largest (screen bottom), as in Processing's `ortho(left, right, bottom, top)`. #[derive(Debug, Clone, Reflect)] pub struct ProcessingProjection { - pub width: f32, - pub height: f32, + pub left: f32, + pub right: f32, + pub bottom: f32, + pub top: f32, pub near: f32, pub far: f32, + /// a 2D canvas follows the render target size; an explicit `ortho()` keeps its bounds + pub fit_canvas: bool, } impl ProcessingProjection { + /// The 2D canvas: pixel units from the top-left corner. pub fn new(width: f32, height: f32) -> Self { Self { - width, - height, - near: 0.0, + left: 0.0, + right: width, + bottom: 0.0, + top: height, + // like bevy's 2d camera: the canvas plane sits mid-range, draw layers grow toward + // the camera + near: -1000.0, far: 1000.0, + fit_canvas: true, } } } impl CameraProjection for ProcessingProjection { fn get_clip_from_view(&self) -> Mat4 { - Mat4::orthographic_rh( - 0.0, - self.width, - self.height, // bottom = height - 0.0, // top = 0 - self.near, - self.far, - ) + // far/near swapped for reverse-z, which the depth compare (GreaterEqual) assumes + Y_FLIP + * Mat4::orthographic_rh( + self.left, + self.right, + self.bottom, + self.top, + self.far, + self.near, + ) } fn get_clip_from_view_for_sub(&self, _sub_view: &bevy::camera::SubCameraView) -> Mat4 { - // TODO: implement sub-view support if needed (probably not) + // sub-views are not supported on the canvas self.get_clip_from_view() } - fn update(&mut self, _width: f32, _height: f32) { - // this gets called with the render target's physical dimensions (i.e. accounting for - // scale factor), but our projection is in logical pixel units - self.width = _width; - self.height = _height; + /// Bevy passes the logical viewport size, which is the canvas's pixel unit. + fn update(&mut self, width: f32, height: f32) { + if self.fit_canvas { + self.left = 0.0; + self.right = width; + self.bottom = 0.0; + self.top = height; + } } fn far(&self) -> f32 { @@ -128,27 +155,54 @@ impl CameraProjection for ProcessingProjection { fn get_frustum_corners(&self, z_near: f32, z_far: f32) -> [Vec3A; 8] { // order: bottom-right, top-right, top-left, bottom-left for near, then far - let near_center = Vec3A::new(self.width / 2.0, self.height / 2.0, z_near); - let far_center = Vec3A::new(self.width / 2.0, self.height / 2.0, z_far); - - let half_width = self.width / 2.0; - let half_height = self.height / 2.0; - + let (l, r, b, t) = (self.left, self.right, self.bottom, self.top); [ - // near plane - near_center + Vec3A::new(half_width, half_height, 0.0), // bottom-right - near_center + Vec3A::new(half_width, -half_height, 0.0), // top-right - near_center + Vec3A::new(-half_width, -half_height, 0.0), // top-left - near_center + Vec3A::new(-half_width, half_height, 0.0), // bottom-left - // far plane - far_center + Vec3A::new(half_width, half_height, 0.0), // bottom-right - far_center + Vec3A::new(half_width, -half_height, 0.0), // top-right - far_center + Vec3A::new(-half_width, -half_height, 0.0), // top-left - far_center + Vec3A::new(-half_width, half_height, 0.0), // bottom-left + Vec3A::new(r, b, z_near), + Vec3A::new(r, t, z_near), + Vec3A::new(l, t, z_near), + Vec3A::new(l, b, z_near), + Vec3A::new(r, b, z_far), + Vec3A::new(r, t, z_far), + Vec3A::new(l, t, z_far), + Vec3A::new(l, b, z_far), ] } } +/// Perspective projection over the same y-down world (3D mode): bevy's reverse-z infinite +/// perspective with the screen-space y flip. +#[derive(Debug, Clone, Reflect)] +pub struct ProcessingPerspective { + pub inner: PerspectiveProjection, + /// the default 3D camera follows the canvas aspect; an explicit `perspective()` keeps its own + pub fit_canvas: bool, +} + +impl CameraProjection for ProcessingPerspective { + fn get_clip_from_view(&self) -> Mat4 { + Y_FLIP * self.inner.get_clip_from_view() + } + + fn get_clip_from_view_for_sub(&self, sub_view: &bevy::camera::SubCameraView) -> Mat4 { + Y_FLIP * self.inner.get_clip_from_view_for_sub(sub_view) + } + + fn update(&mut self, width: f32, height: f32) { + if self.fit_canvas { + self.inner.update(width, height); + } + } + + fn far(&self) -> f32 { + self.inner.far() + } + + fn get_frustum_corners(&self, z_near: f32, z_far: f32) -> [Vec3A; 8] { + // the frustum is symmetric about the view axis, so the flip leaves the corner set as is + self.inner.get_frustum_corners(z_near, z_far) + } +} + pub fn create( In((width, height, surface_entity, texture_format)): In<(u32, u32, Entity, TextureFormat)>, mut commands: Commands, @@ -203,7 +257,8 @@ pub fn create( let mut entity_commands = commands.spawn(( Camera3d::default(), Camera { - // always load the previous frame (provides sketch like behavior) + // the previous frame is kept unless a pass opens with `background()`; see + // `flush_draw_commands` clear_color: ClearColorConfig::None, msaa_writeback: MsaaWriteback::Auto, ..default() @@ -217,6 +272,7 @@ pub fn create( render_layer, CommandBuffer::new(), RenderState::default(), + crate::image::BackgroundBlit::default(), crate::color::ColorMode::default(), SurfaceSize(width, height), Graphics { @@ -315,18 +371,23 @@ pub fn mode_3d( .get_mut(entity) .map_err(|_| ProcessingError::GraphicsNotFound)?; - *projection = Projection::Perspective(PerspectiveProjection { - fov, - aspect_ratio: aspect, - near, - far, - near_clip_plane, + *projection = Projection::custom(ProcessingPerspective { + inner: PerspectiveProjection { + fov, + aspect_ratio: aspect, + near, + far, + near_clip_plane, + }, + fit_canvas: true, }); let mut transform = transforms .get_mut(entity) .map_err(|_| ProcessingError::GraphicsNotFound)?; + // origin at the canvas center, +z toward the viewer; the projection's y flip makes +y + // point down the screen *transform = Transform::from_xyz(0.0, 0.0, camera_z).looking_at(Vec3::ZERO, Vec3::Y); Ok(()) @@ -358,28 +419,16 @@ pub fn mode_2d( } pub fn perspective( - In(( - entity, - PerspectiveProjection { - fov, - aspect_ratio, - near, - far, - near_clip_plane, - }, - )): In<(Entity, PerspectiveProjection)>, + In((entity, inner)): In<(Entity, PerspectiveProjection)>, mut projections: Query<&mut Projection>, ) -> Result<()> { let mut projection = projections .get_mut(entity) .map_err(|_| ProcessingError::GraphicsNotFound)?; - *projection = Projection::Perspective(PerspectiveProjection { - fov, - aspect_ratio, - near, - far, - near_clip_plane, + *projection = Projection::custom(ProcessingPerspective { + inner, + fit_canvas: false, }); Ok(()) @@ -412,13 +461,14 @@ pub fn ortho( .get_mut(entity) .map_err(|_| ProcessingError::GraphicsNotFound)?; - // we need a custom projection to support processing's coordinate system - // but this is in effect an orthographic projection with the given bounds *projection = Projection::custom(ProcessingProjection { - width: right - left, - height: top - bottom, + left, + right, + bottom, + top, near, far, + fit_canvas: false, }); Ok(()) @@ -579,7 +629,16 @@ pub fn screen_point( pub fn flush(app: &mut App, entity: Entity) -> Result<()> { graphics_mut!(app, entity).insert(Flush); - app.update(); + // a mid-frame `background()` leaves the rest of the commands for another pass + loop { + app.update(); + let pending = graphics_mut!(app, entity) + .get::() + .is_some_and(|buffer| !buffer.commands.is_empty()); + if !pending { + break; + } + } graphics_mut!(app, entity).remove::(); Ok(()) } @@ -588,21 +647,19 @@ pub fn apply_filter(app: &mut App, graphics: Entity, filter: Entity) -> Result<( filter::apply(app, graphics, filter) } +/// Only the pass that drains the command buffer writes to the camera's output +#[derive(Component)] +pub struct Present; + pub fn present(app: &mut App, entity: Entity) -> Result<()> { + graphics_mut!(app, entity).insert(Present); + let result = flush(app, entity); graphics_mut!(app, entity) - .get_mut::() - .ok_or(ProcessingError::GraphicsNotFound)? - .output_mode = CameraOutputMode::Write { - blend_state: None, - clear_color: ClearColorConfig::None, - }; - flush(app, entity)?; - graphics_mut!(app, entity) + .remove::() .get_mut::() .ok_or(ProcessingError::GraphicsNotFound)? .output_mode = CameraOutputMode::Skip; - - Ok(()) + result } /// End the current draw @@ -626,7 +683,7 @@ pub fn warmup(app: &mut App, entity: Entity) -> Result<()> { (entity, DrawCommand::BackgroundColor(DEFAULT_CLEAR_COLOR)), ) .unwrap()?; - flush(app, entity)?; + present(app, entity)?; } Ok(()) } @@ -868,16 +925,18 @@ mod tests { #[test] fn test_processing_projection() { let proj = ProcessingProjection { - width: 800.0, - height: 600.0, near: 0.1, far: 1000.0, + ..ProcessingProjection::new(800.0, 600.0) }; let clip_matrix = proj.get_clip_from_view(); - // Check some values in the matrix to ensure it's correct - // In [0,1] depth orthographic projection, w_axis.z = -near/(far-near) - let expected: f32 = -0.1 / (1000.0 - 0.1); - assert!((clip_matrix.w_axis.z - expected).abs() < 1e-6); + // reverse-z [0,1] depth: the near plane maps to 1 and the far plane to 0 + let ndc_z = |z_view: f32| { + let c = clip_matrix * Vec4::new(0.0, 0.0, z_view, 1.0); + c.z / c.w + }; + assert!((ndc_z(-0.1) - 1.0).abs() < 1e-6); + assert!(ndc_z(-1000.0).abs() < 1e-6); } #[test] @@ -892,3 +951,53 @@ mod tests { assert_eq!(layer1_clone, layer3); } } + +#[cfg(test)] +mod projection_tests { + use super::*; + + /// Reverse-z like bevy's cameras: near maps to NDC 1, far to NDC 0, so GreaterEqual + /// depth compares make nearer draws win. + #[test] + fn processing_projection_is_reverse_z() { + let proj = ProcessingProjection::new(640.0, 360.0); + let clip = proj.get_clip_from_view(); + let ndc = |z_view: f32| { + let c = clip * Vec4::new(0.0, 0.0, z_view, 1.0); + c.z / c.w + }; + assert!((ndc(-proj.far) - 0.0).abs() < 1e-6); + assert!((ndc(-proj.near) - 1.0).abs() < 1e-6); + // the canvas plane (z = 0) sits between them and a layer toward the camera is "nearer" + assert!(ndc(0.0) > ndc(-1.0) && ndc(0.0) < ndc(1.0)); + // top-left of the canvas maps to NDC (-1, 1) + let corner = clip * Vec4::new(0.0, 0.0, 0.0, 1.0); + assert!((corner.x / corner.w + 1.0).abs() < 1e-6 && (corner.y / corner.w - 1.0).abs() < 1e-6); + } + + /// 3D is the same y-down world: a point above the origin (negative y) projects to the top + /// of the screen, +x stays on the right, and nearer points get a larger reverse-z depth. + #[test] + fn processing_perspective_is_y_down_reverse_z() { + let proj = ProcessingPerspective { + inner: PerspectiveProjection { + fov: std::f32::consts::PI / 3.0, + aspect_ratio: 16.0 / 9.0, + near: 1.0, + far: 1000.0, + near_clip_plane: Vec4::new(0.0, 0.0, -1.0, -1.0), + }, + fit_canvas: true, + }; + let clip = proj.get_clip_from_view(); + let ndc = |v: Vec3| { + let c = clip * v.extend(1.0); + c.truncate() / c.w + }; + let up = ndc(Vec3::new(0.0, -10.0, -100.0)); + let right = ndc(Vec3::new(10.0, 0.0, -100.0)); + assert!(up.y > 0.0, "negative world y must be screen-up, got {up}"); + assert!(right.x > 0.0, "positive world x must be screen-right, got {right}"); + assert!(ndc(Vec3::new(0.0, 0.0, -10.0)).z > ndc(Vec3::new(0.0, 0.0, -100.0)).z); + } +} diff --git a/crates/processing_render/src/image.rs b/crates/processing_render/src/image.rs index 4945b3b5..57072cb8 100644 --- a/crates/processing_render/src/image.rs +++ b/crates/processing_render/src/image.rs @@ -12,7 +12,8 @@ use bevy::{ image::{ImageAddressMode, ImageFilterMode, ImageSampler, ImageSamplerDescriptor}, prelude::*, render::{ - RenderApp, + Render, RenderApp, RenderSystems, + extract_component::{ExtractComponent, ExtractComponentPlugin}, render_asset::RenderAssets, render_resource::{ Buffer, BufferDescriptor, BufferUsages, CommandEncoderDescriptor, Extent3d, MapMode, @@ -21,6 +22,7 @@ use bevy::{ }, renderer::{RenderDevice, RenderQueue}, texture::GpuImage, + view::ViewTarget, }, }; use half::f16; @@ -32,12 +34,82 @@ pub struct ImagePlugin; impl Plugin for ImagePlugin { fn build(&self, app: &mut App) { + app.add_plugins(ExtractComponentPlugin::::default()); if let Some(render_app) = app.get_sub_app_mut(RenderApp) { render_app.init_resource::(); + render_app.add_systems(Render, blit_backgrounds.in_set(RenderSystems::Prepare)); } } } +/// The image a `background(img)` paints over this camera's target before its next pass +#[derive(Component, Clone, Default, ExtractComponent)] +pub struct BackgroundBlit(pub Option>); + +/// `background(img)` applies to one pass only +pub fn clear_background_blits(mut blits: Query<&mut BackgroundBlit>) { + for mut blit in &mut blits { + if blit.0.is_some() { + blit.0 = None; + } + } +} + +/// Clears each view target with a pending background image, then alpha-blends the image over +/// it like Processing's `set(0, 0, img)`; the pass loads the result +fn blit_backgrounds( + views: Query<(&ViewTarget, &BackgroundBlit)>, + render_device: Res, + render_queue: Res, + gpu_images: Res>, + mut cache: ResMut, +) { + let device = render_device.wgpu_device(); + let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("processing_background_blit"), + }); + let mut pending = false; + for (target, blit) in &views { + let Some(handle) = &blit.0 else { continue }; + pending = true; + let dst: &wgpu::TextureView = target.main_texture_view(); + clear_view(&mut encoder, dst); + // an image still loading leaves the clear alone + if let Some(src) = gpu_images.get(handle) { + cache.copy( + device, + &mut encoder, + &src.texture_view, + dst, + target.main_texture_format(), + true, + ); + } + } + if pending { + render_queue.submit(std::iter::once(encoder.finish())); + } +} + +fn clear_view(encoder: &mut wgpu::CommandEncoder, view: &wgpu::TextureView) { + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("processing_background_clear"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view, + depth_slice: None, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + multiview_mask: None, + }); +} + /// Where a blit reads its source pixels: another image, or a graphics render /// target (via its render-world `ViewTarget`). pub enum BlitSource { @@ -45,11 +117,37 @@ pub enum BlitSource { Graphics(Entity), } -/// Caches one `wgpu::util::TextureBlitter` per destination texture format. Lives +/// Caches one `wgpu::util::TextureBlitter` per destination format and blend. Lives /// in the render world; blitters are cheap to reuse and expensive to rebuild. #[derive(Resource, Default)] pub struct BlitterCache { - blitters: std::collections::HashMap, + blitters: std::collections::HashMap<(TextureFormat, bool), wgpu::util::TextureBlitter>, +} + +impl BlitterCache { + /// Draws `src` over all of `dst`, which has `format`; `blend` alpha-blends instead of replacing + pub fn copy( + &mut self, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + src: &wgpu::TextureView, + dst: &wgpu::TextureView, + format: TextureFormat, + blend: bool, + ) { + let blitter = self.blitters.entry((format, blend)).or_insert_with(|| { + let builder = wgpu::util::TextureBlitterBuilder::new(device, format); + if blend { + builder + .sample_type(wgpu::FilterMode::Linear) + .blend_state(wgpu::BlendState::ALPHA_BLENDING) + .build() + } else { + builder.build() + } + }); + blitter.copy(device, encoder, src, dst); + } } /// Blit `source` into the destination image (a sampling copy: handles differing @@ -87,15 +185,10 @@ pub fn blit( }; let device = render_device.wgpu_device(); - let blitter = cache - .blitters - .entry(format) - .or_insert_with(|| wgpu::util::TextureBlitter::new(device, format)); - let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("processing_blit"), }); - blitter.copy(device, &mut encoder, src_view, dst_view); + cache.copy(device, &mut encoder, src_view, dst_view, format, false); render_queue.submit(std::iter::once(encoder.finish())); Ok(()) } diff --git a/crates/processing_render/src/material/custom.rs b/crates/processing_render/src/material/custom.rs index bc9535cb..44716d3f 100644 --- a/crates/processing_render/src/material/custom.rs +++ b/crates/processing_render/src/material/custom.rs @@ -64,17 +64,19 @@ struct CustomMaterialKey { } fn specialize( - key: &dyn Any, + _pipeline: &dyn Any, descriptor: &mut RenderPipelineDescriptor, _layout: &MeshVertexBufferLayoutRef, - _pipeline_key: ErasedMaterialPipelineKey, + pipeline_key: ErasedMaterialPipelineKey, ) -> std::result::Result<(), SpecializedMeshPipelineError> { - if let Some(key) = key.downcast_ref::() { - crate::material::apply_pipeline_state(descriptor, key.blend_state, key.depth_write); - if let Some(double_sided) = key.double_sided { - descriptor.primitive.cull_mode = if double_sided { None } else { Some(Face::Back) }; - } - } + // the first argument is bevy's `MaterialPipeline`; the material key rides in the pipeline key + let key: CustomMaterialKey = pipeline_key.material_key.to_key(); + crate::material::apply_pipeline_state(descriptor, key.blend_state, key.depth_write); + // two-sided unless asked otherwise, like every other mewnala material + descriptor.primitive.cull_mode = match key.double_sided { + Some(false) => Some(Face::Back), + _ => None, + }; Ok(()) } diff --git a/crates/processing_render/src/material/mod.rs b/crates/processing_render/src/material/mod.rs index f449ab7d..aeabbaa8 100644 --- a/crates/processing_render/src/material/mod.rs +++ b/crates/processing_render/src/material/mod.rs @@ -429,11 +429,19 @@ impl MaterialExtension for ProcessingMaterial { } } +/// The projection's y flip (`graphics::Y_FLIP`) mirrors triangle winding, so clockwise is the +/// front face; keeps `cull_mode` and `double_sided` lighting correct. A shadow pass rendered +/// from a light's view would need the default winding instead. +pub(crate) fn apply_processing_winding(descriptor: &mut RenderPipelineDescriptor) { + descriptor.primitive.front_face = bevy::render::render_resource::FrontFace::Cw; +} + pub(crate) fn apply_pipeline_state( descriptor: &mut RenderPipelineDescriptor, blend_state: Option, depth_write: Option, ) { + apply_processing_winding(descriptor); if let Some(blend_state) = blend_state && let Some(fragment_state) = &mut descriptor.fragment { diff --git a/crates/processing_render/src/particles/material.rs b/crates/processing_render/src/particles/material.rs index 90b55a98..273880c0 100644 --- a/crates/processing_render/src/particles/material.rs +++ b/crates/processing_render/src/particles/material.rs @@ -66,6 +66,7 @@ impl MaterialExtension for ParticlesExtension { _layout: &MeshVertexBufferLayoutRef, key: MaterialExtensionKey, ) -> Result<(), SpecializedMeshPipelineError> { + crate::material::apply_processing_winding(descriptor); if let Some(ref mut fragment) = descriptor.fragment { if key.bind_group_data.has_albedo { fragment.shader_defs.push("HAS_COLORS".into()); diff --git a/crates/processing_render/src/particles/point_render.rs b/crates/processing_render/src/particles/point_render.rs index b82ea6e3..b5483e8d 100644 --- a/crates/processing_render/src/particles/point_render.rs +++ b/crates/processing_render/src/particles/point_render.rs @@ -114,6 +114,7 @@ impl Specializer for RasterSpecializer { descriptor.multisample.count = key.samples; let topology = Topology::from_u8(key.topology).unwrap_or(Topology::PointList); descriptor.primitive.topology = topology.to_primitive_topology(); + crate::material::apply_processing_winding(descriptor); let mut defs: Vec<&str> = Vec::new(); if key.has_color { diff --git a/crates/processing_render/src/render/material.rs b/crates/processing_render/src/render/material.rs index d6ab6e4f..4086883c 100644 --- a/crates/processing_render/src/render/material.rs +++ b/crates/processing_render/src/render/material.rs @@ -28,6 +28,8 @@ pub enum MaterialKey { base_color_texture: Option>, uv_transform: Affine2, blend_state: Option, + /// blend even with an opaque albedo (e.g. translucent vertex colors) + transparent: bool, }, Custom { entity: Entity, @@ -43,6 +45,7 @@ pub struct PbrFields { pub base_color_texture: Option>, pub uv_transform: Affine2, pub blend_state: Option, + pub transparent: bool, } impl Default for PbrFields { @@ -55,6 +58,7 @@ impl Default for PbrFields { base_color_texture: None, uv_transform: Affine2::IDENTITY, blend_state: None, + transparent: false, } } } @@ -69,6 +73,7 @@ impl From for MaterialKey { base_color_texture: f.base_color_texture, uv_transform: f.uv_transform, blend_state: f.blend_state, + transparent: f.transparent, } } } @@ -84,8 +89,10 @@ impl MaterialKey { base_color_texture, uv_transform, blend_state, + transparent, } => PbrFields { albedo: *albedo, + transparent: *transparent, roughness: *roughness, metallic: *metallic, emissive: *emissive, @@ -97,6 +104,30 @@ impl MaterialKey { } } + /// The same key, but rendered in the blended phase (translucent vertex colors). Custom + /// materials own their blend state and are returned unchanged. + pub fn transparent(self) -> MaterialKey { + match self { + MaterialKey::Color { + background_image, + uv_transform, + blend_state, + .. + } => MaterialKey::Color { + transparent: true, + background_image, + uv_transform, + blend_state, + }, + MaterialKey::Pbr { .. } => { + let mut pbr = self.as_pbr(); + pbr.transparent = true; + pbr.into() + } + custom => custom, + } + } + pub fn blend_state(&self) -> Option { match self { MaterialKey::Color { blend_state, .. } => *blend_state, @@ -132,7 +163,8 @@ impl MaterialKey { emissive, base_color_texture, uv_transform, - .. + blend_state, + transparent, } => { let base_color = Color::srgba( albedo[0] as f32 / 255.0, @@ -144,6 +176,11 @@ impl MaterialKey { base_color, unlit: false, cull_mode: None, + alpha_mode: if blend_state.is_some() || albedo[3] < 255 || *transparent { + AlphaMode::Blend + } else { + AlphaMode::Opaque + }, perceptual_roughness: *roughness as f32 / 255.0, metallic: *metallic as f32 / 255.0, emissive: LinearRgba::new( @@ -164,9 +201,11 @@ impl MaterialKey { pub fn to_material( &self, materials: &mut ResMut>, + depth_bias: f32, ) -> UntypedHandle { let blend_state = self.blend_state(); - let base = self.to_standard_material(); + let mut base = self.to_standard_material(); + base.depth_bias = depth_bias; let extended = ProcessingExtendedMaterial { base, extension: ProcessingMaterial { diff --git a/crates/processing_render/src/render/mod.rs b/crates/processing_render/src/render/mod.rs index 0e797032..aec46602 100644 --- a/crates/processing_render/src/render/mod.rs +++ b/crates/processing_render/src/render/mod.rs @@ -8,11 +8,13 @@ pub mod transform; use bevy::{ camera::{ + CameraOutputMode, ClearColorConfig, primitives::Aabb, visibility::{NoFrustumCulling, RenderLayers}, }, - ecs::system::SystemParam, - math::{Affine2, Affine3A, Mat4, Vec3A, Vec4}, + camera::Camera3dDepthLoadOp, + ecs::{query::Has, system::SystemParam}, + math::{Affine2, Affine3A, Vec3A}, pbr::gpu_instance_batch::GpuBatchedMesh3d, prelude::*, render::render_resource::BlendState, @@ -87,6 +89,8 @@ pub struct RenderState { pub style: StyleStack, pub transform: TransformStack, pub shape_builder: Option, + /// Like Processing, every frame starts with a fresh depth buffer + pub clear_depth: bool, } impl RenderState { @@ -95,6 +99,7 @@ impl RenderState { style: StyleStack::new(), transform: TransformStack::new(), shape_builder: None, + clear_depth: true, } } @@ -108,6 +113,7 @@ impl RenderState { self.transform = TransformStack::new(); self.style.clear_saved(); self.shape_builder = None; + self.clear_depth = true; } pub fn fill_is_transparent(&self) -> bool { @@ -140,8 +146,10 @@ pub fn flush_draw_commands( &mut CommandBuffer, &mut RenderState, &RenderLayers, - &Projection, - &Transform, + &mut Camera, + &mut Camera3d, + &mut crate::image::BackgroundBlit, + Has, ), With, >, @@ -161,9 +169,25 @@ pub fn flush_draw_commands( )>, >, ) { - for (graphics_entity, mut cmd_buffer, mut state, render_layers, projection, camera_transform) in - graphics.iter_mut() + for ( + graphics_entity, + mut cmd_buffer, + mut state, + render_layers, + mut camera, + mut camera_3d, + mut background_blit, + presents, + ) in graphics.iter_mut() { + // color is kept unless `background()` opens the pass; depth is kept only within a frame + camera.clear_color = ClearColorConfig::None; + camera_3d.depth_load_op = if std::mem::take(&mut state.clear_depth) { + Camera3dDepthLoadOp::Clear(0.0) + } else { + Camera3dDepthLoadOp::Load + }; + for (raster_entity, raster_layers) in p_raster_draws.iter() { if raster_layers.intersects(render_layers) { res.commands @@ -172,13 +196,15 @@ pub fn flush_draw_commands( } } - let clip_from_view = projection.get_clip_from_view(); - let view_from_world = camera_transform.to_matrix().inverse(); - let world_from_clip = (clip_from_view * view_from_world).inverse(); let draw_commands = std::mem::take(&mut cmd_buffer.commands); let mut batch = BatchState::new(graphics_entity, render_layers.clone()); + let mut pending = draw_commands.into_iter(); + let mut drained = true; - for cmd in draw_commands { + while let Some(cmd) = pending.next() { + // check whether we are the first flush after a present + let opens_pass = + |batch: &BatchState| batch.draw_index == 0 && batch.current_mesh.is_none(); match cmd { DrawCommand::Fill(color) => { state.style.fill = Fill::Color(color); @@ -847,57 +873,27 @@ pub fn flush_draw_commands( flush_batch(&mut res, &mut batch, &p_material_handles); } DrawCommand::BackgroundColor(color) => { - flush_batch(&mut res, &mut batch, &p_material_handles); - - let mesh = create_ndc_background_quad(world_from_clip, color, false); - let mesh_handle = res.meshes.add(mesh); - - let material_key = MaterialKey::Color { - transparent: color.alpha() < 1.0, - background_image: None, - uv_transform: Affine2::IDENTITY, - blend_state: Some(BlendState::REPLACE), - }; - let material_handle = material_key.to_material(&mut res.materials); - - res.commands.spawn(( - Mesh3d(mesh_handle), - UntypedMaterial(material_handle), - BelongsToGraphics(batch.graphics_entity), - Transform::IDENTITY, - batch.render_layers.clone(), - )); - - batch.draw_index += 1; + if !opens_pass(&batch) { + cmd_buffer.commands = std::iter::once(cmd).chain(pending).collect(); + drained = false; + break; + } + camera.clear_color = ClearColorConfig::Custom(color); + camera_3d.depth_load_op = Camera3dDepthLoadOp::Clear(0.0); } DrawCommand::BackgroundImage(entity) => { let Some(p_image) = p_images.get(entity).ok() else { warn!("Could not find PImage for entity {:?}", entity); continue; }; - - flush_batch(&mut res, &mut batch, &p_material_handles); - - let mesh = create_ndc_background_quad(world_from_clip, Color::WHITE, true); - let mesh_handle = res.meshes.add(mesh); - - let material_key = MaterialKey::Color { - transparent: false, - background_image: Some(p_image.handle.clone()), - uv_transform: Affine2::IDENTITY, - blend_state: Some(BlendState::REPLACE), - }; - let material_handle = material_key.to_material(&mut res.materials); - - res.commands.spawn(( - Mesh3d(mesh_handle), - UntypedMaterial(material_handle), - BelongsToGraphics(batch.graphics_entity), - Transform::IDENTITY, - batch.render_layers.clone(), - )); - - batch.draw_index += 1; + if !opens_pass(&batch) { + cmd_buffer.commands = std::iter::once(cmd).chain(pending).collect(); + drained = false; + break; + } + // the image is blitted over the target before the pass, which loads it + camera_3d.depth_load_op = Camera3dDepthLoadOp::Clear(0.0); + background_blit.0 = Some(p_image.handle.clone()); } DrawCommand::PushMatrix => state.transform.push(), DrawCommand::PopMatrix => state.transform.pop(), @@ -918,7 +914,10 @@ pub fn flush_draw_commands( continue; }; - let material_key = material_key_with_fill(&state); + let mut material_key = material_key_with_fill(&state); + if geometry.translucent { + material_key = material_key.transparent(); + } let material_handle = match &material_key { MaterialKey::Custom { entity: mat_entity, @@ -934,12 +933,13 @@ pub fn flush_draw_commands( *blend_state, ) } - _ => material_key.to_material(&mut res.materials), + _ => material_key + .to_material(&mut res.materials, sort_bias(batch.draw_index)), }; flush_batch(&mut res, &mut batch, &p_material_handles); - let z_offset = -(batch.draw_index as f32 * BATCH_INDEX_STEP); + let z_offset = layer_z(batch.draw_index); let mut transform = state.transform.to_bevy_transform(); // if the "source" geometry was parented in a gltf scene, we need to make sure that @@ -1090,7 +1090,8 @@ pub fn flush_draw_commands( *blend_state, ) } - _ => material_key.to_material(&mut res.materials), + _ => material_key + .to_material(&mut res.materials, sort_bias(batch.draw_index)), } }; @@ -1391,6 +1392,17 @@ pub fn flush_draw_commands( } flush_batch(&mut res, &mut batch, &p_material_handles); + + // a pass cut short by a mid-frame `background()` is wiped by the next one, so it + // must not reach the window + camera.output_mode = if presents && drained { + CameraOutputMode::Write { + blend_state: None, + clear_color: ClearColorConfig::None, + } + } else { + CameraOutputMode::Skip + }; } } @@ -1443,7 +1455,7 @@ fn spawn_mesh( }; clone_custom_material_with_blend(&mut res.custom_materials, &untyped.0, *blend_state) } - _ => key.to_material(&mut res.materials), + _ => key.to_material(&mut res.materials, sort_bias(batch.draw_index)), }; res.commands.spawn(( @@ -1614,7 +1626,7 @@ fn flush_batch( material_handles: &Query<&UntypedMaterial>, ) { if let Some(mesh) = batch.current_mesh.take() { - let z_offset = -(batch.draw_index as f32 * BATCH_INDEX_STEP); + let z_offset = layer_z(batch.draw_index); spawn_mesh(res, batch, mesh, z_offset, material_handles); batch.draw_index += 1; } @@ -1649,16 +1661,17 @@ fn add_shape3d( // TODO: in 2d, we use vertex colors. `to_material` becomes complicated if we also encode // a base color in the material, so for simplicity we just create a new material here // that is unlit and uses the fill color as the base color - MaterialKey::Color { transparent, .. } => { + MaterialKey::Color { .. } => { let base = StandardMaterial { base_color: fill_color, unlit: true, cull_mode: None, - alpha_mode: if state.style.blend_state.is_some() || *transparent { + alpha_mode: if state.style.blend_state.is_some() || state.fill_is_transparent() { AlphaMode::Blend } else { AlphaMode::Opaque }, + depth_bias: sort_bias(batch.draw_index), ..default() }; let extended = ProcessingExtendedMaterial { @@ -1672,11 +1685,11 @@ fn add_shape3d( } _ => { let key = material_key_with_fill(state); - key.to_material(&mut res.materials) + key.to_material(&mut res.materials, sort_bias(batch.draw_index)) } }; - let z_offset = -(batch.draw_index as f32 * BATCH_INDEX_STEP); + let z_offset = layer_z(batch.draw_index); let mut transform = state.transform.to_bevy_transform(); transform.translation.z += z_offset; @@ -1704,51 +1717,13 @@ fn add_shape3d( batch.draw_index += 1; } -/// fullscreen quad built by transforming NDC corners by the inverse clip-from-world matrix, -/// so the vertex shader's `clip_from_world` brings them back to NDC. -fn create_ndc_background_quad(world_from_clip: Mat4, color: Color, with_uvs: bool) -> Mesh { - use bevy::asset::RenderAssetUsages; - use bevy::mesh::{Indices, PrimitiveTopology}; - - let ndc_z = f32::EPSILON; - let ndc_corners = [ - Vec4::new(-1.0, -1.0, ndc_z, 1.0), // bl - Vec4::new(1.0, -1.0, ndc_z, 1.0), // br - Vec4::new(1.0, 1.0, ndc_z, 1.0), // tr - Vec4::new(-1.0, 1.0, ndc_z, 1.0), // tl - ]; - - let world_positions: Vec<[f32; 3]> = ndc_corners - .iter() - .map(|ndc| { - let world = world_from_clip * *ndc; - [world.x / world.w, world.y / world.w, world.z / world.w] - }) - .collect(); - - let uvs: Vec<[f32; 2]> = vec![ - [0.0, 1.0], // bl - [1.0, 1.0], // br - [1.0, 0.0], // tr - [0.0, 0.0], // tl - ]; - - let color_array: [f32; 4] = color.to_linear().to_f32_array(); - let colors: Vec<[f32; 4]> = vec![color_array; 4]; - - let indices: Vec = vec![0, 1, 2, 0, 2, 3]; - - let mut mesh = Mesh::new( - PrimitiveTopology::TriangleList, - RenderAssetUsages::default(), - ); - - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, world_positions); - mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, colors); - if with_uvs { - mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - } - mesh.insert_indices(Indices::U32(indices)); +/// Each draw gets its own world-z layer, growing toward the default camera +fn layer_z(draw_index: u32) -> f32 { + draw_index as f32 * BATCH_INDEX_STEP +} - mesh +/// Tiebreak for the blended phase's depth sort +fn sort_bias(draw_index: u32) -> f32 { + draw_index as f32 * 1e-6 } + From 18cb961a1266cc82aa644fad9bee27d7504154a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Mon, 9 Nov 2026 14:33:56 -0800 Subject: [PATCH 2/3] Fix all the other examples. --- assets/shaders/custom_material.wesl | 2 +- assets/shaders/gen_colored_surface.wesl | 4 +- assets/shaders/gen_surface.wesl | 2 +- assets/shaders/particles_emit_gpu_spawn.wesl | 2 +- assets/shaders/particles_lifecycle_aging.wesl | 2 +- assets/shaders/plexus_curve.wesl | 2 +- .../processing_pyo3/examples/animated_mesh.py | 6 +- crates/processing_pyo3/examples/box.py | 4 +- .../examples/camera_controllers.py | 4 +- .../processing_pyo3/examples/flocking_duck.py | 2 +- .../processing_pyo3/examples/flocking_gpu.py | 12 ++-- .../examples/geometry_methods.py | 6 +- crates/processing_pyo3/examples/gltf_load.py | 4 +- crates/processing_pyo3/examples/lights.py | 8 +-- crates/processing_pyo3/examples/materials.py | 2 +- .../examples/particles_animated.py | 2 +- .../examples/particles_basic.py | 2 +- .../examples/particles_density.py | 2 +- .../examples/particles_emit.py | 4 +- .../examples/particles_emit_gpu.py | 8 +-- .../examples/particles_from_mesh.py | 2 +- .../examples/particles_gpu_surface.py | 2 +- .../examples/particles_gpu_surface_lit.py | 2 +- .../examples/particles_lifecycle.py | 4 +- .../examples/particles_lines.py | 4 +- .../examples/particles_lissajous.py | 2 +- .../examples/particles_noise.py | 2 +- .../examples/particles_plexus.py | 2 +- .../examples/particles_points.py | 2 +- .../examples/particles_scatter_volume.py | 4 +- .../examples/particles_sphere.py | 2 +- .../examples/particles_stress.py | 4 +- .../examples/particles_surface.py | 4 +- .../processing_pyo3/examples/primitives_3d.py | 4 +- crates/processing_render/src/gltf.rs | 70 ++++++++++++++++++- crates/processing_render/src/graphics.rs | 9 ++- crates/processing_render/src/render/mod.rs | 5 +- examples/animated_mesh.rs | 6 +- examples/box.rs | 4 +- examples/camera_controllers.rs | 4 +- examples/custom_attribute.rs | 6 +- examples/custom_material.rs | 4 +- examples/gltf_load.rs | 4 +- examples/lights.rs | 8 +-- examples/materials.rs | 6 +- examples/particles_animated.rs | 2 +- examples/particles_colored.rs | 4 +- examples/particles_colored_pbr.rs | 4 +- examples/particles_emit.rs | 4 +- examples/particles_emit_gpu.rs | 10 +-- examples/particles_from_mesh.rs | 2 +- examples/particles_lifecycle.rs | 6 +- examples/particles_noise.rs | 2 +- examples/particles_oriented.rs | 4 +- examples/particles_scatter.rs | 4 +- examples/particles_scatter_volume.rs | 4 +- examples/particles_stress.rs | 6 +- examples/particles_text_whirl.rs | 2 +- examples/pbr.rs | 6 +- examples/primitives_3d.rs | 4 +- examples/stroke_3d.rs | 10 +-- examples/text_3d.rs | 4 +- 62 files changed, 196 insertions(+), 128 deletions(-) diff --git a/assets/shaders/custom_material.wesl b/assets/shaders/custom_material.wesl index cc67c350..cf2a2417 100644 --- a/assets/shaders/custom_material.wesl +++ b/assets/shaders/custom_material.wesl @@ -8,7 +8,7 @@ fn fragment(mesh: VertexOutput) -> @location(0) vec4 { let p = mesh.world_position.xyz * 0.02 + globals.time * 0.1; let n = snoise33(p) * 0.5 + 0.5; - let light_dir = normalize(vec3(0.5, 1.0, 0.3)); + let light_dir = normalize(vec3(0.5, -1.0, 0.3)); let diffuse = max(dot(normalize(mesh.world_normal), light_dir), 0.15); return vec4(n * diffuse, 1.0) * color; diff --git a/assets/shaders/gen_colored_surface.wesl b/assets/shaders/gen_colored_surface.wesl index aba05674..ff5ad26c 100644 --- a/assets/shaders/gen_colored_surface.wesl +++ b/assets/shaders/gen_colored_surface.wesl @@ -33,7 +33,7 @@ fn main(@builtin(global_invocation_id) gid: vec3) { let h = height(x, z, t); position[i * 3u + 0u] = x; - position[i * 3u + 1u] = h; + position[i * 3u + 1u] = -h; position[i * 3u + 2u] = z; let e = 0.12; @@ -41,7 +41,7 @@ fn main(@builtin(global_invocation_id) gid: vec3) { let hr = height(x + e, z, t); let hd = height(x, z - e, t); let hu = height(x, z + e, t); - let n = normalize(vec3(hl - hr, 2.0 * e, hd - hu)); + let n = normalize(vec3(hl - hr, -2.0 * e, hd - hu)); normal[i * 3u + 0u] = n.x; normal[i * 3u + 1u] = n.y; normal[i * 3u + 2u] = n.z; diff --git a/assets/shaders/gen_surface.wesl b/assets/shaders/gen_surface.wesl index 7932c72f..cda5a203 100644 --- a/assets/shaders/gen_surface.wesl +++ b/assets/shaders/gen_surface.wesl @@ -40,7 +40,7 @@ fn main(@builtin(global_invocation_id) gid: vec3) { h = h + 0.25 * h * abs(h); position[i * 3u + 0u] = x; - position[i * 3u + 1u] = h; + position[i * 3u + 1u] = -h; position[i * 3u + 2u] = z; if gx + 1u < nx && gy + 1u < ny { diff --git a/assets/shaders/particles_emit_gpu_spawn.wesl b/assets/shaders/particles_emit_gpu_spawn.wesl index 15d8f2a4..6e517dc2 100644 --- a/assets/shaders/particles_emit_gpu_spawn.wesl +++ b/assets/shaders/particles_emit_gpu_spawn.wesl @@ -39,7 +39,7 @@ fn main(@builtin(global_invocation_id) gid: vec3) { let theta = hash_unit(seed) * 6.2831853; let r = sqrt(hash_unit(seed * 2u + 1u)); let dirxz = vec2(cos(theta), sin(theta)) * r; - let dy = 0.7 + 0.3 * hash_unit(seed * 3u + 7u); + let dy = -(0.7 + 0.3 * hash_unit(seed * 3u + 7u)); let v = vec3(dirxz.x, dy, dirxz.y) * spawn.speed.x; position[slot * 3u + 0u] = spawn.pos.x; diff --git a/assets/shaders/particles_lifecycle_aging.wesl b/assets/shaders/particles_lifecycle_aging.wesl index 4ef6816d..2c218262 100644 --- a/assets/shaders/particles_lifecycle_aging.wesl +++ b/assets/shaders/particles_lifecycle_aging.wesl @@ -19,7 +19,7 @@ fn main(@builtin(global_invocation_id) gid: vec3) { } age[i] = age[i] + dt; - position[i * 3u + 1u] = position[i * 3u + 1u] - dt * 1.5; + position[i * 3u + 1u] = position[i * 3u + 1u] + dt * 1.5; let remaining = clamp(1.0 - age[i] / ttl, 0.0, 1.0); let s = remaining * remaining; diff --git a/assets/shaders/plexus_curve.wesl b/assets/shaders/plexus_curve.wesl index 3885facc..92868f89 100644 --- a/assets/shaders/plexus_curve.wesl +++ b/assets/shaders/plexus_curve.wesl @@ -30,7 +30,7 @@ fn main(@builtin(global_invocation_id) gid: vec3) { sin(params.fz * t + params.time * 0.23), ) * params.scale; position[i * 3u + 0u] = world.x; - position[i * 3u + 1u] = world.y; + position[i * 3u + 1u] = -world.y; position[i * 3u + 2u] = world.z; let rainbow = hsv2rgb(vec3(fract(u + params.time * 0.03), 0.75, 1.0)); diff --git a/crates/processing_pyo3/examples/animated_mesh.py b/crates/processing_pyo3/examples/animated_mesh.py index b0c55690..44030f72 100644 --- a/crates/processing_pyo3/examples/animated_mesh.py +++ b/crates/processing_pyo3/examples/animated_mesh.py @@ -17,7 +17,7 @@ def setup(): px = x * spacing - offset pz = z * spacing - offset geometry.color(x/grid_size, 0.5, z/grid_size, 1.0) - geometry.normal(0.0, 1.0, 0.0) + geometry.normal(0.0, -1.0, 0.0) geometry.vertex(px, 0.0, pz) for z in range(grid_size-1): @@ -43,7 +43,7 @@ def draw(): global spacing global time - camera_position(150.0, 150.0, 150.0) + camera_position(150.0, -150.0, 150.0) camera_look_at( 0.0, 0.0, 0.0) background(220, 200, 140) @@ -53,7 +53,7 @@ def draw(): px = x * spacing - offset pz = z * spacing - offset wave = sin(px * 0.1 + time) * cos(pz * 0.1 + time) * 20.0 - geometry.set_vertex(idx, px, wave, pz) + geometry.set_vertex(idx, px, -wave, pz) draw_geometry(geometry) diff --git a/crates/processing_pyo3/examples/box.py b/crates/processing_pyo3/examples/box.py index 6fdd15ef..337bb5f1 100644 --- a/crates/processing_pyo3/examples/box.py +++ b/crates/processing_pyo3/examples/box.py @@ -8,12 +8,12 @@ def setup(): def draw(): global angle - camera_position(100.0, 100.0, 300.0) + camera_position(100.0, -100.0, 300.0) camera_look_at(0.0, 0.0, 0.0) background(220) push_matrix() - rotate(angle) + rotate(-angle) box(100.0, 100.0, 100.0) pop_matrix() diff --git a/crates/processing_pyo3/examples/camera_controllers.py b/crates/processing_pyo3/examples/camera_controllers.py index 3f2b6602..b05d6de3 100644 --- a/crates/processing_pyo3/examples/camera_controllers.py +++ b/crates/processing_pyo3/examples/camera_controllers.py @@ -9,7 +9,7 @@ def setup(): orbit_camera() dir_light = directional_light((1.0, 0.98, 0.95), 1500.0) - dir_light.position(300.0, 400.0, 300.0) + dir_light.position(300.0, -400.0, 300.0) dir_light.look_at(0.0, 0.0, 0.0) def draw(): @@ -34,7 +34,7 @@ def draw(): roughness(0.3) metallic(0.8) push_matrix() - rotate(angle) + rotate(-angle) box(100.0, 100.0, 100.0) pop_matrix() else: diff --git a/crates/processing_pyo3/examples/flocking_duck.py b/crates/processing_pyo3/examples/flocking_duck.py index 7541dc21..f2651f4d 100644 --- a/crates/processing_pyo3/examples/flocking_duck.py +++ b/crates/processing_pyo3/examples/flocking_duck.py @@ -121,7 +121,7 @@ def draw(): t = elapsed_time * 0.2 r = extent * 1.1 - camera_position(center[0] + cos(t) * r, center[1] + extent * 0.35, center[2] + sin(t) * r) + camera_position(center[0] + cos(t) * r, center[1] - extent * 0.35, center[2] + sin(t) * r) camera_look_at(center[0], center[1], center[2]) background(10, 12, 18) diff --git a/crates/processing_pyo3/examples/flocking_gpu.py b/crates/processing_pyo3/examples/flocking_gpu.py index 27259cef..60cd763d 100644 --- a/crates/processing_pyo3/examples/flocking_gpu.py +++ b/crates/processing_pyo3/examples/flocking_gpu.py @@ -35,14 +35,14 @@ def boid_geometry(half_width, length, droop): n = (half_width * half_width + droop * droop) ** 0.5 nose = (0.0, 0.0, length * 0.5) tail = (0.0, 0.0, -length * 0.5) - g.normal(-droop / n, half_width / n, 0.0) + g.normal(-droop / n, -half_width / n, 0.0) g.vertex(*nose) - g.vertex(-half_width, -droop, -length * 0.5) + g.vertex(-half_width, droop, -length * 0.5) g.vertex(*tail) - g.normal(droop / n, half_width / n, 0.0) + g.normal(droop / n, -half_width / n, 0.0) g.vertex(*nose) g.vertex(*tail) - g.vertex(half_width, -droop, -length * 0.5) + g.vertex(half_width, droop, -length * 0.5) for i in range(6): g.index(i) return g @@ -131,7 +131,7 @@ def draw(): t = elapsed_time * 0.1 r = BOUND * 2.6 - camera_position(cos(t) * r, BOUND * 0.8, sin(t) * r) + camera_position(cos(t) * r, -BOUND * 0.8, sin(t) * r) camera_look_at(0.0, 0.0, 0.0) background(10, 12, 18) @@ -142,7 +142,7 @@ def draw(): p.apply(INTEGRATE, dt=DT) p.apply(BOUNDS_BOX, aabb_min=[-BOUND] * 3, aabb_max=[BOUND] * 3, mode=2) - p.apply(ORIENT, forward=[0.0, 0.0, 1.0], up=[0.0, 1.0, 0.0]) + p.apply(ORIENT, forward=[0.0, 0.0, 1.0], up=[0.0, -1.0, 0.0]) run() diff --git a/crates/processing_pyo3/examples/geometry_methods.py b/crates/processing_pyo3/examples/geometry_methods.py index 1e4c942a..53081d50 100644 --- a/crates/processing_pyo3/examples/geometry_methods.py +++ b/crates/processing_pyo3/examples/geometry_methods.py @@ -13,13 +13,13 @@ def setup(): geometry.normal(0.0, 0.0, 1.0) geometry.uv(0.0, 0.0) - geometry.vertex(-80.0, -80.0, 0.0) + geometry.vertex(-80.0, 80.0, 0.0) geometry.uv(1.0, 0.0) - geometry.vertex(80.0, -80.0, 0.0) + geometry.vertex(80.0, 80.0, 0.0) geometry.uv(0.5, 1.0) - geometry.vertex(0.0, 80.0, 0.0) + geometry.vertex(0.0, -80.0, 0.0) geometry.index(0) geometry.index(1) diff --git a/crates/processing_pyo3/examples/gltf_load.py b/crates/processing_pyo3/examples/gltf_load.py index 141badce..bfef7ec9 100644 --- a/crates/processing_pyo3/examples/gltf_load.py +++ b/crates/processing_pyo3/examples/gltf_load.py @@ -25,10 +25,10 @@ def draw(): radius = 1.5 lx = math.cos(t) * radius - ly = 1.5 + ly = -1.5 lz = math.sin(t) * radius light.position(lx, ly, lz) - light.look_at(0.0, 0.8, 0.0) + light.look_at(0.0, -0.8, 0.0) r = math.sin(t * 8.0) * 0.5 + 0.5 g = math.sin(t * 8.0 + 2.0) * 0.5 + 0.5 diff --git a/crates/processing_pyo3/examples/lights.py b/crates/processing_pyo3/examples/lights.py index ca33f6e1..1abdf982 100644 --- a/crates/processing_pyo3/examples/lights.py +++ b/crates/processing_pyo3/examples/lights.py @@ -11,11 +11,11 @@ def setup(): # Point Lights point_light_a = point_light((1.0, 0.5, 0.25), 1000000.0, 200.0, 0.5) - point_light_a.position(-25.0, 5.0, 51.0) + point_light_a.position(-25.0, -5.0, 51.0) point_light_a.look_at(0.0, 0.0, 0.0) point_light_b = point_light((0.0, 0.5, 0.75), 2000000.0, 200.0, 0.25) - point_light_b.position(0.0, 5.0, 50.5) + point_light_b.position(0.0, -5.0, 50.5) point_light_b.look_at(0.0, 0.0, 0.0) # Spot Light @@ -25,13 +25,13 @@ def setup(): def draw(): global angle - camera_position(100.0, 100.0, 300.0) + camera_position(100.0, -100.0, 300.0) camera_look_at(0.0, 0.0, 0.0) background(220) roughness(0.0) push_matrix() - rotate(angle) + rotate(-angle) box(100.0, 100.0, 100.0) pop_matrix() diff --git a/crates/processing_pyo3/examples/materials.py b/crates/processing_pyo3/examples/materials.py index 9ebf3f23..7e67e271 100644 --- a/crates/processing_pyo3/examples/materials.py +++ b/crates/processing_pyo3/examples/materials.py @@ -9,7 +9,7 @@ def setup(): dir_light = directional_light((1.0, 0.98, 0.95), 1500.0) p_light = point_light((1.0, 1.0, 1.0), 100000.0, 800.0, 0.0) - p_light.position(200.0, 200.0, 400.0) + p_light.position(200.0, -200.0, 400.0) mat = create_material( roughness=0.3, diff --git a/crates/processing_pyo3/examples/particles_animated.py b/crates/processing_pyo3/examples/particles_animated.py index 37fbfece..fec7598b 100644 --- a/crates/processing_pyo3/examples/particles_animated.py +++ b/crates/processing_pyo3/examples/particles_animated.py @@ -32,7 +32,7 @@ def setup(): def draw(): - camera_position(0.0, 8.0, 25.0) + camera_position(0.0, -8.0, 25.0) camera_look_at(0.0, 0.0, 0.0) background(15, 15, 20) fill(230, 128, 75) diff --git a/crates/processing_pyo3/examples/particles_basic.py b/crates/processing_pyo3/examples/particles_basic.py index c05cb1a3..22168953 100644 --- a/crates/processing_pyo3/examples/particles_basic.py +++ b/crates/processing_pyo3/examples/particles_basic.py @@ -33,7 +33,7 @@ def setup(): def draw(): - camera_position(0.0, 4.0, 18.0) + camera_position(0.0, -4.0, 18.0) camera_look_at(0.0, 0.0, 0.0) background(15, 15, 20) diff --git a/crates/processing_pyo3/examples/particles_density.py b/crates/processing_pyo3/examples/particles_density.py index e0731ec3..f1ea3c80 100644 --- a/crates/processing_pyo3/examples/particles_density.py +++ b/crates/processing_pyo3/examples/particles_density.py @@ -38,7 +38,7 @@ def draw(): t = elapsed_time d = BOX * 2.4 - camera_position(cos(t * 0.08) * d, BOX * 0.5, sin(t * 0.08) * d) + camera_position(cos(t * 0.08) * d, -BOX * 0.5, sin(t * 0.08) * d) camera_look_at(0.0, 0.0, 0.0) p.apply(NOISE, scale=0.12, strength=0.06, time=t * 0.15, divergence_free=1) diff --git a/crates/processing_pyo3/examples/particles_emit.py b/crates/processing_pyo3/examples/particles_emit.py index 1e5bbb94..ab6abca6 100644 --- a/crates/processing_pyo3/examples/particles_emit.py +++ b/crates/processing_pyo3/examples/particles_emit.py @@ -30,7 +30,7 @@ def setup(): def draw(): global frame - camera_position(0.0, 4.0, 14.0) + camera_position(0.0, -4.0, 14.0) camera_look_at(0.0, 0.0, 0.0) background(15, 15, 20) @@ -44,7 +44,7 @@ def draw(): i = frame * burst + k t = i * 0.05 radius = 1.5 + min(t * 0.02, 3.0) - height = math.sin(t * 0.1) * 2.0 + height = -math.sin(t * 0.1) * 2.0 positions.extend([math.cos(t) * radius, height, math.sin(t) * radius]) c = hsva((i * 4.32) % 360.0, 0.85, 1.0) colors.extend([c.r, c.g, c.b, 1.0]) diff --git a/crates/processing_pyo3/examples/particles_emit_gpu.py b/crates/processing_pyo3/examples/particles_emit_gpu.py index d3c4f5a2..df763a3a 100644 --- a/crates/processing_pyo3/examples/particles_emit_gpu.py +++ b/crates/processing_pyo3/examples/particles_emit_gpu.py @@ -11,7 +11,7 @@ BURST = 120 DT = 1.0 / 60.0 TTL = 2.5 -GRAVITY = 9.8 +GRAVITY = -9.8 SPEED = 5.0 @@ -47,8 +47,8 @@ def setup(): def draw(): - camera_position(0.0, 4.0, 16.0) - camera_look_at(0.0, 2.0, 0.0) + camera_position(0.0, -4.0, 16.0) + camera_look_at(0.0, -2.0, 0.0) background(10, 10, 18) material(mat) @@ -57,7 +57,7 @@ def draw(): t = elapsed_time sx = math.cos(t) * 0.4 sz = math.sin(t) * 0.4 - spawn.set(pos=[sx, 7.0, sz, 0.0], speed=[SPEED, 0.0, 0.0, 0.0]) + spawn.set(pos=[sx, -7.0, sz, 0.0], speed=[SPEED, 0.0, 0.0, 0.0]) p.emit_gpu(BURST, spawn) motion.set(dt=DT, ttl=TTL, gravity=GRAVITY) diff --git a/crates/processing_pyo3/examples/particles_from_mesh.py b/crates/processing_pyo3/examples/particles_from_mesh.py index 14f18cd6..26fa94b5 100644 --- a/crates/processing_pyo3/examples/particles_from_mesh.py +++ b/crates/processing_pyo3/examples/particles_from_mesh.py @@ -33,7 +33,7 @@ def setup(): def draw(): - camera_position(0.0, 4.0, 18.0) + camera_position(0.0, -4.0, 18.0) camera_look_at(0.0, 0.0, 0.0) background(15, 15, 20) diff --git a/crates/processing_pyo3/examples/particles_gpu_surface.py b/crates/processing_pyo3/examples/particles_gpu_surface.py index 3b30266b..1ec0fcb6 100644 --- a/crates/processing_pyo3/examples/particles_gpu_surface.py +++ b/crates/processing_pyo3/examples/particles_gpu_surface.py @@ -25,7 +25,7 @@ def draw(): t = elapsed_time d = EXTENT * 1.4 - camera_position(cos(t * 0.1) * d, EXTENT * 0.7, sin(t * 0.1) * d) + camera_position(cos(t * 0.1) * d, -EXTENT * 0.7, sin(t * 0.1) * d) camera_look_at(0.0, 0.0, 0.0) gen.set(nx=NX, ny=NY, time=t, extent=EXTENT) diff --git a/crates/processing_pyo3/examples/particles_gpu_surface_lit.py b/crates/processing_pyo3/examples/particles_gpu_surface_lit.py index 4ce8698b..02f2e126 100644 --- a/crates/processing_pyo3/examples/particles_gpu_surface_lit.py +++ b/crates/processing_pyo3/examples/particles_gpu_surface_lit.py @@ -28,7 +28,7 @@ def draw(): t = elapsed_time d = EXTENT * 1.3 - camera_position(cos(t * 0.08) * d, EXTENT * 0.6, sin(t * 0.08) * d) + camera_position(cos(t * 0.08) * d, -EXTENT * 0.6, sin(t * 0.08) * d) camera_look_at(0.0, 0.0, 0.0) gen.set(nx=NX, ny=NY, time=t, extent=EXTENT) diff --git a/crates/processing_pyo3/examples/particles_lifecycle.py b/crates/processing_pyo3/examples/particles_lifecycle.py index faedfff8..f94b6510 100644 --- a/crates/processing_pyo3/examples/particles_lifecycle.py +++ b/crates/processing_pyo3/examples/particles_lifecycle.py @@ -38,7 +38,7 @@ def setup(): def draw(): global frame - camera_position(0.0, 2.0, 14.0) + camera_position(0.0, -2.0, 14.0) camera_look_at(0.0, 0.0, 0.0) background(10, 10, 18) @@ -53,7 +53,7 @@ def draw(): v = (((i * 40503) >> 8) & 0xFFFF) / 65535.0 theta = u * math.tau r = v * 0.6 - positions.extend([math.cos(theta) * r, 2.5, math.sin(theta) * r]) + positions.extend([math.cos(theta) * r, -2.5, math.sin(theta) * r]) c = hsva((i * 4.68) % 360.0, 0.85, 1.0) colors.extend([c.r, c.g, c.b, 1.0]) diff --git a/crates/processing_pyo3/examples/particles_lines.py b/crates/processing_pyo3/examples/particles_lines.py index cf8ee1bb..43fd15bd 100644 --- a/crates/processing_pyo3/examples/particles_lines.py +++ b/crates/processing_pyo3/examples/particles_lines.py @@ -11,7 +11,7 @@ def knot(t, phase): r = cos(Q * t) + 2.0 x = r * cos(P * t + phase) - y = r * sin(P * t + phase) + y = -r * sin(P * t + phase) z = -sin(Q * t) return (x * SCALE, y * SCALE, z * SCALE) @@ -38,7 +38,7 @@ def draw(): t = elapsed_time * 0.12 r = SCALE * 4.5 - camera_position(cos(t) * r, SCALE * 1.5, sin(t) * r) + camera_position(cos(t) * r, -SCALE * 1.5, sin(t) * r) camera_look_at(0.0, 0.0, 0.0) particles(p, topology="line_strip") diff --git a/crates/processing_pyo3/examples/particles_lissajous.py b/crates/processing_pyo3/examples/particles_lissajous.py index e1c46aaa..e3dae4ce 100644 --- a/crates/processing_pyo3/examples/particles_lissajous.py +++ b/crates/processing_pyo3/examples/particles_lissajous.py @@ -55,7 +55,7 @@ def draw(): t = elapsed_time r = 26.0 - camera_position(cos(t * 0.08) * r, sin(t * 0.05) * r * 0.55, sin(t * 0.08) * r) + camera_position(cos(t * 0.08) * r, -sin(t * 0.05) * r * 0.55, sin(t * 0.08) * r) camera_look_at(0.0, 0.0, 0.0) curve.set(count=N, time=t, fx=FX, fy=FY, fz=FZ, loops=1.0, scale=SCALE, hue_mix=HUE_MIX) diff --git a/crates/processing_pyo3/examples/particles_noise.py b/crates/processing_pyo3/examples/particles_noise.py index 3f1284a3..035b0e09 100644 --- a/crates/processing_pyo3/examples/particles_noise.py +++ b/crates/processing_pyo3/examples/particles_noise.py @@ -35,7 +35,7 @@ def setup(): def draw(): - camera_position(0.0, 4.0, 18.0) + camera_position(0.0, -4.0, 18.0) camera_look_at(0.0, 0.0, 0.0) background(15, 15, 20) diff --git a/crates/processing_pyo3/examples/particles_plexus.py b/crates/processing_pyo3/examples/particles_plexus.py index 8127474d..6e0723f8 100644 --- a/crates/processing_pyo3/examples/particles_plexus.py +++ b/crates/processing_pyo3/examples/particles_plexus.py @@ -56,7 +56,7 @@ def draw(): t = elapsed_time * 0.12 r = BOX * 3.0 - camera_position(cos(t) * r, BOX * 0.9, sin(t) * r) + camera_position(cos(t) * r, -BOX * 0.9, sin(t) * r) camera_look_at(0.0, 0.0, 0.0) p.apply(INTEGRATE, dt=DT) diff --git a/crates/processing_pyo3/examples/particles_points.py b/crates/processing_pyo3/examples/particles_points.py index b06c149e..db596f17 100644 --- a/crates/processing_pyo3/examples/particles_points.py +++ b/crates/processing_pyo3/examples/particles_points.py @@ -28,7 +28,7 @@ def draw(): t = elapsed_time * 0.15 r = BOUND * 2.6 - camera_position(cos(t) * r, BOUND * 0.6, sin(t) * r) + camera_position(cos(t) * r, -BOUND * 0.6, sin(t) * r) camera_look_at(0.0, 0.0, 0.0) particles(p) diff --git a/crates/processing_pyo3/examples/particles_scatter_volume.py b/crates/processing_pyo3/examples/particles_scatter_volume.py index bca65628..62954abe 100644 --- a/crates/processing_pyo3/examples/particles_scatter_volume.py +++ b/crates/processing_pyo3/examples/particles_scatter_volume.py @@ -15,8 +15,8 @@ def setup(): size(900, 700) mode_3d() - camera_position(0.0, 100.0, 400.0) - camera_look_at(0.0, 80.0, 0.0) + camera_position(0.0, -100.0, 400.0) + camera_look_at(0.0, -80.0, 0.0) orbit_camera() gltf = load_gltf("gltf/Duck.glb") diff --git a/crates/processing_pyo3/examples/particles_sphere.py b/crates/processing_pyo3/examples/particles_sphere.py index 0d79a4fb..ed1439a7 100644 --- a/crates/processing_pyo3/examples/particles_sphere.py +++ b/crates/processing_pyo3/examples/particles_sphere.py @@ -30,7 +30,7 @@ def draw(): t = elapsed_time r = 5.0 - camera_position(cos(t * 0.15) * r, 1.6, sin(t * 0.15) * r) + camera_position(cos(t * 0.15) * r, -1.6, sin(t * 0.15) * r) camera_look_at(0.0, 0.0, 0.0) p.apply(NOISE, scale=0.9, strength=0.01, time=t * 0.3, divergence_free=1) diff --git a/crates/processing_pyo3/examples/particles_stress.py b/crates/processing_pyo3/examples/particles_stress.py index 8db5085b..7aa4eea0 100644 --- a/crates/processing_pyo3/examples/particles_stress.py +++ b/crates/processing_pyo3/examples/particles_stress.py @@ -16,12 +16,12 @@ def setup(): mode_3d() extent = GRID * SPACING * 0.5 - camera_position(0.0, extent * 0.6, extent * 2.5) + camera_position(0.0, -extent * 0.6, extent * 2.5) camera_look_at(0.0, 0.0, 0.0) orbit_camera() directional_light((1.0, 0.0, 0.0), 1000.0, position=Vec3.X, look_at=Vec3.ZERO) - directional_light((0.0, 1.0, 0.0), 1000.0, position=Vec3.Y, look_at=Vec3.ZERO) + directional_light((0.0, 1.0, 0.0), 1000.0, position=Vec3(0.0, -1.0, 0.0), look_at=Vec3.ZERO) directional_light((0.0, 0.0, 1.0), 1000.0, position=Vec3.Z, look_at=Vec3.ZERO) p = create_particles( diff --git a/crates/processing_pyo3/examples/particles_surface.py b/crates/processing_pyo3/examples/particles_surface.py index 6a204c38..6046297c 100644 --- a/crates/processing_pyo3/examples/particles_surface.py +++ b/crates/processing_pyo3/examples/particles_surface.py @@ -16,7 +16,7 @@ def band(seg, phase): twist = theta * 0.5 + phase w = ( WIDTH * cos(twist) * radial[0], - WIDTH * sin(twist), + -WIDTH * sin(twist), WIDTH * cos(twist) * radial[2], ) left = [center[0] - w[0], center[1] - w[1], center[2] - w[2]] @@ -46,7 +46,7 @@ def draw(): t = elapsed_time * 0.15 r = R * 3.0 - camera_position(cos(t) * r, R * 1.2, sin(t) * r) + camera_position(cos(t) * r, -R * 1.2, sin(t) * r) camera_look_at(0.0, 0.0, 0.0) particles(p, topology="triangle_strip") diff --git a/crates/processing_pyo3/examples/primitives_3d.py b/crates/processing_pyo3/examples/primitives_3d.py index 919883d2..63ad0350 100644 --- a/crates/processing_pyo3/examples/primitives_3d.py +++ b/crates/processing_pyo3/examples/primitives_3d.py @@ -8,7 +8,7 @@ def setup(): def draw(): global t - camera_position(0, 80, 800) + camera_position(0, -80, 800) camera_look_at(0, 0, 0) background(15, 15, 20) @@ -20,7 +20,7 @@ def draw(): for i, x in enumerate(offsets): push_matrix() translate(x, 0) - rotate(t) + rotate(-t) if i == 0: box(50, 50, 50) diff --git a/crates/processing_render/src/gltf.rs b/crates/processing_render/src/gltf.rs index 7b9397be..1bdfa558 100644 --- a/crates/processing_render/src/gltf.rs +++ b/crates/processing_render/src/gltf.rs @@ -9,9 +9,11 @@ use bevy::{ camera::visibility::RenderLayers, ecs::system::RunSystemOnce, gltf::{Gltf, GltfMaterial, GltfMeshName}, + mesh::VertexAttributeValues, pbr::ExtendedMaterial, + platform::collections::HashSet, prelude::*, - world_serialization::WorldInstanceSpawner, + world_serialization::{InstanceId, WorldInstanceSpawner}, }; use crate::geometry::{BuiltinAttributes, Geometry, layout::VertexLayout}; @@ -24,6 +26,66 @@ use processing_core::error::{ProcessingError, Result}; #[derive(Component)] pub struct GltfNodeTransform(pub Transform); +/// Mesh assets already mirrored into the y-down world; a glTF loaded twice shares them +#[derive(Resource, Default)] +struct MirroredMeshes(HashSet>); + +/// `M * T * M` for the y mirror `M`: conjugating every local transform mirrors the hierarchy +fn mirror_y(t: Transform) -> Transform { + let q = t.rotation; + Transform { + translation: Vec3::new(t.translation.x, -t.translation.y, t.translation.z), + rotation: Quat::from_xyzw(-q.x, q.y, -q.z, q.w), + scale: t.scale, + } +} + +fn mirror_mesh(mesh: &mut Mesh) { + for attr in [Mesh::ATTRIBUTE_POSITION, Mesh::ATTRIBUTE_NORMAL] { + if let Some(VertexAttributeValues::Float32x3(v)) = mesh.attribute_mut(attr) { + for p in v.iter_mut() { + p[1] = -p[1]; + } + } + } + // the bitangent is `cross(normal, tangent) * w`, and a mirror flips that handedness + if let Some(VertexAttributeValues::Float32x4(v)) = mesh.attribute_mut(Mesh::ATTRIBUTE_TANGENT) { + for t in v.iter_mut() { + t[1] = -t[1]; + t[3] = -t[3]; + } + } +} + +/// glTF is y-up and the Processing world is y-down, so a scene is mirrored on import to +/// render as authored. The clockwise front face already matches the mirrored winding. +fn mirror_instance(world: &mut World, instance_id: InstanceId) { + world.init_resource::(); + let entities: Vec = world + .resource::() + .iter_instance_entities(instance_id) + .collect(); + for &e in &entities { + if let Some(mut t) = world.get_mut::(e) { + *t = mirror_y(*t); + } + } + let handles: Vec> = entities + .iter() + .filter_map(|&e| world.get::(e).map(|m| m.0.clone())) + .collect(); + world.resource_scope(|world, mut meshes: Mut>| { + let mut done = world.resource_mut::(); + for handle in handles { + if done.0.insert(handle.id()) + && let Some(mut mesh) = meshes.get_mut(&handle) + { + mirror_mesh(&mut mesh); + } + } + }); +} + fn resolve_asset_path(config: &Config, path: &str) -> AssetPath<'static> { let asset_path = AssetPath::parse(path).into_owned(); match config.get(ConfigKey::AssetRootPath) { @@ -118,6 +180,8 @@ pub fn load( } } + mirror_instance(world, instance_id); + let entity = world .spawn(GltfHandle { handle, @@ -320,8 +384,8 @@ pub fn camera(In((gltf_entity, index)): In<(Entity, usize)>, world: &mut World) graphics::OrthoArgs { left: o.area.min.x, right: o.area.max.x, - bottom: o.area.min.y, - top: o.area.max.y, + bottom: -o.area.max.y, + top: -o.area.min.y, near: o.near, far: o.far, }, diff --git a/crates/processing_render/src/graphics.rs b/crates/processing_render/src/graphics.rs index 183046ec..d2007a08 100644 --- a/crates/processing_render/src/graphics.rs +++ b/crates/processing_render/src/graphics.rs @@ -972,7 +972,9 @@ mod projection_tests { assert!(ndc(0.0) > ndc(-1.0) && ndc(0.0) < ndc(1.0)); // top-left of the canvas maps to NDC (-1, 1) let corner = clip * Vec4::new(0.0, 0.0, 0.0, 1.0); - assert!((corner.x / corner.w + 1.0).abs() < 1e-6 && (corner.y / corner.w - 1.0).abs() < 1e-6); + assert!( + (corner.x / corner.w + 1.0).abs() < 1e-6 && (corner.y / corner.w - 1.0).abs() < 1e-6 + ); } /// 3D is the same y-down world: a point above the origin (negative y) projects to the top @@ -997,7 +999,10 @@ mod projection_tests { let up = ndc(Vec3::new(0.0, -10.0, -100.0)); let right = ndc(Vec3::new(10.0, 0.0, -100.0)); assert!(up.y > 0.0, "negative world y must be screen-up, got {up}"); - assert!(right.x > 0.0, "positive world x must be screen-right, got {right}"); + assert!( + right.x > 0.0, + "positive world x must be screen-right, got {right}" + ); assert!(ndc(Vec3::new(0.0, 0.0, -10.0)).z > ndc(Vec3::new(0.0, 0.0, -100.0)).z); } } diff --git a/crates/processing_render/src/render/mod.rs b/crates/processing_render/src/render/mod.rs index aec46602..16717464 100644 --- a/crates/processing_render/src/render/mod.rs +++ b/crates/processing_render/src/render/mod.rs @@ -7,12 +7,12 @@ pub mod style; pub mod transform; use bevy::{ + camera::Camera3dDepthLoadOp, camera::{ CameraOutputMode, ClearColorConfig, primitives::Aabb, visibility::{NoFrustumCulling, RenderLayers}, }, - camera::Camera3dDepthLoadOp, ecs::{query::Has, system::SystemParam}, math::{Affine2, Affine3A, Vec3A}, pbr::gpu_instance_batch::GpuBatchedMesh3d, @@ -202,7 +202,7 @@ pub fn flush_draw_commands( let mut drained = true; while let Some(cmd) = pending.next() { - // check whether we are the first flush after a present + // check whether we are the first flush after a present let opens_pass = |batch: &BatchState| batch.draw_index == 0 && batch.current_mesh.is_none(); match cmd { @@ -1726,4 +1726,3 @@ fn layer_z(draw_index: u32) -> f32 { fn sort_bias(draw_index: u32) -> f32 { draw_index as f32 * 1e-6 } - diff --git a/examples/animated_mesh.rs b/examples/animated_mesh.rs index cefb166d..8d5f7e84 100644 --- a/examples/animated_mesh.rs +++ b/examples/animated_mesh.rs @@ -46,7 +46,7 @@ fn sketch() -> error::Result<()> { 1.0, ), )?; - geometry_normal(mesh, Vec3::new(0.0, 1.0, 0.0))?; + geometry_normal(mesh, Vec3::new(0.0, -1.0, 0.0))?; geometry_vertex(mesh, Vec3::new(px, 0.0, pz))?; } } @@ -69,7 +69,7 @@ fn sketch() -> error::Result<()> { } graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(150.0, 150.0, 150.0))?; + transform_set_position(graphics, Vec3::new(150.0, -150.0, 150.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let mut time = 0.0f32; @@ -81,7 +81,7 @@ fn sketch() -> error::Result<()> { let px = x as f32 * spacing - offset; let pz = z as f32 * spacing - offset; let wave = (px * 0.1 + time).sin() * (pz * 0.1 + time).cos() * 20.0; - geometry_set_vertex(mesh, idx, Vec3::new(px, wave, pz))?; + geometry_set_vertex(mesh, idx, Vec3::new(px, -wave, pz))?; } } diff --git a/examples/box.rs b/examples/box.rs index a4c7f4ac..e687228f 100644 --- a/examples/box.rs +++ b/examples/box.rs @@ -28,7 +28,7 @@ fn sketch() -> error::Result<()> { let box_geo = geometry_box(100.0, 100.0, 100.0)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(100.0, 100.0, 300.0))?; + transform_set_position(graphics, Vec3::new(100.0, -100.0, 300.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let mut angle: f32 = 0.0; @@ -45,7 +45,7 @@ fn sketch() -> error::Result<()> { graphics_record_command( graphics, DrawCommand::Rotate { - angle, + angle: -angle, axis: Vec3::Z, }, )?; diff --git a/examples/camera_controllers.rs b/examples/camera_controllers.rs index 187ceef7..8d3e65cd 100644 --- a/examples/camera_controllers.rs +++ b/examples/camera_controllers.rs @@ -32,7 +32,7 @@ fn sketch() -> error::Result<()> { let dir_light = light_create_directional(graphics, bevy::color::Color::srgb(1.0, 0.98, 0.95), 1_500.0)?; - transform_set_position(dir_light, Vec3::new(300.0, 400.0, 300.0))?; + transform_set_position(dir_light, Vec3::new(300.0, -400.0, 300.0))?; transform_look_at(dir_light, Vec3::ZERO)?; let mut angle: f32 = 0.0; @@ -73,7 +73,7 @@ fn sketch() -> error::Result<()> { graphics_record_command( graphics, DrawCommand::Rotate { - angle, + angle: -angle, axis: Vec3::Z, }, )?; diff --git a/examples/custom_attribute.rs b/examples/custom_attribute.rs index 78dfc0d0..3bb2454c 100644 --- a/examples/custom_attribute.rs +++ b/examples/custom_attribute.rs @@ -40,15 +40,15 @@ fn sketch() -> error::Result<()> { geometry_color(mesh, Vec4::new(1.0, 0.0, 0.0, 1.0))?; geometry_normal(mesh, Vec3::new(0.0, 0.0, 1.0))?; geometry_attribute_float(mesh, custom_attr, 0.0)?; - geometry_vertex(mesh, Vec3::new(-50.0, -50.0, 0.0))?; + geometry_vertex(mesh, Vec3::new(-50.0, 50.0, 0.0))?; geometry_color(mesh, Vec4::new(0.0, 1.0, 0.0, 1.0))?; geometry_attribute_float(mesh, custom_attr, 0.5)?; - geometry_vertex(mesh, Vec3::new(50.0, -50.0, 0.0))?; + geometry_vertex(mesh, Vec3::new(50.0, 50.0, 0.0))?; geometry_color(mesh, Vec4::new(0.0, 0.0, 1.0, 1.0))?; geometry_attribute_float(mesh, custom_attr, 1.0)?; - geometry_vertex(mesh, Vec3::new(0.0, 50.0, 0.0))?; + geometry_vertex(mesh, Vec3::new(0.0, -50.0, 0.0))?; geometry_index(mesh, 0)?; geometry_index(mesh, 1)?; diff --git a/examples/custom_material.rs b/examples/custom_material.rs index 8af6ca23..533a8124 100644 --- a/examples/custom_material.rs +++ b/examples/custom_material.rs @@ -28,7 +28,7 @@ fn sketch() -> error::Result<()> { let box_geo = geometry_box(100.0, 100.0, 100.0)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(100.0, 100.0, 300.0))?; + transform_set_position(graphics, Vec3::new(100.0, -100.0, 300.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let shader = shader_load("shaders/custom_material.wesl")?; @@ -53,7 +53,7 @@ fn sketch() -> error::Result<()> { graphics_record_command( graphics, DrawCommand::Rotate { - angle, + angle: -angle, axis: Vec3::Z, }, )?; diff --git a/examples/gltf_load.rs b/examples/gltf_load.rs index af9d38c5..479e81fb 100644 --- a/examples/gltf_load.rs +++ b/examples/gltf_load.rs @@ -42,10 +42,10 @@ fn sketch() -> error::Result<()> { let radius = 1.5; let lx = t.cos() * radius; - let ly = 1.5; + let ly = -1.5; let lz = t.sin() * radius; transform_set_position(light, Vec3::new(lx, ly, lz))?; - transform_look_at(light, Vec3::new(0.0, 0.8, 0.0))?; + transform_look_at(light, Vec3::new(0.0, -0.8, 0.0))?; let r = (t * 8.0).sin() * 0.5 + 0.5; let g = (t * 8.0 + 2.0).sin() * 0.5 + 0.5; diff --git a/examples/lights.rs b/examples/lights.rs index 224cbf86..a56738c8 100644 --- a/examples/lights.rs +++ b/examples/lights.rs @@ -44,7 +44,7 @@ fn sketch() -> error::Result<()> { 200.0, 0.5, )?; - transform_set_position(point_light_a, Vec3::new(-25.0, 5.0, 51.0))?; + transform_set_position(point_light_a, Vec3::new(-25.0, -5.0, 51.0))?; transform_look_at(point_light_a, Vec3::new(0.0, 0.0, 0.0))?; // create another point light @@ -55,7 +55,7 @@ fn sketch() -> error::Result<()> { 200.0, 0.25, )?; - transform_set_position(point_light_b, Vec3::new(0.0, 5.0, 50.5))?; + transform_set_position(point_light_b, Vec3::new(0.0, -5.0, 50.5))?; transform_look_at(point_light_b, Vec3::new(0.0, 0.0, 0.0))?; // and a spot light, too! @@ -72,7 +72,7 @@ fn sketch() -> error::Result<()> { transform_look_at(spot_light, Vec3::new(0.0, 0.0, 0.0))?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(100.0, 100.0, 300.0))?; + transform_set_position(graphics, Vec3::new(100.0, -100.0, 300.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let mut angle = 0.0; @@ -92,7 +92,7 @@ fn sketch() -> error::Result<()> { graphics_record_command( graphics, DrawCommand::Rotate { - angle, + angle: -angle, axis: Vec3::Z, }, )?; diff --git a/examples/materials.rs b/examples/materials.rs index c3805133..4739d20f 100644 --- a/examples/materials.rs +++ b/examples/materials.rs @@ -33,12 +33,12 @@ fn sketch() -> error::Result<()> { let dir_light = light_create_directional(graphics, bevy::color::Color::srgb(1.0, 0.98, 0.95), 1_500.0)?; - transform_set_position(dir_light, Vec3::new(300.0, 400.0, 300.0))?; + transform_set_position(dir_light, Vec3::new(300.0, -400.0, 300.0))?; transform_look_at(dir_light, Vec3::new(0.0, 0.0, 0.0))?; let point_light = light_create_point(graphics, bevy::color::Color::WHITE, 100_000.0, 800.0, 0.0)?; - transform_set_position(point_light, Vec3::new(200.0, 200.0, 400.0))?; + transform_set_position(point_light, Vec3::new(200.0, -200.0, 400.0))?; // Grid of materials varying roughness (x) and metallic (y) let cols = 11; @@ -86,7 +86,7 @@ fn sketch() -> error::Result<()> { DrawCommand::Translate( Vec2::new( col as f32 * spacing - offset_x, - row as f32 * spacing - offset_y, + offset_y - row as f32 * spacing, ) .extend(0.0), ), diff --git a/examples/particles_animated.rs b/examples/particles_animated.rs index fe22240c..11c30227 100644 --- a/examples/particles_animated.rs +++ b/examples/particles_animated.rs @@ -41,7 +41,7 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 700, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 8.0, 25.0))?; + transform_set_position(graphics, Vec3::new(0.0, -8.0, 25.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let _light = diff --git a/examples/particles_colored.rs b/examples/particles_colored.rs index 9c300784..e952f3d2 100644 --- a/examples/particles_colored.rs +++ b/examples/particles_colored.rs @@ -17,7 +17,7 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 700, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 6.0, 18.0))?; + transform_set_position(graphics, Vec3::new(0.0, -6.0, 18.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let sphere = geometry_sphere(0.25, 12, 8)?; @@ -29,7 +29,7 @@ fn sketch() -> error::Result<()> { for y in 0..10 { for z in 0..10 { positions.push((x as f32 - 4.5) * 1.0); - positions.push((y as f32 - 4.5) * 1.0); + positions.push((4.5 - y as f32) * 1.0); positions.push((z as f32 - 4.5) * 1.0); colors.push(x as f32 / 9.0); colors.push(y as f32 / 9.0); diff --git a/examples/particles_colored_pbr.rs b/examples/particles_colored_pbr.rs index b61311ae..356b4c4e 100644 --- a/examples/particles_colored_pbr.rs +++ b/examples/particles_colored_pbr.rs @@ -17,7 +17,7 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 700, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 6.0, 18.0))?; + transform_set_position(graphics, Vec3::new(0.0, -6.0, 18.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let _light = @@ -32,7 +32,7 @@ fn sketch() -> error::Result<()> { for y in 0..8 { for z in 0..8 { positions.push((x as f32 - 3.5) * 1.4); - positions.push((y as f32 - 3.5) * 1.4); + positions.push((3.5 - y as f32) * 1.4); positions.push((z as f32 - 3.5) * 1.4); colors.push(x as f32 / 7.0); colors.push(y as f32 / 7.0); diff --git a/examples/particles_emit.rs b/examples/particles_emit.rs index d3158c3c..83f66909 100644 --- a/examples/particles_emit.rs +++ b/examples/particles_emit.rs @@ -17,7 +17,7 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 700, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 4.0, 14.0))?; + transform_set_position(graphics, Vec3::new(0.0, -4.0, 14.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let sphere = geometry_sphere(0.08, 8, 6)?; @@ -71,7 +71,7 @@ fn sketch() -> error::Result<()> { let i = frame * burst + k; let t = i as f32 * 0.05; let radius = 1.5 + (t * 0.02).min(3.0); - let height = ((t * 0.1).sin()) * 2.0; + let height = -((t * 0.1).sin()) * 2.0; positions.push(t.cos() * radius); positions.push(height); positions.push(t.sin() * radius); diff --git a/examples/particles_emit_gpu.rs b/examples/particles_emit_gpu.rs index 74565dc3..2ec9a207 100644 --- a/examples/particles_emit_gpu.rs +++ b/examples/particles_emit_gpu.rs @@ -48,7 +48,7 @@ fn main(@builtin(global_invocation_id) gid: vec3) { let theta = hash_unit(seed) * 6.2831853; let r = sqrt(hash_unit(seed * 2u + 1u)); let dirxz = vec2(cos(theta), sin(theta)) * r; - let dy = 0.7 + 0.3 * hash_unit(seed * 3u + 7u); + let dy = -(0.7 + 0.3 * hash_unit(seed * 3u + 7u)); let v = vec3(dirxz.x, dy, dirxz.y) * spawn.speed.x; position[slot * 3u + 0u] = spawn.pos.x; @@ -127,8 +127,8 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 700, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 4.0, 16.0))?; - transform_look_at(graphics, Vec3::new(0.0, 2.0, 0.0))?; + transform_set_position(graphics, Vec3::new(0.0, -4.0, 16.0))?; + transform_look_at(graphics, Vec3::new(0.0, -2.0, 0.0))?; let _light = light_create_directional(graphics, bevy::color::Color::srgb(0.95, 0.9, 0.85), 800.0)?; @@ -172,7 +172,7 @@ fn sketch() -> error::Result<()> { let burst: u32 = 120; let dt: f32 = 1.0 / 60.0; let ttl: f32 = 2.5; - let gravity: f32 = 9.8; + let gravity: f32 = -9.8; let speed: f32 = 5.0; let start = Instant::now(); @@ -199,7 +199,7 @@ fn sketch() -> error::Result<()> { compute_set( spawn, "pos", - shader_value::ShaderValue::Float4([sx, 7.0, sz, 0.0]), + shader_value::ShaderValue::Float4([sx, -7.0, sz, 0.0]), )?; compute_set( spawn, diff --git a/examples/particles_from_mesh.rs b/examples/particles_from_mesh.rs index 8d03f4d4..f6f55b4f 100644 --- a/examples/particles_from_mesh.rs +++ b/examples/particles_from_mesh.rs @@ -17,7 +17,7 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 700, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 4.0, 18.0))?; + transform_set_position(graphics, Vec3::new(0.0, -4.0, 18.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let _light = diff --git a/examples/particles_lifecycle.rs b/examples/particles_lifecycle.rs index 97bd03fe..1677789d 100644 --- a/examples/particles_lifecycle.rs +++ b/examples/particles_lifecycle.rs @@ -27,7 +27,7 @@ fn main(@builtin(global_invocation_id) gid: vec3) { } age[i] = age[i] + dt; - position[i * 3u + 1u] = position[i * 3u + 1u] - dt * 1.5; + position[i * 3u + 1u] = position[i * 3u + 1u] + dt * 1.5; let remaining = clamp(1.0 - age[i] / ttl, 0.0, 1.0); let s = remaining * remaining; @@ -54,7 +54,7 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 700, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 2.0, 14.0))?; + transform_set_position(graphics, Vec3::new(0.0, -2.0, 14.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let sphere = geometry_sphere(0.1, 8, 6)?; @@ -112,7 +112,7 @@ fn sketch() -> error::Result<()> { let theta = u * std::f32::consts::TAU; let r = v * 0.6; positions.push(theta.cos() * r); - positions.push(2.5); + positions.push(-2.5); positions.push(theta.sin() * r); let h = (i as f32 * 0.013) % 1.0; let (cr, cg, cb) = hsv_to_rgb(h, 0.85, 1.0); diff --git a/examples/particles_noise.rs b/examples/particles_noise.rs index 71baabc3..5ad9f6db 100644 --- a/examples/particles_noise.rs +++ b/examples/particles_noise.rs @@ -17,7 +17,7 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 700, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 4.0, 18.0))?; + transform_set_position(graphics, Vec3::new(0.0, -4.0, 18.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let _light = diff --git a/examples/particles_oriented.rs b/examples/particles_oriented.rs index 0740d130..d4e299f9 100644 --- a/examples/particles_oriented.rs +++ b/examples/particles_oriented.rs @@ -52,7 +52,7 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 700, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 6.0, 18.0))?; + transform_set_position(graphics, Vec3::new(0.0, -6.0, 18.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let _light = @@ -68,7 +68,7 @@ fn sketch() -> error::Result<()> { for y in 0..5 { for z in 0..5 { positions.push((x as f32 - 2.0) * 1.6); - positions.push((y as f32 - 2.0) * 1.6); + positions.push((2.0 - y as f32) * 1.6); positions.push((z as f32 - 2.0) * 1.6); rotations.push(0.0); rotations.push(0.0); diff --git a/examples/particles_scatter.rs b/examples/particles_scatter.rs index 86afa512..ff912e7c 100644 --- a/examples/particles_scatter.rs +++ b/examples/particles_scatter.rs @@ -47,7 +47,7 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 700, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 0.4, 4.5))?; + transform_set_position(graphics, Vec3::new(0.0, -0.4, 4.5))?; transform_look_at(graphics, Vec3::ZERO)?; let _key = @@ -104,7 +104,7 @@ fn sketch() -> error::Result<()> { let t = start.elapsed().as_secs_f32(); let cam_x = (t * 0.25).cos() * 4.5; let cam_z = (t * 0.25).sin() * 4.5; - transform_set_position(graphics, Vec3::new(cam_x, 0.4, cam_z))?; + transform_set_position(graphics, Vec3::new(cam_x, -0.4, cam_z))?; transform_look_at(graphics, Vec3::ZERO)?; compute_set( diff --git a/examples/particles_scatter_volume.rs b/examples/particles_scatter_volume.rs index f0496ad6..0f394077 100644 --- a/examples/particles_scatter_volume.rs +++ b/examples/particles_scatter_volume.rs @@ -47,8 +47,8 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 700, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 100.0, 400.0))?; - transform_look_at(graphics, Vec3::new(0.0, 80.0, 0.0))?; + transform_set_position(graphics, Vec3::new(0.0, -100.0, 400.0))?; + transform_look_at(graphics, Vec3::new(0.0, -80.0, 0.0))?; graphics_orbit_camera(graphics)?; let gltf = gltf_load(graphics, "gltf/Duck.glb")?; diff --git a/examples/particles_stress.rs b/examples/particles_stress.rs index ee91d64a..577d4e11 100644 --- a/examples/particles_stress.rs +++ b/examples/particles_stress.rs @@ -56,7 +56,7 @@ fn sketch() -> error::Result<()> { graphics_mode_3d(graphics)?; let extent = (GRID as f32) * SPACING * 0.5; - transform_set_position(graphics, Vec3::new(0.0, extent * 0.6, extent * 2.5))?; + transform_set_position(graphics, Vec3::new(0.0, -extent * 0.6, extent * 2.5))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; graphics_orbit_camera(graphics)?; @@ -66,7 +66,7 @@ fn sketch() -> error::Result<()> { let green = light_create_directional(graphics, bevy::color::Color::srgb(0.0, 1.0, 0.0), 1000.0)?; - transform_set_position(green, Vec3::new(0.0, 1.0, 0.0))?; + transform_set_position(green, Vec3::new(0.0, -1.0, 0.0))?; transform_look_at(green, Vec3::ZERO)?; let blue = light_create_directional(graphics, bevy::color::Color::srgb(0.0, 0.0, 1.0), 1000.0)?; @@ -88,7 +88,7 @@ fn sketch() -> error::Result<()> { let ry = hash_unit(i.wrapping_mul(40503).wrapping_add(0x68E1)); let rz = hash_unit(i.wrapping_mul(2246822519).wrapping_add(0xC2B2)); positions.push((rx * 2.0 - 1.0) * extent_half); - positions.push((ry * 2.0 - 1.0) * extent_half); + positions.push((1.0 - ry * 2.0) * extent_half); positions.push((rz * 2.0 - 1.0) * extent_half); colors.push(rx); colors.push(ry); diff --git a/examples/particles_text_whirl.rs b/examples/particles_text_whirl.rs index 17147540..3fc13afc 100644 --- a/examples/particles_text_whirl.rs +++ b/examples/particles_text_whirl.rs @@ -287,7 +287,7 @@ fn sketch() -> error::Result<()> { let text = "processing5"; let w = graphics_text_width(graphics, text)?; println!("text width = {w} (size = {TEXT_PT}, extrusion = {EXTRUSION})"); - let mesh = graphics_text_to_model(graphics, text, -w / 2.0, -TEXT_PT * 0.4, EXTRUSION)?; + let mesh = graphics_text_to_model(graphics, text, -w / 2.0, TEXT_PT * 0.4, EXTRUSION)?; let source = geometry_create_from_mesh(mesh)?; let (cdf_bytes, indices_bytes, face_count) = processing_core::app_mut(|app| { diff --git a/examples/pbr.rs b/examples/pbr.rs index d02a1843..8d928011 100644 --- a/examples/pbr.rs +++ b/examples/pbr.rs @@ -32,12 +32,12 @@ fn sketch() -> error::Result<()> { let dir_light = light_create_directional(graphics, bevy::color::Color::srgb(1.0, 0.98, 0.95), 1_500.0)?; - transform_set_position(dir_light, Vec3::new(300.0, 400.0, 300.0))?; + transform_set_position(dir_light, Vec3::new(300.0, -400.0, 300.0))?; transform_look_at(dir_light, Vec3::new(0.0, 0.0, 0.0))?; let point_light = light_create_point(graphics, bevy::color::Color::WHITE, 100_000.0, 800.0, 0.0)?; - transform_set_position(point_light, Vec3::new(200.0, 200.0, 400.0))?; + transform_set_position(point_light, Vec3::new(200.0, -200.0, 400.0))?; let cols = 11; let rows = 5; @@ -70,7 +70,7 @@ fn sketch() -> error::Result<()> { DrawCommand::Translate( Vec2::new( col as f32 * spacing - offset_x, - row as f32 * spacing - offset_y, + offset_y - row as f32 * spacing, ) .extend(0.0), ), diff --git a/examples/primitives_3d.rs b/examples/primitives_3d.rs index 4838c7db..7176c626 100644 --- a/examples/primitives_3d.rs +++ b/examples/primitives_3d.rs @@ -17,7 +17,7 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 900, 400, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(0.0, 80.0, 800.0))?; + transform_set_position(graphics, Vec3::new(0.0, -80.0, 800.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let _light = @@ -113,7 +113,7 @@ fn sketch() -> error::Result<()> { graphics_record_command( graphics, DrawCommand::Rotate { - angle: t, + angle: -t, axis: Vec3::Z, }, )?; diff --git a/examples/stroke_3d.rs b/examples/stroke_3d.rs index 5853686c..c76451ff 100644 --- a/examples/stroke_3d.rs +++ b/examples/stroke_3d.rs @@ -17,7 +17,7 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, 600, 400, TextureFormat::Rgba16Float)?; graphics_mode_3d(graphics)?; - transform_set_position(graphics, Vec3::new(200.0, 150.0, 350.0))?; + transform_set_position(graphics, Vec3::new(200.0, -150.0, 350.0))?; transform_look_at(graphics, Vec3::new(0.0, 0.0, 0.0))?; let _light = @@ -42,7 +42,7 @@ fn sketch() -> error::Result<()> { graphics_record_command( graphics, DrawCommand::Rotate { - angle, + angle: -angle, axis: Vec3::Z, }, )?; @@ -73,7 +73,7 @@ fn sketch() -> error::Result<()> { graphics_record_command( graphics, DrawCommand::Rotate { - angle: angle * 0.7, + angle: -angle * 0.7, axis: Vec3::Z, }, )?; @@ -107,7 +107,7 @@ fn sketch() -> error::Result<()> { graphics_record_command( graphics, DrawCommand::Rotate { - angle: angle * 0.5, + angle: -angle * 0.5, axis: Vec3::Z, }, )?; @@ -141,7 +141,7 @@ fn sketch() -> error::Result<()> { graphics_record_command( graphics, DrawCommand::Rotate { - angle: -angle * 0.3, + angle: angle * 0.3, axis: Vec3::Z, }, )?; diff --git a/examples/text_3d.rs b/examples/text_3d.rs index 95f2fd64..585ffd13 100644 --- a/examples/text_3d.rs +++ b/examples/text_3d.rs @@ -24,7 +24,7 @@ fn sketch() -> error::Result<()> { let dir_light = light_create_directional(graphics, bevy::color::Color::srgb(0.3, 0.3, 0.4), 2000.0)?; - transform_set_position(dir_light, Vec3::new(200.0, 300.0, 500.0))?; + transform_set_position(dir_light, Vec3::new(200.0, -300.0, 500.0))?; transform_look_at(dir_light, Vec3::new(0.0, 0.0, 0.0))?; let glow = material_create_pbr()?; @@ -68,7 +68,7 @@ fn sketch() -> error::Result<()> { graphics_record_command( graphics, DrawCommand::Rotate { - angle: t * 0.3, + angle: -t * 0.3, axis: Vec3::Z, }, )?; From cae97e27fc23a82ab0a158dfd93b0264904f0f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Tue, 10 Nov 2026 13:27:01 -0800 Subject: [PATCH 3/3] Fixes for vertex authorship. --- Cargo.lock | 138 +++++++++--------- crates/processing_render/src/geometry/mod.rs | 24 +++ crates/processing_render/src/gltf.rs | 22 +-- crates/processing_render/src/lib.rs | 6 + .../src/render/primitive/shape3d.rs | 24 +-- 5 files changed, 116 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1b7105ba..4db7f80d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -562,7 +562,7 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bevy" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_internal", ] @@ -570,7 +570,7 @@ dependencies = [ [[package]] name = "bevy_a11y" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "accesskit", "bevy_app", @@ -582,7 +582,7 @@ dependencies = [ [[package]] name = "bevy_android" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "android-activity", ] @@ -590,7 +590,7 @@ dependencies = [ [[package]] name = "bevy_animation" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_animation_macros", "bevy_app", @@ -622,7 +622,7 @@ dependencies = [ [[package]] name = "bevy_animation_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_macro_utils 0.19.0", "quote", @@ -632,7 +632,7 @@ dependencies = [ [[package]] name = "bevy_anti_alias" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -653,7 +653,7 @@ dependencies = [ [[package]] name = "bevy_app" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_derive", "bevy_ecs", @@ -674,7 +674,7 @@ dependencies = [ [[package]] name = "bevy_asset" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "async-broadcast", "async-channel", @@ -717,7 +717,7 @@ dependencies = [ [[package]] name = "bevy_asset_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_macro_utils 0.19.0", "proc-macro2", @@ -728,7 +728,7 @@ dependencies = [ [[package]] name = "bevy_audio" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -743,7 +743,7 @@ dependencies = [ [[package]] name = "bevy_camera" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -768,7 +768,7 @@ dependencies = [ [[package]] name = "bevy_camera_controller" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_camera", @@ -785,7 +785,7 @@ dependencies = [ [[package]] name = "bevy_clipboard" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_ecs", @@ -799,7 +799,7 @@ dependencies = [ [[package]] name = "bevy_color" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_math", "bevy_reflect", @@ -814,7 +814,7 @@ dependencies = [ [[package]] name = "bevy_core_pipeline" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -856,7 +856,7 @@ dependencies = [ [[package]] name = "bevy_derive" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_macro_utils 0.19.0", "quote", @@ -866,7 +866,7 @@ dependencies = [ [[package]] name = "bevy_dev_tools" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -897,7 +897,7 @@ dependencies = [ [[package]] name = "bevy_diagnostic" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "atomic-waker", "bevy_app", @@ -914,7 +914,7 @@ dependencies = [ [[package]] name = "bevy_ecs" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "arrayvec", "bevy_ecs_macros", @@ -941,7 +941,7 @@ dependencies = [ [[package]] name = "bevy_ecs_macro_logic" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_macro_utils 0.19.0", "proc-macro2", @@ -952,7 +952,7 @@ dependencies = [ [[package]] name = "bevy_ecs_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_ecs_macro_logic", "bevy_macro_utils 0.19.0", @@ -964,7 +964,7 @@ dependencies = [ [[package]] name = "bevy_encase_derive" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_macro_utils 0.19.0", "encase_derive_impl", @@ -973,7 +973,7 @@ dependencies = [ [[package]] name = "bevy_feathers" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "accesskit", "bevy_a11y", @@ -1004,7 +1004,7 @@ dependencies = [ [[package]] name = "bevy_gilrs" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_ecs", @@ -1019,7 +1019,7 @@ dependencies = [ [[package]] name = "bevy_gizmos" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1041,7 +1041,7 @@ dependencies = [ [[package]] name = "bevy_gizmos_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_macro_utils 0.19.0", "quote", @@ -1051,7 +1051,7 @@ dependencies = [ [[package]] name = "bevy_gizmos_render" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1079,7 +1079,7 @@ dependencies = [ [[package]] name = "bevy_gltf" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "async-lock", "base64", @@ -1114,7 +1114,7 @@ dependencies = [ [[package]] name = "bevy_image" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1142,7 +1142,7 @@ dependencies = [ [[package]] name = "bevy_input" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_ecs", @@ -1158,7 +1158,7 @@ dependencies = [ [[package]] name = "bevy_input_focus" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_ecs", @@ -1174,7 +1174,7 @@ dependencies = [ [[package]] name = "bevy_internal" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_a11y", "bevy_android", @@ -1233,7 +1233,7 @@ dependencies = [ [[package]] name = "bevy_light" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1258,7 +1258,7 @@ dependencies = [ [[package]] name = "bevy_log" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "android_log-sys", "bevy_app", @@ -1275,7 +1275,7 @@ dependencies = [ [[package]] name = "bevy_macro_utils" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "proc-macro2", "quote", @@ -1298,7 +1298,7 @@ dependencies = [ [[package]] name = "bevy_material" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_asset", "bevy_derive", @@ -1320,7 +1320,7 @@ dependencies = [ [[package]] name = "bevy_material_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_macro_utils 0.19.0", "quote", @@ -1330,7 +1330,7 @@ dependencies = [ [[package]] name = "bevy_math" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "approx", "arrayvec", @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "bevy_mesh" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1391,7 +1391,7 @@ dependencies = [ [[package]] name = "bevy_pbr" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "arrayvec", "bevy_app", @@ -1433,7 +1433,7 @@ dependencies = [ [[package]] name = "bevy_picking" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1456,7 +1456,7 @@ dependencies = [ [[package]] name = "bevy_platform" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "critical-section", "foldhash 0.2.0", @@ -1477,7 +1477,7 @@ dependencies = [ [[package]] name = "bevy_post_process" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1501,12 +1501,12 @@ dependencies = [ [[package]] name = "bevy_ptr" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" [[package]] name = "bevy_reflect" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "assert_type_match", "bevy_platform", @@ -1534,7 +1534,7 @@ dependencies = [ [[package]] name = "bevy_reflect_derive" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_macro_utils 0.19.0", "indexmap", @@ -1547,7 +1547,7 @@ dependencies = [ [[package]] name = "bevy_render" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "async-channel", "bevy_app", @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "bevy_render_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_macro_utils 0.19.0", "proc-macro2", @@ -1611,7 +1611,7 @@ dependencies = [ [[package]] name = "bevy_scene" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1631,7 +1631,7 @@ dependencies = [ [[package]] name = "bevy_scene_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_ecs_macro_logic", "bevy_macro_utils 0.19.0", @@ -1680,7 +1680,7 @@ dependencies = [ [[package]] name = "bevy_shader" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_asset", "bevy_platform", @@ -1699,7 +1699,7 @@ dependencies = [ [[package]] name = "bevy_sprite" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1724,7 +1724,7 @@ dependencies = [ [[package]] name = "bevy_sprite_render" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1756,7 +1756,7 @@ dependencies = [ [[package]] name = "bevy_state" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_ecs", @@ -1771,7 +1771,7 @@ dependencies = [ [[package]] name = "bevy_state_macros" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_macro_utils 0.19.0", "quote", @@ -1781,7 +1781,7 @@ dependencies = [ [[package]] name = "bevy_tasks" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "async-channel", "async-executor", @@ -1799,7 +1799,7 @@ dependencies = [ [[package]] name = "bevy_text" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1827,7 +1827,7 @@ dependencies = [ [[package]] name = "bevy_time" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_ecs", @@ -1841,7 +1841,7 @@ dependencies = [ [[package]] name = "bevy_transform" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_ecs", @@ -1857,7 +1857,7 @@ dependencies = [ [[package]] name = "bevy_ui" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "accesskit", "bevy_a11y", @@ -1894,7 +1894,7 @@ dependencies = [ [[package]] name = "bevy_ui_render" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1926,7 +1926,7 @@ dependencies = [ [[package]] name = "bevy_ui_widgets" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "accesskit", "bevy_a11y", @@ -1949,7 +1949,7 @@ dependencies = [ [[package]] name = "bevy_utils" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "async-channel", "bevy_platform", @@ -1961,7 +1961,7 @@ dependencies = [ [[package]] name = "bevy_window" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -1979,7 +1979,7 @@ dependencies = [ [[package]] name = "bevy_winit" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "accesskit", "accesskit_winit", @@ -2011,7 +2011,7 @@ dependencies = [ [[package]] name = "bevy_world_serialization" version = "0.19.0" -source = "git+https://github.com/processing/bevy?branch=main#2b84275f2dd8ea25c9190c4f4c1bfbf5ae6aaf7e" +source = "git+https://github.com/processing/bevy?branch=main#6717bb35291b66ff1925e4387c48e0499e351423" dependencies = [ "bevy_app", "bevy_asset", @@ -3656,7 +3656,7 @@ dependencies = [ "vec_map", "wasm-bindgen", "web-sys", - "windows 0.58.0", + "windows 0.62.2", ] [[package]] @@ -3810,7 +3810,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.20", - "windows 0.58.0", + "windows 0.62.2", ] [[package]] @@ -7220,7 +7220,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c2499c2d826531388872b2268718aed907a39bd785ab0dcfe57fab26283f92e" dependencies = [ - "skrifa 0.37.0", + "skrifa 0.42.1", "yazi", "zeno", ] diff --git a/crates/processing_render/src/geometry/mod.rs b/crates/processing_render/src/geometry/mod.rs index ec4b4d47..b10f6a6f 100644 --- a/crates/processing_render/src/geometry/mod.rs +++ b/crates/processing_render/src/geometry/mod.rs @@ -445,3 +445,27 @@ pub fn destroy( commands.entity(entity).despawn(); Ok(()) } + +/// Reflects a y-up mesh into the y-down world: positions, normals, tangents and winding +pub(crate) fn mirror_y(mesh: &mut Mesh) { + for attr in [Mesh::ATTRIBUTE_POSITION, Mesh::ATTRIBUTE_NORMAL] { + if let Some(VertexAttributeValues::Float32x3(v)) = mesh.attribute_mut(attr) { + for p in v.iter_mut() { + p[1] = -p[1]; + } + } + } + // the bitangent is `cross(normal, tangent) * w`, and a mirror flips that handedness + if let Some(VertexAttributeValues::Float32x4(v)) = mesh.attribute_mut(Mesh::ATTRIBUTE_TANGENT) { + for t in v.iter_mut() { + t[1] = -t[1]; + t[3] = -t[3]; + } + } + // a reflection reverses winding; `invert_winding` skips unindexed meshes, so index them first + if mesh.indices().is_none() && mesh.primitive_topology() == PrimitiveTopology::TriangleList { + let n = mesh.count_vertices() as u32; + mesh.insert_indices(Indices::U32((0..n).collect())); + } + let _ = mesh.invert_winding(); +} diff --git a/crates/processing_render/src/gltf.rs b/crates/processing_render/src/gltf.rs index 1bdfa558..d34b5cbe 100644 --- a/crates/processing_render/src/gltf.rs +++ b/crates/processing_render/src/gltf.rs @@ -9,7 +9,6 @@ use bevy::{ camera::visibility::RenderLayers, ecs::system::RunSystemOnce, gltf::{Gltf, GltfMaterial, GltfMeshName}, - mesh::VertexAttributeValues, pbr::ExtendedMaterial, platform::collections::HashSet, prelude::*, @@ -40,25 +39,8 @@ fn mirror_y(t: Transform) -> Transform { } } -fn mirror_mesh(mesh: &mut Mesh) { - for attr in [Mesh::ATTRIBUTE_POSITION, Mesh::ATTRIBUTE_NORMAL] { - if let Some(VertexAttributeValues::Float32x3(v)) = mesh.attribute_mut(attr) { - for p in v.iter_mut() { - p[1] = -p[1]; - } - } - } - // the bitangent is `cross(normal, tangent) * w`, and a mirror flips that handedness - if let Some(VertexAttributeValues::Float32x4(v)) = mesh.attribute_mut(Mesh::ATTRIBUTE_TANGENT) { - for t in v.iter_mut() { - t[1] = -t[1]; - t[3] = -t[3]; - } - } -} - /// glTF is y-up and the Processing world is y-down, so a scene is mirrored on import to -/// render as authored. The clockwise front face already matches the mirrored winding. +/// render as authored. fn mirror_instance(world: &mut World, instance_id: InstanceId) { world.init_resource::(); let entities: Vec = world @@ -80,7 +62,7 @@ fn mirror_instance(world: &mut World, instance_id: InstanceId) { if done.0.insert(handle.id()) && let Some(mut mesh) = meshes.get_mut(&handle) { - mirror_mesh(&mut mesh); + crate::geometry::mirror_y(&mut mesh); } } }); diff --git a/crates/processing_render/src/lib.rs b/crates/processing_render/src/lib.rs index 6bbfe67f..f79e86a8 100644 --- a/crates/processing_render/src/lib.rs +++ b/crates/processing_render/src/lib.rs @@ -108,6 +108,12 @@ impl Plugin for ProcessingRenderPlugin { )) .add_plugins(ci::CiPlugin); + // Processing strokes every edge of a shape, so the wireframe pass never culls + app.insert_resource(bevy::pbr::wireframe::WireframeConfig { + cull_mode: None, + ..Default::default() + }); + app.add_systems(First, (clear_transient_meshes, activate_cameras)) .add_systems( Update, diff --git a/crates/processing_render/src/render/primitive/shape3d.rs b/crates/processing_render/src/render/primitive/shape3d.rs index 1e4889b3..a7c5b45c 100644 --- a/crates/processing_render/src/render/primitive/shape3d.rs +++ b/crates/processing_render/src/render/primitive/shape3d.rs @@ -16,31 +16,37 @@ fn ensure_vertex_colors(mesh: &mut Mesh) { } } +/// Bevy authors its primitives y-up, so they are mirrored to render as authored +fn finish(mesh: &mut Mesh) { + crate::geometry::mirror_y(mesh); + ensure_vertex_colors(mesh); +} + pub fn box_mesh(width: f32, height: f32, depth: f32) -> Mesh { let cuboid = bevy::math::primitives::Cuboid::new(width, height, depth); let mut mesh = Mesh::from(cuboid); - ensure_vertex_colors(&mut mesh); + finish(&mut mesh); mesh } pub fn sphere_mesh(radius: f32, sectors: u32, stacks: u32) -> Mesh { let sphere = bevy::math::primitives::Sphere::new(radius); let mut mesh = sphere.mesh().uv(sectors, stacks); - ensure_vertex_colors(&mut mesh); + finish(&mut mesh); mesh } pub fn cylinder_mesh(radius: f32, height: f32, detail: u32) -> Mesh { let cylinder = bevy::math::primitives::Cylinder::new(radius, height); let mut mesh = cylinder.mesh().resolution(detail).build(); - ensure_vertex_colors(&mut mesh); + finish(&mut mesh); mesh } pub fn cone_mesh(radius: f32, height: f32, detail: u32) -> Mesh { let cone = bevy::math::primitives::Cone::new(radius, height); let mut mesh = cone.mesh().resolution(detail).build(); - ensure_vertex_colors(&mut mesh); + finish(&mut mesh); mesh } @@ -51,7 +57,7 @@ pub fn torus_mesh(radius: f32, tube_radius: f32, major_segments: u32, minor_segm .major_resolution(major_segments as usize) .minor_resolution(minor_segments as usize) .build(); - ensure_vertex_colors(&mut mesh); + finish(&mut mesh); mesh } @@ -62,7 +68,7 @@ pub fn capsule_mesh(radius: f32, length: f32, detail: u32) -> Mesh { .longitudes(detail) .latitudes(detail / 2) .build(); - ensure_vertex_colors(&mut mesh); + finish(&mut mesh); mesh } @@ -73,7 +79,7 @@ pub fn conical_frustum_mesh(radius_top: f32, radius_bottom: f32, height: f32, de height, }; let mut mesh = frustum.mesh().resolution(detail).build(); - ensure_vertex_colors(&mut mesh); + finish(&mut mesh); mesh } @@ -86,7 +92,7 @@ pub fn tetrahedron_mesh(radius: f32) -> Mesh { bevy::math::Vec3::new(-r, -r, r), ); let mut mesh = Mesh::from(tetrahedron); - ensure_vertex_colors(&mut mesh); + finish(&mut mesh); mesh } @@ -124,6 +130,6 @@ pub fn grid_mesh(nx: u32, ny: u32, nz: u32, spacing: f32) -> Mesh { pub fn plane_mesh(width: f32, height: f32) -> Mesh { let plane = bevy::math::primitives::Plane3d::default(); let mut mesh = plane.mesh().size(width, height).build(); - ensure_vertex_colors(&mut mesh); + finish(&mut mesh); mesh }