From affb8bb85faae95439a47a0e4847c85fe2da14c4 Mon Sep 17 00:00:00 2001 From: Martin Indra Date: Tue, 20 Feb 2024 13:39:17 +0100 Subject: [PATCH] Fix terrain.wgsl --- assets/shaders/terrain.wgsl | 65 ++++++++++------------------------- crates/terrain/src/marker.rs | 10 ++++-- crates/terrain/src/plugin.rs | 36 +++++++++++++------ crates/terrain/src/shader.rs | 18 +++++----- crates/terrain/src/terrain.rs | 7 +++- 5 files changed, 66 insertions(+), 70 deletions(-) diff --git a/assets/shaders/terrain.wgsl b/assets/shaders/terrain.wgsl index 132f17f3a..4f3d514b3 100644 --- a/assets/shaders/terrain.wgsl +++ b/assets/shaders/terrain.wgsl @@ -2,21 +2,11 @@ pbr_fragment::pbr_input_from_standard_material, pbr_functions::alpha_discard, } - -#ifdef PREPASS_PIPELINE -#import bevy_pbr::{ - prepass_io::{VertexOutput, FragmentOutput}, - pbr_deferred_functions::deferred_output, -} -#else #import bevy_pbr::{ forward_io::{VertexOutput, FragmentOutput}, pbr_functions::{apply_pbr_lighting, main_pass_post_lighting_processing}, } -#endif -// How large (in meters) is a texture. -const TEXTURE_SIZE = 16.; const SHAPE_COLOR = vec4(1., 1., 1., 0.75); const SHAPE_THICKNESS = 0.15; // Keep these array lengths in sync with /crates/terrain/src/shader.rs. @@ -43,15 +33,12 @@ struct Rectangles { count: u32, }; -@group(1) @binding(0) +@group(1) @binding(100) +var uv_scale: f32; +@group(1) @binding(101) var circles: KdTree; -@group(1) @binding(1) +@group(1) @binding(102) var rectangles: Rectangles; -@group(1) @binding(2) -var terrain_texture: texture_2d; -@group(1) @binding(3) -var terrain_sampler: sampler; - fn mix_colors(base: vec4, cover: vec4) -> vec4 { let alpha = base.a * cover.a; let rgb = base.rgb * cover.a + cover.rgb * (1. - cover.a); @@ -60,11 +47,11 @@ fn mix_colors(base: vec4, cover: vec4) -> vec4 { fn draw_circle( base: vec4, - uv: vec2, + location: vec2, center: vec2, radius: f32, ) -> vec4 { - let distance: f32 = distance(uv, center); + let distance: f32 = distance(location, center); if distance <= (radius + SHAPE_THICKNESS) && radius <= distance { return mix_colors(base, SHAPE_COLOR); } @@ -82,14 +69,14 @@ struct Next { potential: f32, } -fn nearest(uv: vec2) -> u32 { +fn nearest(location: vec2) -> u32 { if circles.count == 0u { return MAX_KD_TREE_SIZE; } var best: KdRecord; best.index = 0u; - best.distance = distance(circles.nodes[0].location, uv); + best.distance = distance(circles.nodes[0].location, location); var stack_size: u32 = 1u; // Make sure that the stack size is large enought to cover balanced three @@ -109,14 +96,14 @@ fn nearest(uv: vec2) -> u32 { let node = circles.nodes[next.index]; - let distance = distance(node.location, uv); + let distance = distance(node.location, location); if distance < best.distance { best.index = next.index; best.distance = distance; } let axis = next.depth % 2u; - let diff = uv[axis] - node.location[axis]; + let diff = location[axis] - node.location[axis]; var close = 2u * next.index + 2u; var away = 2u * next.index + 1u; @@ -144,25 +131,25 @@ fn nearest(uv: vec2) -> u32 { return best.index; } -fn draw_circles(base: vec4, uv: vec2) -> vec4 { +fn draw_circles(base: vec4, location: vec2) -> vec4 { var output_color = base; - let index = nearest(uv); + let index = nearest(location); if index < MAX_KD_TREE_SIZE { let node = circles.nodes[index]; let center = node.location; let radius = node.radius; - output_color = draw_circle(output_color, uv, center, radius); + output_color = draw_circle(output_color, location, center, radius); } return output_color; } -fn draw_rectangles(base: vec4, uv: vec2) -> vec4 { +fn draw_rectangles(base: vec4, location: vec2) -> vec4 { for (var i = 0u; i < rectangles.count; i++) { let rectangle = rectangles.items[i]; - let local_uv = (rectangle.inverse_transform * vec3(uv, 1.0)).xy; - if all(abs(local_uv) <= rectangle.half_size + SHAPE_THICKNESS) && any(rectangle.half_size <= abs(local_uv)) { + let local_location = (rectangle.inverse_transform * vec3(location, 1.0)).xy; + if all(abs(local_location) <= rectangle.half_size + SHAPE_THICKNESS) && any(rectangle.half_size <= abs(local_location)) { return mix_colors(base, SHAPE_COLOR); } } @@ -176,30 +163,16 @@ fn fragment( @builtin(front_facing) is_front: bool, ) -> FragmentOutput { var pbr_input = pbr_input_from_standard_material(in, is_front); - - pbr_input.material.perceptual_roughness = 0.8; - pbr_input.material.metallic = 0.23; - pbr_input.material.reflectance = 0.06; - - pbr_input.material.base_color = textureSample( - terrain_texture, - terrain_sampler, - in.uv / TEXTURE_SIZE - ); pbr_input.material.base_color = alpha_discard(pbr_input.material, pbr_input.material.base_color); -#ifdef PREPASS_PIPELINE - // TODO remove this if deffered mode is not used - let out = deferred_output(in, pbr_input); -#else var out: FragmentOutput; out.color = apply_pbr_lighting(pbr_input); - out.color = draw_circles(out.color, in.uv); - out.color = draw_rectangles(out.color, in.uv); + let location = uv_scale * in.uv; + out.color = draw_circles(out.color, location); + out.color = draw_rectangles(out.color, location); out.color = main_pass_post_lighting_processing(pbr_input, out.color); -#endif return out; } diff --git a/crates/terrain/src/marker.rs b/crates/terrain/src/marker.rs index 3083ed920..316a40fce 100644 --- a/crates/terrain/src/marker.rs +++ b/crates/terrain/src/marker.rs @@ -1,4 +1,5 @@ use bevy::{ + pbr::ExtendedMaterial, prelude::*, render::{ primitives::{Aabb as BevyAabb, Frustum}, @@ -115,10 +116,13 @@ impl Marker for RectangleMarker { // TODO test this fn update_markers( - mut materials: ResMut>, + mut materials: ResMut>>, solids: SolidObjects, camera: Query<(&Transform, &Frustum), With>, - terrains: Query<(&ViewVisibility, &Handle)>, + terrains: Query<( + &ViewVisibility, + &Handle>, + )>, markers: Query<( &ObjectTypeComponent, &ViewVisibility, @@ -177,6 +181,6 @@ fn update_markers( } let material = materials.get_mut(material).unwrap(); - M::apply_to_material(material, shapes.clone()); + M::apply_to_material(&mut material.extension, shapes.clone()); } } diff --git a/crates/terrain/src/plugin.rs b/crates/terrain/src/plugin.rs index 197458890..ec90a47c8 100644 --- a/crates/terrain/src/plugin.rs +++ b/crates/terrain/src/plugin.rs @@ -1,15 +1,19 @@ use bevy::{ asset::{AssetPath, LoadState}, + pbr::ExtendedMaterial, prelude::*, render::{ render_resource::{AddressMode, SamplerDescriptor}, - texture::ImageSampler, + texture::{ImageAddressMode, ImageSampler, ImageSamplerDescriptor}, }, }; use de_core::{gamestate::GameState, state::AppState}; use iyes_progress::prelude::*; -use crate::{shader::TerrainMaterial, terrain::Terrain}; +use crate::{ + shader::{TerrainMaterial, UV_SCALE}, + terrain::Terrain, +}; const TERRAIN_TEXTURE: &str = "textures/terrain.png"; @@ -17,7 +21,9 @@ pub(crate) struct TerrainPlugin; impl Plugin for TerrainPlugin { fn build(&self, app: &mut App) { - app.add_plugins(MaterialPlugin::::default()) + app.add_plugins(MaterialPlugin::< + ExtendedMaterial, + >::default()) .add_systems(OnEnter(AppState::InGame), load) .add_systems(OnExit(AppState::InGame), cleanup) .add_systems( @@ -65,12 +71,11 @@ fn setup_textures( // // https://github.com/bevyengine/bevy/discussions/3972 let image = images.get_mut(&textures.0).unwrap(); - // TODO - // image.sampler_descriptor = ImageSampler::Descriptor(SamplerDescriptor { - // address_mode_u: AddressMode::Repeat, - // address_mode_v: AddressMode::Repeat, - // ..Default::default() - // }); + image.sampler = ImageSampler::Descriptor(ImageSamplerDescriptor { + address_mode_u: ImageAddressMode::Repeat, + address_mode_v: ImageAddressMode::Repeat, + ..Default::default() + }); true.into() } @@ -83,14 +88,23 @@ fn setup_textures( fn init( mut commands: Commands, mut meshes: ResMut>, - mut materials: ResMut>, + mut materials: ResMut>>, textures: Res, uninitialized: Query<(Entity, &Terrain, &Transform), Without>>, ) { for (entity, terrain, transform) in uninitialized.iter() { commands.entity(entity).insert(MaterialMeshBundle { mesh: meshes.add(terrain.generate_mesh(transform.translation)), - material: materials.add(TerrainMaterial::new(textures.0.clone())), + material: materials.add(ExtendedMaterial { + base: StandardMaterial { + base_color_texture: Some(textures.0.clone()), + perceptual_roughness: 0.8, + metallic: 0.23, + reflectance: 0.06, + ..default() + }, + extension: TerrainMaterial::new(UV_SCALE), + }), transform: *transform, ..Default::default() }); diff --git a/crates/terrain/src/shader.rs b/crates/terrain/src/shader.rs index 7372b6fcf..98d06be07 100644 --- a/crates/terrain/src/shader.rs +++ b/crates/terrain/src/shader.rs @@ -2,12 +2,13 @@ use std::{cmp::Ordering, ops::Range}; use bevy::{ asset::Asset, - prelude::{Handle, Image, Material}, + pbr::MaterialExtension, reflect::{TypePath, TypeUuid}, render::render_resource::{AsBindGroup, ShaderRef, ShaderType}, }; use glam::{Mat3, Vec2}; +pub(crate) const UV_SCALE: f32 = 16.; // * Keep this in sync with terrain.wgsl. // * Keep this smaller or equal to de_types::objects::PLAYER_MAX_UNITS. pub(crate) const CIRCLE_CAPACITY: usize = 127; @@ -18,21 +19,20 @@ pub(crate) const RECTANGLE_CAPACITY: usize = 31; #[derive(Asset, AsBindGroup, TypeUuid, TypePath, Debug, Clone)] #[uuid = "9e124e04-fdf1-4836-b82d-fa2f01fddb62"] pub struct TerrainMaterial { - #[uniform(0)] + #[uniform(100)] + uv_scale: f32, + #[uniform(101)] circles: KdTree, - #[uniform(1)] + #[uniform(102)] rectangles: Rectangles, - #[texture(2)] - #[sampler(3)] - texture: Handle, } impl TerrainMaterial { - pub(crate) fn new(texture: Handle) -> Self { + pub(crate) fn new(uv_scale: f32) -> Self { Self { + uv_scale, circles: KdTree::empty(), rectangles: Rectangles::default(), - texture, } } @@ -45,7 +45,7 @@ impl TerrainMaterial { } } -impl Material for TerrainMaterial { +impl MaterialExtension for TerrainMaterial { fn fragment_shader() -> ShaderRef { "shaders/terrain.wgsl".into() } diff --git a/crates/terrain/src/terrain.rs b/crates/terrain/src/terrain.rs index 6af7a6148..de1826a2a 100644 --- a/crates/terrain/src/terrain.rs +++ b/crates/terrain/src/terrain.rs @@ -14,6 +14,8 @@ use parry3d::{ shape::HeightField, }; +use crate::shader::UV_SCALE; + #[derive(Bundle)] pub struct TerrainBundle { transform: Transform, @@ -76,7 +78,10 @@ impl Terrain { let world = Vec2::new(point.x, point.z).to_msl(); positions.push([world.x, point.y, world.z]); normals.push([0., 1., 0.]); - uvs.push([point.x + translation.x, point.z + translation.y]); + uvs.push([ + (point.x + translation.x) / UV_SCALE, + (point.z + translation.y) / UV_SCALE, + ]); } } }