rend3_pbr/common/
depth_pass.rs

1use std::sync::Arc;
2
3use arrayvec::ArrayVec;
4use rend3::{resources::MaterialManager, ModeData, RendererMode};
5use wgpu::{
6    BindGroupLayout, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState, Device, Face,
7    FragmentState, FrontFace, MultisampleState, PipelineLayoutDescriptor, PolygonMode, PrimitiveState,
8    PrimitiveTopology, RenderPipeline, RenderPipelineDescriptor, StencilState, TextureFormat, VertexState,
9};
10
11use crate::{
12    common::{interfaces::ShaderInterfaces, shaders::mode_safe_shader},
13    material::PbrMaterial,
14    vertex::{cpu_vertex_buffers, gpu_vertex_buffers},
15    SampleCount,
16};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum DepthPassType {
20    Shadow,
21    Prepass,
22}
23
24pub struct BuildDepthPassShaderArgs<'a> {
25    pub mode: RendererMode,
26    pub device: &'a Device,
27
28    pub interfaces: &'a ShaderInterfaces,
29    pub texture_bgl: ModeData<(), &'a BindGroupLayout>,
30
31    pub materials: &'a MaterialManager,
32
33    pub samples: SampleCount,
34    pub ty: DepthPassType,
35}
36
37#[derive(Clone)]
38pub struct DepthPassPipelines {
39    pub cutout: Arc<RenderPipeline>,
40    pub opaque: Arc<RenderPipeline>,
41}
42
43pub fn build_depth_pass_pipeline(args: BuildDepthPassShaderArgs) -> DepthPassPipelines {
44    profiling::scope!("build depth pass pipelines");
45    let depth_vert = unsafe {
46        mode_safe_shader(
47            args.device,
48            args.mode,
49            "depth pass vert",
50            "depth.vert.cpu.spv",
51            "depth.vert.gpu.spv",
52            false,
53        )
54    };
55
56    let depth_opaque_frag = unsafe {
57        mode_safe_shader(
58            args.device,
59            args.mode,
60            "depth pass opaque frag",
61            "depth-opaque.frag.cpu.spv",
62            "depth-opaque.frag.gpu.spv",
63            false,
64        )
65    };
66
67    let depth_cutout_frag = unsafe {
68        mode_safe_shader(
69            args.device,
70            args.mode,
71            "depth pass cutout frag",
72            "depth-cutout.frag.cpu.spv",
73            "depth-cutout.frag.gpu.spv",
74            false,
75        )
76    };
77
78    let mut bgls: ArrayVec<&BindGroupLayout, 4> = ArrayVec::new();
79    bgls.push(&args.interfaces.samplers_bgl);
80    bgls.push(&args.interfaces.culled_object_bgl);
81    bgls.push(args.materials.get_bind_group_layout::<PbrMaterial>());
82    if args.mode == RendererMode::GPUPowered {
83        bgls.push(args.texture_bgl.as_gpu())
84    }
85
86    let pll = args.device.create_pipeline_layout(&PipelineLayoutDescriptor {
87        label: Some("depth prepass"),
88        bind_group_layouts: &bgls,
89        push_constant_ranges: &[],
90    });
91
92    DepthPassPipelines {
93        opaque: Arc::new(create_depth_inner(
94            &args,
95            &pll,
96            &depth_vert,
97            &depth_opaque_frag,
98            match args.ty {
99                DepthPassType::Prepass => "depth opaque prepass",
100                DepthPassType::Shadow => "depth opaque prepass",
101            },
102        )),
103        cutout: Arc::new(create_depth_inner(
104            &args,
105            &pll,
106            &depth_vert,
107            &depth_cutout_frag,
108            match args.ty {
109                DepthPassType::Prepass => "depth cutout prepass",
110                DepthPassType::Shadow => "depth cutout prepass",
111            },
112        )),
113    }
114}
115
116fn create_depth_inner(
117    args: &BuildDepthPassShaderArgs,
118    pll: &wgpu::PipelineLayout,
119    vert: &wgpu::ShaderModule,
120    frag: &wgpu::ShaderModule,
121    name: &str,
122) -> RenderPipeline {
123    profiling::scope!("build depth pipeline", name);
124    let color_state = [ColorTargetState {
125        format: TextureFormat::Rgba16Float,
126        blend: None,
127        write_mask: ColorWrites::empty(),
128    }];
129    let cpu_vertex_buffers = cpu_vertex_buffers();
130    let gpu_vertex_buffers = gpu_vertex_buffers();
131    args.device.create_render_pipeline(&RenderPipelineDescriptor {
132        label: Some(name),
133        layout: Some(pll),
134        vertex: VertexState {
135            module: vert,
136            entry_point: "main",
137            buffers: match args.mode {
138                RendererMode::CPUPowered => &cpu_vertex_buffers,
139                RendererMode::GPUPowered => &gpu_vertex_buffers,
140            },
141        },
142        primitive: PrimitiveState {
143            topology: PrimitiveTopology::TriangleList,
144            strip_index_format: None,
145            front_face: FrontFace::Cw,
146            cull_mode: Some(match args.ty {
147                DepthPassType::Shadow => Face::Front,
148                DepthPassType::Prepass => Face::Back,
149            }),
150            clamp_depth: matches!(args.ty, DepthPassType::Shadow),
151            polygon_mode: PolygonMode::Fill,
152            conservative: false,
153        },
154        depth_stencil: Some(DepthStencilState {
155            format: TextureFormat::Depth32Float,
156            depth_write_enabled: true,
157            depth_compare: match args.ty {
158                DepthPassType::Shadow => CompareFunction::LessEqual,
159                DepthPassType::Prepass => CompareFunction::GreaterEqual,
160            },
161            stencil: StencilState::default(),
162            bias: match args.ty {
163                DepthPassType::Prepass => DepthBiasState::default(),
164                DepthPassType::Shadow => DepthBiasState {
165                    constant: 2,
166                    slope_scale: 2.0,
167                    clamp: 0.0,
168                },
169            },
170        }),
171        multisample: MultisampleState {
172            count: args.samples as u32,
173            ..Default::default()
174        },
175        fragment: Some(FragmentState {
176            module: frag,
177            entry_point: "main",
178            targets: match args.ty {
179                DepthPassType::Prepass => &color_state,
180                DepthPassType::Shadow => &[],
181            },
182        }),
183    })
184}