1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
16pub enum ViewportFocusPolicy {
17 #[default]
18 FocusedAlways,
19 Manual,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
24pub enum PbrDebugMode {
25 #[default]
26 None,
27 BaseColor,
28 Normal,
29 Metallic,
30 Roughness,
31 Occlusion,
32 Emissive,
33 F,
34 G,
35 D,
36 Diffuse,
37 Specular,
38 MipRainbow,
39}
40
41impl PbrDebugMode {
42 pub const ALL: &'static [PbrDebugMode] = &[
43 PbrDebugMode::None,
44 PbrDebugMode::BaseColor,
45 PbrDebugMode::Normal,
46 PbrDebugMode::Metallic,
47 PbrDebugMode::Roughness,
48 PbrDebugMode::Occlusion,
49 PbrDebugMode::Emissive,
50 PbrDebugMode::F,
51 PbrDebugMode::G,
52 PbrDebugMode::D,
53 PbrDebugMode::Diffuse,
54 PbrDebugMode::Specular,
55 PbrDebugMode::MipRainbow,
56 ];
57
58 pub fn name(&self) -> &'static str {
59 match self {
60 PbrDebugMode::None => "None",
61 PbrDebugMode::BaseColor => "Base Color",
62 PbrDebugMode::Normal => "Normal",
63 PbrDebugMode::Metallic => "Metallic",
64 PbrDebugMode::Roughness => "Roughness",
65 PbrDebugMode::Occlusion => "Occlusion",
66 PbrDebugMode::Emissive => "Emissive",
67 PbrDebugMode::F => "Fresnel (F)",
68 PbrDebugMode::G => "Geometry (G)",
69 PbrDebugMode::D => "Distribution (D)",
70 PbrDebugMode::Diffuse => "Diffuse",
71 PbrDebugMode::Specular => "Specular",
72 PbrDebugMode::MipRainbow => "Mip Rainbow",
73 }
74 }
75
76 pub fn as_u32(&self) -> u32 {
77 match self {
78 PbrDebugMode::None => 0,
79 PbrDebugMode::BaseColor => 1,
80 PbrDebugMode::Normal => 2,
81 PbrDebugMode::Metallic => 3,
82 PbrDebugMode::Roughness => 4,
83 PbrDebugMode::Occlusion => 5,
84 PbrDebugMode::Emissive => 6,
85 PbrDebugMode::F => 7,
86 PbrDebugMode::G => 8,
87 PbrDebugMode::D => 9,
88 PbrDebugMode::Diffuse => 10,
89 PbrDebugMode::Specular => 11,
90 PbrDebugMode::MipRainbow => 12,
91 }
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
97pub enum DepthOfFieldQuality {
98 Low,
100 #[default]
102 Medium,
103 High,
105}
106
107impl DepthOfFieldQuality {
108 pub const ALL: &'static [DepthOfFieldQuality] = &[
109 DepthOfFieldQuality::Low,
110 DepthOfFieldQuality::Medium,
111 DepthOfFieldQuality::High,
112 ];
113
114 pub fn name(&self) -> &'static str {
115 match self {
116 DepthOfFieldQuality::Low => "Low",
117 DepthOfFieldQuality::Medium => "Medium",
118 DepthOfFieldQuality::High => "High",
119 }
120 }
121
122 pub fn sample_count(&self) -> u32 {
123 match self {
124 DepthOfFieldQuality::Low => 8,
125 DepthOfFieldQuality::Medium => 16,
126 DepthOfFieldQuality::High => 32,
127 }
128 }
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
133pub struct DepthOfField {
134 pub enabled: bool,
136 pub focus_distance: f32,
138 pub focus_range: f32,
140 pub max_blur_radius: f32,
142 pub bokeh_threshold: f32,
144 pub bokeh_intensity: f32,
146 pub quality: DepthOfFieldQuality,
148 pub visualize_coc: bool,
150 pub tilt_shift_enabled: bool,
152 pub tilt_shift_angle: f32,
154 pub tilt_shift_center: f32,
156 pub tilt_shift_blur_amount: f32,
158 pub visualize_tilt_shift: bool,
160}
161
162impl Default for DepthOfField {
163 fn default() -> Self {
164 Self {
165 enabled: false,
166 focus_distance: 10.0,
167 focus_range: 5.0,
168 max_blur_radius: 8.0,
169 bokeh_threshold: 0.8,
170 bokeh_intensity: 1.0,
171 quality: DepthOfFieldQuality::Medium,
172 visualize_coc: false,
173 tilt_shift_enabled: false,
174 tilt_shift_angle: 0.0,
175 tilt_shift_center: 0.0,
176 tilt_shift_blur_amount: 1.0,
177 visualize_tilt_shift: false,
178 }
179 }
180}
181
182impl DepthOfField {
183 pub fn portrait() -> Self {
185 Self {
186 enabled: true,
187 focus_distance: 3.0,
188 focus_range: 1.5,
189 max_blur_radius: 12.0,
190 bokeh_threshold: 0.6,
191 bokeh_intensity: 1.2,
192 quality: DepthOfFieldQuality::High,
193 visualize_coc: false,
194 tilt_shift_enabled: false,
195 tilt_shift_angle: 0.0,
196 tilt_shift_center: 0.0,
197 tilt_shift_blur_amount: 1.0,
198 visualize_tilt_shift: false,
199 }
200 }
201
202 pub fn cinematic() -> Self {
204 Self {
205 enabled: true,
206 focus_distance: 8.0,
207 focus_range: 4.0,
208 max_blur_radius: 10.0,
209 bokeh_threshold: 0.7,
210 bokeh_intensity: 1.0,
211 quality: DepthOfFieldQuality::Medium,
212 visualize_coc: false,
213 tilt_shift_enabled: false,
214 tilt_shift_angle: 0.0,
215 tilt_shift_center: 0.0,
216 tilt_shift_blur_amount: 1.0,
217 visualize_tilt_shift: false,
218 }
219 }
220
221 pub fn macro_shot() -> Self {
222 Self {
223 enabled: true,
224 focus_distance: 0.5,
225 focus_range: 0.2,
226 max_blur_radius: 16.0,
227 bokeh_threshold: 0.5,
228 bokeh_intensity: 1.5,
229 quality: DepthOfFieldQuality::High,
230 visualize_coc: false,
231 tilt_shift_enabled: false,
232 tilt_shift_angle: 0.0,
233 tilt_shift_center: 0.0,
234 tilt_shift_blur_amount: 1.0,
235 visualize_tilt_shift: false,
236 }
237 }
238
239 pub fn landscape() -> Self {
240 Self {
241 enabled: true,
242 focus_distance: 50.0,
243 focus_range: 100.0,
244 max_blur_radius: 4.0,
245 bokeh_threshold: 0.9,
246 bokeh_intensity: 0.5,
247 quality: DepthOfFieldQuality::Low,
248 visualize_coc: false,
249 tilt_shift_enabled: false,
250 tilt_shift_angle: 0.0,
251 tilt_shift_center: 0.0,
252 tilt_shift_blur_amount: 1.0,
253 visualize_tilt_shift: false,
254 }
255 }
256
257 pub fn tilt_shift() -> Self {
258 Self {
259 enabled: true,
260 focus_distance: 10.0,
261 focus_range: 5.0,
262 max_blur_radius: 12.0,
263 bokeh_threshold: 0.8,
264 bokeh_intensity: 0.8,
265 quality: DepthOfFieldQuality::Medium,
266 visualize_coc: false,
267 tilt_shift_enabled: true,
268 tilt_shift_angle: 0.0,
269 tilt_shift_center: 0.0,
270 tilt_shift_blur_amount: 1.0,
271 visualize_tilt_shift: false,
272 }
273 }
274}
275
276#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
278pub enum TonemapAlgorithm {
279 #[default]
281 Aces,
282 Aces2,
284 Reinhard,
286 ReinhardExtended,
288 Uncharted2,
290 AgX,
292 Neutral,
294 None,
296}
297
298impl TonemapAlgorithm {
299 pub const ALL: &'static [TonemapAlgorithm] = &[
300 TonemapAlgorithm::Aces,
301 TonemapAlgorithm::Aces2,
302 TonemapAlgorithm::Reinhard,
303 TonemapAlgorithm::ReinhardExtended,
304 TonemapAlgorithm::Uncharted2,
305 TonemapAlgorithm::AgX,
306 TonemapAlgorithm::Neutral,
307 TonemapAlgorithm::None,
308 ];
309
310 pub fn as_u32(&self) -> u32 {
311 match self {
312 TonemapAlgorithm::Aces => 0,
313 TonemapAlgorithm::Aces2 => 7,
314 TonemapAlgorithm::Reinhard => 1,
315 TonemapAlgorithm::ReinhardExtended => 2,
316 TonemapAlgorithm::Uncharted2 => 3,
317 TonemapAlgorithm::AgX => 4,
318 TonemapAlgorithm::Neutral => 5,
319 TonemapAlgorithm::None => 6,
320 }
321 }
322
323 pub fn name(&self) -> &'static str {
324 match self {
325 TonemapAlgorithm::Aces => "ACES",
326 TonemapAlgorithm::Aces2 => "ACES (Fitted)",
327 TonemapAlgorithm::Reinhard => "Reinhard",
328 TonemapAlgorithm::ReinhardExtended => "Reinhard Extended",
329 TonemapAlgorithm::Uncharted2 => "Uncharted 2",
330 TonemapAlgorithm::AgX => "AgX",
331 TonemapAlgorithm::Neutral => "Neutral",
332 TonemapAlgorithm::None => "None",
333 }
334 }
335}
336
337#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
339pub enum ColorGradingPreset {
340 #[default]
342 Default,
343 Vibrant,
345 Cinematic,
347 Muted,
349 HighContrast,
351 Warm,
353 Cool,
355 Retro,
357 Desaturated,
359 Custom,
361}
362
363impl ColorGradingPreset {
364 pub const ALL: &'static [ColorGradingPreset] = &[
365 ColorGradingPreset::Default,
366 ColorGradingPreset::Vibrant,
367 ColorGradingPreset::Cinematic,
368 ColorGradingPreset::Muted,
369 ColorGradingPreset::HighContrast,
370 ColorGradingPreset::Warm,
371 ColorGradingPreset::Cool,
372 ColorGradingPreset::Retro,
373 ColorGradingPreset::Desaturated,
374 ColorGradingPreset::Custom,
375 ];
376
377 pub fn name(&self) -> &'static str {
378 match self {
379 ColorGradingPreset::Default => "Default",
380 ColorGradingPreset::Vibrant => "Vibrant",
381 ColorGradingPreset::Cinematic => "Cinematic",
382 ColorGradingPreset::Muted => "Muted",
383 ColorGradingPreset::HighContrast => "High Contrast",
384 ColorGradingPreset::Warm => "Warm",
385 ColorGradingPreset::Cool => "Cool",
386 ColorGradingPreset::Retro => "Retro",
387 ColorGradingPreset::Desaturated => "Desaturated",
388 ColorGradingPreset::Custom => "Custom",
389 }
390 }
391
392 pub fn to_color_grading(&self) -> ColorGrading {
393 let preset = *self;
394 match self {
395 ColorGradingPreset::Default => ColorGrading {
396 preset,
397 ..ColorGrading::default()
398 },
399 ColorGradingPreset::Vibrant => ColorGrading {
400 saturation: 1.3,
401 brightness: 0.02,
402 contrast: 1.1,
403 vibrance: 0.4,
404 preset,
405 ..ColorGrading::default()
406 },
407 ColorGradingPreset::Cinematic => ColorGrading {
408 gamma: 2.4,
409 saturation: 0.9,
410 brightness: -0.02,
411 contrast: 1.15,
412 preset,
413 ..ColorGrading::default()
414 },
415 ColorGradingPreset::Muted => ColorGrading {
416 saturation: 0.7,
417 contrast: 0.9,
418 tonemap_algorithm: TonemapAlgorithm::Reinhard,
419 preset,
420 ..ColorGrading::default()
421 },
422 ColorGradingPreset::HighContrast => ColorGrading {
423 saturation: 1.1,
424 contrast: 1.4,
425 preset,
426 ..ColorGrading::default()
427 },
428 ColorGradingPreset::Warm => ColorGrading {
429 gamma: 2.1,
430 saturation: 1.1,
431 brightness: 0.03,
432 contrast: 1.05,
433 preset,
434 ..ColorGrading::default()
435 },
436 ColorGradingPreset::Cool => ColorGrading {
437 gamma: 2.3,
438 saturation: 0.95,
439 brightness: -0.01,
440 contrast: 1.05,
441 tonemap_algorithm: TonemapAlgorithm::Neutral,
442 preset,
443 ..ColorGrading::default()
444 },
445 ColorGradingPreset::Retro => ColorGrading {
446 gamma: 2.0,
447 saturation: 0.8,
448 brightness: 0.05,
449 contrast: 1.2,
450 tonemap_algorithm: TonemapAlgorithm::Reinhard,
451 preset,
452 ..ColorGrading::default()
453 },
454 ColorGradingPreset::Desaturated => ColorGrading {
455 saturation: 0.3,
456 preset,
457 ..ColorGrading::default()
458 },
459 ColorGradingPreset::Custom => ColorGrading::default(),
460 }
461 }
462}
463
464#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
466pub struct ColorGrading {
467 pub exposure: f32,
470 pub exposure_compensation_ev: f32,
473 pub auto_exposure: bool,
476 pub auto_exposure_target: f32,
479 pub auto_exposure_rate: f32,
482 pub auto_exposure_min_ev: f32,
486 pub auto_exposure_max_ev: f32,
490 pub gamma: f32,
492 pub saturation: f32,
494 pub brightness: f32,
496 pub contrast: f32,
498 pub vibrance: f32,
500 pub vignette_intensity: f32,
502 pub vignette_radius: f32,
504 pub vignette_smoothness: f32,
506 pub chromatic_aberration: f32,
509 pub color_lut_weight: f32,
512 pub tonemap_algorithm: TonemapAlgorithm,
514 pub preset: ColorGradingPreset,
516}
517
518impl Default for ColorGrading {
519 fn default() -> Self {
520 Self {
521 exposure: 1.0,
522 exposure_compensation_ev: 0.0,
523 auto_exposure: false,
524 auto_exposure_target: 0.18,
525 auto_exposure_rate: 1.5,
526 auto_exposure_min_ev: -3.0,
527 auto_exposure_max_ev: 5.0,
528 gamma: 2.2,
529 saturation: 1.0,
530 brightness: 0.0,
531 contrast: 1.0,
532 vibrance: 0.0,
533 vignette_intensity: 0.0,
534 vignette_radius: 0.6,
535 vignette_smoothness: 0.4,
536 chromatic_aberration: 0.0,
537 color_lut_weight: 0.0,
538 tonemap_algorithm: TonemapAlgorithm::Aces,
539 preset: ColorGradingPreset::Default,
540 }
541 }
542}
543
544#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
546pub struct VertexSnap {
547 pub resolution: [f32; 2],
549}
550
551impl Default for VertexSnap {
552 fn default() -> Self {
553 Self {
554 resolution: [160.0, 120.0],
555 }
556 }
557}
558
559#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
561pub struct Fog {
562 pub color: [f32; 3],
564 pub start: f32,
567 pub end: f32,
570 #[serde(default)]
572 pub mode: FogMode,
573}
574
575#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
577pub enum FogMode {
578 #[default]
580 Linear,
581 Exponential,
583 ExponentialSquared,
585}
586
587impl FogMode {
588 pub fn as_u32(self) -> u32 {
590 match self {
591 FogMode::Linear => 1,
592 FogMode::Exponential => 2,
593 FogMode::ExponentialSquared => 3,
594 }
595 }
596
597 pub fn from_u32(value: u32) -> Self {
599 match value {
600 2 => FogMode::Exponential,
601 3 => FogMode::ExponentialSquared,
602 _ => FogMode::Linear,
603 }
604 }
605}
606
607impl Default for Fog {
608 fn default() -> Self {
609 Self {
610 color: [0.5, 0.5, 0.55],
611 start: 2.0,
612 end: 15.0,
613 mode: FogMode::Linear,
614 }
615 }
616}
617
618#[derive(Clone)]
619pub struct DayNightState {
620 pub hour: f32,
621 pub speed: f32,
622 pub auto_cycle: bool,
623 pub sun_entity: Option<crate::entity::RenderEntity>,
624 pub ibl_snapshot_hours: Vec<f32>,
627}
628
629impl Default for DayNightState {
630 fn default() -> Self {
631 Self {
632 hour: 12.0,
633 speed: 0.0,
634 auto_cycle: false,
635 sun_entity: None,
636 ibl_snapshot_hours: vec![0.0, 4.0, 7.0, 10.0, 14.0, 17.0, 20.0],
637 }
638 }
639}
640
641#[derive(
643 Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, enum2schema::Schema,
644)]
645#[schema(string_enum)]
646pub enum Atmosphere {
647 #[default]
649 None,
650 Sky,
652 CloudySky,
654 Space,
656 Nebula,
658 Sunset,
660 DayNight,
662 Hdr,
664 HdrMip0,
666 HdrMip1,
668 HdrMip2,
670 HdrMip3,
672 HdrMip4,
674 Irradiance,
676 PrefilterMip0,
678 PrefilterMip1,
680 PrefilterMip2,
682 PrefilterMip3,
684 PrefilterMip4,
686}
687
688impl Atmosphere {
689 pub const ALL: &'static [Atmosphere] = &[
690 Atmosphere::None,
691 Atmosphere::Sky,
692 Atmosphere::CloudySky,
693 Atmosphere::Space,
694 Atmosphere::Nebula,
695 Atmosphere::Sunset,
696 Atmosphere::DayNight,
697 Atmosphere::Hdr,
698 Atmosphere::HdrMip0,
699 Atmosphere::HdrMip1,
700 Atmosphere::HdrMip2,
701 Atmosphere::HdrMip3,
702 Atmosphere::HdrMip4,
703 Atmosphere::Irradiance,
704 Atmosphere::PrefilterMip0,
705 Atmosphere::PrefilterMip1,
706 Atmosphere::PrefilterMip2,
707 Atmosphere::PrefilterMip3,
708 Atmosphere::PrefilterMip4,
709 ];
710
711 pub fn mip_level(&self) -> f32 {
712 match self {
713 Atmosphere::HdrMip0 | Atmosphere::PrefilterMip0 => 0.0,
714 Atmosphere::HdrMip1 | Atmosphere::PrefilterMip1 => 1.0,
715 Atmosphere::HdrMip2 | Atmosphere::PrefilterMip2 => 2.0,
716 Atmosphere::HdrMip3 | Atmosphere::PrefilterMip3 => 3.0,
717 Atmosphere::HdrMip4 | Atmosphere::PrefilterMip4 => 4.0,
718 _ => 0.0,
719 }
720 }
721
722 pub fn next(self) -> Self {
723 let all = Self::ALL;
724 let current_index = all.iter().position(|&a| a == self).unwrap_or(0);
725 let next_index = (current_index + 1) % all.len();
726 all[next_index]
727 }
728
729 pub fn previous(self) -> Self {
730 let all = Self::ALL;
731 let current_index = all.iter().position(|&a| a == self).unwrap_or(0);
732 let prev_index = if current_index == 0 {
733 all.len() - 1
734 } else {
735 current_index - 1
736 };
737 all[prev_index]
738 }
739
740 pub fn is_procedural(&self) -> bool {
741 matches!(
742 self,
743 Atmosphere::Sky
744 | Atmosphere::CloudySky
745 | Atmosphere::Space
746 | Atmosphere::Nebula
747 | Atmosphere::Sunset
748 | Atmosphere::DayNight
749 )
750 }
751
752 pub fn as_procedural_cubemap_type(&self) -> Option<u32> {
753 match self {
754 Atmosphere::Sky => Some(0),
755 Atmosphere::CloudySky => Some(1),
756 Atmosphere::Space => Some(2),
757 Atmosphere::Nebula => Some(3),
758 Atmosphere::Sunset => Some(4),
759 Atmosphere::DayNight => Some(5),
760 _ => None,
761 }
762 }
763}
764
765#[derive(Default)]
766pub struct IblViews {
767 pub brdf_lut_view: Option<wgpu::TextureView>,
768 pub irradiance_view: Option<wgpu::TextureView>,
769 pub prefiltered_view: Option<wgpu::TextureView>,
770}
771
772impl Clone for IblViews {
773 fn clone(&self) -> Self {
774 Self {
775 brdf_lut_view: self.brdf_lut_view.clone(),
776 irradiance_view: self.irradiance_view.clone(),
777 prefiltered_view: self.prefiltered_view.clone(),
778 }
779 }
780}
781
782#[derive(Clone)]
783pub struct MeshLodLevel {
784 pub mesh_name: String,
785 pub min_screen_pixels: f32,
786}
787
788#[derive(Clone)]
789pub struct MeshLodChain {
790 pub base_mesh: String,
791 pub levels: Vec<MeshLodLevel>,
792}
793
794#[repr(C)]
800#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
801pub struct EffectsUniforms {
802 pub time: f32,
803 pub chromatic_aberration: f32,
804 pub wave_distortion: f32,
805 pub color_shift: f32,
806 pub kaleidoscope_segments: f32,
807 pub crt_scanlines: f32,
808 pub vignette: f32,
809 pub plasma_intensity: f32,
810 pub glitch_intensity: f32,
811 pub mirror_mode: f32,
812 pub invert: f32,
813 pub hue_rotation: f32,
814 pub raymarch_mode: f32,
815 pub raymarch_blend: f32,
816 pub film_grain: f32,
817 pub sharpen: f32,
818 pub pixelate: f32,
819 pub color_posterize: f32,
820 pub radial_blur: f32,
821 pub tunnel_speed: f32,
822 pub fractal_iterations: f32,
823 pub glow_intensity: f32,
824 pub screen_shake: f32,
825 pub zoom_pulse: f32,
826 pub speed_lines: f32,
827 pub color_grade_mode: f32,
828 pub vhs_distortion: f32,
829 pub lens_flare: f32,
830 pub edge_glow: f32,
831 pub saturation: f32,
832 pub warp_speed: f32,
833 pub pulse_rings: f32,
834 pub heat_distortion: f32,
835 pub digital_rain: f32,
836 pub strobe: f32,
837 pub color_cycle_speed: f32,
838 pub feedback_amount: f32,
839 pub ascii_mode: f32,
840}
841
842impl Default for EffectsUniforms {
843 fn default() -> Self {
844 Self {
845 time: 0.0,
846 chromatic_aberration: 0.0,
847 wave_distortion: 0.0,
848 color_shift: 0.0,
849 kaleidoscope_segments: 0.0,
850 crt_scanlines: 0.0,
851 vignette: 0.0,
852 plasma_intensity: 0.0,
853 glitch_intensity: 0.0,
854 mirror_mode: 0.0,
855 invert: 0.0,
856 hue_rotation: 0.0,
857 raymarch_mode: 0.0,
858 raymarch_blend: 0.0,
859 film_grain: 0.0,
860 sharpen: 0.0,
861 pixelate: 0.0,
862 color_posterize: 0.0,
863 radial_blur: 0.0,
864 tunnel_speed: 1.0,
865 fractal_iterations: 4.0,
866 glow_intensity: 0.0,
867 screen_shake: 0.0,
868 zoom_pulse: 0.0,
869 speed_lines: 0.0,
870 color_grade_mode: 0.0,
871 vhs_distortion: 0.0,
872 lens_flare: 0.0,
873 edge_glow: 0.0,
874 saturation: 1.0,
875 warp_speed: 0.0,
876 pulse_rings: 0.0,
877 heat_distortion: 0.0,
878 digital_rain: 0.0,
879 strobe: 0.0,
880 color_cycle_speed: 1.0,
881 feedback_amount: 0.0,
882 ascii_mode: 0.0,
883 }
884 }
885}
886
887#[derive(Clone, Copy, Debug, PartialEq, Eq)]
888pub enum RaymarchMode {
889 Off = 0,
890 Tunnel = 1,
891 Fractal = 2,
892 Mandelbulb = 3,
893 PlasmaVortex = 4,
894 Geometric = 5,
895}
896
897impl From<u32> for RaymarchMode {
898 fn from(value: u32) -> Self {
899 match value {
900 1 => RaymarchMode::Tunnel,
901 2 => RaymarchMode::Fractal,
902 3 => RaymarchMode::Mandelbulb,
903 4 => RaymarchMode::PlasmaVortex,
904 5 => RaymarchMode::Geometric,
905 _ => RaymarchMode::Off,
906 }
907 }
908}
909
910#[derive(Clone, Copy, Debug, PartialEq, Eq)]
911pub enum ColorGradeMode {
912 None = 0,
913 Cyberpunk = 1,
914 Sunset = 2,
915 Grayscale = 3,
916 Sepia = 4,
917 Matrix = 5,
918 HotMetal = 6,
919}
920
921impl From<u32> for ColorGradeMode {
922 fn from(value: u32) -> Self {
923 match value {
924 1 => ColorGradeMode::Cyberpunk,
925 2 => ColorGradeMode::Sunset,
926 3 => ColorGradeMode::Grayscale,
927 4 => ColorGradeMode::Sepia,
928 5 => ColorGradeMode::Matrix,
929 6 => ColorGradeMode::HotMetal,
930 _ => ColorGradeMode::None,
931 }
932 }
933}
934
935#[derive(Clone, Debug)]
941pub struct EffectsState {
942 pub uniforms: EffectsUniforms,
943 pub enabled: bool,
944 pub animate_hue: bool,
945}
946
947impl Default for EffectsState {
948 fn default() -> Self {
949 Self {
950 uniforms: EffectsUniforms::default(),
951 enabled: true,
952 animate_hue: false,
953 }
954 }
955}
956
957#[derive(Clone, Serialize, Deserialize)]
961pub struct RenderSettings {
962 pub frame_rate_limit: Option<f32>,
972 pub atmosphere: Atmosphere,
974 pub show_sky: bool,
977 pub render_layer_world_enabled: bool,
979 pub render_layer_overlay_enabled: bool,
981 pub render_world_to_swapchain: bool,
986 pub clear_color: [f32; 4],
988 pub ui_scale: Option<f32>,
990 pub unlit_mode: bool,
992 pub vertex_snap: Option<VertexSnap>,
994 pub affine_texture_mapping: bool,
996 pub material_anisotropy_filtering: u16,
999 pub fog: Option<Fog>,
1001 pub color_grading: ColorGrading,
1003 pub bloom_enabled: bool,
1005 pub bloom_intensity: f32,
1007 pub bloom_threshold: f32,
1009 pub bloom_knee: f32,
1011 pub bloom_filter_radius: f32,
1013 pub depth_of_field: DepthOfField,
1015 pub ssao_enabled: bool,
1017 pub ssao_radius: f32,
1019 pub ssao_bias: f32,
1021 pub ssao_intensity: f32,
1023 pub ssao_sample_count: u32,
1024 pub ssao_blur_depth_threshold: f32,
1025 pub ssao_blur_normal_power: f32,
1026 pub ssgi_enabled: bool,
1027 pub ssgi_radius: f32,
1028 pub ssgi_intensity: f32,
1029 pub ssgi_max_steps: u32,
1030 pub ssr_enabled: bool,
1031 pub ssr_max_steps: u32,
1032 pub ssr_thickness: f32,
1033 pub ssr_max_distance: f32,
1034 pub ssr_stride: f32,
1035 pub ssr_fade_start: f32,
1036 pub ssr_fade_end: f32,
1037 pub ssr_intensity: f32,
1038 pub ambient_light: [f32; 4],
1040 pub taa_enabled: bool,
1044 pub taa_blend: f32,
1048 pub taa_sharpness: f32,
1050 pub water_enabled: bool,
1053 pub vsync_enabled: bool,
1058 pub render_scale: f32,
1060 pub ibl_blend_factor: f32,
1062}
1063
1064#[derive(Clone)]
1066pub struct DebugDraw {
1067 pub show_grid: bool,
1069 pub show_bounding_volumes: bool,
1071 pub show_selected_bounding_volume: bool,
1073 pub show_normals: bool,
1075 pub normal_line_length: f32,
1077 pub normal_line_color: [f32; 4],
1079 pub pbr_debug_mode: PbrDebugMode,
1081 pub texture_debug_stripes: bool,
1083 pub texture_debug_stripes_speed: f32,
1085 pub ssao_visualization: bool,
1086}
1087
1088#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
1091pub enum GpuDeviceType {
1092 #[default]
1093 Other,
1094 IntegratedGpu,
1095 DiscreteGpu,
1096 VirtualGpu,
1097 Cpu,
1098}
1099
1100#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
1104pub enum GpuBackend {
1105 #[default]
1106 Other,
1107 Vulkan,
1108 Metal,
1109 Dx12,
1110 Gl,
1111 WebGpu,
1112 WebGl,
1113}
1114
1115#[derive(Debug, Clone, Default)]
1118pub struct GpuProfile {
1119 pub backend: GpuBackend,
1120 pub device_type: GpuDeviceType,
1121 pub name: String,
1122}
1123
1124impl GpuProfile {
1125 pub fn is_webgl(&self) -> bool {
1128 self.backend == GpuBackend::WebGl
1129 }
1130
1131 pub fn is_low_power(&self) -> bool {
1134 matches!(
1135 self.device_type,
1136 GpuDeviceType::IntegratedGpu | GpuDeviceType::VirtualGpu | GpuDeviceType::Cpu
1137 )
1138 }
1139}
1140
1141#[derive(Clone, Debug)]
1146pub struct RenderView {
1147 pub view: nalgebra_glm::Mat4,
1148 pub projection: nalgebra_glm::Mat4,
1149 pub view_projection: nalgebra_glm::Mat4,
1150 pub inverse_view: nalgebra_glm::Mat4,
1151 pub inverse_projection: nalgebra_glm::Mat4,
1152 pub inverse_view_projection: nalgebra_glm::Mat4,
1153 pub camera_position: nalgebra_glm::Vec3,
1154 pub camera_right: nalgebra_glm::Vec3,
1155 pub camera_up: nalgebra_glm::Vec3,
1156 pub frustum_planes: [nalgebra_glm::Vec4; 6],
1157 pub z_near: f32,
1158 pub z_far: f32,
1159 pub y_fov_rad: f32,
1160 pub aspect: f32,
1161 pub orthographic: Option<(f32, f32)>,
1162 pub screen_size: (u32, u32),
1163 pub constrained_aspect: Option<f32>,
1164}
1165
1166#[cfg(feature = "wgpu")]
1172#[derive(Clone, Default)]
1173pub struct RenderLighting {
1174 pub lights_data: Vec<crate::wgpu::passes::geometry::projection::LightData>,
1175 pub num_directional_lights: u32,
1176 pub directional_light_direction: [f32; 4],
1177 pub has_directional_light: bool,
1178 pub entity_to_lights_index: std::collections::HashMap<crate::entity::RenderEntity, usize>,
1179 pub cascade_view_projections: [[[f32; 4]; 4]; crate::wgpu::passes::NUM_SHADOW_CASCADES],
1180 pub cascade_diameters: [f32; crate::wgpu::passes::NUM_SHADOW_CASCADES],
1181 pub cascade_split_distances: [f32; crate::wgpu::passes::NUM_SHADOW_CASCADES],
1182 pub light_view_projection: [[f32; 4]; 4],
1183 pub shadow_bias: f32,
1184 pub shadow_normal_bias: f32,
1185 pub directional_light_size: f32,
1186 pub shadows_enabled: f32,
1187 pub area_lights_data: Vec<crate::wgpu::passes::geometry::projection::AreaLightData>,
1188 pub area_entity_to_index: std::collections::HashMap<crate::entity::RenderEntity, usize>,
1189 pub sun_direction: nalgebra_glm::Vec3,
1190 pub sun_color: nalgebra_glm::Vec3,
1191}
1192
1193#[derive(Clone, Copy, Debug)]
1196pub struct DynamicObjectState {
1197 pub visible: u32,
1198 pub morph_weights: [f32; 8],
1199 pub transform: nalgebra_glm::Mat4,
1200 pub culling_mask: u32,
1201 pub is_overlay: u32,
1202 pub render_layer: u32,
1203}
1204
1205#[derive(Clone, Default)]
1209pub struct InstancedObjectData {
1210 pub world_models: Vec<[[f32; 4]; 4]>,
1211 pub world_normals: Vec<[[f32; 4]; 3]>,
1212 pub local_matrices: Vec<nalgebra_glm::Mat4>,
1213 pub custom_tints: Vec<[f32; 4]>,
1214 pub mesh_name: String,
1215 pub render_layer: u32,
1216 pub visible: u32,
1217 pub parent_transform: nalgebra_glm::Mat4,
1218}
1219
1220#[derive(Clone)]
1223pub struct SkinnedChannelData {
1224 pub property: u32,
1225 pub interpolation: u32,
1226 pub input: Vec<f32>,
1227 pub values: Vec<[f32; 4]>,
1228 pub stride: u32,
1229}
1230
1231#[derive(Clone)]
1235pub struct SkinnedJointData {
1236 pub local_index: u32,
1237 pub parent_local: Option<u32>,
1238 pub rest_translation: [f32; 3],
1239 pub rest_rotation: [f32; 4],
1240 pub rest_scale: [f32; 3],
1241 pub cur_channels: Vec<SkinnedChannelData>,
1242 pub blend_channels: Vec<SkinnedChannelData>,
1243 pub layer_channels: Vec<Vec<SkinnedChannelData>>,
1244}
1245
1246#[derive(Clone)]
1249pub struct SkinnedSkeletonData {
1250 pub skin_entity: crate::entity::RenderEntity,
1251 pub player_entity: crate::entity::RenderEntity,
1252 pub armature_parent: Option<crate::entity::RenderEntity>,
1256 pub joint_count: u32,
1257 pub layer_count: u32,
1258 pub joints_ordered: Vec<SkinnedJointData>,
1259}
1260
1261#[derive(Default, Clone)]
1267pub struct RenderSkinning {
1268 pub cache: crate::skinning::SkinningCache,
1269 pub bone_transforms: Vec<nalgebra_glm::Mat4>,
1270 pub static_generation: u64,
1271 pub bone_transforms_generation: u64,
1275}
1276
1277#[derive(Clone, Default)]
1283pub struct SkinnedAnimationSnapshot {
1284 pub signature: u64,
1285 pub skeletons: Vec<SkinnedSkeletonData>,
1286 pub player_runtime: std::collections::HashMap<crate::entity::RenderEntity, [f32; 3]>,
1287 pub layer_runtime: std::collections::HashMap<(crate::entity::RenderEntity, usize), [f32; 2]>,
1288 pub armature_roots: std::collections::HashMap<crate::entity::RenderEntity, nalgebra_glm::Mat4>,
1289}
1290
1291#[derive(Clone, Default)]
1296pub struct RenderMaterialEntry {
1297 pub material: crate::material::Material,
1298 pub texture_ids: crate::material::MaterialTextureIds,
1299}
1300
1301#[derive(Clone, Default)]
1305pub struct RenderMaterials {
1306 pub entries: Vec<RenderMaterialEntry>,
1307 pub name_to_id: std::collections::HashMap<String, u32>,
1308 pub entity_to_id: std::collections::HashMap<crate::entity::RenderEntity, u32>,
1309 pub entity_to_name: std::collections::HashMap<crate::entity::RenderEntity, String>,
1310 pub transparent_ids: std::collections::HashSet<u32>,
1311 pub mask_ids: std::collections::HashSet<u32>,
1312 pub double_sided_ids: std::collections::HashSet<u32>,
1313 pub generation: u64,
1316}
1317
1318#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
1324pub enum RenderLightType {
1325 #[default]
1326 Directional,
1327 Point,
1328 Spot,
1329 Area,
1330}
1331
1332#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
1335pub enum RenderAreaLightShape {
1336 #[default]
1337 Rectangle,
1338 Disk,
1339 Sphere,
1340 Tube,
1341}
1342
1343#[derive(Clone)]
1347pub struct RenderLightData {
1348 pub light_type: RenderLightType,
1349 pub color: nalgebra_glm::Vec3,
1350 pub intensity: f32,
1351 pub range: f32,
1352 pub inner_cone_angle: f32,
1353 pub outer_cone_angle: f32,
1354 pub cast_shadows: bool,
1355 pub shadow_bias: f32,
1356 pub shadow_resolution: u32,
1357 pub shadow_distance: f32,
1358 pub cookie_texture: Option<String>,
1359 pub area_shape: RenderAreaLightShape,
1360 pub area_width: f32,
1361 pub area_height: f32,
1362 pub area_radius: f32,
1363 pub area_two_sided: bool,
1364 pub area_emissive_texture: Option<String>,
1365 pub shadow_normal_bias: f32,
1366 pub shadow_softness: f32,
1367}
1368
1369#[derive(Clone)]
1370pub struct RenderLight {
1371 pub entity: crate::entity::RenderEntity,
1372 pub light: RenderLightData,
1373 pub transform: nalgebra_glm::Mat4,
1374}
1375
1376#[derive(Clone, Default)]
1380pub struct RenderLights {
1381 pub lights: Vec<RenderLight>,
1382 pub entity_to_index: std::collections::HashMap<crate::entity::RenderEntity, usize>,
1383}
1384
1385#[derive(Clone)]
1389pub struct RenderDecalData {
1390 pub texture: Option<String>,
1391 pub emissive_texture: Option<String>,
1392 pub emissive_strength: f32,
1393 pub color: [f32; 4],
1394 pub size: nalgebra_glm::Vec2,
1395 pub depth: f32,
1396 pub normal_threshold: f32,
1397 pub fade_start: f32,
1398 pub fade_end: f32,
1399}
1400
1401#[derive(Clone)]
1404pub struct RenderDecal {
1405 pub decal: RenderDecalData,
1406 pub transform: nalgebra_glm::Mat4,
1407 pub visible: bool,
1408}
1409
1410#[derive(Clone, Debug)]
1413pub struct RenderWaterData {
1414 pub half_extents: nalgebra_glm::Vec2,
1415 pub tessellation: u32,
1416 pub wave_amplitude: f32,
1417 pub wave_steepness: f32,
1418 pub wave_length: f32,
1419 pub wave_speed: f32,
1420 pub wave_direction_radians: f32,
1421 pub shallow_color: [f32; 3],
1422 pub deep_color: [f32; 3],
1423 pub depth_fade_distance: f32,
1424 pub edge_foam_distance: f32,
1425 pub foam_amount: f32,
1426 pub foam_color: [f32; 3],
1427 pub roughness: f32,
1428 pub fresnel_power: f32,
1429 pub reflection_strength: f32,
1430 pub refraction_strength: f32,
1431 pub specular_strength: f32,
1432}
1433
1434#[derive(Clone)]
1437pub struct RenderWater {
1438 pub water: RenderWaterData,
1439 pub transform: nalgebra_glm::Mat4,
1440}
1441
1442#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
1445pub enum RenderClothPinning {
1446 #[default]
1447 TopRow,
1448 TopCorners,
1449 None,
1450}
1451
1452#[derive(Clone, Debug, PartialEq)]
1457pub struct RenderClothData {
1458 pub columns: u32,
1459 pub rows: u32,
1460 pub width: f32,
1461 pub height: f32,
1462 pub pinning: RenderClothPinning,
1463 pub stiffness: f32,
1464 pub damping: f32,
1465 pub substeps: u32,
1466 pub solver_iterations: u32,
1467 pub gravity: nalgebra_glm::Vec3,
1468 pub wind_response: f32,
1469 pub ground_height: Option<f32>,
1470 pub texture_tiling: nalgebra_glm::Vec2,
1471 pub reset_epoch: u32,
1472}
1473
1474#[derive(Clone)]
1477pub struct RenderCloth {
1478 pub entity: crate::entity::RenderEntity,
1479 pub cloth: RenderClothData,
1480 pub transform: nalgebra_glm::Mat4,
1481 pub mesh_name: String,
1482}
1483
1484#[derive(Clone)]
1488pub struct RenderParticleEmitter {
1489 pub entity: crate::entity::RenderEntity,
1490 pub emitter: crate::particles::ParticleEmitter,
1491}
1492
1493#[derive(Clone, Default)]
1497pub struct RenderShadowCasters {
1498 pub meshes: Vec<crate::entity::RenderEntity>,
1499 pub instanced: Vec<crate::entity::RenderEntity>,
1500 pub skinned: Vec<crate::entity::RenderEntity>,
1501}
1502
1503#[derive(Clone)]
1509pub struct RenderText {
1510 pub mesh: crate::text_data::TextMesh,
1511 pub color: nalgebra_glm::Vec4,
1512 pub outline_color: nalgebra_glm::Vec4,
1513 pub outline_width: f32,
1514 pub smoothing: f32,
1515 pub billboard: bool,
1516 pub transform: nalgebra_glm::Mat4,
1517 pub char_count: usize,
1518 pub character_colors: Option<Vec<Option<nalgebra_glm::Vec4>>>,
1519}
1520
1521#[derive(Clone, Copy, Debug, Default)]
1525pub struct RenderBounds {
1526 pub center: nalgebra_glm::Vec3,
1527 pub sphere_radius: f32,
1528}
1529
1530#[derive(Clone)]
1533pub struct RendererState {
1534 pub auto_frame_rate_limit_baseline: Option<f32>,
1536 pub taa_jitter: [f32; 2],
1541 pub view_projection: [[f32; 4]; 4],
1544 pub prev_view_projection: [[f32; 4]; 4],
1546 pub gpu_culling_enabled: bool,
1548 pub occlusion_culling_enabled: bool,
1556 pub gpu_batching_enabled: bool,
1559 pub min_screen_pixel_size: f32,
1560 pub min_window_size: Option<(u32, u32)>,
1562 pub use_fullscreen: bool,
1564 pub show_cursor: bool,
1566 pub letterbox_amount: f32,
1568 pub letterbox_target: f32,
1570 pub day_night: DayNightState,
1571 pub mesh_lod_chains: Vec<MeshLodChain>,
1572 pub active_view: EffectiveShading,
1576 pub render_view: Option<RenderView>,
1581 pub render_dynamic_objects:
1585 std::collections::HashMap<crate::entity::RenderEntity, DynamicObjectState>,
1586 pub render_materials: RenderMaterials,
1589 pub render_object_meshes: std::collections::HashMap<crate::entity::RenderEntity, String>,
1592 pub render_instanced_objects:
1594 std::collections::HashMap<crate::entity::RenderEntity, InstancedObjectData>,
1595 pub render_lights: RenderLights,
1598 pub render_decals: Vec<RenderDecal>,
1601 pub render_particle_emitters: Vec<RenderParticleEmitter>,
1604 pub render_water: Vec<RenderWater>,
1607 pub render_cloth: Vec<RenderCloth>,
1610 pub render_selection_outline_ids: Vec<u32>,
1615 pub render_selection_outline_color: [f32; 4],
1618 pub render_bounds: std::collections::HashMap<crate::entity::RenderEntity, RenderBounds>,
1621 pub render_shadow_casters: RenderShadowCasters,
1624 pub render_skinned_meshes: Vec<crate::entity::RenderEntity>,
1627 pub render_regular_mesh_entities: Vec<crate::entity::RenderEntity>,
1631 pub culling_camera_view_projection: Option<nalgebra_glm::Mat4>,
1635 pub render_skinning: RenderSkinning,
1638 pub render_texts: Vec<RenderText>,
1641 pub render_animation: SkinnedAnimationSnapshot,
1645 #[cfg(feature = "wgpu")]
1649 pub render_lighting: Option<RenderLighting>,
1650 pub skinned_objects_generation: u64,
1654 pub settings_version: u64,
1657 pub focus_policy: ViewportFocusPolicy,
1660 pub adaptive_sampling: AdaptiveSamplingState,
1662 pub effects: EffectsState,
1664 pub gpu_profile: Option<GpuProfile>,
1667}
1668
1669#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
1670pub enum PerformanceTarget {
1671 #[default]
1672 Unbounded,
1673 Interactive,
1674 Balanced,
1675 Quality,
1676}
1677
1678impl PerformanceTarget {
1679 pub fn target_frame_time_ms(self) -> Option<f32> {
1680 match self {
1681 PerformanceTarget::Unbounded => None,
1682 PerformanceTarget::Interactive => Some(1000.0 / 60.0),
1683 PerformanceTarget::Balanced => Some(1000.0 / 30.0),
1684 PerformanceTarget::Quality => Some(1000.0 / 15.0),
1685 }
1686 }
1687}
1688
1689#[derive(Debug, Clone)]
1690pub struct AdaptiveSamplingState {
1691 pub target: PerformanceTarget,
1692 pub frame_time_rolling_ms: f32,
1693 pub frame_time_sample_count: u32,
1694 pub ssao_sample_scale: f32,
1695 pub ssgi_sample_scale: f32,
1696 pub ssr_step_scale: f32,
1697}
1698
1699impl Default for AdaptiveSamplingState {
1700 fn default() -> Self {
1701 Self {
1702 target: PerformanceTarget::Unbounded,
1703 frame_time_rolling_ms: 16.67,
1704 frame_time_sample_count: 0,
1705 ssao_sample_scale: 1.0,
1706 ssgi_sample_scale: 1.0,
1707 ssr_step_scale: 1.0,
1708 }
1709 }
1710}
1711
1712impl AdaptiveSamplingState {
1713 pub fn record_frame_time(&mut self, frame_time_ms: f32) {
1714 const WINDOW: u32 = 100;
1715 if self.frame_time_sample_count == 0 {
1716 self.frame_time_rolling_ms = frame_time_ms;
1717 self.frame_time_sample_count = 1;
1718 } else {
1719 let alpha = 1.0 / (self.frame_time_sample_count.min(WINDOW) as f32 + 1.0);
1720 self.frame_time_rolling_ms =
1721 self.frame_time_rolling_ms * (1.0 - alpha) + frame_time_ms * alpha;
1722 self.frame_time_sample_count = (self.frame_time_sample_count + 1).min(WINDOW);
1723 }
1724
1725 let Some(target_ms) = self.target.target_frame_time_ms() else {
1726 self.ssao_sample_scale = 1.0;
1727 self.ssgi_sample_scale = 1.0;
1728 self.ssr_step_scale = 1.0;
1729 return;
1730 };
1731
1732 let error = self.frame_time_rolling_ms - target_ms;
1733 let sensitivity = 0.002;
1734 let max_delta = 0.05;
1735 let adjustment = (error * sensitivity).clamp(-max_delta, max_delta);
1736
1737 self.ssao_sample_scale = (self.ssao_sample_scale - adjustment).clamp(0.25, 1.0);
1738 self.ssgi_sample_scale = (self.ssgi_sample_scale - adjustment).clamp(0.25, 1.0);
1739 self.ssr_step_scale = (self.ssr_step_scale - adjustment).clamp(0.25, 1.0);
1740 }
1741}
1742
1743pub fn render_settings_signature(
1750 render: &RenderSettings,
1751 debug: &DebugDraw,
1752 outline_ids: &[u32],
1753 outline_color: [f32; 4],
1754) -> u64 {
1755 use std::hash::{Hash, Hasher};
1756 let mut hasher = std::collections::hash_map::DefaultHasher::new();
1757 outline_ids.hash(&mut hasher);
1758 for component in outline_color {
1759 component.to_bits().hash(&mut hasher);
1760 }
1761 debug.show_grid.hash(&mut hasher);
1762 debug.show_bounding_volumes.hash(&mut hasher);
1763 debug.show_normals.hash(&mut hasher);
1764 debug.normal_line_length.to_bits().hash(&mut hasher);
1765 for component in debug.normal_line_color {
1766 component.to_bits().hash(&mut hasher);
1767 }
1768 (render.atmosphere as u32).hash(&mut hasher);
1769 render.show_sky.hash(&mut hasher);
1770 render.render_layer_world_enabled.hash(&mut hasher);
1771 render.render_layer_overlay_enabled.hash(&mut hasher);
1772 render.render_world_to_swapchain.hash(&mut hasher);
1773 for component in render.clear_color {
1774 component.to_bits().hash(&mut hasher);
1775 }
1776 render.unlit_mode.hash(&mut hasher);
1777 render.vertex_snap.is_some().hash(&mut hasher);
1778 if let Some(ref snap) = render.vertex_snap {
1779 for component in snap.resolution {
1780 component.to_bits().hash(&mut hasher);
1781 }
1782 }
1783 render.affine_texture_mapping.hash(&mut hasher);
1784 render.fog.is_some().hash(&mut hasher);
1785 if let Some(ref fog) = render.fog {
1786 for component in fog.color {
1787 component.to_bits().hash(&mut hasher);
1788 }
1789 fog.start.to_bits().hash(&mut hasher);
1790 fog.end.to_bits().hash(&mut hasher);
1791 }
1792 let cg = &render.color_grading;
1793 cg.exposure.to_bits().hash(&mut hasher);
1794 cg.exposure_compensation_ev.to_bits().hash(&mut hasher);
1795 cg.auto_exposure.hash(&mut hasher);
1796 cg.auto_exposure_target.to_bits().hash(&mut hasher);
1797 cg.auto_exposure_rate.to_bits().hash(&mut hasher);
1798 cg.auto_exposure_min_ev.to_bits().hash(&mut hasher);
1799 cg.auto_exposure_max_ev.to_bits().hash(&mut hasher);
1800 cg.gamma.to_bits().hash(&mut hasher);
1801 cg.saturation.to_bits().hash(&mut hasher);
1802 cg.brightness.to_bits().hash(&mut hasher);
1803 cg.contrast.to_bits().hash(&mut hasher);
1804 (cg.tonemap_algorithm as u32).hash(&mut hasher);
1805 render.bloom_enabled.hash(&mut hasher);
1806 render.bloom_intensity.to_bits().hash(&mut hasher);
1807 render.bloom_threshold.to_bits().hash(&mut hasher);
1808 render.bloom_knee.to_bits().hash(&mut hasher);
1809 render.bloom_filter_radius.to_bits().hash(&mut hasher);
1810 let dof = &render.depth_of_field;
1811 dof.enabled.hash(&mut hasher);
1812 dof.focus_distance.to_bits().hash(&mut hasher);
1813 dof.focus_range.to_bits().hash(&mut hasher);
1814 dof.max_blur_radius.to_bits().hash(&mut hasher);
1815 dof.bokeh_threshold.to_bits().hash(&mut hasher);
1816 dof.bokeh_intensity.to_bits().hash(&mut hasher);
1817 (dof.quality as u32).hash(&mut hasher);
1818 dof.visualize_coc.hash(&mut hasher);
1819 dof.tilt_shift_enabled.hash(&mut hasher);
1820 dof.tilt_shift_angle.to_bits().hash(&mut hasher);
1821 dof.tilt_shift_center.to_bits().hash(&mut hasher);
1822 dof.tilt_shift_blur_amount.to_bits().hash(&mut hasher);
1823 dof.visualize_tilt_shift.hash(&mut hasher);
1824 render.ssao_enabled.hash(&mut hasher);
1825 render.ssao_radius.to_bits().hash(&mut hasher);
1826 render.ssao_bias.to_bits().hash(&mut hasher);
1827 render.ssao_intensity.to_bits().hash(&mut hasher);
1828 render.ssao_sample_count.hash(&mut hasher);
1829 debug.ssao_visualization.hash(&mut hasher);
1830 render.ssao_blur_depth_threshold.to_bits().hash(&mut hasher);
1831 render.ssao_blur_normal_power.to_bits().hash(&mut hasher);
1832 render.ssgi_enabled.hash(&mut hasher);
1833 render.ssgi_radius.to_bits().hash(&mut hasher);
1834 render.ssgi_intensity.to_bits().hash(&mut hasher);
1835 render.ssgi_max_steps.hash(&mut hasher);
1836 render.ssr_enabled.hash(&mut hasher);
1837 render.ssr_max_steps.hash(&mut hasher);
1838 render.ssr_thickness.to_bits().hash(&mut hasher);
1839 render.ssr_max_distance.to_bits().hash(&mut hasher);
1840 render.ssr_stride.to_bits().hash(&mut hasher);
1841 render.ssr_fade_start.to_bits().hash(&mut hasher);
1842 render.ssr_fade_end.to_bits().hash(&mut hasher);
1843 render.ssr_intensity.to_bits().hash(&mut hasher);
1844 for component in render.ambient_light {
1845 component.to_bits().hash(&mut hasher);
1846 }
1847 debug.pbr_debug_mode.as_u32().hash(&mut hasher);
1848 debug.texture_debug_stripes.hash(&mut hasher);
1849 debug
1850 .texture_debug_stripes_speed
1851 .to_bits()
1852 .hash(&mut hasher);
1853 render.taa_enabled.hash(&mut hasher);
1854 render.render_scale.to_bits().hash(&mut hasher);
1855 render.ibl_blend_factor.to_bits().hash(&mut hasher);
1856 hasher.finish()
1857}
1858
1859impl Default for RenderSettings {
1860 fn default() -> Self {
1861 Self {
1862 frame_rate_limit: None,
1863 atmosphere: Atmosphere::None,
1864 show_sky: true,
1865 render_layer_world_enabled: true,
1866 render_layer_overlay_enabled: true,
1867 render_world_to_swapchain: true,
1868 clear_color: [0.0, 0.0, 0.0, 1.0],
1869 ui_scale: None,
1870 unlit_mode: false,
1871 vertex_snap: None,
1872 affine_texture_mapping: false,
1873 material_anisotropy_filtering: 16,
1874 fog: None,
1875 color_grading: ColorGrading::default(),
1876 bloom_enabled: true,
1877 bloom_intensity: 0.04,
1878 bloom_threshold: 1.0,
1879 bloom_knee: 0.5,
1880 bloom_filter_radius: 0.005,
1881 depth_of_field: DepthOfField::default(),
1882 ssao_enabled: false,
1883 ssao_radius: 0.5,
1884 ssao_bias: 0.025,
1885 ssao_intensity: 1.0,
1886 ssao_sample_count: 64,
1887 ssao_blur_depth_threshold: 0.005,
1888 ssao_blur_normal_power: 8.0,
1889 ssgi_enabled: false,
1890 ssgi_radius: 2.0,
1891 ssgi_intensity: 1.0,
1892 ssgi_max_steps: 16,
1893 ssr_enabled: false,
1894 ssr_max_steps: 64,
1895 ssr_thickness: 0.3,
1896 ssr_max_distance: 50.0,
1897 ssr_stride: 1.0,
1898 ssr_fade_start: 0.8,
1899 ssr_fade_end: 1.0,
1900 ssr_intensity: 1.0,
1901 ambient_light: [0.1, 0.1, 0.1, 1.0],
1902 taa_enabled: false,
1903 taa_blend: 0.12,
1904 taa_sharpness: 0.5,
1905 water_enabled: true,
1906 vsync_enabled: true,
1907 render_scale: 1.0,
1908 ibl_blend_factor: 0.0,
1909 }
1910 }
1911}
1912
1913impl Default for DebugDraw {
1914 fn default() -> Self {
1915 Self {
1916 show_grid: false,
1917 show_bounding_volumes: false,
1918 show_selected_bounding_volume: false,
1919 show_normals: false,
1920 normal_line_length: 0.1,
1921 normal_line_color: [0.0, 1.0, 0.0, 1.0],
1922 pbr_debug_mode: PbrDebugMode::None,
1923 texture_debug_stripes: false,
1924 texture_debug_stripes_speed: 100.0,
1925 ssao_visualization: false,
1926 }
1927 }
1928}
1929
1930impl Default for RendererState {
1931 fn default() -> Self {
1932 Self {
1933 auto_frame_rate_limit_baseline: None,
1934 taa_jitter: [0.0, 0.0],
1935 view_projection: nalgebra_glm::Mat4::identity().into(),
1936 prev_view_projection: nalgebra_glm::Mat4::identity().into(),
1937 gpu_culling_enabled: true,
1938 occlusion_culling_enabled: true,
1939 gpu_batching_enabled: true,
1940 min_screen_pixel_size: 0.0,
1941 min_window_size: None,
1942 use_fullscreen: false,
1943 show_cursor: true,
1944 letterbox_amount: 0.0,
1945 letterbox_target: 0.0,
1946 day_night: DayNightState::default(),
1947 mesh_lod_chains: Vec::new(),
1948 active_view: EffectiveShading::default(),
1949 render_view: None,
1950 render_dynamic_objects: std::collections::HashMap::new(),
1951 render_materials: RenderMaterials::default(),
1952 render_object_meshes: std::collections::HashMap::new(),
1953 render_instanced_objects: std::collections::HashMap::new(),
1954 render_lights: RenderLights::default(),
1955 render_decals: Vec::new(),
1956 render_particle_emitters: Vec::new(),
1957 render_water: Vec::new(),
1958 render_cloth: Vec::new(),
1959 render_selection_outline_ids: Vec::new(),
1960 render_selection_outline_color: [1.0, 0.45, 0.0, 1.0],
1961 render_bounds: std::collections::HashMap::new(),
1962 render_shadow_casters: RenderShadowCasters::default(),
1963 render_skinned_meshes: Vec::new(),
1964 render_regular_mesh_entities: Vec::new(),
1965 culling_camera_view_projection: None,
1966 render_skinning: RenderSkinning::default(),
1967 render_texts: Vec::new(),
1968 render_animation: SkinnedAnimationSnapshot::default(),
1969 #[cfg(feature = "wgpu")]
1970 render_lighting: None,
1971 skinned_objects_generation: 0,
1972 settings_version: 0,
1973 focus_policy: ViewportFocusPolicy::default(),
1974 adaptive_sampling: AdaptiveSamplingState::default(),
1975 effects: EffectsState::default(),
1976 gpu_profile: None,
1977 }
1978 }
1979}
1980
1981pub const FLAT_SHADING_COLOR: nalgebra_glm::Vec4 = nalgebra_glm::Vec4::new(0.72, 0.72, 0.72, 1.0);
1982
1983#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
1998pub enum ViewportUpdateMode {
1999 #[default]
2000 Always,
2001 WhenVisible,
2002 WhenDirty,
2003 Once,
2004 Disabled,
2005}
2006
2007pub const WIREFRAME_SENTINEL_COLOR: nalgebra_glm::Vec4 =
2012 nalgebra_glm::Vec4::new(0.0, 0.0, 0.0, 2.0);
2013
2014#[derive(Debug, Clone, Copy, PartialEq)]
2015pub struct EffectiveShading {
2016 pub unlit_mode: bool,
2017 pub bloom_enabled: bool,
2018 pub ssao_enabled: bool,
2019 pub ssgi_enabled: bool,
2020 pub ssr_enabled: bool,
2021 pub show_normals: bool,
2022 pub show_bounding_volumes: bool,
2023 pub show_wireframe: bool,
2024 pub selection_outline_enabled: bool,
2025 pub flat_shading_color: Option<nalgebra_glm::Vec4>,
2026 pub shadow_depth_enabled: bool,
2027 pub lines_enabled: bool,
2028 pub color_grading: ColorGrading,
2029 pub depth_of_field: DepthOfField,
2030 pub bloom_intensity: f32,
2031 pub bloom_threshold: f32,
2032 pub bloom_knee: f32,
2033 pub bloom_filter_radius: f32,
2034 pub ssao_radius: f32,
2035 pub ssao_bias: f32,
2036 pub ssao_intensity: f32,
2037 pub ssao_sample_count: u32,
2038 pub ssao_visualization: bool,
2039 pub ssao_blur_depth_threshold: f32,
2040 pub ssao_blur_normal_power: f32,
2041 pub ssgi_radius: f32,
2042 pub ssgi_intensity: f32,
2043 pub ssgi_max_steps: u32,
2044 pub ssr_max_steps: u32,
2045 pub ssr_thickness: f32,
2046 pub ssr_max_distance: f32,
2047 pub ssr_stride: f32,
2048 pub ssr_fade_start: f32,
2049 pub ssr_fade_end: f32,
2050 pub ssr_intensity: f32,
2051 pub ambient_light: [f32; 4],
2052 pub culling_mask: u32,
2059 pub fog: Option<Fog>,
2063 pub atmosphere: Atmosphere,
2068}
2069
2070impl Default for EffectiveShading {
2071 fn default() -> Self {
2072 Self {
2073 unlit_mode: false,
2074 bloom_enabled: true,
2075 ssao_enabled: false,
2076 ssgi_enabled: false,
2077 ssr_enabled: false,
2078 show_normals: false,
2079 show_bounding_volumes: false,
2080 show_wireframe: false,
2081 selection_outline_enabled: false,
2082 flat_shading_color: None,
2083 shadow_depth_enabled: true,
2084 lines_enabled: false,
2085 color_grading: ColorGrading::default(),
2086 depth_of_field: DepthOfField::default(),
2087 bloom_intensity: 0.5,
2088 bloom_threshold: 1.0,
2089 bloom_knee: 0.5,
2090 bloom_filter_radius: 0.005,
2091 ssao_radius: 0.5,
2092 ssao_bias: 0.025,
2093 ssao_intensity: 1.0,
2094 ssao_sample_count: 64,
2095 ssao_visualization: false,
2096 ssao_blur_depth_threshold: 0.005,
2097 ssao_blur_normal_power: 8.0,
2098 ssgi_radius: 2.0,
2099 ssgi_intensity: 1.0,
2100 ssgi_max_steps: 16,
2101 ssr_max_steps: 64,
2102 ssr_thickness: 0.3,
2103 ssr_max_distance: 50.0,
2104 ssr_stride: 1.0,
2105 ssr_fade_start: 0.8,
2106 ssr_fade_end: 1.0,
2107 ssr_intensity: 1.0,
2108 ambient_light: [0.1, 0.1, 0.1, 1.0],
2109 culling_mask: !0,
2110 fog: None,
2111 atmosphere: Atmosphere::None,
2112 }
2113 }
2114}
2115
2116#[derive(Debug, Clone, Copy, Default)]
2117pub struct ViewportRect {
2118 pub x: f32,
2119 pub y: f32,
2120 pub width: f32,
2121 pub height: f32,
2122}
2123
2124impl ViewportRect {
2125 pub fn contains(&self, screen_pos: nalgebra_glm::Vec2) -> bool {
2126 screen_pos.x >= self.x
2127 && screen_pos.x <= self.x + self.width
2128 && screen_pos.y >= self.y
2129 && screen_pos.y <= self.y + self.height
2130 }
2131
2132 pub fn to_local(&self, screen_pos: nalgebra_glm::Vec2) -> nalgebra_glm::Vec2 {
2133 nalgebra_glm::Vec2::new(screen_pos.x - self.x, screen_pos.y - self.y)
2134 }
2135}