three_d/renderer/effect/
water.rs1use crate::core::*;
2use crate::renderer::*;
3use std::sync::Arc;
4
5#[derive(Clone)]
7pub enum Background {
8 Texture(Arc<TextureCubeMap>),
10 Color(Srgba),
12}
13
14impl Default for Background {
15 fn default() -> Self {
16 Self::Color(Srgba::WHITE)
17 }
18}
19
20#[derive(Clone)]
25pub struct WaterEffect {
26 pub background: Background,
28 pub metallic: f32,
30 pub roughness: f32,
32 pub lighting_model: LightingModel,
34}
35
36impl Effect for WaterEffect {
37 fn fragment_shader_source(
38 &self,
39 lights: &[&dyn Light],
40 color_texture: Option<ColorTexture>,
41 depth_texture: Option<DepthTexture>,
42 ) -> String {
43 format!(
44 "{}\n{}\n{}\n{}\n{}\n{}\n{}",
45 match &self.background {
46 Background::Color(_) => "",
47 Background::Texture(_) => "#define USE_BACKGROUND_TEXTURE",
48 },
49 color_texture
50 .expect("Must supply a color texture to apply a water effect")
51 .fragment_shader_source(),
52 depth_texture
53 .expect("Must supply a depth texture to apply a water effect")
54 .fragment_shader_source(),
55 lights_shader_source(lights),
56 ToneMapping::fragment_shader_source(),
57 ColorMapping::fragment_shader_source(),
58 include_str!("shaders/water_effect.frag")
59 )
60 }
61
62 fn id(
63 &self,
64 color_texture: Option<ColorTexture>,
65 depth_texture: Option<DepthTexture>,
66 ) -> EffectMaterialId {
67 EffectMaterialId::WaterEffect(
68 color_texture.expect("Must supply a color texture to apply a water effect"),
69 depth_texture.expect("Must supply a depth texture to apply a water effect"),
70 )
71 }
72
73 fn render_states(&self) -> RenderStates {
74 RenderStates {
75 blend: Blend::TRANSPARENCY,
76 ..Default::default()
77 }
78 }
79
80 fn use_uniforms(
81 &self,
82 program: &Program,
83 viewer: &dyn Viewer,
84 lights: &[&dyn Light],
85 color_texture: Option<ColorTexture>,
86 depth_texture: Option<DepthTexture>,
87 ) {
88 program.use_uniform_if_required("lightingModel", lighting_model_to_id(self.lighting_model));
89 viewer.tone_mapping().use_uniforms(program);
90 viewer.color_mapping().use_uniforms(program);
91 color_texture
92 .expect("Must supply a color texture to apply a water effect")
93 .use_uniforms(program);
94 depth_texture
95 .expect("Must supply a depth texture to apply a water effect")
96 .use_uniforms(program);
97 for (i, light) in lights.iter().enumerate() {
98 light.use_uniforms(program, i as u32);
99 }
100 program.use_uniform("viewProjection", viewer.projection() * viewer.view());
101 program.use_uniform(
102 "viewProjectionInverse",
103 (viewer.projection() * viewer.view()).invert().unwrap(),
104 );
105 program.use_uniform("cameraPosition", viewer.position());
106 program.use_uniform(
107 "screenSize",
108 vec2(
109 viewer.viewport().width as f32,
110 viewer.viewport().height as f32,
111 ),
112 );
113 program.use_uniform("metallic", self.metallic);
114 program.use_uniform("roughness", self.roughness);
115 match &self.background {
116 Background::Color(color) => {
117 program.use_uniform("environmentColor", color.to_linear_srgb())
118 }
119 Background::Texture(tex) => program.use_texture_cube("environmentMap", tex),
120 }
121 }
122}
123
124impl Default for WaterEffect {
125 fn default() -> Self {
126 Self {
127 background: Background::default(),
128 metallic: 0.0,
129 roughness: 1.0,
130 lighting_model: LightingModel::Blinn,
131 }
132 }
133}