-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR implements wireframe rendering. Usage: This is now ready as soon as #1401 gets merged. Usage: ```rust app .insert_resource(WgpuOptions { name: Some("3d_scene"), features: WgpuFeatures::NON_FILL_POLYGON_MODE, ..Default::default() }) // To enable the NON_FILL_POLYGON_MODE feature .add_plugin(WireframePlugin) .run(); ``` Now we just need to add the Wireframe component on an entity, and it'll draw. its wireframe. We can also enable wireframe drawing globally by setting the global property in the `WireframeConfig` resource to `true`. Co-authored-by: Zhixing Zhang <me@neoto.xin>
- Loading branch information
1 parent
079b3ad
commit d9fb61d
Showing
7 changed files
with
240 additions
and
0 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
use crate::{ | ||
draw::DrawContext, | ||
mesh::Indices, | ||
pipeline::{PipelineDescriptor, PipelineSpecialization, RenderPipeline}, | ||
prelude::*, | ||
shader::Shader, | ||
}; | ||
use bevy_app::prelude::*; | ||
use bevy_asset::{Assets, Handle, HandleUntyped}; | ||
use bevy_ecs::{IntoSystem, Mut, Query, QuerySet, Res, With}; | ||
use bevy_reflect::{Reflect, ReflectComponent, TypeUuid}; | ||
use bevy_utils::HashSet; | ||
|
||
mod pipeline; | ||
|
||
pub const WIREFRAME_PIPELINE_HANDLE: HandleUntyped = | ||
HandleUntyped::weak_from_u64(PipelineDescriptor::TYPE_UUID, 0x137c75ab7e9ad7f5); | ||
|
||
#[derive(Debug, Default)] | ||
pub struct WireframePlugin; | ||
|
||
impl Plugin for WireframePlugin { | ||
fn build(&self, app: &mut AppBuilder) { | ||
app.init_resource::<WireframeConfig>() | ||
.add_system_to_stage(crate::RenderStage::Draw, draw_wireframes_system.system()); | ||
let resources = app.resources(); | ||
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap(); | ||
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap(); | ||
pipelines.set( | ||
WIREFRAME_PIPELINE_HANDLE, | ||
pipeline::build_wireframe_pipeline(&mut shaders), | ||
); | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone, Reflect, Default)] | ||
#[reflect(Component)] | ||
pub struct Wireframe; | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct WireframeConfig { | ||
pub global: bool, | ||
} | ||
|
||
impl Default for WireframeConfig { | ||
fn default() -> Self { | ||
WireframeConfig { global: false } | ||
} | ||
} | ||
|
||
pub fn draw_wireframes_system( | ||
mut draw_context: DrawContext, | ||
msaa: Res<Msaa>, | ||
meshes: Res<Assets<Mesh>>, | ||
wireframe_config: Res<WireframeConfig>, | ||
mut query: QuerySet<( | ||
Query<(&mut Draw, &mut RenderPipelines, &Handle<Mesh>, &Visible)>, | ||
Query<(&mut Draw, &mut RenderPipelines, &Handle<Mesh>, &Visible), With<Wireframe>>, | ||
)>, | ||
) { | ||
let iterator = |(mut draw, mut render_pipelines, mesh_handle, visible): ( | ||
Mut<Draw>, | ||
Mut<RenderPipelines>, | ||
&Handle<Mesh>, | ||
&Visible, | ||
)| { | ||
if !visible.is_visible { | ||
return; | ||
} | ||
|
||
// don't render if the mesh isn't loaded yet | ||
let mesh = if let Some(mesh) = meshes.get(mesh_handle) { | ||
mesh | ||
} else { | ||
return; | ||
}; | ||
|
||
let mut render_pipeline = RenderPipeline::specialized( | ||
WIREFRAME_PIPELINE_HANDLE.typed(), | ||
PipelineSpecialization { | ||
sample_count: msaa.samples, | ||
strip_index_format: None, | ||
shader_specialization: Default::default(), | ||
primitive_topology: mesh.primitive_topology(), | ||
dynamic_bindings: render_pipelines | ||
.bindings | ||
.iter_dynamic_bindings() | ||
.map(|name| name.to_string()) | ||
.collect::<HashSet<String>>(), | ||
vertex_buffer_layout: mesh.get_vertex_buffer_layout(), | ||
}, | ||
); | ||
render_pipeline.dynamic_bindings_generation = | ||
render_pipelines.bindings.dynamic_bindings_generation(); | ||
|
||
draw_context | ||
.set_pipeline( | ||
&mut draw, | ||
&render_pipeline.pipeline, | ||
&render_pipeline.specialization, | ||
) | ||
.unwrap(); | ||
draw_context | ||
.set_bind_groups_from_bindings(&mut draw, &mut [&mut render_pipelines.bindings]) | ||
.unwrap(); | ||
draw_context | ||
.set_vertex_buffers_from_bindings(&mut draw, &[&render_pipelines.bindings]) | ||
.unwrap(); | ||
|
||
match mesh.indices() { | ||
Some(Indices::U32(indices)) => draw.draw_indexed(0..indices.len() as u32, 0, 0..1), | ||
Some(Indices::U16(indices)) => draw.draw_indexed(0..indices.len() as u32, 0, 0..1), | ||
None => draw.draw(0..mesh.count_vertices() as u32, 0..1), | ||
}; | ||
}; | ||
|
||
if wireframe_config.global { | ||
query.q0_mut().iter_mut().for_each(iterator); | ||
} else { | ||
query.q1_mut().iter_mut().for_each(iterator); | ||
} | ||
} |
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,30 @@ | ||
use crate::{ | ||
pipeline::{ | ||
CullMode, FrontFace, PipelineDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, | ||
}, | ||
shader::{Shader, ShaderStage, ShaderStages}, | ||
}; | ||
use bevy_asset::Assets; | ||
|
||
pub(crate) fn build_wireframe_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor { | ||
PipelineDescriptor { | ||
name: Some("wireframe".into()), | ||
primitive: PrimitiveState { | ||
topology: PrimitiveTopology::TriangleList, | ||
strip_index_format: None, | ||
front_face: FrontFace::Ccw, | ||
cull_mode: CullMode::None, | ||
polygon_mode: PolygonMode::Line, | ||
}, | ||
..PipelineDescriptor::default_config(ShaderStages { | ||
vertex: shaders.add(Shader::from_glsl( | ||
ShaderStage::Vertex, | ||
include_str!("wireframe.vert"), | ||
)), | ||
fragment: Some(shaders.add(Shader::from_glsl( | ||
ShaderStage::Fragment, | ||
include_str!("wireframe.frag"), | ||
))), | ||
}) | ||
} | ||
} |
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,8 @@ | ||
#version 450 | ||
|
||
layout(location = 0) out vec4 o_Target; | ||
|
||
|
||
void main() { | ||
o_Target = vec4(1.0, 1.0, 1.0, 1.0); | ||
} |
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,16 @@ | ||
#version 450 | ||
|
||
layout(location = 0) in vec3 Vertex_Position; | ||
|
||
layout(set = 0, binding = 0) uniform Camera { | ||
mat4 ViewProj; | ||
}; | ||
|
||
layout(set = 1, binding = 0) uniform Transform { | ||
mat4 Model; | ||
}; | ||
|
||
void main() { | ||
vec3 v_Position = (Model * vec4(Vertex_Position, 1.0)).xyz; | ||
gl_Position = ViewProj * vec4(v_Position, 1.0); | ||
} |
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,59 @@ | ||
use bevy::prelude::*; | ||
use bevy_internal::{ | ||
render::wireframe::{Wireframe, WireframeConfig, WireframePlugin}, | ||
wgpu::{WgpuFeature, WgpuFeatures, WgpuOptions}, | ||
}; | ||
|
||
fn main() { | ||
App::build() | ||
.insert_resource(Msaa { samples: 4 }) | ||
.insert_resource(WgpuOptions { | ||
features: WgpuFeatures { | ||
// The Wireframe requires NonFillPolygonMode feature | ||
features: vec![WgpuFeature::NonFillPolygonMode], | ||
}, | ||
..Default::default() | ||
}) | ||
.add_plugins(DefaultPlugins) | ||
.add_plugin(WireframePlugin) | ||
.add_startup_system(setup.system()) | ||
.run(); | ||
} | ||
|
||
/// set up a simple 3D scene | ||
fn setup( | ||
commands: &mut Commands, | ||
mut wireframe_config: ResMut<WireframeConfig>, | ||
mut meshes: ResMut<Assets<Mesh>>, | ||
mut materials: ResMut<Assets<StandardMaterial>>, | ||
) { | ||
// To draw the wireframe on all entities, set this to 'true' | ||
wireframe_config.global = false; | ||
// add entities to the world | ||
commands | ||
// plane | ||
.spawn(PbrBundle { | ||
mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })), | ||
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), | ||
..Default::default() | ||
}) | ||
// cube | ||
.spawn(PbrBundle { | ||
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), | ||
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()), | ||
transform: Transform::from_xyz(0.0, 0.5, 0.0), | ||
..Default::default() | ||
}) | ||
.with(Wireframe) // This enables wireframe drawing on this entity | ||
// light | ||
.spawn(LightBundle { | ||
transform: Transform::from_xyz(4.0, 8.0, 4.0), | ||
..Default::default() | ||
}) | ||
// camera | ||
.spawn(PerspectiveCameraBundle { | ||
transform: Transform::from_xyz(-2.0, 2.5, 5.0) | ||
.looking_at(Vec3::default(), Vec3::unit_y()), | ||
..Default::default() | ||
}); | ||
} |