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 usage: None,
66 aspect: wgpu::TextureAspect::DepthOnly,
67 base_mip_level: 0,
68 mip_level_count: None,
69 base_array_layer: 0,
70 array_layer_count: None,
71 };
72
73 let sampler_info = wgpu::SamplerDescriptor {
74 label: None,
75 address_mode_u: wgpu::AddressMode::ClampToEdge,
76 address_mode_v: wgpu::AddressMode::ClampToEdge,
77 address_mode_w: wgpu::AddressMode::ClampToEdge,
78 mag_filter: wgpu::FilterMode::Linear,
79 min_filter: wgpu::FilterMode::Linear,
80 mipmap_filter: wgpu::FilterMode::Nearest,
81 compare: Some(wgpu::CompareFunction::LessEqual),
82 ..Default::default()
83 };
84
85 Texture::new_raw(device, &tex, &view, &sampler_info)
86 };
87
88 let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
90 label: Some("Dummy rain occlusion tex clearing encoder"),
91 });
92
93 encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
94 label: Some("Clear dummy rain occlusion texture"),
95 color_attachments: &[],
96 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
97 view: &tex.view,
98 depth_ops: Some(wgpu::Operations {
99 load: wgpu::LoadOp::Clear(1.0),
100 store: wgpu::StoreOp::Store,
101 }),
102 stencil_ops: None,
103 }),
104 timestamp_writes: None,
105 occlusion_query_set: None,
106 });
107
108 queue.submit(std::iter::once(encoder.finish()));
109
110 tex
111 }
112
113 pub(super) fn create_view(
116 device: &wgpu::Device,
117 mode: &ShadowMapMode,
118 max_texture_size: u32,
119 ) -> Result<Texture, RenderError> {
120 let resolution_factor = mode.resolution.clamped(0.25, 4.0);
122
123 let size =
124 (RAIN_OCCLUSION_CHUNKS as f32).sqrt().ceil() as u32 * TerrainChunkSize::RECT_SIZE * 2;
125
126 let size = size.map(|e| {
128 let size = e as f32 * resolution_factor;
129 if size <= max_texture_size as f32 {
132 size as u32
133 } else {
134 max_texture_size
135 }
136 });
137
138 let levels = 1;
139 let two_size = size.map(|e| {
141 u32::checked_next_power_of_two(e)
142 .filter(|&e| e <= max_texture_size)
143 .unwrap_or(max_texture_size)
144 });
145 let min_size = size.reduce_min();
146 let max_size = size.reduce_max();
147 let _min_two_size = two_size.reduce_min();
148 let _max_two_size = two_size.reduce_max();
149 let diag_size = size.map(f64::from).magnitude();
152 let diag_cross_size = f64::from(min_size) / f64::from(max_size) * diag_size;
153 let (diag_size, _diag_cross_size) =
154 if 0.0 < diag_size && diag_size <= f64::from(max_texture_size) {
155 (diag_size as u32, diag_cross_size as u32)
161 } else {
162 (max_texture_size, max_texture_size)
164 };
165 let diag_two_size = u32::checked_next_power_of_two(diag_size)
166 .filter(|&e| e <= max_texture_size)
167 .unwrap_or(max_texture_size)
169 .max(4);
171
172 let rain_occlusion_tex = wgpu::TextureDescriptor {
173 label: None,
174 size: wgpu::Extent3d {
175 width: diag_two_size,
176 height: diag_two_size,
177 depth_or_array_layers: 1,
178 },
179 mip_level_count: levels,
180 sample_count: 1,
181 dimension: wgpu::TextureDimension::D2,
182 format: wgpu::TextureFormat::Depth24Plus,
183 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
184 view_formats: &[],
185 };
186
187 let rain_occlusion_view = wgpu::TextureViewDescriptor {
188 label: None,
189 format: Some(wgpu::TextureFormat::Depth24Plus),
190 dimension: Some(wgpu::TextureViewDimension::D2),
191 usage: None,
192 aspect: wgpu::TextureAspect::DepthOnly,
193 base_mip_level: 0,
194 mip_level_count: None,
195 base_array_layer: 0,
196 array_layer_count: None,
197 };
198
199 let sampler_info = wgpu::SamplerDescriptor {
200 label: None,
201 address_mode_u: wgpu::AddressMode::ClampToEdge,
202 address_mode_v: wgpu::AddressMode::ClampToEdge,
203 address_mode_w: wgpu::AddressMode::ClampToEdge,
204 mag_filter: wgpu::FilterMode::Linear,
205 min_filter: wgpu::FilterMode::Linear,
206 mipmap_filter: wgpu::FilterMode::Nearest,
207 compare: Some(wgpu::CompareFunction::LessEqual),
208 ..Default::default()
209 };
210
211 let rain_occlusion_tex = Texture::new_raw(
212 device,
213 &rain_occlusion_tex,
214 &rain_occlusion_view,
215 &sampler_info,
216 );
217
218 Ok(rain_occlusion_tex)
219 }
220
221 pub fn texture(&self) -> &Texture {
222 match self {
223 Self::Enabled(renderer) => &renderer.depth,
224 Self::Disabled(dummy) => dummy,
225 }
226 }
227}