Skip to content

Commit e2584d1

Browse files
committed
feat: view frustum culling
1 parent bca1ba4 commit e2584d1

File tree

7 files changed

+109
-40
lines changed

7 files changed

+109
-40
lines changed

src/chunk.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use crate::persistence::{Loadable, Saveable};
2+
use crate::player::Player;
3+
use crate::utils::math_utils::Plane;
24
use crate::world::WorldChunk;
35
use crate::{
46
blocks::{
@@ -58,6 +60,7 @@ impl Chunk {
5860
y_blocks[block_position.y as usize] = Some(block);
5961
}
6062
pub fn remove_block(&mut self, block_r_position: &Vec3) {
63+
let mut a = 0;
6164
let mut blocks_borrow = self.blocks.write().unwrap();
6265
let y_blocks = blocks_borrow
6366
.get_mut(((block_r_position.x * CHUNK_SIZE as f32) + block_r_position.z) as usize)
@@ -113,7 +116,8 @@ impl Chunk {
113116
pub fn build_mesh(&self, other_chunks: Vec<WorldChunk>) -> (u32, wgpu::Buffer, wgpu::Buffer) {
114117
let mut vertex: Vec<BlockVertexData> = vec![];
115118
let mut indices: Vec<u32> = vec![];
116-
let mut adjacent_chunks: Vec<((i32, i32), BlockVec)> = vec![((self.x, self.y), self.blocks.clone())];
119+
let mut adjacent_chunks: Vec<((i32, i32), BlockVec)> =
120+
vec![((self.x, self.y), self.blocks.clone())];
117121

118122
for chunk in &other_chunks {
119123
let chunk_read = chunk.read().unwrap();
@@ -316,6 +320,64 @@ impl Chunk {
316320
}
317321
}
318322
}
323+
// https://www.lighthouse3d.com/tutorials/view-frustum-culling/
324+
// Note: we don't compute the top and bottom planes, only far,near,right,left
325+
pub fn is_visible(&self, player: &Player) -> bool {
326+
let forward = player.camera.get_forward_dir();
327+
let right = player.camera.get_right_dir();
328+
let halfvside = player.camera.zfar / f32::tan(player.camera.fovy / 2.0);
329+
let halfhside = halfvside * player.camera.aspect_ratio;
330+
let front_mult_far = player.camera.zfar * forward;
331+
332+
let chunk_points = [
333+
(
334+
(self.x as f32) * CHUNK_SIZE as f32,
335+
(self.y as f32) * CHUNK_SIZE as f32,
336+
),
337+
(
338+
(self.x as f32 + 1.0) * CHUNK_SIZE as f32,
339+
(self.y as f32) * CHUNK_SIZE as f32,
340+
),
341+
(
342+
(self.x as f32) * CHUNK_SIZE as f32,
343+
(self.y as f32 + 1.0) * CHUNK_SIZE as f32,
344+
),
345+
(
346+
(self.x as f32 + 1.0) * CHUNK_SIZE as f32,
347+
(self.y as f32 + 1.0) * CHUNK_SIZE as f32,
348+
),
349+
];
350+
351+
let near_plane = Plane {
352+
point: player.camera.eye + player.camera.znear * forward,
353+
normal: forward,
354+
};
355+
let far_plane = Plane {
356+
point: player.camera.eye + front_mult_far,
357+
normal: -forward,
358+
};
359+
let right_plane = Plane {
360+
point: player.camera.eye,
361+
normal: glam::vec3(0.0, 1.0, 0.0)
362+
.cross(player.camera.eye - (front_mult_far + right * halfhside))
363+
.normalize(),
364+
};
365+
let left_plane = Plane {
366+
point: player.camera.eye,
367+
normal: (player.camera.eye - (front_mult_far - right * halfhside))
368+
.cross(glam::vec3(0.0, 1.0, 0.0))
369+
.normalize(),
370+
};
371+
372+
// returns true if at least one border of a chunk is visible is inside the frustum
373+
[far_plane, near_plane, left_plane, right_plane]
374+
.iter()
375+
.all(|p| {
376+
chunk_points.iter().any(|chunk_point| {
377+
p.signed_plane_dist(glam::vec3(chunk_point.0, 0.0, chunk_point.1)) >= 0.0
378+
})
379+
})
380+
}
319381

320382
pub fn new(
321383
x: i32,

src/main.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ pub mod utils;
4646
pub mod world;
4747

4848
async fn run(event_loop: EventLoop<()>, window: Window) {
49-
// let model: Obj = load_obj(input).unwrap();
50-
5149
let start = Instant::now();
5250
let mut total_time = start.elapsed();
5351
let mut delta_time = start.elapsed();

src/player.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ impl Player {
7070
&mut self,
7171
collisions: &'a Vec<CollisionBox>,
7272
) -> Option<(&'a CollisionBox, FaceDirections)> {
73-
let forward = self.camera.calc_target();
73+
let forward = self.camera.get_forward_dir();
7474
let mut ray_results: Vec<RayResult> = vec![];
7575

7676
let ray = crate::collision::Ray {
@@ -142,7 +142,7 @@ impl Player {
142142
let input_direction = direction;
143143
let player_collision = self.get_collision();
144144

145-
let forward = self.camera.calc_target();
145+
let forward = self.camera.get_forward_dir();
146146

147147
let mut velocity = vec3(0.0, 0.0, 0.0);
148148

@@ -247,13 +247,16 @@ impl Camera {
247247
}
248248
}
249249
pub fn build_view_matrix(&self) -> glam::Mat4 {
250-
glam::Mat4::look_at_lh(self.eye, self.eye + self.calc_target(), glam::Vec3::Y)
250+
glam::Mat4::look_at_lh(self.eye, self.eye + self.get_forward_dir(), glam::Vec3::Y)
251251
}
252252
pub fn build_projection_matrix(&self) -> glam::Mat4 {
253253
glam::Mat4::perspective_lh(self.fovy, self.aspect_ratio, self.znear, self.zfar)
254254
}
255+
pub fn get_right_dir(&self) -> glam::Vec3 {
256+
glam::vec3(0.0, 1.0, 0.0).cross(self.get_forward_dir())
257+
}
255258

256-
pub fn calc_target(&self) -> glam::Vec3 {
259+
pub fn get_forward_dir(&self) -> glam::Vec3 {
257260
let mut direction = glam::Vec3::ZERO;
258261

259262
direction.x = f32::cos(self.yaw) * f32::cos(self.pitch);

src/shaders/shader.wgsl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ var <uniform> current_chunk: vec2<i32>;
3636
fn vs_main(in: VertexInput, instance_data: InstanceInput) -> VertexOutput {
3737
var out: VertexOutput;
3838

39+
3940
let chunk_offset = vec4<f32>(f32(current_chunk.x) * 16.0, 0.0, f32(current_chunk.y) * 16.0, 0.0);
4041

4142
out.clip_position = projection * view * (vec4<f32>(in.position.xyz, 1.0) + chunk_offset);
@@ -70,7 +71,7 @@ fn fs_main(in: FragmentInput) -> @location(0) vec4<f32> {
7071
color = textureSample(diffuse, t_sampler, in.tex_coords);
7172
color *= max(dot(in.normals, normalize(light_direction)), 0.2);
7273
color += vec4<f32>(vec3<f32>(ambient_light), 0.0);
73-
color *= 1.0 - in.ao;
74+
color *= 1.0 - (in.ao * 0.9);
7475

7576
return color;
7677
}

src/shaders/ui_shader.wgsl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ fn vs_main(in: VertexInput) -> VertexOutput {
2626
return out;
2727
}
2828

29-
3029
@group(1) @binding(0)
3130
var diffuse: texture_2d<f32>;
3231
@group(1) @binding(1)

src/state.rs

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,7 @@ impl State {
6666
view_formats: vec![],
6767
};
6868

69-
let camera = Camera {
70-
aspect_ratio: surface_config.width as f32 / surface_config.height as f32,
71-
eye: glam::vec3(-4.0, 50.0, 4.0),
72-
yaw: consts::FRAC_PI_2,
73-
pitch: 0.0,
74-
75-
fovy: consts::FRAC_PI_4,
76-
znear: 0.1,
77-
zfar: 1000.,
78-
needs_update: false,
79-
};
69+
let camera = Camera::new(surface_config.width as f32, surface_config.height as f32);
8070
let player = Player {
8171
camera,
8272
current_chunk: (0, 0),
@@ -345,24 +335,26 @@ impl State {
345335
rpass.set_bind_group(1, pipeline.bind_group_1(), &[]);
346336

347337
for chunk in chunks.iter() {
348-
rpass.set_bind_group(2, &chunk.chunk_bind_group, &[]);
349-
rpass.set_vertex_buffer(
350-
0,
351-
chunk
352-
.chunk_vertex_buffer
353-
.as_ref()
354-
.expect("Vertex buffer not initiated")
355-
.slice(..),
356-
);
357-
rpass.set_index_buffer(
358-
chunk
359-
.chunk_index_buffer
360-
.as_ref()
361-
.expect("Index buffer not initiated")
362-
.slice(..),
363-
wgpu::IndexFormat::Uint32,
364-
);
365-
rpass.draw_indexed(0..chunk.indices, 0, 0..1);
338+
if chunk.is_visible(&self.player) {
339+
rpass.set_bind_group(2, &chunk.chunk_bind_group, &[]);
340+
rpass.set_vertex_buffer(
341+
0,
342+
chunk
343+
.chunk_vertex_buffer
344+
.as_ref()
345+
.expect("Vertex buffer not initiated")
346+
.slice(..),
347+
);
348+
rpass.set_index_buffer(
349+
chunk
350+
.chunk_index_buffer
351+
.as_ref()
352+
.expect("Index buffer not initiated")
353+
.slice(..),
354+
wgpu::IndexFormat::Uint32,
355+
);
356+
rpass.draw_indexed(0..chunk.indices, 0, 0..1);
357+
};
366358
}
367359
}
368360
{

src/utils.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ fn fade(t: f32) -> f32 {
88
fn lerp(a: f32, b: f32, t: f32) -> f32 {
99
a + ((b - a) * t)
1010
}
11+
pub(crate) mod math_utils {
12+
#[derive(Debug)]
13+
pub struct Plane {
14+
pub point: glam::Vec3,
15+
pub normal: glam::Vec3,
16+
}
17+
impl Plane {
18+
pub fn signed_plane_dist(&self, point: glam::Vec3) -> f32 {
19+
(point - self.point).dot(self.normal)
20+
}
21+
}
22+
}
1123
pub(crate) mod noise {
1224
use std::fmt::Debug;
1325

@@ -130,8 +142,10 @@ pub(crate) mod threadpool {
130142
impl Worker {
131143
pub fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
132144
let thread = thread::spawn(move || loop {
133-
let job = receiver.lock().unwrap().recv().unwrap();
134-
job();
145+
let receiver = receiver.lock().unwrap();
146+
if let Ok(job) = receiver.recv() {
147+
job();
148+
}
135149
});
136150
Worker { id, thread }
137151
}

0 commit comments

Comments
 (0)