pub struct ParticleSkin { /* private fields */ }Expand description
A particle cloud’s attachment to a skeleton.
Built once from the cloud’s rest positions and reused for every frame after
that. Holds one Bind per particle and nothing else: the rest positions
stay with the caller, because the caller already has them and copying a
hundred thousand of them twice would be the most expensive thing here.
Implementations§
Source§impl ParticleSkin
impl ParticleSkin
Sourcepub fn new() -> ParticleSkin
pub fn new() -> ParticleSkin
An empty skin.
pub fn is_empty(&self) -> bool
Sourcepub fn from_binds(binds: Vec<Bind>) -> ParticleSkin
pub fn from_binds(binds: Vec<Bind>) -> ParticleSkin
Build a skin from explicit bindings.
Sourcepub fn bind_nearest(
points: &[Vec3],
skeleton: &Skeleton,
falloff: f32,
) -> ParticleSkin
pub fn bind_nearest( points: &[Vec3], skeleton: &Skeleton, falloff: f32, ) -> ParticleSkin
Attach every point to the bones nearest it.
points are in the skeleton’s bind-pose space. falloff is how far
beyond the closest bone a second bone may be and still take a share of
the particle, in the same units as the points: it is the width of the
soft band around each joint, so a value near a limb’s thickness gives a
joint that bends and a value of zero gives a rigid, shearing one.
Bones with no children still bind — a hand, a head, the end of a tail — using a short stub along the direction they came from, so the tip of a limb is not left orphaned to whatever happens to be nearest.
Sourcepub fn bind_grouped(
points: &[Vec3],
skeleton: &Skeleton,
falloff: f32,
groups: &[u16],
group_bones: &[Vec<BoneId>],
) -> ParticleSkin
pub fn bind_grouped( points: &[Vec3], skeleton: &Skeleton, falloff: f32, groups: &[u16], group_bones: &[Vec<BoneId>], ) -> ParticleSkin
Attach every point to the nearest of the bones it is allowed to use.
Proximity on its own is not enough for a cloud that was sculpted rather
than modelled. A figure holding a two-handed sword has the blade up
beside its head at rest, so the nearest bone to most of the weapon is
the skull: bind by distance alone and swinging the arm leaves the sword
behind while nodding drags it around. The caller knows which parts of
the sculpt are the weapon, the cloak, the legs — that knowledge is what
groups carries.
groups[i] names which entry of group_bones point i may bind to. A
group that is empty, or an index past the end, falls back to the whole
skeleton, so a caller that forgets to classify something still gets a
particle that moves with the body rather than one left in mid-air.
Sourcepub fn apply(
&self,
skeleton: &Skeleton,
pose: &Pose,
rest: &[Vec3],
out: &mut Vec<Vec3>,
)
pub fn apply( &self, skeleton: &Skeleton, pose: &Pose, rest: &[Vec3], out: &mut Vec<Vec3>, )
Move a cloud into a pose.
rest are the same points the skin was bound from and out receives
the posed positions; out is resized to match. Both may be the same
length as the skin or shorter — a cloud that has grown since it was
bound leaves its extra particles where they are rather than panicking,
because a figure gaining matter mid-animation is a real thing that
happens here and is not worth crashing over.
Linear blend skinning: the classic artefact is that a joint under heavy twist loses volume. At the scale one particle occupies that is not visible, and the springs downstream hide what is left of it.
Sourcepub fn apply_with(&self, matrices: &[Mat4], rest: &[Vec3], out: &mut Vec<Vec3>)
pub fn apply_with(&self, matrices: &[Mat4], rest: &[Vec3], out: &mut Vec<Vec3>)
The same, against matrices the caller already has.
Building the matrices walks the whole hierarchy and inverts a matrix per bone. That is nothing next to skinning a hundred thousand particles, but it is pure waste when positions and normals are both being skinned against the same pose — which is every frame, for every figure.
Sourcepub fn skin_one(p: Vec3, bind: &Bind, matrices: &[Mat4]) -> Vec3
pub fn skin_one(p: Vec3, bind: &Bind, matrices: &[Mat4]) -> Vec3
Where one point goes, given the skinning matrices for a pose.
Exposed because a caller often needs a single position — where a hand is, so an effect can be thrown from it — without posing the whole cloud.
Sourcepub fn apply_normals(
&self,
skeleton: &Skeleton,
pose: &Pose,
rest: &[Vec3],
out: &mut Vec<Vec3>,
)
pub fn apply_normals( &self, skeleton: &Skeleton, pose: &Pose, rest: &[Vec3], out: &mut Vec<Vec3>, )
Turn a cloud’s surface normals to match a pose.
Lighting here is per particle against a real normal, so a normal left pointing where the bone used to be is an arm that bends while its shading stays behind — which reads as the limb going flat exactly when it moves. Uses the dominant bone rather than blending: a normal is a direction, blending two of them needs a renormalise, and across a joint the difference is a fraction of a degree on a particle a few pixels wide.
Trait Implementations§
Source§impl Clone for ParticleSkin
impl Clone for ParticleSkin
Source§impl Debug for ParticleSkin
impl Debug for ParticleSkin
Auto Trait Implementations§
impl Freeze for ParticleSkin
impl RefUnwindSafe for ParticleSkin
impl Send for ParticleSkin
impl Sync for ParticleSkin
impl Unpin for ParticleSkin
impl UnsafeUnpin for ParticleSkin
impl UnwindSafe for ParticleSkin
Blanket Implementations§
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
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>
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>
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)
&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)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.