Skip to content

Commit 58474d7

Browse files
update wireframe rendering to new renderer (#3193)
Updates the wireframe rendering initialliy implemented in #562 to the new renderer. It lives in `bevy_pbr2` instead of `bevy_render2` because that way it can reuse the `MeshPipeline`.
1 parent cf48132 commit 58474d7

File tree

3 files changed

+175
-0
lines changed

3 files changed

+175
-0
lines changed

pipelined/bevy_pbr2/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
pub mod wireframe;
2+
13
mod alpha;
24
mod bundle;
35
mod light;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#import bevy_pbr::mesh_view_bind_group
2+
#import bevy_pbr::mesh_struct
3+
4+
struct Vertex {
5+
[[location(0)]] position: vec3<f32>;
6+
};
7+
8+
[[group(1), binding(0)]]
9+
var<uniform> mesh: Mesh;
10+
11+
struct VertexOutput {
12+
[[builtin(position)]] clip_position: vec4<f32>;
13+
};
14+
15+
[[stage(vertex)]]
16+
fn vertex(vertex: Vertex) -> VertexOutput {
17+
let world_position = mesh.model * vec4<f32>(vertex.position, 1.0);
18+
19+
var out: VertexOutput;
20+
out.clip_position = view.view_proj * world_position;
21+
22+
return out;
23+
}
24+
25+
[[stage(fragment)]]
26+
fn fragment() -> [[location(0)]] vec4<f32> {
27+
return vec4<f32>(1.0, 1.0, 1.0, 1.0);
28+
}

pipelined/bevy_pbr2/src/wireframe.rs

+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
use crate::MeshPipeline;
2+
use crate::{DrawMesh, MeshPipelineKey, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup};
3+
use bevy_app::Plugin;
4+
use bevy_asset::{Assets, Handle, HandleUntyped};
5+
use bevy_core_pipeline::Opaque3d;
6+
use bevy_ecs::{prelude::*, reflect::ReflectComponent};
7+
use bevy_reflect::Reflect;
8+
use bevy_reflect::TypeUuid;
9+
use bevy_render2::{
10+
mesh::Mesh,
11+
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline},
12+
render_resource::{RenderPipelineCache, Shader, SpecializedPipeline, SpecializedPipelines},
13+
view::{ExtractedView, Msaa},
14+
RenderApp, RenderStage,
15+
};
16+
use wgpu::PolygonMode;
17+
18+
pub const WIREFRAME_SHADER_HANDLE: HandleUntyped =
19+
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 192598014480025766);
20+
21+
#[derive(Debug, Default)]
22+
pub struct WireframePlugin;
23+
24+
impl Plugin for WireframePlugin {
25+
fn build(&self, app: &mut bevy_app::App) {
26+
let mut shaders = app.world.get_resource_mut::<Assets<Shader>>().unwrap();
27+
shaders.set_untracked(
28+
WIREFRAME_SHADER_HANDLE,
29+
Shader::from_wgsl(include_str!("render/wireframe.wgsl")),
30+
);
31+
32+
app.init_resource::<WireframeConfig>();
33+
34+
app.sub_app(RenderApp)
35+
.add_render_command::<Opaque3d, DrawWireframes>()
36+
.init_resource::<WireframePipeline>()
37+
.init_resource::<SpecializedPipelines<WireframePipeline>>()
38+
.add_system_to_stage(RenderStage::Extract, extract_wireframes)
39+
.add_system_to_stage(RenderStage::Extract, extract_wireframe_config)
40+
.add_system_to_stage(RenderStage::Queue, queue_wireframes);
41+
}
42+
}
43+
44+
fn extract_wireframe_config(mut commands: Commands, wireframe_config: Res<WireframeConfig>) {
45+
if wireframe_config.is_added() || wireframe_config.is_changed() {
46+
commands.insert_resource(wireframe_config.into_inner().clone());
47+
}
48+
}
49+
50+
fn extract_wireframes(mut commands: Commands, query: Query<Entity, With<Wireframe>>) {
51+
for entity in query.iter() {
52+
commands.get_or_spawn(entity).insert(Wireframe);
53+
}
54+
}
55+
56+
/// Controls whether an entity should rendered in wireframe-mode if the [WireframePlugin] is enabled
57+
#[derive(Component, Debug, Clone, Default, Reflect)]
58+
#[reflect(Component)]
59+
pub struct Wireframe;
60+
61+
#[derive(Debug, Clone, Default)]
62+
pub struct WireframeConfig {
63+
/// Whether to show wireframes for all meshes. If `false`, only meshes with a [Wireframe] component will be rendered.
64+
pub global: bool,
65+
}
66+
67+
pub struct WireframePipeline {
68+
mesh_pipeline: MeshPipeline,
69+
shader: Handle<Shader>,
70+
}
71+
impl FromWorld for WireframePipeline {
72+
fn from_world(render_world: &mut World) -> Self {
73+
WireframePipeline {
74+
mesh_pipeline: render_world.get_resource::<MeshPipeline>().unwrap().clone(),
75+
shader: WIREFRAME_SHADER_HANDLE.typed(),
76+
}
77+
}
78+
}
79+
80+
impl SpecializedPipeline for WireframePipeline {
81+
type Key = MeshPipelineKey;
82+
83+
fn specialize(
84+
&self,
85+
key: Self::Key,
86+
) -> bevy_render2::render_resource::RenderPipelineDescriptor {
87+
let mut descriptor = self.mesh_pipeline.specialize(key);
88+
descriptor.vertex.shader = self.shader.clone_weak();
89+
descriptor.fragment.as_mut().unwrap().shader = self.shader.clone_weak();
90+
descriptor.primitive.polygon_mode = PolygonMode::Line;
91+
descriptor.depth_stencil.as_mut().unwrap().bias.slope_scale = 1.0;
92+
descriptor
93+
}
94+
}
95+
96+
#[allow(clippy::too_many_arguments)]
97+
fn queue_wireframes(
98+
opaque_3d_draw_functions: Res<DrawFunctions<Opaque3d>>,
99+
wireframe_config: Res<WireframeConfig>,
100+
wireframe_pipeline: Res<WireframePipeline>,
101+
mut pipeline_cache: ResMut<RenderPipelineCache>,
102+
mut specialized_pipelines: ResMut<SpecializedPipelines<WireframePipeline>>,
103+
msaa: Res<Msaa>,
104+
mut material_meshes: QuerySet<(
105+
QueryState<(Entity, &MeshUniform), With<Handle<Mesh>>>,
106+
QueryState<(Entity, &MeshUniform), (With<Handle<Mesh>>, With<Wireframe>)>,
107+
)>,
108+
mut views: Query<(&ExtractedView, &mut RenderPhase<Opaque3d>)>,
109+
) {
110+
let draw_custom = opaque_3d_draw_functions
111+
.read()
112+
.get_id::<DrawWireframes>()
113+
.unwrap();
114+
let key = MeshPipelineKey::from_msaa_samples(msaa.samples);
115+
for (view, mut transparent_phase) in views.iter_mut() {
116+
let view_matrix = view.transform.compute_matrix();
117+
let view_row_2 = view_matrix.row(2);
118+
119+
let add_render_phase = |(entity, mesh_uniform): (Entity, &MeshUniform)| {
120+
transparent_phase.add(Opaque3d {
121+
entity,
122+
pipeline: specialized_pipelines.specialize(
123+
&mut pipeline_cache,
124+
&wireframe_pipeline,
125+
key,
126+
),
127+
draw_function: draw_custom,
128+
distance: view_row_2.dot(mesh_uniform.transform.col(3)),
129+
});
130+
};
131+
132+
if wireframe_config.global {
133+
material_meshes.q0().iter().for_each(add_render_phase);
134+
} else {
135+
material_meshes.q1().iter().for_each(add_render_phase);
136+
}
137+
}
138+
}
139+
140+
type DrawWireframes = (
141+
SetItemPipeline,
142+
SetMeshViewBindGroup<0>,
143+
SetMeshBindGroup<1>,
144+
DrawMesh,
145+
);

0 commit comments

Comments
 (0)