Skip to content

Commit

Permalink
animation
Browse files Browse the repository at this point in the history
  • Loading branch information
robtfm committed Jul 5, 2022
1 parent 7bcf49d commit b6e619b
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 15 deletions.
32 changes: 27 additions & 5 deletions examples/gltf_gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bevy::{
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
// log::LogSettings,
prelude::*,
window::PresentMode,
window::PresentMode, math::Vec3A,
};
use mesh2sdf::{shader::SimpleTextureMaterial, create_sdf_image, compute::{SdfComputeRequests, SdfComputePlugin}};
use mesh2sdf::{
Expand Down Expand Up @@ -33,25 +33,45 @@ fn main() {
});

app.add_startup_system(setup);
app.add_system(setup_scene_once_loaded);
app.add_system(system);
app.add_system(toggle);
app.add_system(rotate);
app.run();
}

struct Animations(Vec<Handle<AnimationClip>>);

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let filename = std::env::args().nth(1).unwrap_or("teapot".into());

let scene = asset_server.load(format!("gltf/{}.glb#Scene0", filename).as_str());
commands
.spawn_bundle(TransformBundle::default())
.insert(Rotate)
// .insert(Rotate)
.with_children(|p| {
p.spawn_bundle(SceneBundle {
scene,
..Default::default()
});
});

commands.insert_resource(Animations(vec![
asset_server.load(format!("gltf/{}.glb#Animation0", filename).as_str()),
]));
}

fn setup_scene_once_loaded(
animations: Res<Animations>,
mut player: Query<&mut AnimationPlayer>,
mut done: Local<bool>,
) {
if !*done {
if let Ok(mut player) = player.get_single_mut() {
player.play(animations.0[0].clone_weak()).repeat();
*done = true;
}
}
}

