Skip to content

Commit

Permalink
Mesh refactor and mesh pipeline specialization
Browse files Browse the repository at this point in the history
  • Loading branch information
parasyte authored and cart committed Feb 18, 2022
1 parent b3a1db6 commit fb43380
Show file tree
Hide file tree
Showing 25 changed files with 664 additions and 514 deletions.
10 changes: 5 additions & 5 deletions crates/bevy_gltf/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,33 +125,33 @@ async fn load_gltf<'a, 'b>(
.read_positions()
.map(|v| VertexAttributeValues::Float32x3(v.collect()))
{
mesh.set_attribute(Mesh::ATTRIBUTE_POSITION, vertex_attribute);
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertex_attribute);
}

if let Some(vertex_attribute) = reader
.read_normals()
.map(|v| VertexAttributeValues::Float32x3(v.collect()))
{
mesh.set_attribute(Mesh::ATTRIBUTE_NORMAL, vertex_attribute);
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, vertex_attribute);
}

if let Some(vertex_attribute) = reader
.read_tangents()
.map(|v| VertexAttributeValues::Float32x4(v.collect()))
{
mesh.set_attribute(Mesh::ATTRIBUTE_TANGENT, vertex_attribute);
mesh.insert_attribute(Mesh::ATTRIBUTE_TANGENT, vertex_attribute);
}

if let Some(vertex_attribute) = reader
.read_tex_coords(0)
.map(|v| VertexAttributeValues::Float32x2(v.into_f32().collect()))
{
mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, vertex_attribute);
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, vertex_attribute);
} else {
let len = mesh.count_vertices();
let uvs = vec![[0.0, 0.0]; len];
bevy_log::debug!("missing `TEXCOORD_0` vertex attribute, loading zeroed out UVs");
mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
}

