22#[ path = "../helpers/camera_controller.rs" ]
33mod camera_controller;
44
5+ use bevy_image:: {
6+ ImageAddressMode , ImageFilterMode , ImageLoaderSettings , ImageSampler , ImageSamplerDescriptor ,
7+ } ;
8+ use bevy_render:: render_resource:: { AsBindGroup , ShaderType } ;
59use camera_controller:: { CameraController , CameraControllerPlugin } ;
610use std:: f32:: consts:: PI ;
711
812use bevy:: {
913 anti_alias:: fxaa:: Fxaa ,
1014 camera:: Exposure ,
15+ color:: palettes:: css:: BLACK ,
1116 core_pipeline:: tonemapping:: Tonemapping ,
1217 diagnostic:: LogDiagnosticsPlugin ,
1318 input:: keyboard:: KeyCode ,
@@ -17,10 +22,11 @@ use bevy::{
1722 } ,
1823 pbr:: {
1924 Atmosphere , AtmosphereMode , AtmosphereSettings , DefaultOpaqueRendererMethod ,
20- ScreenSpaceReflections ,
25+ ExtendedMaterial , MaterialExtension , ScreenSpaceReflections ,
2126 } ,
2227 post_process:: bloom:: Bloom ,
2328 prelude:: * ,
29+ shader:: ShaderRef ,
2430} ;
2531
2632#[ derive( Resource , Default ) ]
@@ -38,6 +44,7 @@ fn main() {
3844 CameraControllerPlugin ,
3945 LogDiagnosticsPlugin :: default ( ) ,
4046 ) )
47+ . add_plugins ( MaterialPlugin :: < ExtendedMaterial < StandardMaterial , Water > > :: default ( ) )
4148 . add_systems (
4249 Startup ,
4350 ( setup_camera_fog, setup_terrain_scene, print_controls) ,
@@ -95,7 +102,7 @@ fn atmosphere_controls(
95102fn setup_camera_fog ( mut commands : Commands ) {
96103 commands. spawn ( (
97104 Camera3d :: default ( ) ,
98- Transform :: from_xyz ( -1 .2, 0.15 , 0.0 ) . looking_at ( Vec3 :: Y * 0.1 , Vec3 :: Y ) ,
105+ Transform :: from_xyz ( -3 .2, 0.15 , 0.0 ) . looking_at ( Vec3 :: Y * 0.1 , Vec3 :: Y ) ,
99106 // This is the component that enables atmospheric scattering for a camera
100107 Atmosphere :: EARTH ,
101108 // Can be adjusted to change the scene scale and rendering quality
@@ -123,10 +130,44 @@ fn setup_camera_fog(mut commands: Commands) {
123130#[ derive( Component ) ]
124131struct Terrain ;
125132
133+ /// A custom [`ExtendedMaterial`] that creates animated water ripples.
134+ #[ derive( Asset , TypePath , AsBindGroup , Debug , Clone ) ]
135+ struct Water {
136+ /// The normal map image.
137+ ///
138+ /// Note that, like all normal maps, this must not be loaded as sRGB.
139+ #[ texture( 100 ) ]
140+ #[ sampler( 101 ) ]
141+ normals : Handle < Image > ,
142+
143+ // Parameters to the water shader.
144+ #[ uniform( 102 ) ]
145+ settings : WaterSettings ,
146+ }
147+
148+ /// Parameters to the water shader.
149+ #[ derive( ShaderType , Debug , Clone ) ]
150+ struct WaterSettings {
151+ /// How much to displace each octave each frame, in the u and v directions.
152+ /// Two octaves are packed into each `vec4`.
153+ octave_vectors : [ Vec4 ; 2 ] ,
154+ /// How wide the waves are in each octave.
155+ octave_scales : Vec4 ,
156+ /// How high the waves are in each octave.
157+ octave_strengths : Vec4 ,
158+ }
159+
160+ impl MaterialExtension for Water {
161+ fn deferred_fragment_shader ( ) -> ShaderRef {
162+ "shaders/water_material.wgsl" . into ( )
163+ }
164+ }
165+
126166fn setup_terrain_scene (
127167 mut commands : Commands ,
128168 mut meshes : ResMut < Assets < Mesh > > ,
129169 mut materials : ResMut < Assets < StandardMaterial > > ,
170+ mut water_materials : ResMut < Assets < ExtendedMaterial < StandardMaterial , Water > > > ,
130171 asset_server : Res < AssetServer > ,
131172) {
132173 // Configure a properly scaled cascade shadow map for this scene (defaults are too large, mesh units are in km)
@@ -195,6 +236,58 @@ fn setup_terrain_scene(
195236 . with_scale ( Vec3 :: splat ( 0.5 ) )
196237 . with_rotation ( Quat :: from_rotation_y ( PI / 2.0 ) ) ,
197238 ) ) ;
239+
240+ spawn_water (
241+ & mut commands,
242+ & asset_server,
243+ & mut meshes,
244+ & mut water_materials,
245+ ) ;
246+ }
247+
248+ // Spawns the water plane.
249+ fn spawn_water (
250+ commands : & mut Commands ,
251+ asset_server : & AssetServer ,
252+ meshes : & mut Assets < Mesh > ,
253+ water_materials : & mut Assets < ExtendedMaterial < StandardMaterial , Water > > ,
254+ ) {
255+ commands. spawn ( (
256+ Mesh3d ( meshes. add ( Plane3d :: new ( Vec3 :: Y , Vec2 :: splat ( 1.0 ) ) ) ) ,
257+ MeshMaterial3d ( water_materials. add ( ExtendedMaterial {
258+ base : StandardMaterial {
259+ base_color : BLACK . into ( ) ,
260+ perceptual_roughness : 0.0 ,
261+ ..default ( )
262+ } ,
263+ extension : Water {
264+ normals : asset_server. load_with_settings :: < Image , ImageLoaderSettings > (
265+ "textures/water_normals.png" ,
266+ |settings| {
267+ settings. is_srgb = false ;
268+ settings. sampler = ImageSampler :: Descriptor ( ImageSamplerDescriptor {
269+ address_mode_u : ImageAddressMode :: Repeat ,
270+ address_mode_v : ImageAddressMode :: Repeat ,
271+ mag_filter : ImageFilterMode :: Linear ,
272+ min_filter : ImageFilterMode :: Linear ,
273+ ..default ( )
274+ } ) ;
275+ } ,
276+ ) ,
277+ // These water settings are just random values to create some
278+ // variety.
279+ settings : WaterSettings {
280+ octave_vectors : [
281+ vec4 ( 0.080 , 0.059 , 0.073 , -0.062 ) ,
282+ vec4 ( 0.153 , 0.138 , -0.149 , -0.195 ) ,
283+ ] ,
284+ octave_scales : vec4 ( 1.0 , 2.1 , 7.9 , 14.9 ) * 500.0 ,
285+ octave_strengths : vec4 ( 0.16 , 0.18 , 0.093 , 0.044 ) * 0.2 ,
286+ } ,
287+ } ,
288+ } ) ) ,
289+ Transform :: from_scale ( Vec3 :: splat ( 100.0 ) ) ,
290+ ) ) ;
198291}
199292
200293fn dynamic_scene (
0 commit comments