-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Atmosphere as entity with transforms #23651
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b300a5c
8a25136
8d12248
e5f7aca
2c8f037
9ffe41d
53aa60e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,36 +2,46 @@ | |
|
|
||
| use alloc::{borrow::Cow, sync::Arc}; | ||
| use bevy_asset::{Asset, AssetEvent, AssetId, Handle}; | ||
| use bevy_camera::Hdr; | ||
| use bevy_color::{ColorToComponents, Gray, LinearRgba}; | ||
| use bevy_ecs::{ | ||
| component::Component, | ||
| lifecycle::HookContext, | ||
| message::MessageReader, | ||
| system::{Res, ResMut}, | ||
| world::DeferredWorld, | ||
| }; | ||
| use bevy_image::Image; | ||
| use bevy_math::curve::{FunctionCurve, Interval, SampleAutoCurve}; | ||
| use bevy_math::{ops, Curve, FloatPow, Vec3}; | ||
| use bevy_platform::collections::HashSet; | ||
| use bevy_reflect::TypePath; | ||
| use bevy_transform::components::GlobalTransform; | ||
| use core::f32::{self, consts::PI}; | ||
| use smallvec::SmallVec; | ||
| use wgpu_types::TextureFormat; | ||
|
|
||
| /// Enables atmospheric scattering for an HDR camera. | ||
| /// Atmosphere for one planet. The entity's [`GlobalTransform`] is the planet center in world space. | ||
| /// | ||
| /// Add `AtmosphereSettings` to each 3D camera that should use it, the nearest atmosphere is used for rendering. | ||
| /// | ||
| /// If [`GlobalTransform`] is still [`Default`] when this component is first added, it is placed `radius` units directly below the origin on the `Y` axis, so that the planet's normal is roughly `Vec3::Y` around the origin, likely where your camera/scene is located. Unless you're making a game set in space, this is probably what you want. Otherwise, feel free to override this default by setting a transform manually. | ||
| /// | ||
| /// The scale on [`GlobalTransform`] rescales the planet in world space. Tune it with the radius offset | ||
| /// when your scene uses other units, like kilometer-sized scenes. | ||
| #[derive(Clone, Component)] | ||
| #[require(Hdr)] | ||
| #[require(GlobalTransform::default())] | ||
| #[component(on_add = set_default_transform)] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice if there was some way to opt out of setting the The only thing I can think of is making the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I need to better understand the use case, maybe I should test this change with
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Not really, it integrates with
No, because it would just get overwritten by whatever transform system is present, including bevy's. That's why I was suggesting making the atmosphere positioning entirely opt-in: you get good default behavior for bevy out of the box, and don't have any dependency on |
||
| pub struct Atmosphere { | ||
| /// Radius of the planet | ||
| /// | ||
| /// units: m | ||
| pub bottom_radius: f32, | ||
| pub inner_radius: f32, | ||
|
|
||
| /// Radius at which we consider the atmosphere to 'end' for our | ||
| /// calculations (from center of planet) | ||
| /// | ||
| /// units: m | ||
| pub top_radius: f32, | ||
| pub outer_radius: f32, | ||
|
|
||
| /// An approximation of the average albedo (or color, roughly) of the | ||
| /// planet's surface. This is used when calculating multiscattering. | ||
|
|
@@ -44,15 +54,27 @@ pub struct Atmosphere { | |
| pub medium: Handle<ScatteringMedium>, | ||
| } | ||
|
|
||
| fn set_default_transform(mut world: DeferredWorld<'_>, HookContext { entity, .. }: HookContext) { | ||
| let Some(inner_radius) = world.get::<Atmosphere>(entity).map(|a| a.inner_radius) else { | ||
| unreachable!("on_add hooks guarantee the component is present"); | ||
| }; | ||
|
|
||
| if let Some(mut transform) = world.get_mut::<GlobalTransform>(entity) | ||
| && *transform == GlobalTransform::default() | ||
| { | ||
| *transform = GlobalTransform::from_translation(-Vec3::Y * inner_radius); | ||
| } | ||
| } | ||
|
|
||
| impl Atmosphere { | ||
| /// An atmosphere like that of earth. Use this with a [`ScatteringMedium::earth`] handle. | ||
| pub fn earth(medium: Handle<ScatteringMedium>) -> Self { | ||
| const EARTH_BOTTOM_RADIUS: f32 = 6_360_000.0; | ||
| const EARTH_TOP_RADIUS: f32 = 6_460_000.0; | ||
| const EARTH_INNER_RADIUS: f32 = 6_360_000.0; | ||
| const EARTH_OUTER_RADIUS: f32 = 6_460_000.0; | ||
| const EARTH_ALBEDO: Vec3 = Vec3::splat(0.3); | ||
| Self { | ||
| bottom_radius: EARTH_BOTTOM_RADIUS, | ||
| top_radius: EARTH_TOP_RADIUS, | ||
| inner_radius: EARTH_INNER_RADIUS, | ||
| outer_radius: EARTH_OUTER_RADIUS, | ||
| ground_albedo: EARTH_ALBEDO, | ||
| medium, | ||
| } | ||
|
|
@@ -64,12 +86,12 @@ impl Atmosphere { | |
| /// | ||
| /// [Seidelmann et al. 2007, Table 4]: https://doi.org/10.1007/s10569-007-9072-y | ||
| pub fn mars(medium: Handle<ScatteringMedium>) -> Self { | ||
| const MARS_BOTTOM_RADIUS: f32 = 3_389_500.0; | ||
| const MARS_TOP_RADIUS: f32 = 3_509_500.0; | ||
| const MARS_INNER_RADIUS: f32 = 3_389_500.0; | ||
| const MARS_OUTER_RADIUS: f32 = 3_509_500.0; | ||
| const MARS_ALBEDO: Vec3 = Vec3::splat(0.1); | ||
| Self { | ||
| bottom_radius: MARS_BOTTOM_RADIUS, | ||
| top_radius: MARS_TOP_RADIUS, | ||
| inner_radius: MARS_INNER_RADIUS, | ||
| outer_radius: MARS_OUTER_RADIUS, | ||
| ground_albedo: MARS_ALBEDO, | ||
| medium, | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
Atmospherefields sayunits: m. But according to this comment this is only accurate for scale =Vec3::ONE.Maybe there should also be a note about transforms that are not x==y==z.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point I never tested non-uniform scale, hopefully it doesn't break too badly 😬 However, regarding the units: m that should stay the same since these units are still expressed in atmosphere-space and not world-space. So scaling the atmosphere doesn't change the meaning of those units, those are still meters. For actually scaling the atmosphere in a physically based way you'd set a smaller
inner_radiusandouter_radius. Now I realize this might be confusing so maybe it deserves more docs.