// if let Some(vertex_attribute) = reader
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_pbr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use bevy_render::{
prelude::Color,
render_graph::RenderGraph,
render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions},
render_resource::{Shader, SpecializedPipelines},
render_resource::{Shader, SpecializedMeshPipelines},
view::VisibilitySystems,
RenderApp, RenderStage,
};
Expand Down Expand Up @@ -178,7 +178,7 @@ impl Plugin for PbrPlugin {
.init_resource::<DrawFunctions<Shadow>>()
.init_resource::<LightMeta>()
.init_resource::<GlobalLightMeta>()
.init_resource::<SpecializedPipelines<ShadowPipeline>>();
.init_resource::<SpecializedMeshPipelines<ShadowPipeline>>();

let shadow_pass_node = ShadowPassNode::new(&mut render_app.world);
render_app.add_render_command::<Shadow, DrawShadowMesh>();
Expand Down
146 changes: 79 additions & 67 deletions crates/bevy_pbr/src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use bevy_ecs::{
world::FromWorld,
};
use bevy_render::{
mesh::Mesh,
mesh::{Mesh, MeshVertexBufferLayout},
render_asset::{RenderAsset, RenderAssetPlugin, RenderAssets},
render_component::ExtractComponentPlugin,
render_phase::{
Expand All @@ -24,7 +24,7 @@ use bevy_render::{
},
render_resource::{
BindGroup, BindGroupLayout, RenderPipelineCache, RenderPipelineDescriptor, Shader,
SpecializedPipeline, SpecializedPipelines,
SpecializedMeshPipeline, SpecializedMeshPipelines,
},
renderer::RenderDevice,
view::{ExtractedView, Msaa, VisibleEntities},
Expand Down Expand Up @@ -81,7 +81,12 @@ impl<M: Material> SpecializedMaterial for M {
fn key(_material: &<Self as RenderAsset>::PreparedAsset) -> Self::Key {}

#[inline]
fn specialize(_key: Self::Key, _descriptor: &mut RenderPipelineDescriptor) {}
fn specialize(
_descriptor: &mut RenderPipelineDescriptor,
_key: Self::Key,
_layout: &MeshVertexBufferLayout,
) {
}

#[inline]
fn bind_group(material: &<Self as RenderAsset>::PreparedAsset) -> &BindGroup {
Expand Down Expand Up @@ -130,7 +135,11 @@ pub trait SpecializedMaterial: Asset + RenderAsset {
fn key(material: &<Self as RenderAsset>::PreparedAsset) -> Self::Key;

/// Specializes the given `descriptor` according to the given `key`.
fn specialize(key: Self::Key, descriptor: &mut RenderPipelineDescriptor);
fn specialize(
descriptor: &mut RenderPipelineDescriptor,
key: Self::Key,
layout: &MeshVertexBufferLayout,
);

/// Returns this material's [`BindGroup`]. This should match the layout returned by [`SpecializedMaterial::bind_group_layout`].
fn bind_group(material: &<Self as RenderAsset>::PreparedAsset) -> &BindGroup;
Expand Down Expand Up @@ -188,7 +197,7 @@ impl<M: SpecializedMaterial> Plugin for MaterialPlugin<M> {
.add_render_command::<Opaque3d, DrawMaterial<M>>()
.add_render_command::<AlphaMask3d, DrawMaterial<M>>()
.init_resource::<MaterialPipeline<M>>()
.init_resource::<SpecializedPipelines<MaterialPipeline<M>>>()
.init_resource::<SpecializedMeshPipelines<MaterialPipeline<M>>>()
.add_system_to_stage(RenderStage::Queue, queue_material_meshes::<M>);
}
}
Expand All @@ -202,11 +211,15 @@ pub struct MaterialPipeline<M: SpecializedMaterial> {
marker: PhantomData<M>,
}

impl<M: SpecializedMaterial> SpecializedPipeline for MaterialPipeline<M> {
impl<M: SpecializedMaterial> SpecializedMeshPipeline for MaterialPipeline<M> {
type Key = (MeshPipelineKey, M::Key);

fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
let mut descriptor = self.mesh_pipeline.specialize(key.0);
fn specialize(
&self,
key: Self::Key,
layout: &MeshVertexBufferLayout,
) -> RenderPipelineDescriptor {
let mut descriptor = self.mesh_pipeline.specialize(key.0, layout);
if let Some(vertex_shader) = &self.vertex_shader {
descriptor.vertex.shader = vertex_shader.clone();
}
Expand All @@ -220,7 +233,7 @@ impl<M: SpecializedMaterial> SpecializedPipeline for MaterialPipeline<M> {
self.mesh_pipeline.mesh_layout.clone(),
]);

M::specialize(key.1, &mut descriptor);
M::specialize(&mut descriptor, key.1, layout);
descriptor
}
}
Expand Down Expand Up @@ -275,7 +288,7 @@ pub fn queue_material_meshes<M: SpecializedMaterial>(
alpha_mask_draw_functions: Res<DrawFunctions<AlphaMask3d>>,
transparent_draw_functions: Res<DrawFunctions<Transparent3d>>,
material_pipeline: Res<MaterialPipeline<M>>,
mut pipelines: ResMut<SpecializedPipelines<MaterialPipeline<M>>>,
mut pipelines: ResMut<SpecializedMeshPipelines<MaterialPipeline<M>>>,
mut pipeline_cache: ResMut<RenderPipelineCache>,
msaa: Res<Msaa>,
render_meshes: Res<RenderAssets<Mesh>>,
Expand Down Expand Up @@ -307,72 +320,71 @@ pub fn queue_material_meshes<M: SpecializedMaterial>(

let inverse_view_matrix = view.transform.compute_matrix().inverse();
let inverse_view_row_2 = inverse_view_matrix.row(2);
let mesh_key = MeshPipelineKey::from_msaa_samples(msaa.samples);
let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples);

for visible_entity in &visible_entities.entities {
if let Ok((material_handle, mesh_handle, mesh_uniform)) =
material_meshes.get(*visible_entity)
{
if let Some(material) = render_materials.get(material_handle) {
let mut mesh_key = mesh_key;
if let Some(mesh) = render_meshes.get(mesh_handle) {
if mesh.has_tangents {
mesh_key |= MeshPipelineKey::VERTEX_TANGENTS;
let mut mesh_key =
MeshPipelineKey::from_primitive_topology(mesh.primitive_topology)
| msaa_key;
let alpha_mode = M::alpha_mode(material);
if let AlphaMode::Blend = alpha_mode {
mesh_key |= MeshPipelineKey::TRANSPARENT_MAIN_PASS;
}
mesh_key |=
MeshPipelineKey::from_primitive_topology(mesh.primitive_topology);
}
let alpha_mode = M::alpha_mode(material);
if let AlphaMode::Blend = alpha_mode {
mesh_key |= MeshPipelineKey::TRANSPARENT_MAIN_PASS;
}

let specialized_key = M::key(material);
let pipeline_id = pipelines.specialize(
&mut pipeline_cache,
&material_pipeline,
(mesh_key, specialized_key),
);

// NOTE: row 2 of the inverse view matrix dotted with column 3 of the model matrix
// gives the z component of translation of the mesh in view space
let mesh_z = inverse_view_row_2.dot(mesh_uniform.transform.col(3));
match alpha_mode {
AlphaMode::Opaque => {
opaque_phase.add(Opaque3d {
entity: *visible_entity,
draw_function: draw_opaque_pbr,
pipeline: pipeline_id,
// NOTE: Front-to-back ordering for opaque with ascending sort means near should have the
// lowest sort key and getting further away should increase. As we have
// -z in front of the camera, values in view space decrease away from the
// camera. Flipping the sign of mesh_z results in the correct front-to-back ordering
distance: -mesh_z,
});
}
AlphaMode::Mask(_) => {
alpha_mask_phase.add(AlphaMask3d {
entity: *visible_entity,
draw_function: draw_alpha_mask_pbr,
pipeline: pipeline_id,
// NOTE: Front-to-back ordering for alpha mask with ascending sort means near should have the
// lowest sort key and getting further away should increase. As we have
// -z in front of the camera, values in view space decrease away from the
// camera. Flipping the sign of mesh_z results in the correct front-to-back ordering
distance: -mesh_z,
});
}
AlphaMode::Blend => {
transparent_phase.add(Transparent3d {
entity: *visible_entity,
draw_function: draw_transparent_pbr,
pipeline: pipeline_id,
// NOTE: Back-to-front ordering for transparent with ascending sort means far should have the
// lowest sort key and getting closer should increase. As we have
// -z in front of the camera, the largest distance is -far with values increasing toward the
// camera. As such we can just use mesh_z as the distance
distance: mesh_z,
});
let specialized_key = M::key(material);

let pipeline_id = pipelines.specialize(
&mut pipeline_cache,
&material_pipeline,
(mesh_key, specialized_key),
&mesh.layout,
);

// NOTE: row 2 of the inverse view matrix dotted with column 3 of the model matrix
// gives the z component of translation of the mesh in view space
let mesh_z = inverse_view_row_2.dot(mesh_uniform.transform.col(3));
match alpha_mode {
AlphaMode::Opaque => {
opaque_phase.add(Opaque3d {
entity: *visible_entity,
draw_function: draw_opaque_pbr,
pipeline: pipeline_id,
// NOTE: Front-to-back ordering for opaque with ascending sort means near should have the
// lowest sort key and getting further away should increase. As we have
// -z in front of the camera, values in view space decrease away from the
// camera. Flipping the sign of mesh_z results in the correct front-to-back ordering
distance: -mesh_z,
});
}
AlphaMode::Mask(_) => {
alpha_mask_phase.add(AlphaMask3d {
entity: *visible_entity,
draw_function: draw_alpha_mask_pbr,
pipeline: pipeline_id,
// NOTE: Front-to-back ordering for alpha mask with ascending sort means near should have the
// lowest sort key and getting further away should increase. As we have
// -z in front of the camera, values in view space decrease away from the
// camera. Flipping the sign of mesh_z results in the correct front-to-back ordering
distance: -mesh_z,
});
}
AlphaMode::Blend => {
transparent_phase.add(Transparent3d {
entity: *visible_entity,
draw_function: draw_transparent_pbr,
pipeline: pipeline_id,
// NOTE: Back-to-front ordering for transparent with ascending sort means far should have the
// lowest sort key and getting closer should increase. As we have
// -z in front of the camera, the largest distance is -far with values increasing toward the
// camera. As such we can just use mesh_z as the distance
distance: mesh_z,
});
}
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion crates/bevy_pbr/src/pbr_material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use bevy_math::Vec4;
use bevy_reflect::TypeUuid;
use bevy_render::{
color::Color,
mesh::MeshVertexBufferLayout,
prelude::Shader,
render_asset::{PrepareAssetError, RenderAsset, RenderAssets},
render_resource::{
Expand Down Expand Up @@ -338,7 +339,11 @@ impl SpecializedMaterial for StandardMaterial {
}
}

fn specialize(key: Self::Key, descriptor: &mut RenderPipelineDescriptor) {
fn specialize(
descriptor: &mut RenderPipelineDescriptor,
key: Self::Key,
_layout: &MeshVertexBufferLayout,
) {
if key.normal_map {
descriptor
.fragment
Expand Down
Loading

0 comments on commit fb43380

Please sign in to comment.