veloren_voxygen/render/renderer/
rain_occlusion_map.rs1use crate::{render::pipelines::rain_occlusion, scene::terrain::RAIN_OCCLUSION_CHUNKS};
2
3use super::super::{RenderError, ShadowMapMode, texture::Texture};
4use common::{terrain::TerrainChunkSize, vol::RectVolSize};
5use vek::*;
6
7pub struct RainOcclusionMapRenderer {
10 pub depth: Texture,
11
12 pub terrain_pipeline: rain_occlusion::RainOcclusionPipeline,
13 pub figure_pipeline: rain_occlusion::RainOcclusionFigurePipeline,
14}
15
16pub enum RainOcclusionMap {
17 Enabled(RainOcclusionMapRenderer),
18 Disabled(Texture),
20}
21
22impl RainOcclusionMap {
23 pub fn new(
24 device: &wgpu::Device,
25 queue: &wgpu::Queue,
26 directed: Option<rain_occlusion::RainOcclusionPipeline>,
27 figure: Option<rain_occlusion::RainOcclusionFigurePipeline>,
28 view: Option<Texture>,
29 ) -> Self {
30 if let (Some(terrain_pipeline), Some(figure_pipeline), Some(depth)) =
31 (directed, figure, view)
32 {
33 Self::Enabled(RainOcclusionMapRenderer {
34 depth,
35 terrain_pipeline,
36 figure_pipeline,
37 })
38 } else {
39 Self::Disabled(Self::create_dummy_tex(device, queue))
40 }
41 }
42
43 fn create_dummy_tex(device: &wgpu::Device, queue: &wgpu::Queue) -> Texture {
44 let tex = {
45 let tex = wgpu::TextureDescriptor {
46 label: None,
47 size: wgpu::Extent3d {
48 width: 4,
49 height: 4,
50 depth_or_array_layers: 1,
51 },
52 mip_level_count: 1,
53 sample_count: 1,
54 dimension: wgpu::TextureDimension::D2,
55 format: wgpu::TextureFormat::Depth24Plus,
56 usage: wgpu::TextureUsages::TEXTURE_BINDING
57 | wgpu::TextureUsages::RENDER_ATTACHMENT,
58 view_formats: &[],
59 };
60
61 let view = wgpu::TextureViewDescriptor {
62 label: None,
63 format: Some(wgpu::TextureFormat::Depth24Plus),
64 dimension: Some(wgpu::TextureViewDimension::D2),
65 aspect: wgpu::TextureAspect::DepthOnly,
66 base_mip_level: 0,
67 mip_level_count: None,
68 base_array_layer: 0,
69 array_layer_count: None,
70 };
71
72 let sampler_info = wgpu::SamplerDescriptor {
73 label: None,
74 address_mode_u: wgpu::AddressMode::ClampToEdge,
75 address_mode_v: wgpu::AddressMode::ClampToEdge,
76 address_mode_w: wgpu::AddressMode::ClampToEdge,
77 mag_filter: wgpu::FilterMode::Linear,
78 min_filter: wgpu::FilterMode::Linear,
79 mipmap_filter: wgpu::FilterMode::Nearest,
80 compare: Some(wgpu::CompareFunction::LessEqual),
81 ..Default::default()
82 };
83
84 Texture::new_raw(device, &tex, &view, &sampler_info)
85 };
86
87 let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
89 label: Some("Dummy rain occlusion tex clearing encoder"),
90 });
91
92 encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
93 label: Some("Clear dummy rain occlusion texture"),
94 color_attachments: &[],
95 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
96 view: &tex.view,
97 depth_ops: Some(wgpu::Operations {
98 load: wgpu::LoadOp::Clear(1.0),
99 store: wgpu::StoreOp::Store,
100 }),
101 stencil_ops: None,
102 }),
103 timestamp_writes: None,
104 occlusion_query_set: None,
105 });
106
107 queue.submit(std::iter::once(encoder.finish()));
108
109 tex
110 }
111
112 pub(super) fn create_view(
115 device: &wgpu::Device,
116 mode: &ShadowMapMode,
117 max_texture_size: u32,
118 ) -> Result<Texture, RenderError> {
119 let resolution_factor = mode.resolution.clamped(0.25, 4.0);
121
122 let size =
123 (RAIN_OCCLUSION_CHUNKS as f32).sqrt().ceil() as u32 * TerrainChunkSize::RECT_SIZE * 2;
124
125 let size = size.map(|e| {
127 let size = e as f32 * resolution_factor;
128 if size <= max_texture_size as f32 {
131 size as u32
132 } else {
133 max_texture_size
134 }
135 });
136
137 let levels = 1;
138 let two_size = size.map(|e| {
140 u32::checked_next_power_of_two(e)
141 .filter(|&e| e <= max_texture_size)
142 .unwrap_or(max_texture_size)
143 });
144 let min_size = size.reduce_min();
145 let max_size = size.reduce_max();
146 let _min_two_size = two_size.reduce_min();
147 let _max_two_size = two_size.reduce_max();
148 let diag_size = size.map(f64::from).magnitude();
151 let diag_cross_size = f64::from(min_size) / f64::from(max_size) * diag_size;
152 let (diag_size, _diag_cross_size) =
153 if 0.0 < diag_size && diag_size <= f64::from(max_texture_size) {
154 (diag_size as u32, diag_cross_size as u32)
160 } else {
161 (max_texture_size, max_texture_size)
163 };
164 let diag_two_size = u32::checked_next_power_of_two(diag_size)
165 .filter(|&e| e <= max_texture_size)
166 .unwrap_or(max_texture_size)
168 .max(4);
170
171 let rain_occlusion_tex = wgpu::TextureDescriptor {
172 label: None,
173 size: wgpu::Extent3d {
174 width: diag_two_size,
175 height: diag_two_size,
176 depth_or_array_layers: 1,
177 },
178 mip_level_count: levels,
179 sample_count: 1,
180 dimension: wgpu::TextureDimension::D2,
181 format: wgpu::TextureFormat::Depth24Plus,
182 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
183 view_formats: &[],
184 };
185
186 let rain_occlusion_view = wgpu::TextureViewDescriptor {
187 label: None,
188 format: Some(wgpu::TextureFormat::Depth24Plus),
189 dimension: Some(wgpu::TextureViewDimension::D2),
190 aspect: wgpu::TextureAspect::DepthOnly,
191 base_mip_level: 0,
192 mip_level_count: None,
193 base_array_layer: 0,
194 array_layer_count: None,
195 };
196
197 let sampler_info = wgpu::SamplerDescriptor {
198 label: None,
199 address_mode_u: wgpu::AddressMode::ClampToEdge,
200 address_mode_v: wgpu::AddressMode::ClampToEdge,
201 address_mode_w: wgpu::AddressMode::ClampToEdge,
202 mag_filter: wgpu::FilterMode::Linear,
203 min_filter: wgpu::FilterMode::Linear,
204 mipmap_filter: wgpu::FilterMode::Nearest,
205 compare: Some(wgpu::CompareFunction::LessEqual),
206 ..Default::default()
207 };
208
209 let rain_occlusion_tex = Texture::new_raw(
210 device,
211 &rain_occlusion_tex,
212 &rain_occlusion_view,
213 &sampler_info,
214 );
215
216 Ok(rain_occlusion_tex)
217 }
218
219 pub fn texture(&self) -> &Texture {
220 match self {
221 Self::Enabled(renderer) => &renderer.depth,
222 Self::Disabled(dummy) => dummy,
223 }
224 }
225}