Skip to content
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

[Merged by Bors] - Wireframe Rendering Pipeline #562

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod render_graph;
pub mod renderer;
pub mod shader;
pub mod texture;
pub mod wireframe;

use bevy_ecs::{IntoExclusiveSystem, IntoSystem, SystemStage};
use bevy_reflect::RegisterTypeBuilder;
Expand Down
122 changes: 122 additions & 0 deletions crates/bevy_render/src/wireframe/mod.rs
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);
}
}
30 changes: 30 additions & 0 deletions crates/bevy_render/src/wireframe/pipeline.rs
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"),
))),
})
}
}
8 changes: 8 additions & 0 deletions crates/bevy_render/src/wireframe/wireframe.frag
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);
}
16 changes: 16 additions & 0 deletions crates/bevy_render/src/wireframe/wireframe.vert
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);
}
15 changes: 15 additions & 0 deletions examples/3d/3d_scene.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
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 {
Neo-Zhixing marked this conversation as resolved.
Show resolved Hide resolved
features: WgpuFeatures {
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
Expand All @@ -29,6 +43,7 @@ fn setup(
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),
Expand Down