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_enabled: bool,
398    pub rain_occlusion: ShadowMapMode,
399    pub bloom: BloomMode,
400    /// 0.0..1.0
401    pub point_glow: f32,
402
403    pub flashing_lights_enabled: bool,
404
405    pub experimental_shaders: HashSet<ExperimentalShader>,
406
407    pub upscale_mode: UpscaleMode,
408    pub present_mode: PresentMode,
409    pub profiler_enabled: bool,
410}
411
412impl Default for RenderMode {
413    fn default() -> Self {
414        Self {
415            aa: AaMode::default(),
416            cloud: CloudMode::default(),
417            fluid: FluidMode::default(),
418            reflection: ReflectionMode::default(),
419            lighting: LightingMode::default(),
420            shadow: ShadowMode::default(),
421            rain_enabled: true,
422            rain_occlusion: ShadowMapMode::default(),
423            bloom: BloomMode::default(),
424            point_glow: 0.35,
425            flashing_lights_enabled: true,
426            experimental_shaders: HashSet::default(),
427            upscale_mode: UpscaleMode::default(),
428            present_mode: PresentMode::default(),
429            profiler_enabled: false,
430        }
431    }
432}
433
434impl RenderMode {
435    fn split(self) -> (PipelineModes, OtherModes) {
436        (
437            PipelineModes {
438                aa: self.aa,
439                cloud: self.cloud,
440                fluid: self.fluid,
441                reflection: self.reflection,
442                lighting: self.lighting,
443                shadow: self.shadow,
444                rain_enabled: self.rain_enabled,
445                rain_occlusion: self.rain_occlusion,
446                bloom: self.bloom,
447                point_glow: self.point_glow,
448                flashing_lights_enabled: self.flashing_lights_enabled,
449                experimental_shaders: self.experimental_shaders,
450            },
451            OtherModes {
452                upscale_mode: self.upscale_mode,
453                present_mode: self.present_mode,
454                profiler_enabled: self.profiler_enabled,
455            },
456        )
457    }
458}
459
460/// Render modes that require pipeline recreation (e.g. shader recompilation)
461/// when changed
462#[derive(PartialEq, Clone, Debug)]
463pub struct PipelineModes {
464    aa: AaMode,
465    pub cloud: CloudMode,
466    fluid: FluidMode,
467    reflection: ReflectionMode,
468    lighting: LightingMode,
469    pub shadow: ShadowMode,
470    pub rain_enabled: bool,
471    pub rain_occlusion: ShadowMapMode,
472    bloom: BloomMode,
473    point_glow: f32,
474    flashing_lights_enabled: bool,
475    experimental_shaders: HashSet<ExperimentalShader>,
476}
477
478/// Other render modes that don't effect pipelines
479#[derive(PartialEq, Clone, Debug)]
480struct OtherModes {
481    upscale_mode: UpscaleMode,
482    present_mode: PresentMode,
483    profiler_enabled: bool,
484}
485
486/// Experimental shader modes.
487///
488/// You can enable these using Voxygen's `settings.ron`. See
489/// [here](https://book.veloren.net/players/voxygen.html#experimental-shaders) for more information.
490#[derive(
491    Clone,
492    Debug,
493    PartialEq,
494    Eq,
495    Hash,
496    Serialize,
497    Deserialize,
498    strum::EnumIter,
499    strum::Display,
500    strum::EnumString,
501)]
502pub enum ExperimentalShader {
503    /// Add brick-like normal mapping to the world.
504    Brickloren,
505    /// Remove the default procedural noise from terrain.
506    NoNoise,
507    /// Add a sobel filter that draws lines in post-process by detecting edges
508    /// inbetween colors. This does perform 8 times more texture samples in
509    /// post-processing so there is potentially a significant performance
510    /// impact especially with anti aliasing enabled.
511    Sobel,
512    /// Like Sobel, but on the gradient texture instead of the color texture.
513    GradientSobel,
514    /// Simulate a curved world.
515    CurvedWorld,
516    /// Adds extra detail to distant LoD (Level of Detail) terrain procedurally.
517    ProceduralLodDetail,
518    /// Add a warping effect when underwater.
519    Underwarper,
520    /// Remove caustics from underwater terrain when shiny water is enabled.
521    NoCaustics,
522    /// Don't dither color in post-processing.
523    NoDither,
524    /// Don't use the nonlinear srgb space for dithering color.
525    NonSrgbDither,
526    /// Use triangle PDF noise for dithering instead of uniform noise.
527    TriangleNoiseDither,
528    /// Removes as many effects (including lighting) as possible in the name of
529    /// performance.
530    BareMinimum,
531    /// Lowers strength of the glow effect for lights near the camera.
532    LowGlowNearCamera,
533    /// Disable the fake voxel effect on LoD features.
534    NoLodVoxels,
535    /// Enable a 'pop-in' effect when loading terrain.
536    TerrainPop,
537    /// Display grid lines to visualize the distribution of shadow map texels
538    /// for the directional light from the sun.
539    DirectionalShadowMapTexelGrid,
540    /// Disable rainbows
541    NoRainbows,
542    /// Add extra detailing to puddles.
543    PuddleDetails,
544    /// Show gbuffer surface normals.
545    ViewNormals,
546    /// Show gbuffer materials.
547    ViewMaterials,
548    /// Show gbuffer depth.
549    ViewDepth,
550    /// Rather than fading out screen-space reflections at view space borders,
551    /// smear screen space to cover the reflection vector.
552    SmearReflections,
553    /// Apply the point shadows from cheap shadows on top of shadow mapping.
554    PointShadowsWithShadowMapping,
555    /// Make the UI uses nearest neighbor filtering for scaling images instead
556    /// of trying to filter based on the coverage of the sampled pixels.
557    UiNearestScaling,
558    /// Prefer using physically-based values for various rendering parameters,
559    /// where possible.
560    Photorealistic,
561    /// A noisy newspaper effect.
562    Newspaper,
563    /// A colorful dithering effect.
564    ColorDithering,
565    /// Cinematic color grading.
566    Cinematic,
567    /// Glittering snow.
568    SnowGlitter,
569    /// Enables optimizations when shaderc is processing shaders (currently on
570    /// by default, but keep this for now in case we have to switch back to
571    /// being off by default).
572    EnableShadercOptimization,
573    /// Disables optimizations when shaderc is processing shaders (has priority
574    /// over `EnableShadercOptimization`).
575    DisableShadercOptimization,
576}