-
Notifications
You must be signed in to change notification settings - Fork 0
Less blocking terrain mesh generation #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 12 commits
7be2443
5218b0b
09905bf
71b5354
2191fc6
060f285
dfba6e8
c969a3c
088f1ee
972004d
818290b
36c81b8
6d5499a
6c40e67
09af598
ea89014
83ddaa3
3280693
8c87304
5adc654
9541f0a
2940e1d
68ab49e
90e272b
f9e5cbd
7085d21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
use terrain_resources::RenderMaterials; | ||
use terrain_util::create_cross_mesh_for_chunk; | ||
use bevy::tasks::{futures_lite::future, AsyncComputeTaskPool}; | ||
use terrain_resources::{FutureChunkMesh, MeshTask, MeshType, MesherTasks, RenderMaterials}; | ||
|
||
use crate::prelude::*; | ||
|
||
|
@@ -46,7 +46,7 @@ pub fn generate_world_system( | |
mut client: ResMut<RenetClient>, | ||
mut chunk_manager: ResMut<ChunkManager>, | ||
) { | ||
let render_distance = Vec3::new(4.0, 4.0, 4.0); | ||
let render_distance = Vec3::new(8.0, 4.0, 8.0); | ||
CuddlyBunion341 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
info!("Sending chunk requests for chunks"); | ||
|
||
|
@@ -71,12 +71,11 @@ pub fn generate_world_system( | |
|
||
pub fn handle_chunk_mesh_update_events_system( | ||
mut commands: Commands, | ||
mut meshes: ResMut<Assets<Mesh>>, | ||
chunk_manager: ResMut<ChunkManager>, | ||
mut chunk_mesh_update_events: EventReader<terrain_events::ChunkMeshUpdateEvent>, | ||
mut mesh_query: Query<(Entity, &terrain_components::ChunkMesh)>, | ||
texture_manager: ResMut<terrain_util::TextureManager>, | ||
materials: Res<RenderMaterials>, | ||
mut tasks: ResMut<MesherTasks>, | ||
) { | ||
for event in chunk_mesh_update_events.read() { | ||
info!( | ||
|
@@ -91,20 +90,16 @@ pub fn handle_chunk_mesh_update_events_system( | |
commands.entity(entity).despawn(); | ||
} | ||
} | ||
add_chunk_objects( | ||
&mut commands, | ||
&mut meshes, | ||
chunk, | ||
&texture_manager, | ||
&materials, | ||
); | ||
add_cross_objects( | ||
&mut commands, | ||
chunk, | ||
&materials, | ||
&texture_manager, | ||
&mut meshes, | ||
); | ||
tasks.task_list.push(FutureChunkMesh { | ||
position: chunk.position, | ||
mesh_task: create_cube_mesher_task(chunk, &texture_manager), | ||
mesh_type: terrain_resources::MeshType::Solid, | ||
}); | ||
tasks.task_list.push(FutureChunkMesh { | ||
position: chunk.position, | ||
mesh_task: create_cross_mesher_task(chunk, &texture_manager), | ||
mesh_type: terrain_resources::MeshType::Transparent, | ||
}); | ||
} | ||
None => { | ||
println!("No chunk found"); | ||
|
@@ -113,73 +108,92 @@ pub fn handle_chunk_mesh_update_events_system( | |
} | ||
} | ||
|
||
fn add_chunk_objects( | ||
commands: &mut Commands, | ||
meshes: &mut ResMut<Assets<Mesh>>, | ||
fn create_cube_mesher_task( | ||
chunk: &Chunk, | ||
texture_manager: &terrain_util::TextureManager, | ||
materials: &RenderMaterials, | ||
) { | ||
if let Some(mesh) = terrain_util::create_chunk_mesh(chunk, texture_manager) { | ||
let material = materials | ||
.chunk_material | ||
.clone() | ||
.expect("Chunk material is loaded"); | ||
|
||
let meshes: &mut Mut<Assets<Mesh>> = &mut ResMut::reborrow(meshes); | ||
commands.spawn(( | ||
Mesh3d(meshes.add(mesh)), | ||
Transform::from_xyz( | ||
chunk.position.x * CHUNK_SIZE as f32, | ||
chunk.position.y * CHUNK_SIZE as f32, | ||
chunk.position.z * CHUNK_SIZE as f32, | ||
), | ||
MeshMaterial3d(material), | ||
player_components::Raycastable, | ||
terrain_components::ChunkMesh { | ||
key: [ | ||
chunk.position.x as i32, | ||
chunk.position.y as i32, | ||
chunk.position.z as i32, | ||
], | ||
}, | ||
Name::from("Transparent Chunk Mesh"), | ||
)); | ||
} | ||
) -> MeshTask { | ||
let task_pool = AsyncComputeTaskPool::get(); | ||
|
||
let chunk = *chunk; | ||
let texture_manager = texture_manager.clone(); | ||
|
||
let task = | ||
task_pool.spawn(async move { terrain_util::create_chunk_mesh(&chunk, &texture_manager) }); | ||
|
||
MeshTask(task) | ||
} | ||
|
||
fn add_cross_objects( | ||
commands: &mut Commands, | ||
fn create_cross_mesher_task( | ||
chunk: &Chunk, | ||
materials: &RenderMaterials, | ||
texture_manager: &terrain_util::TextureManager, | ||
meshes: &mut ResMut<Assets<Mesh>>, | ||
) -> MeshTask { | ||
let task_pool = AsyncComputeTaskPool::get(); | ||
|
||
let chunk = *chunk; | ||
let texture_manager = texture_manager.clone(); | ||
|
||
let task = task_pool | ||
.spawn(async move { terrain_util::create_cross_mesh_for_chunk(&chunk, &texture_manager) }); | ||
|
||
MeshTask(task) | ||
} | ||
|
||
pub fn handle_chunk_tasks_system( | ||
mut commands: Commands, | ||
materials: Res<RenderMaterials>, | ||
mut tasks: ResMut<MesherTasks>, | ||
mut meshes: ResMut<Assets<Mesh>>, | ||
) { | ||
if let Some(mesh) = create_cross_mesh_for_chunk(chunk, texture_manager) { | ||
let mesh_handle = meshes.add(mesh); | ||
|
||
commands.spawn(( | ||
Mesh3d(mesh_handle), | ||
MeshMaterial3d( | ||
materials | ||
.transparent_material | ||
.clone() | ||
.expect("Transparent material exists"), | ||
), | ||
Transform::from_xyz( | ||
chunk.position.x * CHUNK_SIZE as f32, | ||
chunk.position.y * CHUNK_SIZE as f32, | ||
chunk.position.z * CHUNK_SIZE as f32, | ||
), | ||
terrain_components::ChunkMesh { | ||
key: [ | ||
chunk.position.x as i32, | ||
chunk.position.y as i32, | ||
chunk.position.z as i32, | ||
], | ||
}, | ||
)); | ||
} | ||
let mut next_poll_indicies: Vec<usize> = Vec::new(); | ||
tasks | ||
.task_list | ||
.iter_mut() | ||
.enumerate() | ||
.for_each(|(index, future_chunk)| { | ||
let chunk_position = future_chunk.position; | ||
let task_result = | ||
bevy::tasks::block_on(future::poll_once(&mut future_chunk.mesh_task.0)); | ||
if task_result.is_none() { | ||
// Check next poll | ||
CuddlyBunion341 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
next_poll_indicies.push(index); | ||
return; | ||
} | ||
let mesh_option = task_result.unwrap(); | ||
if mesh_option.is_none() { | ||
return; | ||
|
||
} | ||
let mesh = mesh_option.expect("Mesh exists"); | ||
let mesh_handle = meshes.add(mesh); | ||
|
||
let material_handle = match future_chunk.mesh_type { | ||
MeshType::Solid => materials.chunk_material.clone(), | ||
MeshType::Transparent => materials.transparent_material.clone(), | ||
}; | ||
|
||
commands.spawn(( | ||
Mesh3d(mesh_handle), | ||
MeshMaterial3d(material_handle.expect("Material exists")), | ||
Transform::from_xyz( | ||
chunk_position.x * CHUNK_SIZE as f32, | ||
chunk_position.y * CHUNK_SIZE as f32, | ||
chunk_position.z * CHUNK_SIZE as f32, | ||
), | ||
terrain_components::ChunkMesh { | ||
key: [ | ||
chunk_position.x as i32, | ||
chunk_position.y as i32, | ||
chunk_position.z as i32, | ||
], | ||
}, | ||
)); | ||
CuddlyBunion341 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
}); | ||
|
||
let mut index = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ugly index, can't use enumerate() in this context. |
||
tasks.task_list.retain(|_| { | ||
let contains = next_poll_indicies.contains(&index); | ||
index += 1; | ||
contains | ||
}) | ||
} | ||
|
||
fn create_transparent_material(texture_handle: Handle<Image>) -> StandardMaterial { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,7 +87,7 @@ pub mod client_block { | |
use client_block::block_properties; | ||
use TextureName::*; | ||
|
||
#[derive(Resource)] | ||
#[derive(Resource, Clone)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No idea how to circumvent this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The clone shouldn't be too expensive though, as we are only cloning a hashmap with a few primitives. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The atlas currently consists of 16 slots, so there are not many UVs and enum values that will be cloned. |
||
pub struct TextureManager { | ||
textures: HashMap<TextureName, TextureUV>, | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reminder:
A logical Chunk of terrain has two geometrical representations:
A solid one, for the cubes like stone and dirt and a transparent one for the grass at the moment, perhaps glass and other stuff in the future.