Skip to content

Commit

Permalink
Fix terrain.wgsl
Browse files Browse the repository at this point in the history
  • Loading branch information
Indy2222 committed Feb 20, 2024
1 parent 741990d commit affb8bb
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 70 deletions.
65 changes: 19 additions & 46 deletions assets/shaders/terrain.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -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<f32>(1., 1., 1., 0.75);
const SHAPE_THICKNESS = 0.15;
// Keep these array lengths in sync with /crates/terrain/src/shader.rs.
Expand All @@ -43,15 +33,12 @@ struct Rectangles {
count: u32,
};

@group(1) @binding(0)
@group(1) @binding(100)
var<uniform> uv_scale: f32;
@group(1) @binding(101)
var<uniform> circles: KdTree;
@group(1) @binding(1)
@group(1) @binding(102)
var<uniform> rectangles: Rectangles;
@group(1) @binding(2)
var terrain_texture: texture_2d<f32>;
@group(1) @binding(3)
var terrain_sampler: sampler;

fn mix_colors(base: vec4<f32>, cover: vec4<f32>) -> vec4<f32> {
let alpha = base.a * cover.a;
let rgb = base.rgb * cover.a + cover.rgb * (1. - cover.a);
Expand All @@ -60,11 +47,11 @@ fn mix_colors(base: vec4<f32>, cover: vec4<f32>) -> vec4<f32> {

fn draw_circle(
base: vec4<f32>,
uv: vec2<f32>,
location: vec2<f32>,
center: vec2<f32>,
radius: f32,
) -> vec4<f32> {
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);
}
Expand All @@ -82,14 +69,14 @@ struct Next {
potential: f32,
}

fn nearest(uv: vec2<f32>) -> u32 {
fn nearest(location: vec2<f32>) -> 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
Expand All @@ -109,14 +96,14 @@ fn nearest(uv: vec2<f32>) -> 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;
Expand Down Expand Up @@ -144,25 +131,25 @@ fn nearest(uv: vec2<f32>) -> u32 {
return best.index;
}

fn draw_circles(base: vec4<f32>, uv: vec2<f32>) -> vec4<f32> {
fn draw_circles(base: vec4<f32>, location: vec2<f32>) -> vec4<f32> {
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<f32>, uv: vec2<f32>) -> vec4<f32> {
fn draw_rectangles(base: vec4<f32>, location: vec2<f32>) -> vec4<f32> {
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);
}
}
Expand All @@ -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;
}
10 changes: 7 additions & 3 deletions crates/terrain/src/marker.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use bevy::{
pbr::ExtendedMaterial,
prelude::*,
render::{
primitives::{Aabb as BevyAabb, Frustum},
Expand Down Expand Up @@ -115,10 +116,13 @@ impl Marker for RectangleMarker {

// TODO test this
fn update_markers<M>(
mut materials: ResMut<Assets<TerrainMaterial>>,
mut materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, TerrainMaterial>>>,
solids: SolidObjects,
camera: Query<(&Transform, &Frustum), With<Camera3d>>,
terrains: Query<(&ViewVisibility, &Handle<TerrainMaterial>)>,
terrains: Query<(
&ViewVisibility,
&Handle<ExtendedMaterial<StandardMaterial, TerrainMaterial>>,
)>,
markers: Query<(
&ObjectTypeComponent,
&ViewVisibility,
Expand Down Expand Up @@ -177,6 +181,6 @@ fn update_markers<M>(
}

let material = materials.get_mut(material).unwrap();
M::apply_to_material(material, shapes.clone());
M::apply_to_material(&mut material.extension, shapes.clone());
}
}
36 changes: 25 additions & 11 deletions crates/terrain/src/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
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";

pub(crate) struct TerrainPlugin;

impl Plugin for TerrainPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(MaterialPlugin::<TerrainMaterial>::default())
app.add_plugins(MaterialPlugin::<
ExtendedMaterial<StandardMaterial, TerrainMaterial>,
>::default())
.add_systems(OnEnter(AppState::InGame), load)
.add_systems(OnExit(AppState::InGame), cleanup)
.add_systems(
Expand Down Expand Up @@ -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()
}
Expand All @@ -83,14 +88,23 @@ fn setup_textures(
fn init(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<TerrainMaterial>>,
mut materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, TerrainMaterial>>>,
textures: Res<Textures>,
uninitialized: Query<(Entity, &Terrain, &Transform), Without<Handle<Mesh>>>,
) {
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()
});
Expand Down
18 changes: 9 additions & 9 deletions crates/terrain/src/shader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Image>,
}

impl TerrainMaterial {
pub(crate) fn new(texture: Handle<Image>) -> Self {
pub(crate) fn new(uv_scale: f32) -> Self {
Self {
uv_scale,
circles: KdTree::empty(),
rectangles: Rectangles::default(),
texture,
}
}

Expand All @@ -45,7 +45,7 @@ impl TerrainMaterial {
}
}

impl Material for TerrainMaterial {
impl MaterialExtension for TerrainMaterial {
fn fragment_shader() -> ShaderRef {
"shaders/terrain.wgsl".into()
}
Expand Down
7 changes: 6 additions & 1 deletion crates/terrain/src/terrain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use parry3d::{
shape::HeightField,
};

use crate::shader::UV_SCALE;

#[derive(Bundle)]
pub struct TerrainBundle {
transform: Transform,
Expand Down Expand Up @@ -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,
]);
}
}
}
Expand Down

0 comments on commit affb8bb

Please sign in to comment.