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 selection_outline_enabled: bool,
1081 pub selection_outline_color: [f32; 4],
1083 pub pbr_debug_mode: PbrDebugMode,
1085 pub texture_debug_stripes: bool,
1087 pub texture_debug_stripes_speed: f32,
1089 pub ssao_visualization: bool,
1090}
1091
1092#[derive(Clone, Default)]
1095pub struct EditorSelection {
1096 pub bounding_volume_selected_entity: Option<crate::entity::RenderEntity>,
1098 pub selected_entities: Vec<crate::entity::RenderEntity>,
1102 pub culling_camera_override: Option<crate::entity::RenderEntity>,
1104}
1105
1106#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
1109pub enum GpuDeviceType {
1110 #[default]
1111 Other,
1112 IntegratedGpu,
1113 DiscreteGpu,
1114 VirtualGpu,
1115 Cpu,
1116}
1117
1118#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
1122pub enum GpuBackend {
1123 #[default]
1124 Other,
1125 Vulkan,
1126 Metal,
1127 Dx12,
1128 Gl,
1129 WebGpu,
1130 WebGl,
1131}
1132
1133#[derive(Debug, Clone, Default)]
1136pub struct GpuProfile {
1137 pub backend: GpuBackend,
1138 pub device_type: GpuDeviceType,
1139 pub name: String,
1140}
1141
1142impl GpuProfile {
1143 pub fn is_webgl(&self) -> bool {
1146 self.backend == GpuBackend::WebGl
1147 }
1148
1149 pub fn is_low_power(&self) -> bool {
1152 matches!(
1153 self.device_type,
1154 GpuDeviceType::IntegratedGpu | GpuDeviceType::VirtualGpu | GpuDeviceType::Cpu
1155 )
1156 }
1157}
1158
1159#[derive(Clone, Debug)]
1164pub struct RenderView {
1165 pub view: nalgebra_glm::Mat4,
1166 pub projection: nalgebra_glm::Mat4,
1167 pub view_projection: nalgebra_glm::Mat4,
1168 pub inverse_view: nalgebra_glm::Mat4,
1169 pub inverse_projection: nalgebra_glm::Mat4,
1170 pub inverse_view_projection: nalgebra_glm::Mat4,
1171 pub camera_position: nalgebra_glm::Vec3,
1172 pub camera_right: nalgebra_glm::Vec3,
1173 pub camera_up: nalgebra_glm::Vec3,
1174 pub frustum_planes: [nalgebra_glm::Vec4; 6],
1175 pub z_near: f32,
1176 pub z_far: f32,
1177 pub y_fov_rad: f32,
1178 pub aspect: f32,
1179 pub orthographic: Option<(f32, f32)>,
1180 pub screen_size: (u32, u32),
1181 pub constrained_aspect: Option<f32>,
1182}
1183
1184#[cfg(feature = "wgpu")]
1190#[derive(Clone, Default)]
1191pub struct RenderLighting {
1192 pub lights_data: Vec<crate::wgpu::passes::geometry::projection::LightData>,
1193 pub num_directional_lights: u32,
1194 pub directional_light_direction: [f32; 4],
1195 pub has_directional_light: bool,
1196 pub entity_to_lights_index: std::collections::HashMap<crate::entity::RenderEntity, usize>,
1197 pub cascade_view_projections: [[[f32; 4]; 4]; crate::wgpu::passes::NUM_SHADOW_CASCADES],
1198 pub cascade_diameters: [f32; crate::wgpu::passes::NUM_SHADOW_CASCADES],
1199 pub cascade_split_distances: [f32; crate::wgpu::passes::NUM_SHADOW_CASCADES],
1200 pub light_view_projection: [[f32; 4]; 4],
1201 pub shadow_bias: f32,
1202 pub shadow_normal_bias: f32,
1203 pub directional_light_size: f32,
1204 pub shadows_enabled: f32,
1205 pub area_lights_data: Vec<crate::wgpu::passes::geometry::projection::AreaLightData>,
1206 pub area_entity_to_index: std::collections::HashMap<crate::entity::RenderEntity, usize>,
1207 pub sun_direction: nalgebra_glm::Vec3,
1208 pub sun_color: nalgebra_glm::Vec3,
1209}
1210
1211#[derive(Clone, Copy, Debug)]
1214pub struct DynamicObjectState {
1215 pub visible: u32,
1216 pub morph_weights: [f32; 8],
1217 pub transform: nalgebra_glm::Mat4,
1218 pub culling_mask: u32,
1219 pub is_overlay: u32,
1220 pub render_layer: u32,
1221}
1222
1223#[derive(Clone, Default)]
1227pub struct InstancedObjectData {
1228 pub world_models: Vec<[[f32; 4]; 4]>,
1229 pub world_normals: Vec<[[f32; 4]; 3]>,
1230 pub local_matrices: Vec<nalgebra_glm::Mat4>,
1231 pub custom_tints: Vec<[f32; 4]>,
1232 pub mesh_name: String,
1233 pub render_layer: u32,
1234 pub visible: u32,
1235 pub parent_transform: nalgebra_glm::Mat4,
1236}
1237
1238#[derive(Clone)]
1241pub struct SkinnedChannelData {
1242 pub property: u32,
1243 pub interpolation: u32,
1244 pub input: Vec<f32>,
1245 pub values: Vec<[f32; 4]>,
1246 pub stride: u32,
1247}
1248
1249#[derive(Clone)]
1253pub struct SkinnedJointData {
1254 pub local_index: u32,
1255 pub parent_local: Option<u32>,
1256 pub rest_translation: [f32; 3],
1257 pub rest_rotation: [f32; 4],
1258 pub rest_scale: [f32; 3],
1259 pub cur_channels: Vec<SkinnedChannelData>,
1260 pub blend_channels: Vec<SkinnedChannelData>,
1261 pub layer_channels: Vec<Vec<SkinnedChannelData>>,
1262}
1263
1264#[derive(Clone)]
1267pub struct SkinnedSkeletonData {
1268 pub skin_entity: crate::entity::RenderEntity,
1269 pub player_entity: crate::entity::RenderEntity,
1270 pub armature_parent: Option<crate::entity::RenderEntity>,
1274 pub joint_count: u32,
1275 pub layer_count: u32,
1276 pub joints_ordered: Vec<SkinnedJointData>,
1277}
1278
1279#[derive(Default, Clone)]
1285pub struct RenderSkinning {
1286 pub cache: crate::skinning::SkinningCache,
1287 pub bone_transforms: Vec<nalgebra_glm::Mat4>,
1288 pub static_generation: u64,
1289 pub bone_transforms_generation: u64,
1293}
1294
1295#[derive(Clone, Default)]
1301pub struct SkinnedAnimationSnapshot {
1302 pub signature: u64,
1303 pub skeletons: Vec<SkinnedSkeletonData>,
1304 pub player_runtime: std::collections::HashMap<crate::entity::RenderEntity, [f32; 3]>,
1305 pub layer_runtime: std::collections::HashMap<(crate::entity::RenderEntity, usize), [f32; 2]>,
1306 pub armature_roots: std::collections::HashMap<crate::entity::RenderEntity, nalgebra_glm::Mat4>,
1307}
1308
1309#[derive(Clone, Default)]
1314pub struct RenderMaterialEntry {
1315 pub material: crate::material::Material,
1316 pub texture_ids: crate::material::MaterialTextureIds,
1317}
1318
1319#[derive(Clone, Default)]
1323pub struct RenderMaterials {
1324 pub entries: Vec<RenderMaterialEntry>,
1325 pub name_to_id: std::collections::HashMap<String, u32>,
1326 pub entity_to_id: std::collections::HashMap<crate::entity::RenderEntity, u32>,
1327 pub entity_to_name: std::collections::HashMap<crate::entity::RenderEntity, String>,
1328 pub transparent_ids: std::collections::HashSet<u32>,
1329 pub mask_ids: std::collections::HashSet<u32>,
1330 pub double_sided_ids: std::collections::HashSet<u32>,
1331 pub generation: u64,
1334}
1335
1336#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
1342pub enum RenderLightType {
1343 #[default]
1344 Directional,
1345 Point,
1346 Spot,
1347 Area,
1348}
1349
1350#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
1353pub enum RenderAreaLightShape {
1354 #[default]
1355 Rectangle,
1356 Disk,
1357 Sphere,
1358 Tube,
1359}
1360
1361#[derive(Clone)]
1365pub struct RenderLightData {
1366 pub light_type: RenderLightType,
1367 pub color: nalgebra_glm::Vec3,
1368 pub intensity: f32,
1369 pub range: f32,
1370 pub inner_cone_angle: f32,
1371 pub outer_cone_angle: f32,
1372 pub cast_shadows: bool,
1373 pub shadow_bias: f32,
1374 pub shadow_resolution: u32,
1375 pub shadow_distance: f32,
1376 pub cookie_texture: Option<String>,
1377 pub area_shape: RenderAreaLightShape,
1378 pub area_width: f32,
1379 pub area_height: f32,
1380 pub area_radius: f32,
1381 pub area_two_sided: bool,
1382 pub area_emissive_texture: Option<String>,
1383 pub shadow_normal_bias: f32,
1384 pub shadow_softness: f32,
1385}
1386
1387#[derive(Clone)]
1388pub struct RenderLight {
1389 pub entity: crate::entity::RenderEntity,
1390 pub light: RenderLightData,
1391 pub transform: nalgebra_glm::Mat4,
1392}
1393
1394#[derive(Clone, Default)]
1398pub struct RenderLights {
1399 pub lights: Vec<RenderLight>,
1400 pub entity_to_index: std::collections::HashMap<crate::entity::RenderEntity, usize>,
1401}
1402
1403#[derive(Clone)]
1407pub struct RenderDecalData {
1408 pub texture: Option<String>,
1409 pub emissive_texture: Option<String>,
1410 pub emissive_strength: f32,
1411 pub color: [f32; 4],
1412 pub size: nalgebra_glm::Vec2,
1413 pub depth: f32,
1414 pub normal_threshold: f32,
1415 pub fade_start: f32,
1416 pub fade_end: f32,
1417}
1418
1419#[derive(Clone)]
1422pub struct RenderDecal {
1423 pub decal: RenderDecalData,
1424 pub transform: nalgebra_glm::Mat4,
1425 pub visible: bool,
1426}
1427
1428#[derive(Clone, Debug)]
1431pub struct RenderWaterData {
1432 pub half_extents: nalgebra_glm::Vec2,
1433 pub tessellation: u32,
1434 pub wave_amplitude: f32,
1435 pub wave_steepness: f32,
1436 pub wave_length: f32,
1437 pub wave_speed: f32,
1438 pub wave_direction_radians: f32,
1439 pub shallow_color: [f32; 3],
1440 pub deep_color: [f32; 3],
1441 pub depth_fade_distance: f32,
1442 pub edge_foam_distance: f32,
1443 pub foam_amount: f32,
1444 pub foam_color: [f32; 3],
1445 pub roughness: f32,
1446 pub fresnel_power: f32,
1447 pub reflection_strength: f32,
1448 pub refraction_strength: f32,
1449 pub specular_strength: f32,
1450}
1451
1452#[derive(Clone)]
1455pub struct RenderWater {
1456 pub water: RenderWaterData,
1457 pub transform: nalgebra_glm::Mat4,
1458}
1459
1460#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
1463pub enum RenderClothPinning {
1464 #[default]
1465 TopRow,
1466 TopCorners,
1467 None,
1468}
1469
1470#[derive(Clone, Debug, PartialEq)]
1475pub struct RenderClothData {
1476 pub columns: u32,
1477 pub rows: u32,
1478 pub width: f32,
1479 pub height: f32,
1480 pub pinning: RenderClothPinning,
1481 pub stiffness: f32,
1482 pub damping: f32,
1483 pub substeps: u32,
1484 pub solver_iterations: u32,
1485 pub gravity: nalgebra_glm::Vec3,
1486 pub wind_response: f32,
1487 pub ground_height: Option<f32>,
1488 pub texture_tiling: nalgebra_glm::Vec2,
1489 pub reset_epoch: u32,
1490}
1491
1492#[derive(Clone)]
1495pub struct RenderCloth {
1496 pub entity: crate::entity::RenderEntity,
1497 pub cloth: RenderClothData,
1498 pub transform: nalgebra_glm::Mat4,
1499 pub mesh_name: String,
1500}
1501
1502#[derive(Clone)]
1506pub struct RenderParticleEmitter {
1507 pub entity: crate::entity::RenderEntity,
1508 pub emitter: crate::particles::ParticleEmitter,
1509}
1510
1511#[derive(Clone, Default)]
1515pub struct RenderShadowCasters {
1516 pub meshes: Vec<crate::entity::RenderEntity>,
1517 pub instanced: Vec<crate::entity::RenderEntity>,
1518 pub skinned: Vec<crate::entity::RenderEntity>,
1519}
1520
1521#[derive(Clone)]
1527pub struct RenderText {
1528 pub mesh: crate::text_data::TextMesh,
1529 pub color: nalgebra_glm::Vec4,
1530 pub outline_color: nalgebra_glm::Vec4,
1531 pub outline_width: f32,
1532 pub smoothing: f32,
1533 pub billboard: bool,
1534 pub transform: nalgebra_glm::Mat4,
1535 pub char_count: usize,
1536 pub character_colors: Option<Vec<Option<nalgebra_glm::Vec4>>>,
1537}
1538
1539#[derive(Clone, Copy, Debug, Default)]
1543pub struct RenderBounds {
1544 pub center: nalgebra_glm::Vec3,
1545 pub sphere_radius: f32,
1546}
1547
1548#[derive(Clone)]
1551pub struct RendererState {
1552 pub auto_frame_rate_limit_baseline: Option<f32>,
1554 pub taa_jitter: [f32; 2],
1559 pub view_projection: [[f32; 4]; 4],
1562 pub prev_view_projection: [[f32; 4]; 4],
1564 pub gpu_culling_enabled: bool,
1566 pub occlusion_culling_enabled: bool,
1574 pub gpu_batching_enabled: bool,
1577 pub min_screen_pixel_size: f32,
1578 pub min_window_size: Option<(u32, u32)>,
1580 pub use_fullscreen: bool,
1582 pub show_cursor: bool,
1584 pub letterbox_amount: f32,
1586 pub letterbox_target: f32,
1588 pub day_night: DayNightState,
1589 pub mesh_lod_chains: Vec<MeshLodChain>,
1590 pub active_view: EffectiveShading,
1594 pub render_view: Option<RenderView>,
1599 pub render_dynamic_objects:
1603 std::collections::HashMap<crate::entity::RenderEntity, DynamicObjectState>,
1604 pub render_materials: RenderMaterials,
1607 pub render_object_meshes: std::collections::HashMap<crate::entity::RenderEntity, String>,
1610 pub render_instanced_objects:
1612 std::collections::HashMap<crate::entity::RenderEntity, InstancedObjectData>,
1613 pub render_lights: RenderLights,
1616 pub render_decals: Vec<RenderDecal>,
1619 pub render_particle_emitters: Vec<RenderParticleEmitter>,
1622 pub render_water: Vec<RenderWater>,
1625 pub render_cloth: Vec<RenderCloth>,
1628 pub render_selection_outline_ids: Vec<u32>,
1633 pub render_bounds: std::collections::HashMap<crate::entity::RenderEntity, RenderBounds>,
1636 pub render_shadow_casters: RenderShadowCasters,
1639 pub render_skinned_meshes: Vec<crate::entity::RenderEntity>,
1642 pub render_regular_mesh_entities: Vec<crate::entity::RenderEntity>,
1646 pub culling_camera_view_projection: Option<nalgebra_glm::Mat4>,
1650 pub render_skinning: RenderSkinning,
1653 pub render_texts: Vec<RenderText>,
1656 pub render_animation: SkinnedAnimationSnapshot,
1660 #[cfg(feature = "wgpu")]
1664 pub render_lighting: Option<RenderLighting>,
1665 pub skinned_objects_generation: u64,
1669 pub settings_version: u64,
1672 pub focus_policy: ViewportFocusPolicy,
1675 pub adaptive_sampling: AdaptiveSamplingState,
1677 pub effects: EffectsState,
1679 pub gpu_profile: Option<GpuProfile>,
1682}
1683
1684#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
1685pub enum PerformanceTarget {
1686 #[default]
1687 Unbounded,
1688 Interactive,
1689 Balanced,
1690 Quality,
1691}
1692
1693impl PerformanceTarget {
1694 pub fn target_frame_time_ms(self) -> Option<f32> {
1695 match self {
1696 PerformanceTarget::Unbounded => None,
1697 PerformanceTarget::Interactive => Some(1000.0 / 60.0),
1698 PerformanceTarget::Balanced => Some(1000.0 / 30.0),
1699 PerformanceTarget::Quality => Some(1000.0 / 15.0),
1700 }
1701 }
1702}
1703
1704#[derive(Debug, Clone)]
1705pub struct AdaptiveSamplingState {
1706 pub target: PerformanceTarget,
1707 pub frame_time_rolling_ms: f32,
1708 pub frame_time_sample_count: u32,
1709 pub ssao_sample_scale: f32,
1710 pub ssgi_sample_scale: f32,
1711 pub ssr_step_scale: f32,
1712}
1713
1714impl Default for AdaptiveSamplingState {
1715 fn default() -> Self {
1716 Self {
1717 target: PerformanceTarget::Unbounded,
1718 frame_time_rolling_ms: 16.67,
1719 frame_time_sample_count: 0,
1720 ssao_sample_scale: 1.0,
1721 ssgi_sample_scale: 1.0,
1722 ssr_step_scale: 1.0,
1723 }
1724 }
1725}
1726
1727impl AdaptiveSamplingState {
1728 pub fn record_frame_time(&mut self, frame_time_ms: f32) {
1729 const WINDOW: u32 = 100;
1730 if self.frame_time_sample_count == 0 {
1731 self.frame_time_rolling_ms = frame_time_ms;
1732 self.frame_time_sample_count = 1;
1733 } else {
1734 let alpha = 1.0 / (self.frame_time_sample_count.min(WINDOW) as f32 + 1.0);
1735 self.frame_time_rolling_ms =
1736 self.frame_time_rolling_ms * (1.0 - alpha) + frame_time_ms * alpha;
1737 self.frame_time_sample_count = (self.frame_time_sample_count + 1).min(WINDOW);
1738 }
1739
1740 let Some(target_ms) = self.target.target_frame_time_ms() else {
1741 self.ssao_sample_scale = 1.0;
1742 self.ssgi_sample_scale = 1.0;
1743 self.ssr_step_scale = 1.0;
1744 return;
1745 };
1746
1747 let error = self.frame_time_rolling_ms - target_ms;
1748 let sensitivity = 0.002;
1749 let max_delta = 0.05;
1750 let adjustment = (error * sensitivity).clamp(-max_delta, max_delta);
1751
1752 self.ssao_sample_scale = (self.ssao_sample_scale - adjustment).clamp(0.25, 1.0);
1753 self.ssgi_sample_scale = (self.ssgi_sample_scale - adjustment).clamp(0.25, 1.0);
1754 self.ssr_step_scale = (self.ssr_step_scale - adjustment).clamp(0.25, 1.0);
1755 }
1756}
1757
1758pub fn render_settings_signature(
1764 render: &RenderSettings,
1765 debug: &DebugDraw,
1766 selection: &EditorSelection,
1767) -> u64 {
1768 use std::hash::{Hash, Hasher};
1769 let mut hasher = std::collections::hash_map::DefaultHasher::new();
1770 selection
1771 .bounding_volume_selected_entity
1772 .map(|entity| (entity.id, entity.generation))
1773 .hash(&mut hasher);
1774 for entity in &selection.selected_entities {
1775 (entity.id, entity.generation).hash(&mut hasher);
1776 }
1777 debug.show_grid.hash(&mut hasher);
1778 debug.show_bounding_volumes.hash(&mut hasher);
1779 debug.show_normals.hash(&mut hasher);
1780 debug.normal_line_length.to_bits().hash(&mut hasher);
1781 for component in debug.normal_line_color {
1782 component.to_bits().hash(&mut hasher);
1783 }
1784 (render.atmosphere as u32).hash(&mut hasher);
1785 render.show_sky.hash(&mut hasher);
1786 render.render_layer_world_enabled.hash(&mut hasher);
1787 render.render_layer_overlay_enabled.hash(&mut hasher);
1788 render.render_world_to_swapchain.hash(&mut hasher);
1789 for component in render.clear_color {
1790 component.to_bits().hash(&mut hasher);
1791 }
1792 render.unlit_mode.hash(&mut hasher);
1793 debug.selection_outline_enabled.hash(&mut hasher);
1794 for component in debug.selection_outline_color {
1795 component.to_bits().hash(&mut hasher);
1796 }
1797 render.vertex_snap.is_some().hash(&mut hasher);
1798 if let Some(ref snap) = render.vertex_snap {
1799 for component in snap.resolution {
1800 component.to_bits().hash(&mut hasher);
1801 }
1802 }
1803 render.affine_texture_mapping.hash(&mut hasher);
1804 render.fog.is_some().hash(&mut hasher);
1805 if let Some(ref fog) = render.fog {
1806 for component in fog.color {
1807 component.to_bits().hash(&mut hasher);
1808 }
1809 fog.start.to_bits().hash(&mut hasher);
1810 fog.end.to_bits().hash(&mut hasher);
1811 }
1812 let cg = &render.color_grading;
1813 cg.exposure.to_bits().hash(&mut hasher);
1814 cg.exposure_compensation_ev.to_bits().hash(&mut hasher);
1815 cg.auto_exposure.hash(&mut hasher);
1816 cg.auto_exposure_target.to_bits().hash(&mut hasher);
1817 cg.auto_exposure_rate.to_bits().hash(&mut hasher);
1818 cg.auto_exposure_min_ev.to_bits().hash(&mut hasher);
1819 cg.auto_exposure_max_ev.to_bits().hash(&mut hasher);
1820 cg.gamma.to_bits().hash(&mut hasher);
1821 cg.saturation.to_bits().hash(&mut hasher);
1822 cg.brightness.to_bits().hash(&mut hasher);
1823 cg.contrast.to_bits().hash(&mut hasher);
1824 (cg.tonemap_algorithm as u32).hash(&mut hasher);
1825 render.bloom_enabled.hash(&mut hasher);
1826 render.bloom_intensity.to_bits().hash(&mut hasher);
1827 render.bloom_threshold.to_bits().hash(&mut hasher);
1828 render.bloom_knee.to_bits().hash(&mut hasher);
1829 render.bloom_filter_radius.to_bits().hash(&mut hasher);
1830 let dof = &render.depth_of_field;
1831 dof.enabled.hash(&mut hasher);
1832 dof.focus_distance.to_bits().hash(&mut hasher);
1833 dof.focus_range.to_bits().hash(&mut hasher);
1834 dof.max_blur_radius.to_bits().hash(&mut hasher);
1835 dof.bokeh_threshold.to_bits().hash(&mut hasher);
1836 dof.bokeh_intensity.to_bits().hash(&mut hasher);
1837 (dof.quality as u32).hash(&mut hasher);
1838 dof.visualize_coc.hash(&mut hasher);
1839 dof.tilt_shift_enabled.hash(&mut hasher);
1840 dof.tilt_shift_angle.to_bits().hash(&mut hasher);
1841 dof.tilt_shift_center.to_bits().hash(&mut hasher);
1842 dof.tilt_shift_blur_amount.to_bits().hash(&mut hasher);
1843 dof.visualize_tilt_shift.hash(&mut hasher);
1844 render.ssao_enabled.hash(&mut hasher);
1845 render.ssao_radius.to_bits().hash(&mut hasher);
1846 render.ssao_bias.to_bits().hash(&mut hasher);
1847 render.ssao_intensity.to_bits().hash(&mut hasher);
1848 render.ssao_sample_count.hash(&mut hasher);
1849 debug.ssao_visualization.hash(&mut hasher);
1850 render.ssao_blur_depth_threshold.to_bits().hash(&mut hasher);
1851 render.ssao_blur_normal_power.to_bits().hash(&mut hasher);
1852 render.ssgi_enabled.hash(&mut hasher);
1853 render.ssgi_radius.to_bits().hash(&mut hasher);
1854 render.ssgi_intensity.to_bits().hash(&mut hasher);
1855 render.ssgi_max_steps.hash(&mut hasher);
1856 render.ssr_enabled.hash(&mut hasher);
1857 render.ssr_max_steps.hash(&mut hasher);
1858 render.ssr_thickness.to_bits().hash(&mut hasher);
1859 render.ssr_max_distance.to_bits().hash(&mut hasher);
1860 render.ssr_stride.to_bits().hash(&mut hasher);
1861 render.ssr_fade_start.to_bits().hash(&mut hasher);
1862 render.ssr_fade_end.to_bits().hash(&mut hasher);
1863 render.ssr_intensity.to_bits().hash(&mut hasher);
1864 for component in render.ambient_light {
1865 component.to_bits().hash(&mut hasher);
1866 }
1867 debug.pbr_debug_mode.as_u32().hash(&mut hasher);
1868 debug.texture_debug_stripes.hash(&mut hasher);
1869 debug
1870 .texture_debug_stripes_speed
1871 .to_bits()
1872 .hash(&mut hasher);
1873 render.taa_enabled.hash(&mut hasher);
1874 render.render_scale.to_bits().hash(&mut hasher);
1875 render.ibl_blend_factor.to_bits().hash(&mut hasher);
1876 hasher.finish()
1877}
1878
1879impl Default for RenderSettings {
1880 fn default() -> Self {
1881 Self {
1882 frame_rate_limit: None,
1883 atmosphere: Atmosphere::None,
1884 show_sky: true,
1885 render_layer_world_enabled: true,
1886 render_layer_overlay_enabled: true,
1887 render_world_to_swapchain: true,
1888 clear_color: [0.0, 0.0, 0.0, 1.0],
1889 ui_scale: None,
1890 unlit_mode: false,
1891 vertex_snap: None,
1892 affine_texture_mapping: false,
1893 material_anisotropy_filtering: 16,
1894 fog: None,
1895 color_grading: ColorGrading::default(),
1896 bloom_enabled: true,
1897 bloom_intensity: 0.04,
1898 bloom_threshold: 1.0,
1899 bloom_knee: 0.5,
1900 bloom_filter_radius: 0.005,
1901 depth_of_field: DepthOfField::default(),
1902 ssao_enabled: false,
1903 ssao_radius: 0.5,
1904 ssao_bias: 0.025,
1905 ssao_intensity: 1.0,
1906 ssao_sample_count: 64,
1907 ssao_blur_depth_threshold: 0.005,
1908 ssao_blur_normal_power: 8.0,
1909 ssgi_enabled: false,
1910 ssgi_radius: 2.0,
1911 ssgi_intensity: 1.0,
1912 ssgi_max_steps: 16,
1913 ssr_enabled: false,
1914 ssr_max_steps: 64,
1915 ssr_thickness: 0.3,
1916 ssr_max_distance: 50.0,
1917 ssr_stride: 1.0,
1918 ssr_fade_start: 0.8,
1919 ssr_fade_end: 1.0,
1920 ssr_intensity: 1.0,
1921 ambient_light: [0.1, 0.1, 0.1, 1.0],
1922 taa_enabled: false,
1923 taa_blend: 0.12,
1924 taa_sharpness: 0.5,
1925 water_enabled: true,
1926 vsync_enabled: true,
1927 render_scale: 1.0,
1928 ibl_blend_factor: 0.0,
1929 }
1930 }
1931}
1932
1933impl Default for DebugDraw {
1934 fn default() -> Self {
1935 Self {
1936 show_grid: false,
1937 show_bounding_volumes: false,
1938 show_selected_bounding_volume: false,
1939 show_normals: false,
1940 normal_line_length: 0.1,
1941 normal_line_color: [0.0, 1.0, 0.0, 1.0],
1942 selection_outline_enabled: false,
1943 selection_outline_color: [1.0, 0.45, 0.0, 1.0],
1944 pbr_debug_mode: PbrDebugMode::None,
1945 texture_debug_stripes: false,
1946 texture_debug_stripes_speed: 100.0,
1947 ssao_visualization: false,
1948 }
1949 }
1950}
1951
1952impl Default for RendererState {
1953 fn default() -> Self {
1954 Self {
1955 auto_frame_rate_limit_baseline: None,
1956 taa_jitter: [0.0, 0.0],
1957 view_projection: nalgebra_glm::Mat4::identity().into(),
1958 prev_view_projection: nalgebra_glm::Mat4::identity().into(),
1959 gpu_culling_enabled: true,
1960 occlusion_culling_enabled: true,
1961 gpu_batching_enabled: true,
1962 min_screen_pixel_size: 0.0,
1963 min_window_size: None,
1964 use_fullscreen: false,
1965 show_cursor: true,
1966 letterbox_amount: 0.0,
1967 letterbox_target: 0.0,
1968 day_night: DayNightState::default(),
1969 mesh_lod_chains: Vec::new(),
1970 active_view: EffectiveShading::default(),
1971 render_view: None,
1972 render_dynamic_objects: std::collections::HashMap::new(),
1973 render_materials: RenderMaterials::default(),
1974 render_object_meshes: std::collections::HashMap::new(),
1975 render_instanced_objects: std::collections::HashMap::new(),
1976 render_lights: RenderLights::default(),
1977 render_decals: Vec::new(),
1978 render_particle_emitters: Vec::new(),
1979 render_water: Vec::new(),
1980 render_cloth: Vec::new(),
1981 render_selection_outline_ids: Vec::new(),
1982 render_bounds: std::collections::HashMap::new(),
1983 render_shadow_casters: RenderShadowCasters::default(),
1984 render_skinned_meshes: Vec::new(),
1985 render_regular_mesh_entities: Vec::new(),
1986 culling_camera_view_projection: None,
1987 render_skinning: RenderSkinning::default(),
1988 render_texts: Vec::new(),
1989 render_animation: SkinnedAnimationSnapshot::default(),
1990 #[cfg(feature = "wgpu")]
1991 render_lighting: None,
1992 skinned_objects_generation: 0,
1993 settings_version: 0,
1994 focus_policy: ViewportFocusPolicy::default(),
1995 adaptive_sampling: AdaptiveSamplingState::default(),
1996 effects: EffectsState::default(),
1997 gpu_profile: None,
1998 }
1999 }
2000}
2001
2002pub const FLAT_SHADING_COLOR: nalgebra_glm::Vec4 = nalgebra_glm::Vec4::new(0.72, 0.72, 0.72, 1.0);
2003
2004#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
2019pub enum ViewportUpdateMode {
2020 #[default]
2021 Always,
2022 WhenVisible,
2023 WhenDirty,
2024 Once,
2025 Disabled,
2026}
2027
2028pub const WIREFRAME_SENTINEL_COLOR: nalgebra_glm::Vec4 =
2033 nalgebra_glm::Vec4::new(0.0, 0.0, 0.0, 2.0);
2034
2035#[derive(Debug, Clone, Copy, PartialEq)]
2036pub struct EffectiveShading {
2037 pub unlit_mode: bool,
2038 pub bloom_enabled: bool,
2039 pub ssao_enabled: bool,
2040 pub ssgi_enabled: bool,
2041 pub ssr_enabled: bool,
2042 pub show_normals: bool,
2043 pub show_bounding_volumes: bool,
2044 pub show_wireframe: bool,
2045 pub selection_outline_enabled: bool,
2046 pub flat_shading_color: Option<nalgebra_glm::Vec4>,
2047 pub shadow_depth_enabled: bool,
2048 pub lines_enabled: bool,
2049 pub color_grading: ColorGrading,
2050 pub depth_of_field: DepthOfField,
2051 pub bloom_intensity: f32,
2052 pub bloom_threshold: f32,
2053 pub bloom_knee: f32,
2054 pub bloom_filter_radius: f32,
2055 pub ssao_radius: f32,
2056 pub ssao_bias: f32,
2057 pub ssao_intensity: f32,
2058 pub ssao_sample_count: u32,
2059 pub ssao_visualization: bool,
2060 pub ssao_blur_depth_threshold: f32,
2061 pub ssao_blur_normal_power: f32,
2062 pub ssgi_radius: f32,
2063 pub ssgi_intensity: f32,
2064 pub ssgi_max_steps: u32,
2065 pub ssr_max_steps: u32,
2066 pub ssr_thickness: f32,
2067 pub ssr_max_distance: f32,
2068 pub ssr_stride: f32,
2069 pub ssr_fade_start: f32,
2070 pub ssr_fade_end: f32,
2071 pub ssr_intensity: f32,
2072 pub ambient_light: [f32; 4],
2073 pub culling_mask: u32,
2080 pub fog: Option<Fog>,
2084 pub atmosphere: Atmosphere,
2089}
2090
2091impl Default for EffectiveShading {
2092 fn default() -> Self {
2093 Self {
2094 unlit_mode: false,
2095 bloom_enabled: true,
2096 ssao_enabled: false,
2097 ssgi_enabled: false,
2098 ssr_enabled: false,
2099 show_normals: false,
2100 show_bounding_volumes: false,
2101 show_wireframe: false,
2102 selection_outline_enabled: false,
2103 flat_shading_color: None,
2104 shadow_depth_enabled: true,
2105 lines_enabled: false,
2106 color_grading: ColorGrading::default(),
2107 depth_of_field: DepthOfField::default(),
2108 bloom_intensity: 0.5,
2109 bloom_threshold: 1.0,
2110 bloom_knee: 0.5,
2111 bloom_filter_radius: 0.005,
2112 ssao_radius: 0.5,
2113 ssao_bias: 0.025,
2114 ssao_intensity: 1.0,
2115 ssao_sample_count: 64,
2116 ssao_visualization: false,
2117 ssao_blur_depth_threshold: 0.005,
2118 ssao_blur_normal_power: 8.0,
2119 ssgi_radius: 2.0,
2120 ssgi_intensity: 1.0,
2121 ssgi_max_steps: 16,
2122 ssr_max_steps: 64,
2123 ssr_thickness: 0.3,
2124 ssr_max_distance: 50.0,
2125 ssr_stride: 1.0,
2126 ssr_fade_start: 0.8,
2127 ssr_fade_end: 1.0,
2128 ssr_intensity: 1.0,
2129 ambient_light: [0.1, 0.1, 0.1, 1.0],
2130 culling_mask: !0,
2131 fog: None,
2132 atmosphere: Atmosphere::None,
2133 }
2134 }
2135}
2136
2137#[derive(Debug, Clone, Copy, Default)]
2138pub struct ViewportRect {
2139 pub x: f32,
2140 pub y: f32,
2141 pub width: f32,
2142 pub height: f32,
2143}
2144
2145impl ViewportRect {
2146 pub fn contains(&self, screen_pos: nalgebra_glm::Vec2) -> bool {
2147 screen_pos.x >= self.x
2148 && screen_pos.x <= self.x + self.width
2149 && screen_pos.y >= self.y
2150 && screen_pos.y <= self.y + self.height
2151 }
2152
2153 pub fn to_local(&self, screen_pos: nalgebra_glm::Vec2) -> nalgebra_glm::Vec2 {
2154 nalgebra_glm::Vec2::new(screen_pos.x - self.x, screen_pos.y - self.y)
2155 }
2156}