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