Skip to main content

ranim_render/pipelines/
mesh_item.rs

1use std::ops::Deref;
2
3use bevy_ecs::prelude::*;
4
5use crate::{
6    ResolutionInfo, WgpuContext,
7    primitives::{
8        mesh_items::MeshItemsBuffer,
9        viewport::{ViewportBindGroup, ViewportGpuPacket},
10    },
11    resource::{GpuResource, OUTPUT_TEXTURE_FORMAT, PipelinesPool},
12    schedule::{FrameTarget, RenderContext, RenderProfiler},
13};
14
15#[allow(clippy::too_many_arguments)]
16pub(crate) fn depth(
17    mut render: RenderContext,
18    ctx: Res<WgpuContext>,
19    pipelines: Res<PipelinesPool>,
20    resolution: Res<ResolutionInfo>,
21    target: Res<FrameTarget>,
22    viewport: Res<ViewportGpuPacket>,
23    merged: Res<MeshItemsBuffer>,
24    profiler: Res<RenderProfiler>,
25) {
26    if merged.item_count() == 0 {
27        return;
28    }
29    let mut pass = render
30        .encoder()
31        .begin_render_pass(&wgpu::RenderPassDescriptor {
32            label: Some("Merged MeshItem Depth Render Pass"),
33            color_attachments: &[],
34            depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
35                view: &target.depth_stencil_view,
36                depth_ops: Some(wgpu::Operations {
37                    load: wgpu::LoadOp::Load,
38                    store: wgpu::StoreOp::Store,
39                }),
40                stencil_ops: None,
41            }),
42            timestamp_writes: None,
43            occlusion_query_set: None,
44            multiview_mask: None,
45        });
46    profiler.scope_pass("mesh::depth", &mut pass, |pass| {
47        pass.set_pipeline(&pipelines.get_or_init::<MeshItemDepthPipeline>(&ctx));
48        pass.set_bind_group(0, &resolution.bind_group, &[]);
49        pass.set_bind_group(1, &viewport.uniforms_bind_group.bind_group, &[]);
50        pass.set_bind_group(2, merged.render_bind_group.as_ref().unwrap(), &[]);
51        pass.set_vertex_buffer(0, merged.vertices_buffer.buffer.slice(..));
52        pass.set_vertex_buffer(1, merged.mesh_ids_buffer.buffer.slice(..));
53        pass.set_vertex_buffer(2, merged.vertex_colors_buffer.buffer.slice(..));
54        pass.set_vertex_buffer(3, merged.vertex_normals_buffer.buffer.slice(..));
55        pass.set_index_buffer(
56            merged.indices_buffer.buffer.slice(..),
57            wgpu::IndexFormat::Uint32,
58        );
59        pass.draw_indexed(0..merged.total_indices(), 0, 0..1);
60    });
61}
62
63#[allow(clippy::too_many_arguments)]
64pub(crate) fn color(
65    mut render: RenderContext,
66    ctx: Res<WgpuContext>,
67    pipelines: Res<PipelinesPool>,
68    resolution: Res<ResolutionInfo>,
69    target: Res<FrameTarget>,
70    viewport: Res<ViewportGpuPacket>,
71    merged: Res<MeshItemsBuffer>,
72    profiler: Res<RenderProfiler>,
73) {
74    if merged.item_count() == 0 {
75        return;
76    }
77    let mut pass = render
78        .encoder()
79        .begin_render_pass(&wgpu::RenderPassDescriptor {
80            label: Some("Merged MeshItem Color Render Pass"),
81            color_attachments: &[Some(wgpu::RenderPassColorAttachment {
82                view: &target.render_view,
83                resolve_target: None,
84                depth_slice: None,
85                ops: wgpu::Operations {
86                    load: wgpu::LoadOp::Load,
87                    store: wgpu::StoreOp::Store,
88                },
89            })],
90            depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
91                view: &target.depth_stencil_view,
92                depth_ops: Some(wgpu::Operations {
93                    load: wgpu::LoadOp::Load,
94                    store: wgpu::StoreOp::Store,
95                }),
96                stencil_ops: None,
97            }),
98            timestamp_writes: None,
99            occlusion_query_set: None,
100            multiview_mask: None,
101        });
102    profiler.scope_pass("mesh::color", &mut pass, |pass| {
103        pass.set_pipeline(&pipelines.get_or_init::<MeshItemColorPipeline>(&ctx));
104        pass.set_bind_group(0, &resolution.bind_group, &[]);
105        pass.set_bind_group(1, &viewport.uniforms_bind_group.bind_group, &[]);
106        pass.set_bind_group(2, merged.render_bind_group.as_ref().unwrap(), &[]);
107        pass.set_vertex_buffer(0, merged.vertices_buffer.buffer.slice(..));
108        pass.set_vertex_buffer(1, merged.mesh_ids_buffer.buffer.slice(..));
109        pass.set_vertex_buffer(2, merged.vertex_colors_buffer.buffer.slice(..));
110        pass.set_vertex_buffer(3, merged.vertex_normals_buffer.buffer.slice(..));
111        pass.set_index_buffer(
112            merged.indices_buffer.buffer.slice(..),
113            wgpu::IndexFormat::Uint32,
114        );
115        pass.draw_indexed(0..merged.total_indices(), 0, 0..1);
116    });
117}
118
119pub struct MeshItemColorPipeline {
120    pipeline: wgpu::RenderPipeline,
121}
122
123impl Deref for MeshItemColorPipeline {
124    type Target = wgpu::RenderPipeline;
125    fn deref(&self) -> &Self::Target {
126        &self.pipeline
127    }
128}
129
130impl GpuResource for MeshItemColorPipeline {
131    fn new(ctx: &WgpuContext) -> Self {
132        let module = &ctx
133            .device
134            .create_shader_module(wgpu::include_wgsl!("./shaders/mesh_item.wgsl"));
135        let layout = ctx
136            .device
137            .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
138                label: Some("MeshItem Color Pipeline Layout"),
139                bind_group_layouts: &[
140                    Some(&ResolutionInfo::create_bind_group_layout(ctx)),
141                    Some(&ViewportBindGroup::bind_group_layout(ctx)),
142                    Some(&MeshItemsBuffer::render_bind_group_layout(ctx)),
143                ],
144                immediate_size: 0,
145            });
146        let vertex_buffer_layouts = MeshItemsBuffer::vertex_buffer_layouts().map(Some);
147        let pipeline = ctx
148            .device
149            .create_render_pipeline(&wgpu::RenderPipelineDescriptor {
150                label: Some("MeshItem Color Pipeline"),
151                layout: Some(&layout),
152                vertex: wgpu::VertexState {
153                    module,
154                    entry_point: Some("vs_main"),
155                    buffers: &vertex_buffer_layouts,
156                    compilation_options: wgpu::PipelineCompilationOptions::default(),
157                },
158                fragment: Some(wgpu::FragmentState {
159                    module,
160                    entry_point: Some("fs_color"),
161                    compilation_options: wgpu::PipelineCompilationOptions::default(),
162                    targets: &[Some(wgpu::ColorTargetState {
163                        format: OUTPUT_TEXTURE_FORMAT,
164                        blend: Some(wgpu::BlendState::ALPHA_BLENDING),
165                        write_mask: wgpu::ColorWrites::ALL,
166                    })],
167                }),
168                primitive: wgpu::PrimitiveState {
169                    topology: wgpu::PrimitiveTopology::TriangleList,
170                    ..Default::default()
171                },
172                depth_stencil: Some(wgpu::DepthStencilState {
173                    format: wgpu::TextureFormat::Depth32Float,
174                    depth_write_enabled: Some(false),
175                    depth_compare: Some(wgpu::CompareFunction::LessEqual),
176                    stencil: wgpu::StencilState::default(),
177                    bias: wgpu::DepthBiasState::default(),
178                }),
179                multisample: wgpu::MultisampleState {
180                    count: 1,
181                    mask: !0,
182                    alpha_to_coverage_enabled: false,
183                },
184                multiview_mask: None,
185                cache: None,
186            });
187        Self { pipeline }
188    }
189}
190
191pub struct MeshItemDepthPipeline {
192    pipeline: wgpu::RenderPipeline,
193}
194
195impl Deref for MeshItemDepthPipeline {
196    type Target = wgpu::RenderPipeline;
197    fn deref(&self) -> &Self::Target {
198        &self.pipeline
199    }
200}
201
202impl GpuResource for MeshItemDepthPipeline {
203    fn new(ctx: &WgpuContext) -> Self {
204        let module = &ctx
205            .device
206            .create_shader_module(wgpu::include_wgsl!("./shaders/mesh_item.wgsl"));
207        let layout = ctx
208            .device
209            .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
210                label: Some("MeshItem Depth Pipeline Layout"),
211                bind_group_layouts: &[
212                    Some(&ResolutionInfo::create_bind_group_layout(ctx)),
213                    Some(&ViewportBindGroup::bind_group_layout(ctx)),
214                    Some(&MeshItemsBuffer::render_bind_group_layout(ctx)),
215                ],
216                immediate_size: 0,
217            });
218        let vertex_buffer_layouts = MeshItemsBuffer::vertex_buffer_layouts().map(Some);
219        let pipeline = ctx
220            .device
221            .create_render_pipeline(&wgpu::RenderPipelineDescriptor {
222                label: Some("MeshItem Depth Pipeline"),
223                layout: Some(&layout),
224                vertex: wgpu::VertexState {
225                    module,
226                    entry_point: Some("vs_main"),
227                    buffers: &vertex_buffer_layouts,
228                    compilation_options: wgpu::PipelineCompilationOptions::default(),
229                },
230                fragment: Some(wgpu::FragmentState {
231                    module,
232                    entry_point: Some("fs_depth"),
233                    compilation_options: wgpu::PipelineCompilationOptions::default(),
234                    targets: &[],
235                }),
236                primitive: wgpu::PrimitiveState {
237                    topology: wgpu::PrimitiveTopology::TriangleList,
238                    ..Default::default()
239                },
240                depth_stencil: Some(wgpu::DepthStencilState {
241                    format: wgpu::TextureFormat::Depth32Float,
242                    depth_write_enabled: Some(true),
243                    depth_compare: Some(wgpu::CompareFunction::Less),
244                    stencil: wgpu::StencilState::default(),
245                    bias: wgpu::DepthBiasState::default(),
246                }),
247                multisample: wgpu::MultisampleState {
248                    count: 1,
249                    mask: !0,
250                    alpha_to_coverage_enabled: false,
251                },
252                multiview_mask: None,
253                cache: None,
254            });
255        Self { pipeline }
256    }
257}