-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Built-in skybox #8275
Merged
Merged
Built-in skybox #8275
Changes from 28 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
5a4ba5c
WIP SkyboxPlugin
JMS55 28eb2aa
Shader WIP
JMS55 73f7192
Hook up bind group
JMS55 4559cbd
Fixes
JMS55 14ff0c2
Misc refactor
JMS55 2279f09
Misc fix
JMS55 addf220
Extract skybox
JMS55 c952cc6
Shader fixes
JMS55 121ce48
Fix shader
JMS55 2ad5eaa
Remove camera translation from skybox
JMS55 b23e640
Fix skybox shader
JMS55 9eb67d9
Improve shader
JMS55 6286b8f
Move skybox module
JMS55 0b8e3d5
Add doc
JMS55 9b29b5d
Misc doc
JMS55 0d57752
Doc tweak
JMS55 9f147c1
Change visibilities
JMS55 637a313
Misc
JMS55 73089f7
Fix imports
JMS55 00a62df
Combine SkyboxNode and MainOpaquePass3dNode
JMS55 34a8ee9
Misc removal
JMS55 6e1bfee
Use the view type shader import
superdump ec9f0c2
Use a fullscreen triangle to render the skybox
superdump d00802d
Add documentation to how the fullscreen shader works
superdump bbbb708
Update the skybox example to use the new Skybox component
superdump 144f88b
Cleanup after rebase
superdump be50268
Remove debug notes
superdump f0c7f70
Merge pull request #10 from superdump/skybox-fullscreen-triangle
JMS55 0d9216c
Update crates/bevy_core_pipeline/src/skybox/skybox.wgsl
JMS55 b0c1a15
Flip environment map light sampling
JMS55 36f4939
Remove separator
JMS55 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
use bevy_app::{App, Plugin}; | ||
use bevy_asset::{load_internal_asset, Handle, HandleUntyped}; | ||
use bevy_ecs::{ | ||
prelude::{Component, Entity}, | ||
query::With, | ||
schedule::IntoSystemConfigs, | ||
system::{Commands, Query, Res, ResMut, Resource}, | ||
}; | ||
use bevy_reflect::TypeUuid; | ||
use bevy_render::{ | ||
extract_component::{ExtractComponent, ExtractComponentPlugin}, | ||
render_asset::RenderAssets, | ||
render_resource::{ | ||
BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, | ||
BindGroupLayoutEntry, BindingResource, BindingType, BlendState, BufferBindingType, | ||
CachedRenderPipelineId, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, | ||
DepthStencilState, FragmentState, MultisampleState, PipelineCache, PrimitiveState, | ||
RenderPipelineDescriptor, SamplerBindingType, Shader, ShaderStages, ShaderType, | ||
SpecializedRenderPipeline, SpecializedRenderPipelines, StencilFaceState, StencilState, | ||
TextureFormat, TextureSampleType, TextureViewDimension, VertexState, | ||
}, | ||
renderer::RenderDevice, | ||
texture::{BevyDefault, Image}, | ||
view::{ExtractedView, Msaa, ViewTarget, ViewUniform, ViewUniforms}, | ||
Render, RenderApp, RenderSet, | ||
}; | ||
|
||
const SKYBOX_SHADER_HANDLE: HandleUntyped = | ||
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 55594763423201); | ||
|
||
pub struct SkyboxPlugin; | ||
JMS55 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
impl Plugin for SkyboxPlugin { | ||
fn build(&self, app: &mut App) { | ||
load_internal_asset!(app, SKYBOX_SHADER_HANDLE, "skybox.wgsl", Shader::from_wgsl); | ||
|
||
app.add_plugin(ExtractComponentPlugin::<Skybox>::default()); | ||
|
||
let render_app = match app.get_sub_app_mut(RenderApp) { | ||
Ok(render_app) => render_app, | ||
Err(_) => return, | ||
}; | ||
|
||
let render_device = render_app.world.resource::<RenderDevice>().clone(); | ||
|
||
render_app | ||
.insert_resource(SkyboxPipeline::new(&render_device)) | ||
.init_resource::<SpecializedRenderPipelines<SkyboxPipeline>>() | ||
.add_systems( | ||
Render, | ||
( | ||
prepare_skybox_pipelines.in_set(RenderSet::Prepare), | ||
queue_skybox_bind_groups.in_set(RenderSet::Queue), | ||
), | ||
); | ||
} | ||
} | ||
|
||
/// Adds a skybox to a 3D camera, based on a cubemap texture. | ||
/// | ||
/// Note that this component does not (currently) affect the scene's lighting. | ||
/// To do so, use `EnvironmentMapLight` alongside this component. | ||
JMS55 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// | ||
/// See also <https://en.wikipedia.org/wiki/Skybox_(video_games)>. | ||
#[derive(Component, ExtractComponent, Clone)] | ||
pub struct Skybox(pub Handle<Image>); | ||
|
||
// ---------------------------------------------------------------------------- | ||
JMS55 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#[derive(Resource)] | ||
struct SkyboxPipeline { | ||
bind_group_layout: BindGroupLayout, | ||
} | ||
|
||
impl SkyboxPipeline { | ||
fn new(render_device: &RenderDevice) -> Self { | ||
let bind_group_layout_descriptor = BindGroupLayoutDescriptor { | ||
label: Some("skybox_bind_group_layout"), | ||
entries: &[ | ||
BindGroupLayoutEntry { | ||
binding: 0, | ||
visibility: ShaderStages::FRAGMENT, | ||
ty: BindingType::Texture { | ||
sample_type: TextureSampleType::Float { filterable: true }, | ||
view_dimension: TextureViewDimension::Cube, | ||
multisampled: false, | ||
}, | ||
count: None, | ||
}, | ||
BindGroupLayoutEntry { | ||
binding: 1, | ||
visibility: ShaderStages::FRAGMENT, | ||
ty: BindingType::Sampler(SamplerBindingType::Filtering), | ||
count: None, | ||
}, | ||
BindGroupLayoutEntry { | ||
binding: 2, | ||
visibility: ShaderStages::VERTEX_FRAGMENT, | ||
ty: BindingType::Buffer { | ||
ty: BufferBindingType::Uniform, | ||
has_dynamic_offset: true, | ||
min_binding_size: Some(ViewUniform::min_size()), | ||
}, | ||
count: None, | ||
}, | ||
], | ||
}; | ||
|
||
Self { | ||
bind_group_layout: render_device | ||
.create_bind_group_layout(&bind_group_layout_descriptor), | ||
} | ||
} | ||
} | ||
|
||
#[derive(PartialEq, Eq, Hash, Clone, Copy)] | ||
struct SkyboxPipelineKey { | ||
hdr: bool, | ||
samples: u32, | ||
} | ||
|
||
impl SpecializedRenderPipeline for SkyboxPipeline { | ||
type Key = SkyboxPipelineKey; | ||
|
||
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { | ||
RenderPipelineDescriptor { | ||
label: Some("skybox_pipeline".into()), | ||
layout: vec![self.bind_group_layout.clone()], | ||
push_constant_ranges: Vec::new(), | ||
vertex: VertexState { | ||
shader: SKYBOX_SHADER_HANDLE.typed(), | ||
shader_defs: Vec::new(), | ||
entry_point: "skybox_vertex".into(), | ||
buffers: Vec::new(), | ||
}, | ||
primitive: PrimitiveState::default(), | ||
depth_stencil: Some(DepthStencilState { | ||
format: TextureFormat::Depth32Float, | ||
depth_write_enabled: false, | ||
depth_compare: CompareFunction::GreaterEqual, | ||
stencil: StencilState { | ||
front: StencilFaceState::IGNORE, | ||
back: StencilFaceState::IGNORE, | ||
read_mask: 0, | ||
write_mask: 0, | ||
}, | ||
bias: DepthBiasState { | ||
constant: 0, | ||
slope_scale: 0.0, | ||
clamp: 0.0, | ||
}, | ||
}), | ||
multisample: MultisampleState { | ||
count: key.samples, | ||
mask: !0, | ||
alpha_to_coverage_enabled: false, | ||
}, | ||
fragment: Some(FragmentState { | ||
shader: SKYBOX_SHADER_HANDLE.typed(), | ||
shader_defs: Vec::new(), | ||
entry_point: "skybox_fragment".into(), | ||
targets: vec![Some(ColorTargetState { | ||
format: if key.hdr { | ||
ViewTarget::TEXTURE_FORMAT_HDR | ||
} else { | ||
TextureFormat::bevy_default() | ||
}, | ||
blend: Some(BlendState::REPLACE), | ||
write_mask: ColorWrites::ALL, | ||
})], | ||
}), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Component)] | ||
pub struct SkyboxPipelineId(pub CachedRenderPipelineId); | ||
|
||
fn prepare_skybox_pipelines( | ||
mut commands: Commands, | ||
pipeline_cache: Res<PipelineCache>, | ||
mut pipelines: ResMut<SpecializedRenderPipelines<SkyboxPipeline>>, | ||
pipeline: Res<SkyboxPipeline>, | ||
msaa: Res<Msaa>, | ||
views: Query<(Entity, &ExtractedView), With<Skybox>>, | ||
) { | ||
for (entity, view) in &views { | ||
let pipeline_id = pipelines.specialize( | ||
&pipeline_cache, | ||
&pipeline, | ||
SkyboxPipelineKey { | ||
hdr: view.hdr, | ||
samples: msaa.samples(), | ||
}, | ||
); | ||
|
||
commands | ||
.entity(entity) | ||
.insert(SkyboxPipelineId(pipeline_id)); | ||
} | ||
} | ||
|
||
#[derive(Component)] | ||
pub struct SkyboxBindGroup(pub BindGroup); | ||
|
||
fn queue_skybox_bind_groups( | ||
mut commands: Commands, | ||
pipeline: Res<SkyboxPipeline>, | ||
view_uniforms: Res<ViewUniforms>, | ||
images: Res<RenderAssets<Image>>, | ||
render_device: Res<RenderDevice>, | ||
views: Query<(Entity, &Skybox)>, | ||
) { | ||
for (entity, skybox) in &views { | ||
if let (Some(skybox), Some(view_uniforms)) = | ||
(images.get(&skybox.0), view_uniforms.uniforms.binding()) | ||
{ | ||
let bind_group = render_device.create_bind_group(&BindGroupDescriptor { | ||
label: Some("skybox_bind_group"), | ||
layout: &pipeline.bind_group_layout, | ||
entries: &[ | ||
BindGroupEntry { | ||
binding: 0, | ||
resource: BindingResource::TextureView(&skybox.texture_view), | ||
}, | ||
BindGroupEntry { | ||
binding: 1, | ||
resource: BindingResource::Sampler(&skybox.sampler), | ||
}, | ||
BindGroupEntry { | ||
binding: 2, | ||
resource: view_uniforms, | ||
}, | ||
], | ||
}); | ||
|
||
commands.entity(entity).insert(SkyboxBindGroup(bind_group)); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
For other reviewers, I added this documentation as part of figuring out how to do the fullscreen triangle approach.