fn system(
Expand All @@ -69,7 +89,9 @@ fn system(
Some(i) => i.len(),
None => mesh.attribute(Mesh::ATTRIBUTE_POSITION).unwrap().len(),
} / 3);
let aabb = mesh.compute_aabb().unwrap();
let mut aabb = mesh.compute_aabb().unwrap();
// todo compute aabb dynamically based on animation data
aabb.half_extents += Vec3A::new(20.0, 0.0, 10.0);
println!("aabb: {:?}", aabb);
let max_dim = aabb.half_extents.max_element();
let mult = std::env::args().nth(2).unwrap_or("4".into()).parse::<u32>().unwrap();
Expand All @@ -80,9 +102,9 @@ fn system(
let render = render_sdfs.add(SimpleTextureMaterial(SdfMaterialSpec {
aabb: aabb.clone(),
image: image.clone(),
min_step_size: 0.001,
min_step_size: 0.1,
hit_threshold: -0.0001,
max_step_count: 200,
max_step_count: 50,
// hit_color: Color::NONE,
// step_color: Color::NONE,
..Default::default()
Expand Down
Binary file added fox.mp4
Binary file not shown.
3 changes: 3 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
realtime gpu-based conversion of meshes to sdfs

<video src='fox.mp4' width=180> </video>
20 changes: 15 additions & 5 deletions src/compute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use bevy::{
render_graph::{self, RenderGraph},
render_resource::{*, encase::private::WriteInto},
renderer::{RenderContext, RenderDevice},
RenderApp, RenderStage, extract_component::{ExtractComponentPlugin, ExtractComponent},
RenderApp, RenderStage, extract_component::{ExtractComponentPlugin, ExtractComponent}, mesh::skinning::{SkinnedMesh, SkinnedMeshInverseBindposes},
},
utils::HashMap,
};
Expand Down Expand Up @@ -131,10 +131,12 @@ fn preprocess_sdfs(
meshes: Res<Assets<Mesh>>,
images: Res<Assets<Image>>,
reqs: Res<SdfComputeRequests>,
sdfs: Query<(&Sdf, &Handle<Mesh>)>,
sdfs: Query<(&Sdf, &Handle<Mesh>, Option<&SkinnedMesh>)>,
inverse_bindposes: Res<Assets<SkinnedMeshInverseBindposes>>,
joint_transforms: Query<&GlobalTransform>,
) {
for ent in reqs.0.iter() {
let Ok((sdf, mesh)) = sdfs.get(*ent) else {
let Ok((sdf, mesh, maybe_skin)) = sdfs.get(*ent) else {
warn!("can't get sdf + mesh handle");
continue;
};
Expand All @@ -156,9 +158,17 @@ fn preprocess_sdfs(
scale: (sdf.aabb.half_extents * 2.0 / (dimensions - 1).as_vec3a()).into(),
};

// println!("scale: {}", uniform.scale);
let preprocessed = match maybe_skin {
Some(skin) => {
let Some(poses) = inverse_bindposes.get(&skin.inverse_bindposes) else {panic!("no bindposes")};

let preprocessed = preprocess_mesh_for_sdf(mesh);
let joints = skin.joints.iter().zip(poses.iter()).map(|(joint_ent, pose)| {
joint_transforms.get(*joint_ent).unwrap().compute_affine() * *pose
}).collect::<Vec<_>>();
preprocess_mesh_for_sdf(mesh, Some(&joints))
}
_ => preprocess_mesh_for_sdf(mesh, None)
};

let vertices = SdfVerticesData {
data: preprocessed.vertices.into_iter().map(|(v,n)| [Vec3::from(v), Vec3::from(n)]).collect(),
Expand Down
31 changes: 26 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,36 @@ pub struct PreprocessedMeshData {
}

pub fn preprocess_mesh_for_sdf(
mesh: &Mesh
mesh: &Mesh,
joints: Option<&[Mat4]>,
) -> PreprocessedMeshData {
let Some(VertexAttributeValues::Float32x3(values)) = mesh.attribute(Mesh::ATTRIBUTE_POSITION) else {
panic!("bad mesh");
};

let values: Vec<[f32; 3]> = match mesh.indices() {
Some(ix) => ix.iter().map(|ix| values[ix]).collect(),
None => values.iter().copied().collect(),

let weight_with_joints = |v: Vec3, index: usize| -> Vec3 {
let Some(VertexAttributeValues::Float32x4(joint_weights)) = mesh.attribute(Mesh::ATTRIBUTE_JOINT_WEIGHT) else {panic!("bad joint weights!")};
let Some(VertexAttributeValues::Uint16x4(joint_indexes)) = mesh.attribute(Mesh::ATTRIBUTE_JOINT_INDEX) else {panic!("bad joint indexes!")};
let joints = joints.unwrap();
let indexes = joint_indexes[index];
let weights = joint_weights[index];
let mat = joints[indexes[0] as usize] * weights[0] + joints[indexes[1] as usize] * weights[1] + joints[indexes[2] as usize] * weights[2] + joints[indexes[3] as usize] * weights[3];
let res = mat * v.extend(1.0);
res.truncate() / res.w
};

let weight = |v: Vec3, index: usize| -> Vec3 {
if joints.is_some() {
weight_with_joints(v, index)
} else {
v
}
};

let values: Vec<Vec3> = match mesh.indices() {
Some(ix) => ix.iter().map(|ix| weight(Vec3::from(values[ix]), ix)).collect(),
None => values.iter().enumerate().map(|(ix, v)| weight(Vec3::from(*v), ix)).collect(),
};

let mut vertices = BTreeMap::<OrderedVec, Vec3A>::new();
Expand Down Expand Up @@ -124,7 +145,7 @@ pub fn create_sdf_from_mesh_cpu(mesh: &Mesh, aabb: &Aabb, dimension: UVec3, debu
"`sdf generation can only work on `TriangleList`s"
);

let preprocessed = preprocess_mesh_for_sdf(mesh);
let preprocessed = preprocess_mesh_for_sdf(mesh, None);

let compute_distance = |point: Vec3A, debug: bool| -> f32 {
if debug {
Expand Down

0 comments on commit b6e619b

Please sign in to comment.