veloren_voxygen/render/mod.rs
1pub mod bound;
2mod buffer;
3pub mod consts;
4mod error;
5pub mod instances;
6pub mod mesh;
7pub mod model;
8pub mod pipelines;
9pub mod renderer;
10pub mod texture;
11
12// Reexports
13pub use self::{
14 bound::Bound,
15 buffer::Buffer,
16 consts::Consts,
17 error::RenderError,
18 instances::Instances,
19 mesh::{Mesh, Quad, Tri},
20 model::{DynamicModel, Model, SubModel},
21 pipelines::{
22 FigureSpriteAtlasData, GlobalModel, Globals, GlobalsBindGroup, GlobalsLayouts, Light,
23 Shadow, TerrainAtlasData,
24 clouds::Locals as CloudsLocals,
25 debug::{DebugLayout, DebugPipeline, Locals as DebugLocals, Vertex as DebugVertex},
26 figure::{
27 BoneData as FigureBoneData, BoneMeshes, FigureLayout, FigureModel,
28 Locals as FigureLocals,
29 },
30 fluid::Vertex as FluidVertex,
31 lod_object::{Instance as LodObjectInstance, Vertex as LodObjectVertex},
32 lod_terrain::{LodData, Vertex as LodTerrainVertex},
33 particle::{Instance as ParticleInstance, Vertex as ParticleVertex},
34 postprocess::Locals as PostProcessLocals,
35 rain_occlusion::Locals as RainOcclusionLocals,
36 shadow::{Locals as ShadowLocals, PointLightMatrix},
37 skybox::{Vertex as SkyboxVertex, create_mesh as create_skybox_mesh},
38 sprite::{
39 Instance as SpriteInstance, SpriteGlobalsBindGroup, SpriteVerts,
40 VERT_PAGE_SIZE as SPRITE_VERT_PAGE_SIZE, Vertex as SpriteVertex,
41 },
42 terrain::{Locals as TerrainLocals, TerrainLayout, Vertex as TerrainVertex},
43 trail::Vertex as TrailVertex,
44 ui::{
45 BoundLocals as UiBoundLocals, Locals as UiLocals, Mode as UiMode,
46 TextureBindGroup as UiTextureBindGroup, UploadBatchId as UiUploadBatchId,
47 Vertex as UiVertex, create_quad as create_ui_quad,
48 create_quad_vert_gradient as create_ui_quad_vert_gradient, create_tri as create_ui_tri,
49 },
50 },
51 renderer::{
52 AltIndices, CullingMode, Renderer,
53 drawer::{
54 DebugDrawer, DebugShadowDrawer, Drawer, FigureDrawer, FigureShadowDrawer,
55 FirstPassDrawer, ParticleDrawer, PreparedUiDrawer, ShadowPassDrawer, SpriteDrawer,
56 TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, TrailDrawer,
57 TransparentPassDrawer, UI_PREMULTIPLY_PASS, UiDrawer, VolumetricPassDrawer,
58 },
59 },
60 texture::Texture,
61};
62use hashbrown::HashSet;
63pub use wgpu::{AddressMode, FilterMode};
64
65pub trait Vertex: Clone + bytemuck::Pod {
66 const STRIDE: wgpu::BufferAddress;
67 // Whether these types of verts use the quad index buffer for drawing them
68 const QUADS_INDEX: Option<wgpu::IndexFormat>;
69}
70
71use serde::{Deserialize, Serialize};
72/// Anti-aliasing modes
73#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
74pub enum AaMode {
75 /// Fast approximate antialiasing.
76 ///
77 /// This is a screen-space technique, and therefore works fine with greedy
78 /// meshing.
79 #[default]
80 Fxaa,
81 /// Multisampling AA, up to 4 samples per pixel.
82 ///
83 /// NOTE: MSAA modes don't (currently) work with greedy meshing, and will
84 /// also struggle in the future with deferred shading, so they may be
85 /// removed in the future.
86 MsaaX4,
87 /// Multisampling AA, up to 8 samples per pixel.
88 ///
89 /// NOTE: MSAA modes don't (currently) work with greedy meshing, and will
90 /// also struggle in the future with deferred shading, so they may be
91 /// removed in the future.
92 MsaaX8,
93 /// Multisampling AA, up to 16 samples per pixel.
94 ///
95 /// NOTE: MSAA modes don't (currently) work with greedy meshing, and will
96 /// also struggle in the future with deferred shading, so they may be
97 /// removed in the future.
98 MsaaX16,
99 /// Fast edge-detecting upscaling.
100 ///
101 /// Screen-space technique that attempts to reconstruct lines and edges
102 /// in the original image. Useless at internal resolutions higher than 1.0x,
103 /// but potentially very effective at much lower internal resolutions.
104 Hqx,
105 /// Fast upscaling informed by FXAA.
106 ///
107 /// Screen-space technique that uses a combination of FXAA and
108 /// nearest-neighbour sample retargeting to produce crisp, clean upscaling.
109 FxUpscale,
110 /// Bilinear filtering.
111 ///
112 /// Linear interpolation of the color buffer in each axis to determine the
113 /// pixel.
114 Bilinear,
115 /// Nearest-neighbour filtering.
116 ///
117 /// The colour of each pixel is determined by the colour of the spatially
118 /// closest texel in the color buffer.
119 #[serde(other)]
120 None,
121}
122
123impl AaMode {
124 pub fn samples(&self) -> u32 {
125 match self {
126 AaMode::None | AaMode::Bilinear | AaMode::Fxaa | AaMode::Hqx | AaMode::FxUpscale => 1,
127 AaMode::MsaaX4 => 4,
128 AaMode::MsaaX8 => 8,
129 AaMode::MsaaX16 => 16,
130 }
131 }
132}
133
134/// Cloud modes
135#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
136pub enum CloudMode {
137 /// No clouds. As cheap as it gets.
138 None,
139 /// Clouds, but barely. Ideally, any machine should be able to handle this
140 /// just fine.
141 Minimal,
142 /// Enough visual detail to be pleasing, but generally using poor-but-cheap
143 /// approximations to derive parameters
144 Low,
145 /// More detail. Enough to look good in most cases. For those that value
146 /// looks but also high framerates.
147 Medium,
148 /// High, but with extra compute power thrown at it to smooth out subtle
149 /// imperfections
150 Ultra,
151 /// Lots of detail with good-but-costly derivation of parameters.
152 #[serde(other)]
153 #[default]
154 High,
155}
156
157impl CloudMode {
158 pub fn is_enabled(&self) -> bool { *self != CloudMode::None }
159}
160
161/// Fluid modes
162#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
163pub enum FluidMode {
164 /// "Low" water. This water implements no waves, no reflections, no
165 /// diffraction, and no light attenuation through water. As a result,
166 /// it can be much cheaper than shiny reflection.
167 Low,
168 High,
169 /// This water implements waves on the surfaces, some attempt at
170 /// reflections, and tries to compute accurate light attenuation through
171 /// water (this is what results in the colors changing as you descend
172 /// into deep water).
173 ///
174 /// Unfortunately, the way the engine is currently set up, calculating
175 /// accurate attenuation is a bit difficult; we use estimates from
176 /// horizon maps for the current water altitude, which can both be off
177 /// by up to (max_altitude / 255) meters, only has per-chunk horizontal
178 /// resolution, and cannot handle edge cases like horizontal water (e.g.
179 /// waterfalls) well. We are okay with the latter, and will try to fix
180 /// the former soon.
181 ///
182 /// Another issue is that we don't always know whether light is *blocked*,
183 /// which causes attenuation to be computed incorrectly; this can be
184 /// addressed by using shadow maps (at least for terrain).
185 #[serde(other)]
186 #[default]
187 Medium,
188}
189
190/// Reflection modes
191#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
192pub enum ReflectionMode {
193 /// No or minimal reflections.
194 Low,
195 /// High quality reflections with screen-space raycasting and
196 /// all the bells & whistles.
197 #[default]
198 High,
199 // Medium quality screen-space reflections.
200 #[serde(other)]
201 Medium,
202}
203
204/// Lighting modes
205#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
206pub enum LightingMode {
207 /// Ashikhmin-Shirley BRDF lighting model. Attempts to generate a
208 /// physically plausible (to some extent) lighting distribution.
209 ///
210 /// This model may not work as well with purely directional lighting, and is
211 /// more expensive than the other models.
212 Ashikhmin,
213 /// Standard Lambertian lighting model, with only diffuse reflections. The
214 /// cheapest lighting model by a decent margin, but the performance
215 /// difference between it and Blinn-Phong will probably only be
216 /// significant on low-end machines that are bottlenecked on fragment
217 /// shading.
218 Lambertian,
219 /// Standard Blinn-Phong shading, combing Lambertian diffuse reflections and
220 /// specular highlights.
221 #[serde(other)]
222 #[default]
223 BlinnPhong,
224}
225
226/// Shadow map settings.
227#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
228pub struct ShadowMapMode {
229 /// Multiple of default resolution (default, which is 1.0, is currently
230 /// the closest higher power of two above the length of the longest
231 /// diagonal of the screen resolution, but this may change).
232 pub resolution: f32,
233}
234
235impl Default for ShadowMapMode {
236 fn default() -> Self { Self { resolution: 1.0 } }
237}
238
239/// Shadow modes
240#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
241pub enum ShadowMode {
242 /// No shadows at all. By far the cheapest option.
243 None,
244 /// Shadow map (render the scene from each light source, and also renders
245 /// LOD shadows using horizon maps).
246 Map(ShadowMapMode),
247 /// Point shadows (draw circles under figures, up to a configured maximum;
248 /// also render LOD shadows using horizon maps). Can be expensive on
249 /// some machines, probably mostly due to horizon mapping; the point
250 /// shadows are not rendered too efficiently, but that can probably
251 /// be addressed later.
252 #[serde(other)] // Would normally be on `Map`, but only allowed on unit variants
253 Cheap,
254}
255
256impl Default for ShadowMode {
257 fn default() -> Self { ShadowMode::Map(Default::default()) }
258}
259
260impl TryFrom<ShadowMode> for ShadowMapMode {
261 type Error = ();
262
263 /// Get the shadow map details if they exist.
264 fn try_from(value: ShadowMode) -> Result<Self, Self::Error> {
265 if let ShadowMode::Map(map) = value {
266 Ok(map)
267 } else {
268 Err(())
269 }
270 }
271}
272
273impl ShadowMode {
274 pub fn is_map(&self) -> bool { matches!(self, Self::Map(_)) }
275}
276
277/// Upscale mode settings.
278#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
279pub struct UpscaleMode {
280 // Determines non-UI graphics upscaling. 0.25 to 2.0.
281 pub factor: f32,
282}
283
284impl Default for UpscaleMode {
285 fn default() -> Self { Self { factor: 1.0 } }
286}
287
288/// Present modes
289/// See https://docs.rs/wgpu/0.7.0/wgpu/enum.PresentMode.html
290#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
291pub enum PresentMode {
292 Mailbox,
293 Immediate,
294 FifoRelaxed,
295 #[default]
296 #[serde(other)]
297 Fifo, // has to be last for `#[serde(other)]`
298}
299
300impl From<PresentMode> for wgpu::PresentMode {
301 fn from(mode: PresentMode) -> Self {
302 match mode {
303 PresentMode::Fifo => wgpu::PresentMode::Fifo,
304 PresentMode::FifoRelaxed => wgpu::PresentMode::FifoRelaxed,
305 PresentMode::Mailbox => wgpu::PresentMode::Mailbox,
306 PresentMode::Immediate => wgpu::PresentMode::Immediate,
307 }
308 }
309}
310
311impl TryFrom<wgpu::PresentMode> for PresentMode {
312 type Error = ();
313
314 fn try_from(mode: wgpu::PresentMode) -> Result<Self, ()> {
315 match mode {
316 wgpu::PresentMode::Fifo => Ok(PresentMode::Fifo),
317 wgpu::PresentMode::FifoRelaxed => Ok(PresentMode::FifoRelaxed),
318 wgpu::PresentMode::Mailbox => Ok(PresentMode::Mailbox),
319 wgpu::PresentMode::Immediate => Ok(PresentMode::Immediate),
320 _ => Err(()),
321 }
322 }
323}
324
325/// Bloom factor
326/// Controls fraction of output image luminosity that is blurred bloom
327#[derive(Default, PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
328pub enum BloomFactor {
329 Low,
330 High,
331 /// Max valid value is 1.0
332 Custom(f32),
333 // other variant has to be placed last
334 #[serde(other)]
335 #[default]
336 Medium,
337}
338
339impl BloomFactor {
340 /// Fraction of output image luminosity that is blurred bloom
341 pub fn fraction(self) -> f32 {
342 match self {
343 Self::Low => 0.1,
344 Self::Medium => 0.2,
345 Self::High => 0.3,
346 Self::Custom(val) => val.clamp(0.0, 1.0),
347 }
348 }
349}
350
351/// Bloom settings
352#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
353pub struct BloomConfig {
354 /// Controls fraction of output image luminosity that is blurred bloom
355 ///
356 /// Defaults to `Medium`
357 pub factor: BloomFactor,
358 /// Turning this on make the bloom blur less sharply concentrated around the
359 /// high intensity phenomena (removes adding in less blurred layers to the
360 /// final blur)
361 ///
362 /// Defaults to `false`
363 pub uniform_blur: bool,
364 // TODO: allow configuring the blur radius and/or the number of passes
365}
366
367#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
368pub enum BloomMode {
369 On(BloomConfig),
370 #[serde(other)]
371 Off,
372}
373
374impl Default for BloomMode {
375 fn default() -> Self {
376 Self::On(BloomConfig {
377 factor: BloomFactor::default(),
378 uniform_blur: false,
379 })
380 }
381}
382
383impl BloomMode {
384 fn is_on(&self) -> bool { matches!(self, BloomMode::On(_)) }
385}
386
387/// Render modes
388#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
389#[serde(default)]
390pub struct RenderMode {
391 pub aa: AaMode,
392 pub cloud: CloudMode,
393 pub reflection: ReflectionMode,
394 pub fluid: FluidMode,
395 pub lighting: LightingMode,
396 pub shadow: ShadowMode,
397 pub rain_occlusion: ShadowMapMode,
398 pub bloom: BloomMode,
399 /// 0.0..1.0
400 pub point_glow: f32,
401
402 pub flashing_lights_enabled: bool,
403
404 pub experimental_shaders: HashSet<ExperimentalShader>,
405
406 pub upscale_mode: UpscaleMode,
407 pub present_mode: PresentMode,
408 pub profiler_enabled: bool,
409}
410
411impl Default for RenderMode {
412 fn default() -> Self {
413 Self {
414 aa: AaMode::default(),
415 cloud: CloudMode::default(),
416 fluid: FluidMode::default(),
417 reflection: ReflectionMode::default(),
418 lighting: LightingMode::default(),
419 shadow: ShadowMode::default(),
420 rain_occlusion: ShadowMapMode::default(),
421 bloom: BloomMode::default(),
422 point_glow: 0.35,
423 flashing_lights_enabled: true,
424 experimental_shaders: HashSet::default(),
425 upscale_mode: UpscaleMode::default(),
426 present_mode: PresentMode::default(),
427 profiler_enabled: false,
428 }
429 }
430}
431
432impl RenderMode {
433 fn split(self) -> (PipelineModes, OtherModes) {
434 (
435 PipelineModes {
436 aa: self.aa,
437 cloud: self.cloud,
438 fluid: self.fluid,
439 reflection: self.reflection,
440 lighting: self.lighting,
441 shadow: self.shadow,
442 rain_occlusion: self.rain_occlusion,
443 bloom: self.bloom,
444 point_glow: self.point_glow,
445 flashing_lights_enabled: self.flashing_lights_enabled,
446 experimental_shaders: self.experimental_shaders,
447 },
448 OtherModes {
449 upscale_mode: self.upscale_mode,
450 present_mode: self.present_mode,
451 profiler_enabled: self.profiler_enabled,
452 },
453 )
454 }
455}
456
457/// Render modes that require pipeline recreation (e.g. shader recompilation)
458/// when changed
459#[derive(PartialEq, Clone, Debug)]
460pub struct PipelineModes {
461 aa: AaMode,
462 pub cloud: CloudMode,
463 fluid: FluidMode,
464 reflection: ReflectionMode,
465 lighting: LightingMode,
466 pub shadow: ShadowMode,
467 pub rain_occlusion: ShadowMapMode,
468 bloom: BloomMode,
469 point_glow: f32,
470 flashing_lights_enabled: bool,
471 experimental_shaders: HashSet<ExperimentalShader>,
472}
473
474/// Other render modes that don't effect pipelines
475#[derive(PartialEq, Clone, Debug)]
476struct OtherModes {
477 upscale_mode: UpscaleMode,
478 present_mode: PresentMode,
479 profiler_enabled: bool,
480}
481
482/// Experimental shader modes.
483///
484/// You can enable these using Voxygen's `settings.ron`. See
485/// [here](https://book.veloren.net/players/voxygen.html#experimental-shaders) for more information.
486#[derive(
487 Clone,
488 Debug,
489 PartialEq,
490 Eq,
491 Hash,
492 Serialize,
493 Deserialize,
494 strum::EnumIter,
495 strum::Display,
496 strum::EnumString,
497)]
498pub enum ExperimentalShader {
499 /// Add brick-like normal mapping to the world.
500 Brickloren,
501 /// Remove the default procedural noise from terrain.
502 NoNoise,
503 /// Add a sobel filter that draws lines in post-process by detecting edges
504 /// inbetween colors. This does perform 8 times more texture samples in
505 /// post-processing so there is potentially a significant performance
506 /// impact especially with anti aliasing enabled.
507 Sobel,
508 /// Like Sobel, but on the gradient texture instead of the color texture.
509 GradientSobel,
510 /// Simulate a curved world.
511 CurvedWorld,
512 /// Adds extra detail to distant LoD (Level of Detail) terrain procedurally.
513 ProceduralLodDetail,
514 /// Add a warping effect when underwater.
515 Underwarper,
516 /// Remove caustics from underwater terrain when shiny water is enabled.
517 NoCaustics,
518 /// Don't dither color in post-processing.
519 NoDither,
520 /// Don't use the nonlinear srgb space for dithering color.
521 NonSrgbDither,
522 /// Use triangle PDF noise for dithering instead of uniform noise.
523 TriangleNoiseDither,
524 /// Removes as many effects (including lighting) as possible in the name of
525 /// performance.
526 BareMinimum,
527 /// Lowers strength of the glow effect for lights near the camera.
528 LowGlowNearCamera,
529 /// Disable the fake voxel effect on LoD features.
530 NoLodVoxels,
531 /// Enable a 'pop-in' effect when loading terrain.
532 TerrainPop,
533 /// Display grid lines to visualize the distribution of shadow map texels
534 /// for the directional light from the sun.
535 DirectionalShadowMapTexelGrid,
536 /// Disable rainbows
537 NoRainbows,
538 /// Add extra detailing to puddles.
539 PuddleDetails,
540 /// Show gbuffer surface normals.
541 ViewNormals,
542 /// Show gbuffer materials.
543 ViewMaterials,
544 /// Show gbuffer depth.
545 ViewDepth,
546 /// Rather than fading out screen-space reflections at view space borders,
547 /// smear screen space to cover the reflection vector.
548 SmearReflections,
549 /// Apply the point shadows from cheap shadows on top of shadow mapping.
550 PointShadowsWithShadowMapping,
551 /// Make the UI uses nearest neighbor filtering for scaling images instead
552 /// of trying to filter based on the coverage of the sampled pixels.
553 UiNearestScaling,
554 /// Prefer using physically-based values for various rendering parameters,
555 /// where possible.
556 Photorealistic,
557 /// A noisy newspaper effect.
558 Newspaper,
559 /// A colorful dithering effect.
560 ColorDithering,
561 /// Cinematic color grading.
562 Cinematic,
563 /// Glittering snow.
564 SnowGlitter,
565 /// Enables optimizations when shaderc is processing shaders (currently on
566 /// by default, but keep this for now in case we have to switch back to
567 /// being off by default).
568 EnableShadercOptimization,
569 /// Disables optimizations when shaderc is processing shaders (has priority
570 /// over `EnableShadercOptimization`).
571 DisableShadercOptimization,
572}