pub struct ChunkPos(pub IVec3);Expand description
The position of a chunk in chunk-space coordinates.
When added to an entity, automatically updates the entity’s Transform
to match the chunk’s world position.
§Example
use bevy::prelude::*;
use chunky_bevy::prelude::*;
fn spawn_chunk(mut commands: Commands) {
// Spawns a chunk at chunk position (5, 0, 3)
// With default 10x10x10 chunks, this will be at world position (50, 0, 30)
commands.spawn((
Chunk,
ChunkPos(IVec3::new(5, 0, 3)),
));
}Tuple Fields§
§0: IVec3Methods from Deref<Target = IVec3>§
pub const ZERO: IVec3
pub const ONE: IVec3
pub const NEG_ONE: IVec3
pub const MIN: IVec3
pub const MAX: IVec3
pub const X: IVec3
pub const Y: IVec3
pub const Z: IVec3
pub const NEG_X: IVec3
pub const NEG_Y: IVec3
pub const NEG_Z: IVec3
pub const AXES: [IVec3; 3]
Sourcepub fn as_vec3(&self) -> Vec3
pub fn as_vec3(&self) -> Vec3
Casts all elements of self to f32.
Examples found in repository?
examples/sculpt.rs (line 276)
234fn sculpt_terrain(
235 time: Res<Time>,
236 keyboard: Res<ButtonInput<KeyCode>>,
237 mouse_buttons: Res<ButtonInput<MouseButton>>,
238 window_q: Query<&Window, With<PrimaryWindow>>,
239 camera_q: Query<(&Camera, &GlobalTransform), With<FlyCam>>,
240 mut chunks: Query<(&ChunkPos, &mut DensityField)>,
241 mesh_size: Res<DensityFieldMeshSize>,
242 brush: Res<SculptBrush>,
243 mut commands: Commands,
244 chunk_entities: Query<Entity, With<ChunkPos>>,
245) {
246 let adding = mouse_buttons.pressed(MouseButton::Right);
247 let removing = mouse_buttons.pressed(MouseButton::Left);
248
249 if !adding && !removing {
250 return;
251 }
252
253 let Ok(window) = window_q.single() else {
254 return;
255 };
256 let Some(cursor_pos) = window.cursor_position() else {
257 return;
258 };
259 let Ok((camera, cam_transform)) = camera_q.single() else {
260 return;
261 };
262 let Ok(ray) = camera.viewport_to_world(cam_transform, cursor_pos) else {
263 return;
264 };
265
266 let Some(hit_point) = raycast_terrain(&chunks, &mesh_size, ray) else {
267 return;
268 };
269
270 let world_brush_radius = brush.radius;
271 let chunk_world_size = mesh_size.0;
272 let use_hard_brush =
273 keyboard.pressed(KeyCode::ControlLeft) || keyboard.pressed(KeyCode::ControlRight);
274
275 for (chunk_pos, mut field) in chunks.iter_mut() {
276 let chunk_world_origin = chunk_pos.0.as_vec3() * chunk_world_size;
277 let local_hit = hit_point - chunk_world_origin;
278
279 let scale = Vec3::new(32.0, 32.0, 32.0) / chunk_world_size;
280 let grid_center = local_hit * scale;
281 let grid_radius = world_brush_radius * scale.x;
282
283 // AABB check
284 let chunk_min = Vec3::ZERO;
285 let chunk_max = Vec3::splat(32.0);
286 let brush_min = grid_center - Vec3::splat(grid_radius);
287 let brush_max = grid_center + Vec3::splat(grid_radius);
288
289 if brush_max.x < chunk_min.x
290 || brush_min.x > chunk_max.x
291 || brush_max.y < chunk_min.y
292 || brush_min.y > chunk_max.y
293 || brush_max.z < chunk_min.z
294 || brush_min.z > chunk_max.z
295 {
296 continue;
297 }
298
299 if use_hard_brush {
300 // Hard CSG brush (instant)
301 bevy_sculpter::helpers::brush_sphere(&mut field, grid_center, grid_radius, adding);
302 } else {
303 match brush.mode {
304 BrushMode::Smooth => {
305 // Smooth brush: rate is strength per second
306 // Negative rate = add material (decrease SDF)
307 // Positive rate = remove material (increase SDF)
308 let rate = if adding {
309 -brush.strength
310 } else {
311 brush.strength
312 };
313 bevy_sculpter::helpers::brush_smooth_timed(
314 &mut field,
315 grid_center,
316 grid_radius,
317 rate,
318 time.delta_secs(),
319 brush.falloff,
320 );
321 }
322 BrushMode::Blur => {
323 // Blur/smooth brush
324 bevy_sculpter::helpers::brush_blur(
325 &mut field,
326 grid_center,
327 grid_radius,
328 brush.strength * 0.1 * time.delta_secs(),
329 brush.falloff,
330 );
331 }
332 BrushMode::_Hard => {
333 bevy_sculpter::helpers::brush_sphere(
334 &mut field,
335 grid_center,
336 grid_radius,
337 adding,
338 );
339 }
340 }
341 }
342 }
343
344 for entity in chunk_entities.iter() {
345 commands.entity(entity).insert(DensityFieldDirty);
346 }
347}
348
349fn raycast_terrain(
350 chunks: &Query<(&ChunkPos, &mut DensityField)>,
351 mesh_size: &DensityFieldMeshSize,
352 ray: Ray3d,
353) -> Option<Vec3> {
354 let chunk_world_size = mesh_size.0;
355 let max_dist = 200.0;
356 let step = 0.1;
357 let mut t = 0.0;
358
359 while t < max_dist {
360 let point = ray.origin + ray.direction * t;
361 let chunk_coord = (point / chunk_world_size).floor().as_ivec3();
362
363 for (chunk_pos, field) in chunks.iter() {
364 if chunk_pos.0 != chunk_coord {
365 continue;
366 }
367
368 let chunk_origin = chunk_pos.0.as_vec3() * chunk_world_size;
369 let local_pos = point - chunk_origin;
370 let scale = Vec3::new(32.0, 32.0, 32.0) / chunk_world_size;
371 let grid_pos = local_pos * scale;
372
373 if grid_pos.x >= 0.0
374 && grid_pos.x < 32.0
375 && grid_pos.y >= 0.0
376 && grid_pos.y < 32.0
377 && grid_pos.z >= 0.0
378 && grid_pos.z < 32.0
379 {
380 let density = field.get(grid_pos.x as u32, grid_pos.y as u32, grid_pos.z as u32);
381 if density < 0.0 {
382 return Some(point);
383 }
384 }
385 }
386 t += step;
387 }
388 None
389}Sourcepub fn as_i16vec3(&self) -> I16Vec3
pub fn as_i16vec3(&self) -> I16Vec3
Casts all elements of self to i16.
Sourcepub fn as_u16vec3(&self) -> U16Vec3
pub fn as_u16vec3(&self) -> U16Vec3
Casts all elements of self to u16.
Sourcepub fn as_i64vec3(&self) -> I64Vec3
pub fn as_i64vec3(&self) -> I64Vec3
Casts all elements of self to i64.
Sourcepub fn as_u64vec3(&self) -> U64Vec3
pub fn as_u64vec3(&self) -> U64Vec3
Casts all elements of self to u64.
Sourcepub fn as_usizevec3(&self) -> USizeVec3
pub fn as_usizevec3(&self) -> USizeVec3
Casts all elements of self to usize.
Trait Implementations§
Source§impl Component for ChunkPos
Required Components: Transform.
impl Component for ChunkPos
Required Components: Transform.
A component’s Required Components are inserted whenever it is inserted. Note that this will also insert the required components of the required components, recursively, in depth-first order.
Source§const STORAGE_TYPE: StorageType = ::bevy::ecs::component::StorageType::Table
const STORAGE_TYPE: StorageType = ::bevy::ecs::component::StorageType::Table
A constant indicating the storage type used for this component.
Source§type Mutability = Immutable
type Mutability = Immutable
A marker type to assist Bevy with determining if this component is
mutable, or immutable. Mutable components will have
Component<Mutability = Mutable>,
while immutable components will instead have Component<Mutability = Immutable>. Read moreSource§fn register_required_components(
_requiree: ComponentId,
required_components: &mut RequiredComponentsRegistrator<'_, '_>,
)
fn register_required_components( _requiree: ComponentId, required_components: &mut RequiredComponentsRegistrator<'_, '_>, )
Registers required components. Read more
Source§fn on_add() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
fn on_add() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
Source§fn clone_behavior() -> ComponentCloneBehavior
fn clone_behavior() -> ComponentCloneBehavior
Called when registering this component, allowing to override clone function (or disable cloning altogether) for this component. Read more
Source§fn on_insert() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
fn on_insert() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
Source§fn on_replace() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
fn on_replace() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
Source§fn on_remove() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
fn on_remove() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
Source§fn on_despawn() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
fn on_despawn() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>
Source§fn map_entities<E>(_this: &mut Self, _mapper: &mut E)where
E: EntityMapper,
fn map_entities<E>(_this: &mut Self, _mapper: &mut E)where
E: EntityMapper,
Maps the entities on this component using the given
EntityMapper. This is used to remap entities in contexts like scenes and entity cloning.
When deriving Component, this is populated by annotating fields containing entities with #[entities] Read moreAuto Trait Implementations§
impl Freeze for ChunkPos
impl RefUnwindSafe for ChunkPos
impl Send for ChunkPos
impl Sync for ChunkPos
impl Unpin for ChunkPos
impl UnwindSafe for ChunkPos
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
Return the
T ShaderType for self. When used in AsBindGroup
derives, it is safe to assume that all images in self exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<C> Bundle for Cwhere
C: Component,
impl<C> Bundle for Cwhere
C: Component,
fn component_ids( components: &mut ComponentsRegistrator<'_>, ids: &mut impl FnMut(ComponentId), )
Source§fn get_component_ids(
components: &Components,
ids: &mut impl FnMut(Option<ComponentId>),
)
fn get_component_ids( components: &Components, ids: &mut impl FnMut(Option<ComponentId>), )
Source§impl<C> BundleFromComponents for Cwhere
C: Component,
impl<C> BundleFromComponents for Cwhere
C: Component,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Converts
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Converts
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Converts
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
Converts
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Convert
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Convert
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Convert
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
Convert
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<C> DynamicBundle for Cwhere
C: Component,
impl<C> DynamicBundle for Cwhere
C: Component,
Source§unsafe fn get_components(
ptr: MovingPtr<'_, C>,
func: &mut impl FnMut(StorageType, OwningPtr<'_>),
) -> <C as DynamicBundle>::Effect
unsafe fn get_components( ptr: MovingPtr<'_, C>, func: &mut impl FnMut(StorageType, OwningPtr<'_>), ) -> <C as DynamicBundle>::Effect
Moves the components out of the bundle. Read more
Source§unsafe fn apply_effect(
_ptr: MovingPtr<'_, MaybeUninit<C>>,
_entity: &mut EntityWorldMut<'_>,
)
unsafe fn apply_effect( _ptr: MovingPtr<'_, MaybeUninit<C>>, _entity: &mut EntityWorldMut<'_>, )
Applies the after-effects of spawning this bundle. Read more
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> FromWorld for Twhere
T: Default,
impl<T> FromWorld for Twhere
T: Default,
Source§fn from_world(_world: &mut World) -> T
fn from_world(_world: &mut World) -> T
Creates Self using default().
Source§impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
Source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoResult<T> for T
impl<T> IntoResult<T> for T
Source§fn into_result(self) -> Result<T, RunSystemError>
fn into_result(self) -> Result<T, RunSystemError>
Converts this type into the system output type.