Skip to content

Commit

Permalink
Switch to weighted smooth normals as Bevy#16050
Browse files Browse the repository at this point in the history
  • Loading branch information
TheGrimsey committed Dec 6, 2024
1 parent fa493d7 commit d03ec96
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 32 deletions.
51 changes: 19 additions & 32 deletions src/meshing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use bevy_math::{IVec2, Vec2, Vec3, Vec3A, Vec4};
use crate::{
terrain::{Holes, TileToTerrain},
update_terrain_heights,
utils::face_normal,
utils::face_area_normal,
Heights, TerrainSets, TerrainSettings, TileHeightsRebuilt,
};

Expand Down Expand Up @@ -207,7 +207,6 @@ fn create_terrain_mesh(

// Generate normals
let mut normals = vec![Vec3::ZERO; positions.len()];
let mut adjacency_counts = vec![0_u8; positions.len()];

// Create triangles.
// Using U16 when possible to save memory.
Expand Down Expand Up @@ -245,15 +244,14 @@ fn create_terrain_mesh(

indices.chunks_exact(3).for_each(|face| {
let [a, b, c] = [face[0], face[1], face[2]];
let normal = face_normal(
let normal = face_area_normal(
positions[a as usize],
positions[b as usize],
positions[c as usize],
);

[a, b, c].iter().for_each(|pos| {
normals[*pos as usize] += normal;
adjacency_counts[*pos as usize] += 1;
});
});

Expand Down Expand Up @@ -291,15 +289,14 @@ fn create_terrain_mesh(

indices.chunks_exact(3).for_each(|face| {
let [a, b, c] = [face[0], face[1], face[2]];
let normal = face_normal(
let normal = face_area_normal(
positions[a as usize],
positions[b as usize],
positions[c as usize],
);

[a, b, c].iter().for_each(|pos| {
normals[*pos as usize] += normal;
adjacency_counts[*pos as usize] += 1;
});
});

Expand All @@ -326,10 +323,9 @@ fn create_terrain_mesh(
let c_i = x + edge_length as usize - 2;
let c = Vec3::new(s.x - step, neighbors[c_i], s.z);

let face_a = face_normal(b, a, s);
let face_b = face_normal(c, b, s);
let face_a = face_area_normal(b, a, s);
let face_b = face_area_normal(c, b, s);

adjacency_counts[x] += 2;
normals[x] += face_a + face_b;
}

Expand All @@ -350,11 +346,9 @@ fn create_terrain_mesh(
let d_i = x - edge_length as usize;
let d = Vec3::new(s.x, heights[d_i], s.z - step);

let face_a = face_normal(b, a, s);
let face_b = face_normal(c, b, s);
let face_c = face_normal(d, c, s);

adjacency_counts[x] += 3;
let face_a = face_area_normal(b, a, s);
let face_b = face_area_normal(c, b, s);
let face_c = face_area_normal(d, c, s);

normals[x] += face_a + face_b + face_c;
}
Expand All @@ -381,11 +375,9 @@ fn create_terrain_mesh(
let d_i = x + edge_length as usize;
let d = Vec3::new(s.x, heights[d_i], s.z + step);

let face_a = face_normal(b, a, s);
let face_b = face_normal(c, b, s);
let face_c = face_normal(d, c, s);

adjacency_counts[x] += 3;
let face_a = face_area_normal(b, a, s);
let face_b = face_area_normal(c, b, s);
let face_c = face_area_normal(d, c, s);

normals[x] += face_a + face_b + face_c;
}
Expand All @@ -406,11 +398,9 @@ fn create_terrain_mesh(
let c = Vec3::new(s.x + step, neighbor_row[x + 1], s.z - step);
let d = Vec3::new(s.x + step, heights[x + 1], s.z);

let face_a = face_normal(b, a, s);
let face_b = face_normal(c, b, s);
let face_c = face_normal(d, c, s);

adjacency_counts[x] += 3;
let face_a = face_area_normal(b, a, s);
let face_b = face_area_normal(c, b, s);
let face_c = face_area_normal(d, c, s);

normals[x] += face_a + face_b + face_c;
}
Expand All @@ -432,20 +422,17 @@ fn create_terrain_mesh(
let c = Vec3::new(s.x - step, neighbor_row[x - 1], s.z + step);
let d = Vec3::new(s.x - step, heights[s_x - 1], s.z);

let face_a = face_normal(b, a, s);
let face_b = face_normal(c, b, s);
let face_c = face_normal(d, c, s);

adjacency_counts[s_x] += 3;
let face_a = face_area_normal(b, a, s);
let face_b = face_area_normal(c, b, s);
let face_c = face_area_normal(d, c, s);

normals[s_x] += face_a + face_b + face_c;
}
}

// average (smooth) normals for shared vertices...
for i in 0..normals.len() {
let count = adjacency_counts[i];
normals[i] = (normals[i] / (count as f32)).normalize();
for normal in &mut normals {
*normal = normal.try_normalize().unwrap_or(Vec3::ZERO);
}

let generated_tangents = generate_tangents(&indices, &positions, &uvs, &normals);
Expand Down
7 changes: 7 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,13 @@ pub fn face_normal(a: Vec3, b: Vec3, c: Vec3) -> Vec3 {
(b - a).cross(c - a).normalize()
}

/// Proportionate normals grabbed from https://github.com/bevyengine/bevy/pull/16050
#[inline]
pub fn face_area_normal(a: Vec3, b: Vec3, c: Vec3) -> Vec3 {
(b - a).cross(c - a)
}


#[test]
fn test_height_in_tile() {
let terrain_settings = TerrainSettings {
Expand Down

0 comments on commit d03ec96

Please sign in to comment.