From a7eff539e13b88b71a32ba021708f0527d820fdb Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Sun, 11 Sep 2022 20:15:25 +0530 Subject: [PATCH 01/25] addding skinning tutorial with bones --- .../01_introductory/viz_skinning_bones.py | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 docs/tutorials/01_introductory/viz_skinning_bones.py diff --git a/docs/tutorials/01_introductory/viz_skinning_bones.py b/docs/tutorials/01_introductory/viz_skinning_bones.py new file mode 100644 index 000000000..c1f8c667a --- /dev/null +++ b/docs/tutorials/01_introductory/viz_skinning_bones.py @@ -0,0 +1,76 @@ +import numpy as np +from fury import window, utils, actor, transform +from fury.gltf import glTF +from fury.data import fetch_gltf, read_viz_gltf +from fury.lib import Transform + +scene = window.Scene() + +fetch_gltf('SimpleSkin', 'glTF') +filename = read_viz_gltf('RiggedFigure') + +gltf_obj = glTF(filename, apply_normals=False) +actors = gltf_obj.actors() +print(len(actors)) + +vertices = utils.vertices_from_actor(actors[0]) +clone = np.copy(vertices) + +timeline = gltf_obj.get_skin_timeline2() +timeline.add_actor(actors[0]) + +scene = window.Scene() +showm = window.ShowManager(scene, size=(900, 768), reset_camera=False, + order_transparent=True) +showm.initialize() + +bactors = gltf_obj.get_joint_actors(length=0.2) +bverts = [] +for bone, joint_actor in bactors.items(): + bverts.append(utils.vertices_from_actor(joint_actor)) + +bvert_copy = np.copy(bverts) + +scene.add(* bactors.values()) +scene.add(timeline) + +bones = gltf_obj.bones[0] +parent_transforms = gltf_obj.bone_tranforms + +# target_bone = 12 +# print(parent_transforms[target_bone], '\n') +# print(timeline.get_value(f'transform{target_bone}', 0.0), '\n') +# print(timeline.get_value(f'transform{target_bone}', 1.25)) + + +def timer_callback(_obj, _event): + timeline.update_animation() + joint_matrices = [] + ibms = [] + + for i, bone in enumerate(bones): + if timeline.is_interpolatable(f'transform{bone}'): + deform = timeline.get_value(f'transform{bone}', + timeline.current_timestamp) + ibm = gltf_obj.ibms[0][i].T + ibms.append(ibm) + + parent_transform = parent_transforms[bone] + joint_mat = np.dot(parent_transform, deform) + joint_mat = np.dot(joint_mat, ibm) + joint_matrices.append(joint_mat) + + # if bone == 12: + bverts[i][:] = transform.apply_transfomation(bvert_copy[i], deform) + utils.update_actor(bactors[bone]) + + vertices[:] = gltf_obj.apply_skin_matrix(clone, joint_matrices, + bones, ibms) + utils.update_actor(actors[0]) + utils.compute_bounds(actors[0]) + showm.render() + + +showm.add_timer_callback(True, 10, timer_callback) + +showm.start() From d145500e454bc8a357f4e288e5ab079d27745a59 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Tue, 13 Sep 2022 01:56:59 +0530 Subject: [PATCH 02/25] using hirearchical timelines --- .../iz_skinning_hirerachical_transform.py | 75 +++++++++++++++++++ fury/gltf.py | 35 ++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 docs/tutorials/01_introductory/iz_skinning_hirerachical_transform.py diff --git a/docs/tutorials/01_introductory/iz_skinning_hirerachical_transform.py b/docs/tutorials/01_introductory/iz_skinning_hirerachical_transform.py new file mode 100644 index 000000000..0d7f197bb --- /dev/null +++ b/docs/tutorials/01_introductory/iz_skinning_hirerachical_transform.py @@ -0,0 +1,75 @@ +import numpy as np +from fury import window, utils, actor, transform +from fury.gltf import glTF +from fury.data import fetch_gltf, read_viz_gltf +from fury.lib import Transform + +scene = window.Scene() + +fetch_gltf('SimpleSkin', 'glTF') +filename = read_viz_gltf('RiggedFigure') + +gltf_obj = glTF(filename, apply_normals=False) +actors = gltf_obj.actors() +print(len(actors)) + +vertices = utils.vertices_from_actor(actors[0]) +clone = np.copy(vertices) + +timeline = gltf_obj.get_skin_timeline3() +timeline.add_actor(actors[0]) + +scene = window.Scene() +showm = window.ShowManager(scene, size=(900, 768), reset_camera=False, + order_transparent=True) +showm.initialize() + +bactors = gltf_obj.get_joint_actors(length=0.2) +bverts = [] +for bone, joint_actor in bactors.items(): + bverts.append(utils.vertices_from_actor(joint_actor)) + +bvert_copy = np.copy(bverts) + +scene.add(* bactors.values()) +scene.add(timeline) + +bones = gltf_obj.bones[0] +parent_transforms = gltf_obj.bone_tranforms + + +print(len(gltf_obj.child_timelines)) + + +def timer_callback(_obj, _event): + timeline.update_animation() + # timeline.timelines + # joint_matrices = [] + # ibms = [] + + # for i, bone in enumerate(bones): + # if timeline.is_interpolatable(f'transform{bone}'): + # deform = timeline.get_value(f'transform{bone}', + # timeline.current_timestamp) + # ibm = gltf_obj.ibms[0][i].T + # ibms.append(ibm) + + # parent_transform = parent_transforms[bone] + # joint_mat = np.dot(parent_transform, deform) + # joint_mat = np.dot(joint_mat, ibm) + # joint_matrices.append(joint_mat) + + # # if bone == 12: + # bverts[i][:] = transform.apply_transfomation(bvert_copy[i], deform) + # utils.update_actor(bactors[bone]) + + # vertices[:] = gltf_obj.apply_skin_matrix(clone, joint_matrices, + # bones, ibms) + # utils.update_actor(actors[0]) + # utils.compute_bounds(actors[0]) + showm.render() + + +showm.add_timer_callback(True, 10, timer_callback) + +showm.start() diff --git a/fury/gltf.py b/fury/gltf.py index f091de0b5..fdc357f37 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -80,6 +80,7 @@ def __init__(self, filename, apply_normals=False): self.bones = [] self.ibms = [] self.vertices = [] + self.child_timelines = [] self.inspect_scene(0) @@ -620,7 +621,7 @@ def get_skin_timeline(self): timeline.set_keyframe(f'transform{nodes}', 0.0, transform) return timeline - + def get_skin_timeline2(self): """Alternate version of `get_skin_timeline` Using pre-multiplied matrices. @@ -640,6 +641,38 @@ def get_skin_timeline2(self): # timeline.set_keyframe(f'transform{bone}', 0.0, np.identity(4)) return timeline + def transverse_bones(self, bone_id, parent_timeline: Timeline): + """ + bone_id : int + Index of the bone. + parent_timeline : Timeline + timeline of the parent bone. Should be `root_timeline` by default. + """ + node = self.gltf.nodes[bone_id] + timeline = Timeline(playback_panel=False) + transforms = self.sampler_matrices[bone_id] + timestamps = transforms['timestamps'] + metrices = transforms['matrix'] + + for time, matrix in zip(timestamps, metrices): + timeline.set_keyframe('transform', time[0], matrix) + + if node.children: + for child_bone in node.children: + self.transverse_bones(child_bone, timeline) + else: + self.child_timelines.append(timeline) + parent_timeline.add(timeline) + + def get_skin_timeline3(self): + """One timeline for each bone, contains parent transforms. + """ + root_timeline = Timeline(playback_panel=True) + root_bone = self.gltf.skins[0].skeleton + root_bone = root_bone if root_bone else self.bones[0][0] + self.transverse_bones(root_bone, root_timeline) + return root_timeline + def get_animation_timelines(self): """Returns list of animation timeline. From 5a33224f66b189a47c3b7c97956b37fa87f54c0b Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Tue, 13 Sep 2022 20:16:40 +0530 Subject: [PATCH 03/25] hirearchical animation in examples --- .../iz_skinning_hirerachical_transform.py | 52 ++++++++----------- .../01_introductory/viz_skinning_bones.py | 6 +-- fury/gltf.py | 8 +-- 3 files changed, 30 insertions(+), 36 deletions(-) diff --git a/docs/tutorials/01_introductory/iz_skinning_hirerachical_transform.py b/docs/tutorials/01_introductory/iz_skinning_hirerachical_transform.py index 0d7f197bb..18f86f661 100644 --- a/docs/tutorials/01_introductory/iz_skinning_hirerachical_transform.py +++ b/docs/tutorials/01_introductory/iz_skinning_hirerachical_transform.py @@ -3,11 +3,12 @@ from fury.gltf import glTF from fury.data import fetch_gltf, read_viz_gltf from fury.lib import Transform +import copy scene = window.Scene() fetch_gltf('SimpleSkin', 'glTF') -filename = read_viz_gltf('RiggedFigure') +filename = read_viz_gltf('CesiumMan') gltf_obj = glTF(filename, apply_normals=False) actors = gltf_obj.actors() @@ -25,11 +26,11 @@ showm.initialize() bactors = gltf_obj.get_joint_actors(length=0.2) -bverts = [] +bverts = {} for bone, joint_actor in bactors.items(): - bverts.append(utils.vertices_from_actor(joint_actor)) + bverts[bone] = utils.vertices_from_actor(joint_actor) -bvert_copy = np.copy(bverts) +bvert_copy = copy.deepcopy(bverts) scene.add(* bactors.values()) scene.add(timeline) @@ -38,35 +39,28 @@ parent_transforms = gltf_obj.bone_tranforms -print(len(gltf_obj.child_timelines)) +def transverse_timelines(timeline, bone_id, timestamp, + parent_bone_deform=np.identity(4)): + deform = timeline.get_value('transform', timestamp) + new_deform = np.dot(parent_bone_deform, deform) + + node = gltf_obj.gltf.nodes[bone_id] + bverts[bone_id][:] = transform.apply_transfomation(bvert_copy[bone_id], + new_deform) + utils.update_actor(bactors[bone_id]) + # if bone_id == 11: + # print(bverts[bone_id]) + if node.children: + for c_timeline, c_bone in zip(timeline.timelines, node.children): + transverse_timelines(c_timeline, c_bone, timestamp, new_deform) def timer_callback(_obj, _event): timeline.update_animation() - # timeline.timelines - # joint_matrices = [] - # ibms = [] - - # for i, bone in enumerate(bones): - # if timeline.is_interpolatable(f'transform{bone}'): - # deform = timeline.get_value(f'transform{bone}', - # timeline.current_timestamp) - # ibm = gltf_obj.ibms[0][i].T - # ibms.append(ibm) - - # parent_transform = parent_transforms[bone] - # joint_mat = np.dot(parent_transform, deform) - # joint_mat = np.dot(joint_mat, ibm) - # joint_matrices.append(joint_mat) - - # # if bone == 12: - # bverts[i][:] = transform.apply_transfomation(bvert_copy[i], deform) - # utils.update_actor(bactors[bone]) - - # vertices[:] = gltf_obj.apply_skin_matrix(clone, joint_matrices, - # bones, ibms) - # utils.update_actor(actors[0]) - # utils.compute_bounds(actors[0]) + timestamp = timeline.current_timestamp + + for child in timeline.timelines: + transverse_timelines(child, bones[0], timestamp) showm.render() diff --git a/docs/tutorials/01_introductory/viz_skinning_bones.py b/docs/tutorials/01_introductory/viz_skinning_bones.py index c1f8c667a..8b27d641a 100644 --- a/docs/tutorials/01_introductory/viz_skinning_bones.py +++ b/docs/tutorials/01_introductory/viz_skinning_bones.py @@ -37,11 +37,11 @@ bones = gltf_obj.bones[0] parent_transforms = gltf_obj.bone_tranforms -# target_bone = 12 -# print(parent_transforms[target_bone], '\n') +target_bone = 2 +print(parent_transforms[target_bone], '\n') # print(timeline.get_value(f'transform{target_bone}', 0.0), '\n') # print(timeline.get_value(f'transform{target_bone}', 1.25)) - +matrix2 = [] def timer_callback(_obj, _event): timeline.update_animation() diff --git a/fury/gltf.py b/fury/gltf.py index fdc357f37..82aa9f79c 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -806,10 +806,10 @@ def get_joint_actors(self, length=0.5): for bone in self.bones[0]: # print(transf) arrow = actor.arrow(origin, [0, 1, 0], [1, 0, 0], scales=length) - verts = utils.vertices_from_actor(arrow) - verts[:] = transform.apply_transfomation(verts, - parent_transforms[bone]) - utils.update_actor(arrow) + # verts = utils.vertices_from_actor(arrow) + # verts[:] = transform.apply_transfomation(verts, + # parent_transforms[bone]) + # utils.update_actor(arrow) actors[bone] = arrow # actors[bone] = arrow return actors From 1fbfcac174a25f8be59d1d436282f6de5320c7c5 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Tue, 13 Sep 2022 20:22:24 +0530 Subject: [PATCH 04/25] removing unnessesary examples --- .../01_introductory/viz_gltf_animated.py | 13 +- .../01_introductory/viz_gltf_animation.py | 53 ------- .../viz_simple_gltf_animation.py | 136 ------------------ .../01_introductory/viz_skinning_bones.py | 5 - ...=> viz_skinning_hirerachical_transform.py} | 0 5 files changed, 6 insertions(+), 201 deletions(-) delete mode 100644 docs/tutorials/01_introductory/viz_gltf_animation.py delete mode 100644 docs/tutorials/01_introductory/viz_simple_gltf_animation.py rename docs/tutorials/01_introductory/{iz_skinning_hirerachical_transform.py => viz_skinning_hirerachical_transform.py} (100%) diff --git a/docs/tutorials/01_introductory/viz_gltf_animated.py b/docs/tutorials/01_introductory/viz_gltf_animated.py index 26113acf1..f6d14bdf9 100644 --- a/docs/tutorials/01_introductory/viz_gltf_animated.py +++ b/docs/tutorials/01_introductory/viz_gltf_animated.py @@ -2,7 +2,8 @@ ======================= Visualizing a glTF file ======================= -In this tutorial, we will show how to display a glTF file in a scene. +In this tutorial, we will show how to display a simple animated glTF in a +scene. """ from fury import window @@ -22,25 +23,23 @@ ############################################################################## # Retrieving the gltf model. -fetch_gltf('CesiumMilkTruck', 'glTF') +fetch_gltf('InterpolationTest', 'glTF') filename = read_viz_gltf('InterpolationTest') ############################################################################## # Initialize the glTF object and get actors using `actors` method. -# Note: You can always manually create actor from polydata, and apply texture -# or materials manually afterwards. -# Experimental: For smooth mesh/actor you can set `apply_normals=True`. +# Get the main_timeline (which contains multiple Timeline objects). gltf_obj = glTF(filename) timeline = gltf_obj.get_main_timeline() ############################################################################## -# Add all the actor from list of actors to the scene. +# Add the timeline to the scene (No need to add actors seperately). scene.add(timeline) ############################################################################## -# Applying camera +# define a timer_callback that updates the timeline. def timer_callback(_obj, _event): diff --git a/docs/tutorials/01_introductory/viz_gltf_animation.py b/docs/tutorials/01_introductory/viz_gltf_animation.py deleted file mode 100644 index 541af1690..000000000 --- a/docs/tutorials/01_introductory/viz_gltf_animation.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -======================= -Visualizing a glTF file -======================= -In this tutorial, we will show how to display a glTF file in a scene. -""" - -from fury import window -from fury.gltf import glTF -from fury.data import fetch_gltf, read_viz_gltf - -############################################################################## -# Create a scene. - -scene = window.Scene() - -showm = window.ShowManager(scene, - size=(900, 768), reset_camera=False, - order_transparent=True) -showm.initialize() - - -############################################################################## -# Retrieving the gltf model. -fetch_gltf('BoxAnimated', 'glTF') -filename = read_viz_gltf('BoxAnimated') - -############################################################################## -# Initialize the glTF object and get actors using `actors` method. -# Note: You can always manually create actor from polydata, and apply texture -# or materials manually afterwards. -# Experimental: For smooth mesh/actor you can set `apply_normals=True`. - -gltf_obj = glTF(filename) -timeline = gltf_obj.get_main_timeline() - -############################################################################## -# Add all the actor from list of actors to the scene. - -scene.add(timeline) - -############################################################################## -# Applying camera - - -def timer_callback(_obj, _event): - timeline.update_animation() - showm.render() - - -showm.add_timer_callback(True, 10, timer_callback) - -showm.start() diff --git a/docs/tutorials/01_introductory/viz_simple_gltf_animation.py b/docs/tutorials/01_introductory/viz_simple_gltf_animation.py deleted file mode 100644 index db8e89291..000000000 --- a/docs/tutorials/01_introductory/viz_simple_gltf_animation.py +++ /dev/null @@ -1,136 +0,0 @@ -import numpy as np -from fury import window -from fury.animation.timeline import Timeline -from fury.animation.interpolator import (linear_interpolator, - step_interpolator, slerp) -from fury.animation import helpers -from fury.gltf import glTF -from fury.data import fetch_gltf, read_viz_gltf - -scene = window.Scene() - -showm = window.ShowManager(scene, - size=(900, 768), reset_camera=False, - order_transparent=True) -showm.initialize() - - -def tan_cubic_spline_interpolator(keyframes): - # First we must get ordered timestamps array: - timestamps = helpers.get_timestamps_from_keyframes(keyframes) - - for time in keyframes: - data = keyframes.get(time) - value = data.get('value') - if data.get('in_tangent') is None: - data['in_tangent'] = np.zeros_like(value) - if data.get('in_tangent') is None: - data['in_tangent'] = np.zeros_like(value) - - def interpolate(t): - # `get_previous_timestamp`and `get_next_timestamp` functions take - # timestamps array and current time as inputs and returns the - # surrounding timestamps. - t0 = helpers.get_previous_timestamp(timestamps, t) - t1 = helpers.get_next_timestamp(timestamps, t) - - # `get_time_tau` function takes current time and surrounding - # timestamps and returns a value from 0 to 1 - dt = helpers.get_time_tau(t, t0, t1) - - time_delta = t1 - t0 - - p0 = keyframes.get(t0).get('value') - tan_0 = keyframes.get(t0).get('out_tangent') * time_delta - p1 = keyframes.get(t1).get('value') - tan_1 = keyframes.get(t1).get('in_tangent') * time_delta - # cubic spline equation using tangents - t2 = dt * dt - t3 = t2 * dt - return (2 * t3 - 3 * t2 + 1) * p0 + (t3 - 2 * t2 + dt) * tan_0 + ( - -2 * t3 + 3 * t2) * p1 + (t3 - t2) * tan_1 - return interpolate - - -fetch_gltf('InterpolationTest', 'glTF') -filename = read_viz_gltf('InterpolationTest') - -gltf_obj = glTF(filename) -actors = gltf_obj.actors() - -print(len(actors)) - -# simplyfy the example, add the followingcode to a function indide the glTF -# object. -transforms = gltf_obj.node_transform -nodes = gltf_obj.nodes - -print(nodes) - -interpolator = { - 'LINEAR': linear_interpolator, - 'STEP': step_interpolator, - 'CUBICSPLINE': tan_cubic_spline_interpolator -} - -main_timeline = Timeline(playback_panel=True) - -for transform in transforms: - target_node = transform['node'] - for i, node_list in enumerate(nodes): - if target_node in node_list: - timeline = Timeline() - timeline.add_actor(actors[i]) - - timeframes = transform['input'] - transforms = transform['output'] - prop = transform['property'] - interp = interpolator.get(transform['interpolation']) - timeshape = timeframes.shape - transhape = transforms.shape - if transform['interpolation'] == 'CUBICSPLINE': - transforms = transforms.reshape((timeshape[0], -1, transhape[1])) - - for time, node_tran in zip(timeframes, transforms): - - in_tan, out_tan = None, None - if node_tran.ndim == 2: - cubicspline = node_tran - in_tan = cubicspline[0] - node_tran = cubicspline[1] - out_tan = cubicspline[2] - - if prop == 'rotation': - timeline.set_rotation(time[0], node_tran, - in_tangent=in_tan, - out_tangent=out_tan) - - timeline.set_rotation_interpolator(slerp) - if prop == 'translation': - timeline.set_position(time[0], node_tran, - in_tangent=in_tan, - out_tangent=out_tan) - - timeline.set_position_interpolator(interp) - if prop == 'scale': - timeline.set_scale(time[0], node_tran, - in_tangent=in_tan, - out_tangent=out_tan) - timeline.set_scale_interpolator(interp) - main_timeline.add_timeline(timeline) - else: - print('Adding static actor') - main_timeline.add_static_actor(actors[i]) - -scene.add(main_timeline) - - -def timer_callback(_obj, _event): - main_timeline.update_animation() - showm.render() - - -# Adding the callback function that updates the animation -showm.add_timer_callback(True, 10, timer_callback) - -showm.start() diff --git a/docs/tutorials/01_introductory/viz_skinning_bones.py b/docs/tutorials/01_introductory/viz_skinning_bones.py index 8b27d641a..fee4b5df0 100644 --- a/docs/tutorials/01_introductory/viz_skinning_bones.py +++ b/docs/tutorials/01_introductory/viz_skinning_bones.py @@ -37,11 +37,6 @@ bones = gltf_obj.bones[0] parent_transforms = gltf_obj.bone_tranforms -target_bone = 2 -print(parent_transforms[target_bone], '\n') -# print(timeline.get_value(f'transform{target_bone}', 0.0), '\n') -# print(timeline.get_value(f'transform{target_bone}', 1.25)) -matrix2 = [] def timer_callback(_obj, _event): timeline.update_animation() diff --git a/docs/tutorials/01_introductory/iz_skinning_hirerachical_transform.py b/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py similarity index 100% rename from docs/tutorials/01_introductory/iz_skinning_hirerachical_transform.py rename to docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py From 8463b0bf8b568fd04b60a8aac7f0acaa1a1c9fe6 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Tue, 13 Sep 2022 20:24:13 +0530 Subject: [PATCH 05/25] modifying tutorial --- docs/tutorials/01_introductory/viz_gltf.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_gltf.py b/docs/tutorials/01_introductory/viz_gltf.py index 009fc2938..d615eef95 100644 --- a/docs/tutorials/01_introductory/viz_gltf.py +++ b/docs/tutorials/01_introductory/viz_gltf.py @@ -13,6 +13,7 @@ # Create a scene. scene = window.Scene() +scene.SetBackground(0.1, 0.1, 0.4) ############################################################################## # Retrieving the gltf model. @@ -25,7 +26,7 @@ # or materials manually afterwards. # Experimental: For smooth mesh/actor you can set `apply_normals=True`. -gltf_obj = glTF(filename, apply_normals=True) +gltf_obj = glTF(filename) actors = gltf_obj.actors() ############################################################################## @@ -40,7 +41,7 @@ if cameras: scene.SetActiveCamera(cameras[0]) -interactive = True +interactive = False if interactive: window.show(scene, size=(1280, 720)) From 4faea2692074766fda11d7a7ab5f4b5745d32e72 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Wed, 14 Sep 2022 02:33:42 +0530 Subject: [PATCH 06/25] first working prototype --- .../01_introductory/viz_skinning_bones.py | 9 ++--- .../viz_skinning_hirerachical_transform.py | 28 +++++++++----- fury/gltf.py | 37 +++++++++++-------- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning_bones.py b/docs/tutorials/01_introductory/viz_skinning_bones.py index fee4b5df0..2bcf5e7ca 100644 --- a/docs/tutorials/01_introductory/viz_skinning_bones.py +++ b/docs/tutorials/01_introductory/viz_skinning_bones.py @@ -7,7 +7,7 @@ scene = window.Scene() fetch_gltf('SimpleSkin', 'glTF') -filename = read_viz_gltf('RiggedFigure') +filename = read_viz_gltf('SimpleSkin') gltf_obj = glTF(filename, apply_normals=False) actors = gltf_obj.actors() @@ -34,7 +34,7 @@ scene.add(* bactors.values()) scene.add(timeline) -bones = gltf_obj.bones[0] +bones = gltf_obj.bones parent_transforms = gltf_obj.bone_tranforms @@ -47,7 +47,7 @@ def timer_callback(_obj, _event): if timeline.is_interpolatable(f'transform{bone}'): deform = timeline.get_value(f'transform{bone}', timeline.current_timestamp) - ibm = gltf_obj.ibms[0][i].T + ibm = gltf_obj.ibms[bone].T ibms.append(ibm) parent_transform = parent_transforms[bone] @@ -59,8 +59,7 @@ def timer_callback(_obj, _event): bverts[i][:] = transform.apply_transfomation(bvert_copy[i], deform) utils.update_actor(bactors[bone]) - vertices[:] = gltf_obj.apply_skin_matrix(clone, joint_matrices, - bones, ibms) + vertices[:] = gltf_obj.apply_skin_matrix(clone, joint_matrices) utils.update_actor(actors[0]) utils.compute_bounds(actors[0]) showm.render() diff --git a/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py b/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py index 18f86f661..c1f14ae13 100644 --- a/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py +++ b/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py @@ -7,12 +7,11 @@ scene = window.Scene() -fetch_gltf('SimpleSkin', 'glTF') +fetch_gltf('RiggedFigure', 'glTF') filename = read_viz_gltf('CesiumMan') -gltf_obj = glTF(filename, apply_normals=False) +gltf_obj = glTF(filename, apply_normals=True) actors = gltf_obj.actors() -print(len(actors)) vertices = utils.vertices_from_actor(actors[0]) clone = np.copy(vertices) @@ -35,32 +34,43 @@ scene.add(* bactors.values()) scene.add(timeline) -bones = gltf_obj.bones[0] +bones = gltf_obj.bones parent_transforms = gltf_obj.bone_tranforms -def transverse_timelines(timeline, bone_id, timestamp, +def transverse_timelines(timeline, bone_id, timestamp, joint_matrices, parent_bone_deform=np.identity(4)): deform = timeline.get_value('transform', timestamp) new_deform = np.dot(parent_bone_deform, deform) + # calculating skinning metrix + ibm = gltf_obj.ibms[bone_id].T + parent_transform = parent_transforms[bone_id] + skin_matrix = np.dot(new_deform, ibm) + # skin_matrix = np.dot(skin_matrix, ibm) + joint_matrices[bone_id] = skin_matrix + node = gltf_obj.gltf.nodes[bone_id] bverts[bone_id][:] = transform.apply_transfomation(bvert_copy[bone_id], new_deform) utils.update_actor(bactors[bone_id]) - # if bone_id == 11: - # print(bverts[bone_id]) if node.children: for c_timeline, c_bone in zip(timeline.timelines, node.children): - transverse_timelines(c_timeline, c_bone, timestamp, new_deform) + transverse_timelines(c_timeline, c_bone, timestamp, + joint_matrices, new_deform) def timer_callback(_obj, _event): timeline.update_animation() timestamp = timeline.current_timestamp + joint_matrices = {} for child in timeline.timelines: - transverse_timelines(child, bones[0], timestamp) + transverse_timelines(child, bones[0], timestamp, joint_matrices) + # print(len(joint_matrices.keys())) + vertices[:] = gltf_obj.apply_skin_matrix(clone, joint_matrices) + utils.update_actor(actors[0]) + utils.compute_bounds(actors[0]) showm.render() diff --git a/fury/gltf.py b/fury/gltf.py index 82aa9f79c..5ac60979c 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -78,7 +78,7 @@ def __init__(self, filename, apply_normals=False): self.joints_0 = [] self.weights_0 = [] self.bones = [] - self.ibms = [] + self.ibms = {} self.vertices = [] self.child_timelines = [] @@ -188,8 +188,9 @@ def transverse_node(self, nextnode_id, matrix, parent=None, isJoint=False): if node.skin is not None: skin_id = node.skin joints, ibms = self.get_skin_data(skin_id) - self.bones.append(joints) # for each skin will contain nodes - self.ibms.append(ibms) + for bone, ibm in zip(joints, ibms): + self.bones.append(bone) + self.ibms[bone] = ibm self.transverse_node(joints[0], np.identity(4), parent, isJoint=True) if node.camera is not None: @@ -554,7 +555,7 @@ def generate_tmatrix(self, transf, prop): return matrix def apply_skin_matrix(self, vertices, - joint_matrices, bones, ibms=None): + joint_matrices): """Applies the skinnig matrix, that transforms the vertices. NOTE: vertices has joint_matrix applied already. @@ -573,6 +574,7 @@ def apply_skin_matrix(self, vertices, for i, xyz in enumerate(clone): a_joint = joints[i] + a_joint = [self.bones[i] for i in a_joint] a_weight = weights[i] skin_mat = \ @@ -629,13 +631,14 @@ def get_skin_timeline2(self): timeline = Timeline(playback_panel=True) for target, transforms in self.sampler_matrices.items(): # target = transforms['node'] - for i, bone in enumerate(self.bones[0]): + for i, bone in enumerate(self.bones): if target == bone: timestamps = transforms['timestamps'] mertices = transforms['matrix'] for time, matrix in zip(timestamps, mertices): - timeline.set_keyframe(f'transform{bone}', time[0], matrix) + timeline.set_keyframe(f'transform{bone}', + time[0], matrix) # else: # timeline.set_keyframe(f'transform{bone}', 0.0, np.identity(4)) @@ -650,12 +653,16 @@ def transverse_bones(self, bone_id, parent_timeline: Timeline): """ node = self.gltf.nodes[bone_id] timeline = Timeline(playback_panel=False) - transforms = self.sampler_matrices[bone_id] - timestamps = transforms['timestamps'] - metrices = transforms['matrix'] - - for time, matrix in zip(timestamps, metrices): - timeline.set_keyframe('transform', time[0], matrix) + # transforms = self.sampler_matrices[bone_id] + if bone_id in self.sampler_matrices: + transforms = self.sampler_matrices[bone_id] + timestamps = transforms['timestamps'] + metrices = transforms['matrix'] + + for time, matrix in zip(timestamps, metrices): + timeline.set_keyframe('transform', time[0], matrix) + else: + timeline.set_keyframe('transform', 0.0, np.identity(4)) if node.children: for child_bone in node.children: @@ -669,7 +676,7 @@ def get_skin_timeline3(self): """ root_timeline = Timeline(playback_panel=True) root_bone = self.gltf.skins[0].skeleton - root_bone = root_bone if root_bone else self.bones[0][0] + root_bone = root_bone if root_bone else self.bones[0] self.transverse_bones(root_bone, root_timeline) return root_timeline @@ -797,13 +804,13 @@ def interpolate(t): return interpolate - def get_joint_actors(self, length=0.5): + def get_joint_actors(self, length=0.5, with_transforms=False): origin = np.zeros((3, 3)) actors = {} # print(self.bone_tranforms) parent_transforms = self.bone_tranforms # print(parent_transforms) - for bone in self.bones[0]: + for bone in self.bones: # print(transf) arrow = actor.arrow(origin, [0, 1, 0], [1, 0, 0], scales=length) # verts = utils.vertices_from_actor(arrow) From c9576a4bb2a489eaf70a61dba25b1483f01501f5 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Wed, 14 Sep 2022 03:09:51 +0530 Subject: [PATCH 07/25] made it optional to get the bones in position --- .../viz_skinning_hirerachical_transform.py | 6 +-- fury/gltf.py | 43 +++++++++++-------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py b/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py index c1f14ae13..b6e5a3e92 100644 --- a/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py +++ b/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py @@ -1,16 +1,16 @@ +import copy import numpy as np from fury import window, utils, actor, transform from fury.gltf import glTF from fury.data import fetch_gltf, read_viz_gltf from fury.lib import Transform -import copy scene = window.Scene() fetch_gltf('RiggedFigure', 'glTF') -filename = read_viz_gltf('CesiumMan') +filename = read_viz_gltf('SimpleSkin') -gltf_obj = glTF(filename, apply_normals=True) +gltf_obj = glTF(filename, apply_normals=False) actors = gltf_obj.actors() vertices = utils.vertices_from_actor(actors[0]) diff --git a/fury/gltf.py b/fury/gltf.py index 5ac60979c..93a86d7eb 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -680,6 +680,29 @@ def get_skin_timeline3(self): self.transverse_bones(root_bone, root_timeline) return root_timeline + def get_joint_actors(self, length=0.5, with_transforms=False): + """Creates an arrow actor for each bone in a skinned model. + + Parameters + ---------- + length : float (default = 0.5) + Length of the arrow actor + with_transforms : bool (default = False) + """ + origin = np.zeros((3, 3)) + actors = {} + parent_transforms = self.bone_tranforms + + for bone in self.bones: + arrow = actor.arrow(origin, [0, 1, 0], [1, 0, 0], scales=length) + if with_transforms: + verts = utils.vertices_from_actor(arrow) + verts[:] = transform.apply_transfomation( + verts, parent_transforms[bone]) + utils.update_actor(arrow) + actors[bone] = arrow + return actors + def get_animation_timelines(self): """Returns list of animation timeline. @@ -796,30 +819,12 @@ def interpolate(t): joint_mat = np.dot(joint_mat, ibm) joint_matrices.append(joint_mat) - vertices[:] = self.apply_skin_matrix(clone, joint_matrices, bones) + vertices[:] = self.apply_skin_matrix(clone, joint_matrices) utils.update_actor(actor) utils.compute_bounds(actor) - # print('updating actor') return vertices return interpolate - - def get_joint_actors(self, length=0.5, with_transforms=False): - origin = np.zeros((3, 3)) - actors = {} - # print(self.bone_tranforms) - parent_transforms = self.bone_tranforms - # print(parent_transforms) - for bone in self.bones: - # print(transf) - arrow = actor.arrow(origin, [0, 1, 0], [1, 0, 0], scales=length) - # verts = utils.vertices_from_actor(arrow) - # verts[:] = transform.apply_transfomation(verts, - # parent_transforms[bone]) - # utils.update_actor(arrow) - actors[bone] = arrow - # actors[bone] = arrow - return actors def tan_cubic_spline_interpolator(keyframes): From 67b6493e1a9c91e4d896735c91f538ce12f35c3f Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Thu, 15 Sep 2022 03:20:36 +0530 Subject: [PATCH 08/25] fixes camera --- .../tutorials/01_introductory/viz_skinning.py | 68 ++++++---- .../01_introductory/viz_skinning_bones.py | 70 ----------- .../viz_skinning_hirerachical_transform.py | 79 ------------ fury/gltf.py | 116 +++++++----------- 4 files changed, 90 insertions(+), 243 deletions(-) delete mode 100644 docs/tutorials/01_introductory/viz_skinning_bones.py delete mode 100644 docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index 66dffe9f6..a98c24d4a 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -1,3 +1,4 @@ +import copy import numpy as np from fury import window, utils, actor, transform from fury.gltf import glTF @@ -6,49 +7,72 @@ scene = window.Scene() -fetch_gltf('SimpleSkin', 'glTF') +fetch_gltf('RiggedFigure', 'glTF') filename = read_viz_gltf('RiggedFigure') gltf_obj = glTF(filename, apply_normals=False) actors = gltf_obj.actors() +# Setting custom opacity to see the bones +# for act in actors: +# act.GetProperty().SetOpacity(0.7) + vertices = utils.vertices_from_actor(actors[0]) clone = np.copy(vertices) timeline = gltf_obj.get_skin_timeline() -timeline.add_actor(actors[0]) +timeline.add_actor(actors) scene = window.Scene() -showm = window.ShowManager(scene, size=(900, 768), reset_camera=False, +showm = window.ShowManager(scene, size=(900, 768), reset_camera=True, order_transparent=True) showm.initialize() +bactors = gltf_obj.get_joint_actors(length=0.2, with_transforms=False) +bverts = {} +for bone, joint_actor in bactors.items(): + bverts[bone] = utils.vertices_from_actor(joint_actor) + +bvert_copy = copy.deepcopy(bverts) + scene.add(timeline) +scene.add(* bactors.values()) -bones = gltf_obj.bones[0] +bones = gltf_obj.bones parent_transforms = gltf_obj.bone_tranforms -# print(parent_transforms) + + +def transverse_timelines(timeline, bone_id, timestamp, joint_matrices, + parent_bone_deform=np.identity(4)): + deform = timeline.get_value('transform', timestamp) + new_deform = np.dot(parent_bone_deform, deform) + + # calculating skinning metrix + ibm = gltf_obj.ibms[bone_id].T + skin_matrix = np.dot(new_deform, ibm) + joint_matrices[bone_id] = skin_matrix + + node = gltf_obj.gltf.nodes[bone_id] + actor_transform = gltf_obj.transformations[0] + bone_transform = np.dot(actor_transform, new_deform) + bverts[bone_id][:] = transform.apply_transfomation(bvert_copy[bone_id], + bone_transform) + utils.update_actor(bactors[bone_id]) + if node.children: + for c_timeline, c_bone in zip(timeline.timelines, node.children): + transverse_timelines(c_timeline, c_bone, timestamp, + joint_matrices, new_deform) def timer_callback(_obj, _event): timeline.update_animation() - joint_matrices = [] - ibms = [] - for i, bone in enumerate(bones): - if timeline.is_interpolatable(f'transform{bone}'): - deform = timeline.get_value(f'transform{bone}', - timeline.current_timestamp) - ibm = gltf_obj.ibms[0][i].T - ibms.append(ibm) - - parent_transform = parent_transforms[bone] - joint_mat = np.dot(parent_transform, deform) - joint_mat = np.dot(joint_mat, ibm) - joint_matrices.append(joint_mat) - # parent_transforms[bone] = np.dot(parent_transform, deform) - - vertices[:] = gltf_obj.apply_skin_matrix(clone, joint_matrices, - bones, ibms) + timestamp = timeline.current_timestamp + joint_matrices = {} + + for child in timeline.timelines: + transverse_timelines(child, bones[0], timestamp, joint_matrices) + + vertices[:] = gltf_obj.apply_skin_matrix(clone, joint_matrices) utils.update_actor(actors[0]) utils.compute_bounds(actors[0]) showm.render() diff --git a/docs/tutorials/01_introductory/viz_skinning_bones.py b/docs/tutorials/01_introductory/viz_skinning_bones.py deleted file mode 100644 index 2bcf5e7ca..000000000 --- a/docs/tutorials/01_introductory/viz_skinning_bones.py +++ /dev/null @@ -1,70 +0,0 @@ -import numpy as np -from fury import window, utils, actor, transform -from fury.gltf import glTF -from fury.data import fetch_gltf, read_viz_gltf -from fury.lib import Transform - -scene = window.Scene() - -fetch_gltf('SimpleSkin', 'glTF') -filename = read_viz_gltf('SimpleSkin') - -gltf_obj = glTF(filename, apply_normals=False) -actors = gltf_obj.actors() -print(len(actors)) - -vertices = utils.vertices_from_actor(actors[0]) -clone = np.copy(vertices) - -timeline = gltf_obj.get_skin_timeline2() -timeline.add_actor(actors[0]) - -scene = window.Scene() -showm = window.ShowManager(scene, size=(900, 768), reset_camera=False, - order_transparent=True) -showm.initialize() - -bactors = gltf_obj.get_joint_actors(length=0.2) -bverts = [] -for bone, joint_actor in bactors.items(): - bverts.append(utils.vertices_from_actor(joint_actor)) - -bvert_copy = np.copy(bverts) - -scene.add(* bactors.values()) -scene.add(timeline) - -bones = gltf_obj.bones -parent_transforms = gltf_obj.bone_tranforms - - -def timer_callback(_obj, _event): - timeline.update_animation() - joint_matrices = [] - ibms = [] - - for i, bone in enumerate(bones): - if timeline.is_interpolatable(f'transform{bone}'): - deform = timeline.get_value(f'transform{bone}', - timeline.current_timestamp) - ibm = gltf_obj.ibms[bone].T - ibms.append(ibm) - - parent_transform = parent_transforms[bone] - joint_mat = np.dot(parent_transform, deform) - joint_mat = np.dot(joint_mat, ibm) - joint_matrices.append(joint_mat) - - # if bone == 12: - bverts[i][:] = transform.apply_transfomation(bvert_copy[i], deform) - utils.update_actor(bactors[bone]) - - vertices[:] = gltf_obj.apply_skin_matrix(clone, joint_matrices) - utils.update_actor(actors[0]) - utils.compute_bounds(actors[0]) - showm.render() - - -showm.add_timer_callback(True, 10, timer_callback) - -showm.start() diff --git a/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py b/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py deleted file mode 100644 index b6e5a3e92..000000000 --- a/docs/tutorials/01_introductory/viz_skinning_hirerachical_transform.py +++ /dev/null @@ -1,79 +0,0 @@ -import copy -import numpy as np -from fury import window, utils, actor, transform -from fury.gltf import glTF -from fury.data import fetch_gltf, read_viz_gltf -from fury.lib import Transform - -scene = window.Scene() - -fetch_gltf('RiggedFigure', 'glTF') -filename = read_viz_gltf('SimpleSkin') - -gltf_obj = glTF(filename, apply_normals=False) -actors = gltf_obj.actors() - -vertices = utils.vertices_from_actor(actors[0]) -clone = np.copy(vertices) - -timeline = gltf_obj.get_skin_timeline3() -timeline.add_actor(actors[0]) - -scene = window.Scene() -showm = window.ShowManager(scene, size=(900, 768), reset_camera=False, - order_transparent=True) -showm.initialize() - -bactors = gltf_obj.get_joint_actors(length=0.2) -bverts = {} -for bone, joint_actor in bactors.items(): - bverts[bone] = utils.vertices_from_actor(joint_actor) - -bvert_copy = copy.deepcopy(bverts) - -scene.add(* bactors.values()) -scene.add(timeline) - -bones = gltf_obj.bones -parent_transforms = gltf_obj.bone_tranforms - - -def transverse_timelines(timeline, bone_id, timestamp, joint_matrices, - parent_bone_deform=np.identity(4)): - deform = timeline.get_value('transform', timestamp) - new_deform = np.dot(parent_bone_deform, deform) - - # calculating skinning metrix - ibm = gltf_obj.ibms[bone_id].T - parent_transform = parent_transforms[bone_id] - skin_matrix = np.dot(new_deform, ibm) - # skin_matrix = np.dot(skin_matrix, ibm) - joint_matrices[bone_id] = skin_matrix - - node = gltf_obj.gltf.nodes[bone_id] - bverts[bone_id][:] = transform.apply_transfomation(bvert_copy[bone_id], - new_deform) - utils.update_actor(bactors[bone_id]) - if node.children: - for c_timeline, c_bone in zip(timeline.timelines, node.children): - transverse_timelines(c_timeline, c_bone, timestamp, - joint_matrices, new_deform) - - -def timer_callback(_obj, _event): - timeline.update_animation() - timestamp = timeline.current_timestamp - joint_matrices = {} - - for child in timeline.timelines: - transverse_timelines(child, bones[0], timestamp, joint_matrices) - # print(len(joint_matrices.keys())) - vertices[:] = gltf_obj.apply_skin_matrix(clone, joint_matrices) - utils.update_actor(actors[0]) - utils.compute_bounds(actors[0]) - showm.render() - - -showm.add_timer_callback(True, 10, timer_callback) - -showm.start() diff --git a/fury/gltf.py b/fury/gltf.py index 93a86d7eb..01c05cc7b 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -99,9 +99,9 @@ def actors(self): position, rot, scale = transform.trs_from_matrix(transform_mat) # We don't need this as we are already applying it in skinnning part - # actor.SetPosition(position) - # actor.SetScale(scale) - # actor.RotateWXYZ(*rot) + actor.SetPosition(position) + actor.SetScale(scale) + actor.RotateWXYZ(*rot) if self.materials[i] is not None: base_col_tex = self.materials[i]['baseColorTexture'] @@ -170,7 +170,6 @@ def transverse_node(self, nextnode_id, matrix, parent=None, isJoint=False): matnode = np.dot(matnode, scale) next_matrix = np.dot(matrix, matnode) - # print(f'node: {nextnode_id}\nmatrix: \n{next_matrix}\n') if (nextnode_id in self.gltf.skins[0].joints and nextnode_id not in self.bone_tranforms): @@ -178,7 +177,6 @@ def transverse_node(self, nextnode_id, matrix, parent=None, isJoint=False): if isJoint: if not (nextnode_id in self.bone_tranforms): - # print(f'Not there {nextnode_id}') self.bone_tranforms[nextnode_id] = next_matrix[:] if node.mesh is not None: @@ -191,7 +189,8 @@ def transverse_node(self, nextnode_id, matrix, parent=None, isJoint=False): for bone, ibm in zip(joints, ibms): self.bones.append(bone) self.ibms[bone] = ibm - self.transverse_node(joints[0], np.identity(4), parent, isJoint=True) + self.transverse_node(joints[0], np.identity(4), parent, + isJoint=True) if node.camera is not None: camera_id = node.camera @@ -537,11 +536,23 @@ def get_matrix_from_sampler(self, prop, node, sampler: gltflib.Sampler): self.sampler_matrices[node] = data def get_skin_data(self, skin_id): + """Gets the inverse bind matrix for each bone in the skin. + + Parameters + ---------- + skin_id : int + Index of the skin. + + Returns + ------- + joint_nodes : list + List of bones in the skin. + inv_bind_matrix : ndarray + Numpy array containing inverse bind pose for each bone. + """ skin = self.gltf.skins[skin_id] inv_bind_matrix = self.get_acc_data(skin.inverseBindMatrices) - # print(inv_bind_matrix) inv_bind_matrix = inv_bind_matrix.reshape((-1, 4, 4)) - # print(f'ibm:\n{inv_bind_matrix}') joint_nodes = skin.joints return joint_nodes, inv_bind_matrix @@ -554,11 +565,17 @@ def generate_tmatrix(self, transf, prop): matrix = transform.scale(transf) return matrix - def apply_skin_matrix(self, vertices, - joint_matrices): + def apply_skin_matrix(self, vertices, joint_matrices): """Applies the skinnig matrix, that transforms the vertices. - NOTE: vertices has joint_matrix applied already. + + Parameters + ---------- + vertices : ndarray + Vertices of an actor. + join_matrices : list + List of skinning matrix to calculate the weighted transformation. + Returns ------- vertices : ndarray @@ -568,10 +585,6 @@ def apply_skin_matrix(self, vertices, weights = self.weights_0[0] joints = self.joints_0[0] - # if ibms is not None: - # for ibm in ibms: - # clone = transform.apply_transfomation(clone, ibm) - for i, xyz in enumerate(clone): a_joint = joints[i] a_joint = [self.bones[i] for i in a_joint] @@ -589,61 +602,6 @@ def apply_skin_matrix(self, vertices, return clone - def get_skin_timeline(self): - """Returns list of animation timeline. - - Returns - ------- - timeline : Timeline - Timelines containing actors. - """ - # actors = self.actors() - - timeline = Timeline(playback_panel=True) - for num, transforms in enumerate(self.node_transform): - target_node = transforms['node'] - - for i, nodes in enumerate(self.bones[0]): - - if target_node == nodes: - timestamp = transforms['input'] - transform = transforms['output'] - prop = transforms['property'] - # timeline.set_keyframe(f'transform{nodes}', 0., transform) - for time, trs in zip(timestamp, transform): - matrix = self.generate_tmatrix(trs, prop) - if num > 0: - prev_matrix = timeline.get_value(f'transform{nodes}', time[0]) - matrix = np.dot(prev_matrix, matrix) - timeline.set_keyframe(f'transform{nodes}', time[0], matrix) - # print(f'timestap: {time[0]} node: {nodes}') - else: - # print(f'target node is not nodes {target_node} {nodes}') - transform = np.identity(4) - timeline.set_keyframe(f'transform{nodes}', 0.0, transform) - - return timeline - - def get_skin_timeline2(self): - """Alternate version of `get_skin_timeline` - Using pre-multiplied matrices. - """ - timeline = Timeline(playback_panel=True) - for target, transforms in self.sampler_matrices.items(): - # target = transforms['node'] - for i, bone in enumerate(self.bones): - if target == bone: - timestamps = transforms['timestamps'] - mertices = transforms['matrix'] - - for time, matrix in zip(timestamps, mertices): - timeline.set_keyframe(f'transform{bone}', - time[0], matrix) - - # else: - # timeline.set_keyframe(f'transform{bone}', 0.0, np.identity(4)) - return timeline - def transverse_bones(self, bone_id, parent_timeline: Timeline): """ bone_id : int @@ -653,7 +611,6 @@ def transverse_bones(self, bone_id, parent_timeline: Timeline): """ node = self.gltf.nodes[bone_id] timeline = Timeline(playback_panel=False) - # transforms = self.sampler_matrices[bone_id] if bone_id in self.sampler_matrices: transforms = self.sampler_matrices[bone_id] timestamps = transforms['timestamps'] @@ -671,8 +628,13 @@ def transverse_bones(self, bone_id, parent_timeline: Timeline): self.child_timelines.append(timeline) parent_timeline.add(timeline) - def get_skin_timeline3(self): + def get_skin_timeline(self): """One timeline for each bone, contains parent transforms. + + Returns + ------- + root_timeline : Timeline + A timeline containing all the child timelines for bones. """ root_timeline = Timeline(playback_panel=True) root_bone = self.gltf.skins[0].skeleton @@ -688,6 +650,14 @@ def get_joint_actors(self, length=0.5, with_transforms=False): length : float (default = 0.5) Length of the arrow actor with_transforms : bool (default = False) + Applies respective transformations to bone. Bones will be at origin + if set to `False`. + + Returns + ------- + actors : dict + Dictionary conatining bones as keys and corresponding actor as + values. """ origin = np.zeros((3, 3)) actors = {} @@ -697,6 +667,8 @@ def get_joint_actors(self, length=0.5, with_transforms=False): arrow = actor.arrow(origin, [0, 1, 0], [1, 0, 0], scales=length) if with_transforms: verts = utils.vertices_from_actor(arrow) + actor_transf = self.transformations[0] + arrow_transf = np.dot(parent_transforms[bone], actor_transf) verts[:] = transform.apply_transfomation( verts, parent_transforms[bone]) utils.update_actor(arrow) From e59ba3cb4a48742d221bf6b6421262fe08c3454c Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Sun, 18 Sep 2022 22:47:29 +0530 Subject: [PATCH 09/25] removing unnessesary functions --- .../tutorials/01_introductory/viz_skinning.py | 3 +- fury/gltf.py | 74 ++----------------- 2 files changed, 8 insertions(+), 69 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index a98c24d4a..fd811e789 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -1,9 +1,8 @@ import copy import numpy as np -from fury import window, utils, actor, transform +from fury import window, utils, transform from fury.gltf import glTF from fury.data import fetch_gltf, read_viz_gltf -from fury.lib import Transform scene = window.Scene() diff --git a/fury/gltf.py b/fury/gltf.py index 01c05cc7b..34fb0c75e 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -4,9 +4,9 @@ import numpy as np import json import pygltflib as gltflib -from pygltflib.utils import glb2gltf +from pygltflib.utils import glb2gltf, gltf2glb from PIL import Image -from fury.lib import Texture, Camera +from fury.lib import Texture, Camera, numpy_support from fury import transform, utils, io, actor from fury.animation.timeline import Timeline from fury.animation.interpolator import (linear_interpolator, lerp, @@ -98,7 +98,7 @@ def actors(self): transform_mat = self.transformations[i] position, rot, scale = transform.trs_from_matrix(transform_mat) - # We don't need this as we are already applying it in skinnning part + # We don't need this as we are already applying it in skinnning actor.SetPosition(position) actor.SetScale(scale) actor.RotateWXYZ(*rot) @@ -171,9 +171,10 @@ def transverse_node(self, nextnode_id, matrix, parent=None, isJoint=False): next_matrix = np.dot(matrix, matnode) - if (nextnode_id in self.gltf.skins[0].joints and - nextnode_id not in self.bone_tranforms): - self.bone_tranforms[nextnode_id] = next_matrix[:] + if node.skin is not None: + if (nextnode_id in self.gltf.skins[0].joints and + nextnode_id not in self.bone_tranforms): + self.bone_tranforms[nextnode_id] = next_matrix[:] if isJoint: if not (nextnode_id in self.bone_tranforms): @@ -799,67 +800,6 @@ def interpolate(t): return interpolate -def tan_cubic_spline_interpolator(keyframes): - - timestamps = helpers.get_timestamps_from_keyframes(keyframes) - for time in keyframes: - data = keyframes.get(time) - value = data.get('value') - if data.get('in_tangent') is None: - data['in_tangent'] = np.zeros_like(value) - if data.get('in_tangent') is None: - data['in_tangent'] = np.zeros_like(value) - - def interpolate(t): - t0 = helpers.get_previous_timestamp(timestamps, t) - t1 = helpers.get_next_timestamp(timestamps, t) - - dt = helpers.get_time_tau(t, t0, t1) - - time_delta = t1 - t0 - - p0 = keyframes.get(t0).get('value') - tan_0 = keyframes.get(t0).get('out_tangent') * time_delta - p1 = keyframes.get(t1).get('value') - tan_1 = keyframes.get(t1).get('in_tangent') * time_delta - # cubic spline equation using tangents - t2 = dt * dt - t3 = t2 * dt - return (2 * t3 - 3 * t2 + 1) * p0 + (t3 - 2 * t2 + dt) * tan_0 + ( - -2 * t3 + 3 * t2) * p1 + (t3 - t2) * tan_1 - return interpolate - - -def transformation_interpolator(keyframes): - timestamps = helpers.get_timestamps_from_keyframes(keyframes) - for time in keyframes: - data = keyframes.get(time) - if data.get('in_matrix1') is None: - data['in_matrix1'] = np.identity(4) - if data.get('out_matrix1') is None: - data['out_matrix1'] = np.identity(4) - if data.get('in_matrix2') is None: - data['in_matrix2'] = np.identity(4) - if data.get('out_matrix2') is None: - data['out_matrix2'] = np.identity(4) - - def interpolate(t): - t0 = helpers.get_previous_timestamp(timestamps, t) - t1 = helpers.get_next_timestamp(timestamps, t) - - mat_0 = keyframes.get(t0).get('in_matrix1') - mat_1 = keyframes.get(t1).get('out_matrix1') - - mat_2 = keyframes.get(t0).get('in_matrix2') - mat_3 = keyframes.get(t1).get('out_matrix2') - - out_1 = lerp(mat_0, mat_1, t0, t1, t) - out_2 = lerp(mat_2, mat_3, t0, t1, t) - - return (out_1, out_2) - return interpolate - - def export_scene(scene, filename='default.gltf'): """Generate gltf from FURY scene. From 16d4fbd0d57d63f5c463a3cd12dd599814f87337 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Fri, 23 Sep 2022 20:49:22 +0530 Subject: [PATCH 10/25] skin --- docs/tutorials/01_introductory/viz_gltf.py | 2 +- .../tutorials/01_introductory/viz_skinning.py | 35 +++++++++++++------ fury/gltf.py | 22 +++++++----- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_gltf.py b/docs/tutorials/01_introductory/viz_gltf.py index d615eef95..46de7ca47 100644 --- a/docs/tutorials/01_introductory/viz_gltf.py +++ b/docs/tutorials/01_introductory/viz_gltf.py @@ -18,7 +18,7 @@ ############################################################################## # Retrieving the gltf model. fetch_gltf('Duck', 'glTF') -filename = read_viz_gltf('Duck') +filename = read_viz_gltf('BrainStem') ############################################################################## # Initialize the glTF object and get actors using `actors` method. diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index fd811e789..33de90eb1 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -1,22 +1,25 @@ import copy import numpy as np -from fury import window, utils, transform +from fury import window, transform +from fury.utils import vertices_from_actor, update_actor, compute_bounds from fury.gltf import glTF from fury.data import fetch_gltf, read_viz_gltf scene = window.Scene() fetch_gltf('RiggedFigure', 'glTF') -filename = read_viz_gltf('RiggedFigure') +filename = read_viz_gltf('BrainStem') -gltf_obj = glTF(filename, apply_normals=False) +gltf_obj = glTF(filename, apply_normals=True) actors = gltf_obj.actors() # Setting custom opacity to see the bones # for act in actors: # act.GetProperty().SetOpacity(0.7) -vertices = utils.vertices_from_actor(actors[0]) +vertices = [vertices_from_actor(actor) for actor in actors] + +# vertices = vertices_from_actor(actors[0]) clone = np.copy(vertices) timeline = gltf_obj.get_skin_timeline() @@ -30,7 +33,7 @@ bactors = gltf_obj.get_joint_actors(length=0.2, with_transforms=False) bverts = {} for bone, joint_actor in bactors.items(): - bverts[bone] = utils.vertices_from_actor(joint_actor) + bverts[bone] = vertices_from_actor(joint_actor) bvert_copy = copy.deepcopy(bverts) @@ -56,9 +59,11 @@ def transverse_timelines(timeline, bone_id, timestamp, joint_matrices, bone_transform = np.dot(actor_transform, new_deform) bverts[bone_id][:] = transform.apply_transfomation(bvert_copy[bone_id], bone_transform) - utils.update_actor(bactors[bone_id]) + update_actor(bactors[bone_id]) if node.children: - for c_timeline, c_bone in zip(timeline.timelines, node.children): + c_timelines = timeline.timelines + c_bones = node.children + for c_timeline, c_bone in zip(c_timelines, c_bones): transverse_timelines(c_timeline, c_bone, timestamp, joint_matrices, new_deform) @@ -67,13 +72,21 @@ def timer_callback(_obj, _event): timeline.update_animation() timestamp = timeline.current_timestamp joint_matrices = {} + root_bone = gltf_obj.gltf.skins[0].skeleton + root_bone = root_bone if root_bone else gltf_obj.bones[0] - for child in timeline.timelines: + # if not root_bone == gltf_obj.bones[0]: + # timeline = timeline.timelines[0] + # parent_deform = gltf_obj.nodes[root_bone] + for child in timeline.timelines[0].timelines: transverse_timelines(child, bones[0], timestamp, joint_matrices) - vertices[:] = gltf_obj.apply_skin_matrix(clone, joint_matrices) - utils.update_actor(actors[0]) - utils.compute_bounds(actors[0]) + # print(joint_matrices.keys()) + for i, vertex in enumerate(vertices): + # print(i) + vertex[:] = gltf_obj.apply_skin_matrix(clone[i], joint_matrices, i) + update_actor(actors[i]) + compute_bounds(actors[i]) showm.render() diff --git a/fury/gltf.py b/fury/gltf.py index 34fb0c75e..27d29bca9 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -81,6 +81,7 @@ def __init__(self, filename, apply_normals=False): self.ibms = {} self.vertices = [] self.child_timelines = [] + self.timeline_order = [] self.inspect_scene(0) @@ -106,6 +107,8 @@ def actors(self): if self.materials[i] is not None: base_col_tex = self.materials[i]['baseColorTexture'] actor.SetTexture(base_col_tex) + base_color = self.materials[i]['baseColor'] + actor.GetProperty().SetColor(tuple(base_color[:3])) self.actors_list.append(actor) @@ -373,8 +376,9 @@ def get_materials(self, mat_id): if pbr.baseColorTexture is not None: bct = pbr.baseColorTexture.index bct = self.get_texture(bct) - - return {'baseColorTexture': bct} + colors = pbr.baseColorFactor + return {'baseColorTexture': bct, + 'baseColor': colors} def get_texture(self, tex_id): """Read and convert image into vtk texture. @@ -566,7 +570,7 @@ def generate_tmatrix(self, transf, prop): matrix = transform.scale(transf) return matrix - def apply_skin_matrix(self, vertices, joint_matrices): + def apply_skin_matrix(self, vertices, joint_matrices, ac_index): """Applies the skinnig matrix, that transforms the vertices. NOTE: vertices has joint_matrix applied already. @@ -583,8 +587,8 @@ def apply_skin_matrix(self, vertices, joint_matrices): Modified vertices """ clone = np.copy(vertices) - weights = self.weights_0[0] - joints = self.joints_0[0] + weights = self.weights_0[ac_index] + joints = self.joints_0[ac_index] for i, xyz in enumerate(clone): a_joint = joints[i] @@ -622,12 +626,13 @@ def transverse_bones(self, bone_id, parent_timeline: Timeline): else: timeline.set_keyframe('transform', 0.0, np.identity(4)) + parent_timeline.add(timeline) + self.timeline_order.append(bone_id) if node.children: for child_bone in node.children: self.transverse_bones(child_bone, timeline) - else: - self.child_timelines.append(timeline) - parent_timeline.add(timeline) + # else: + # self.child_timelines.append(timeline) def get_skin_timeline(self): """One timeline for each bone, contains parent transforms. @@ -640,6 +645,7 @@ def get_skin_timeline(self): root_timeline = Timeline(playback_panel=True) root_bone = self.gltf.skins[0].skeleton root_bone = root_bone if root_bone else self.bones[0] + print(f'root bone: {root_bone}') self.transverse_bones(root_bone, root_timeline) return root_timeline From 97572400f1f882fc55087c36ce84f2372658bb20 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Mon, 26 Sep 2022 21:57:14 +0530 Subject: [PATCH 11/25] multi-actor support --- .../tutorials/01_introductory/viz_skinning.py | 35 +++++++------------ fury/gltf.py | 28 ++++++++++----- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index 33de90eb1..51571b337 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -10,17 +10,11 @@ fetch_gltf('RiggedFigure', 'glTF') filename = read_viz_gltf('BrainStem') -gltf_obj = glTF(filename, apply_normals=True) +gltf_obj = glTF(filename, apply_normals=False) actors = gltf_obj.actors() -# Setting custom opacity to see the bones -# for act in actors: -# act.GetProperty().SetOpacity(0.7) - vertices = [vertices_from_actor(actor) for actor in actors] - -# vertices = vertices_from_actor(actors[0]) -clone = np.copy(vertices) +clone = [np.copy(vert) for vert in vertices] timeline = gltf_obj.get_skin_timeline() timeline.add_actor(actors) @@ -38,7 +32,6 @@ bvert_copy = copy.deepcopy(bverts) scene.add(timeline) -scene.add(* bactors.values()) bones = gltf_obj.bones parent_transforms = gltf_obj.bone_tranforms @@ -55,11 +48,6 @@ def transverse_timelines(timeline, bone_id, timestamp, joint_matrices, joint_matrices[bone_id] = skin_matrix node = gltf_obj.gltf.nodes[bone_id] - actor_transform = gltf_obj.transformations[0] - bone_transform = np.dot(actor_transform, new_deform) - bverts[bone_id][:] = transform.apply_transfomation(bvert_copy[bone_id], - bone_transform) - update_actor(bactors[bone_id]) if node.children: c_timelines = timeline.timelines c_bones = node.children @@ -75,21 +63,22 @@ def timer_callback(_obj, _event): root_bone = gltf_obj.gltf.skins[0].skeleton root_bone = root_bone if root_bone else gltf_obj.bones[0] - # if not root_bone == gltf_obj.bones[0]: - # timeline = timeline.timelines[0] - # parent_deform = gltf_obj.nodes[root_bone] - for child in timeline.timelines[0].timelines: - transverse_timelines(child, bones[0], timestamp, joint_matrices) - - # print(joint_matrices.keys()) + if not root_bone == bones[0]: + _timeline = timeline.timelines[0] + parent_transform = gltf_obj.transformations[root_bone].T + else: + _timeline = timeline + parent_transform = np.identity(4) + for child in _timeline.timelines: + transverse_timelines(child, bones[0], timestamp, + joint_matrices, parent_transform) for i, vertex in enumerate(vertices): - # print(i) vertex[:] = gltf_obj.apply_skin_matrix(clone[i], joint_matrices, i) update_actor(actors[i]) compute_bounds(actors[i]) showm.render() -showm.add_timer_callback(True, 10, timer_callback) +showm.add_timer_callback(True, 50, timer_callback) showm.start() diff --git a/fury/gltf.py b/fury/gltf.py index 27d29bca9..c4116d90a 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -68,8 +68,8 @@ def __init__(self, filename, apply_normals=False): self.transformations = [] self.polydatas = [] self.init_transform = np.identity(4) - self.animations = [] self.node_transform = [] + self.animation_channels = {} self.sampler_matrices = {} # Skinning Informations @@ -128,7 +128,7 @@ def inspect_scene(self, scene_id=0): for node_id in nodes: self.transverse_node(node_id, self.init_transform) - for animation in self.gltf.animations: + for animation in self.gltf.animations[:1]: self.transverse_channels(animation) def transverse_node(self, nextnode_id, matrix, parent=None, isJoint=False): @@ -247,7 +247,9 @@ def load_mesh(self, mesh_id, transform_mat, parent): if primitive.indices is not None: indices = self.get_acc_data(primitive.indices).reshape(-1, 3) - utils.set_polydata_triangles(polydata, indices) + else: + indices = np.arange(0, len(vertices)).reshape((-1, 3)) + utils.set_polydata_triangles(polydata, indices) if attributes.JOINTS_0 is not None: vertex_joints = self.get_acc_data(attributes.JOINTS_0) @@ -352,7 +354,7 @@ def get_buff_array(self, buff_id, d_type, byte_length, return out_arr except IOError as e: - print(f'Failed to read ! Error in opening file: {e}') + print(f'Failed to read ! Error in opening file:') def get_materials(self, mat_id): """Get the materials data. @@ -484,6 +486,7 @@ def transverse_channels(self, animation: gltflib.Animation): pygltflib animation object. """ name = animation.name + anim_channel = {} for channel in animation.channels: sampler = animation.samplers[channel.sampler] @@ -491,7 +494,10 @@ def transverse_channels(self, animation: gltflib.Animation): path = channel.target.path anim_data = self.get_sampler_data(sampler, node_id, path) self.node_transform.append(anim_data) - self.get_matrix_from_sampler(path, node_id, sampler) + sampler_data = self.get_matrix_from_sampler(path, node_id, + name, sampler) + anim_channel[node_id] = sampler_data + self.animation_channels[name] = anim_channel def get_sampler_data(self, sampler: gltflib.Sampler, node_id: int, transform_type): @@ -523,7 +529,7 @@ def get_sampler_data(self, sampler: gltflib.Sampler, node_id: int, 'interpolation': interpolation, 'property': transform_type} - def get_matrix_from_sampler(self, prop, node, sampler: gltflib.Sampler): + def get_matrix_from_sampler(self, prop, node, name, sampler: gltflib.Sampler): time_array = self.get_acc_data(sampler.input) tran_array = self.get_acc_data(sampler.output) tran_matrix = [] @@ -539,6 +545,7 @@ def get_matrix_from_sampler(self, prop, node, sampler: gltflib.Sampler): 'matrix': tran_matrix } self.sampler_matrices[node] = data + return data def get_skin_data(self, skin_id): """Gets the inverse bind matrix for each bone in the skin. @@ -570,7 +577,7 @@ def generate_tmatrix(self, transf, prop): matrix = transform.scale(transf) return matrix - def apply_skin_matrix(self, vertices, joint_matrices, ac_index): + def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): """Applies the skinnig matrix, that transforms the vertices. NOTE: vertices has joint_matrix applied already. @@ -587,8 +594,10 @@ def apply_skin_matrix(self, vertices, joint_matrices, ac_index): Modified vertices """ clone = np.copy(vertices) - weights = self.weights_0[ac_index] - joints = self.joints_0[ac_index] + weights = self.weights_0[actor_index] + joints = self.joints_0[actor_index] + # print(weights) + # print(joints) for i, xyz in enumerate(clone): a_joint = joints[i] @@ -600,6 +609,7 @@ def apply_skin_matrix(self, vertices, joint_matrices, ac_index): np.multiply(a_weight[1], joint_matrices[a_joint[1]]) +\ np.multiply(a_weight[2], joint_matrices[a_joint[2]]) +\ np.multiply(a_weight[3], joint_matrices[a_joint[3]]) + # print(skin_mat) xyz = np.dot(skin_mat, np.append(xyz, [1.0])) # xyz = np.dot(np.append(xyz, [1.0]), skin_mat) From bf9c8052e324d276bb021ff257f16e9b19b22be0 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Tue, 27 Sep 2022 13:16:13 +0530 Subject: [PATCH 12/25] multiple timeline for multiple animation channels --- .../tutorials/01_introductory/viz_skinning.py | 33 +++++++----- fury/gltf.py | 51 +++++++++---------- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index 51571b337..9e8dcce99 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -6,9 +6,10 @@ from fury.data import fetch_gltf, read_viz_gltf scene = window.Scene() +bone = False fetch_gltf('RiggedFigure', 'glTF') -filename = read_viz_gltf('BrainStem') +filename = read_viz_gltf('RiggedFigure') gltf_obj = glTF(filename, apply_normals=False) actors = gltf_obj.actors() @@ -16,23 +17,23 @@ vertices = [vertices_from_actor(actor) for actor in actors] clone = [np.copy(vert) for vert in vertices] -timeline = gltf_obj.get_skin_timeline() +timeline = gltf_obj.get_skin_timeline()['0'] timeline.add_actor(actors) scene = window.Scene() showm = window.ShowManager(scene, size=(900, 768), reset_camera=True, order_transparent=True) showm.initialize() - -bactors = gltf_obj.get_joint_actors(length=0.2, with_transforms=False) -bverts = {} -for bone, joint_actor in bactors.items(): - bverts[bone] = vertices_from_actor(joint_actor) - -bvert_copy = copy.deepcopy(bverts) - scene.add(timeline) +if bone: + bactors = gltf_obj.get_joint_actors(length=0.2, with_transforms=False) + bverts = {} + for bone, joint_actor in bactors.items(): + bverts[bone] = vertices_from_actor(joint_actor) + bvert_copy = copy.deepcopy(bverts) + scene.add(* bactors.values()) + bones = gltf_obj.bones parent_transforms = gltf_obj.bone_tranforms @@ -42,12 +43,20 @@ def transverse_timelines(timeline, bone_id, timestamp, joint_matrices, deform = timeline.get_value('transform', timestamp) new_deform = np.dot(parent_bone_deform, deform) - # calculating skinning metrix + # calculating skinning matrix ibm = gltf_obj.ibms[bone_id].T skin_matrix = np.dot(new_deform, ibm) joint_matrices[bone_id] = skin_matrix node = gltf_obj.gltf.nodes[bone_id] + + if bone: + actor_transform = gltf_obj.transformations[0] + bone_transform = np.dot(actor_transform, new_deform) + bverts[bone_id][:] = transform.apply_transfomation(bvert_copy[bone_id], + bone_transform) + update_actor(bactors[bone_id]) + if node.children: c_timelines = timeline.timelines c_bones = node.children @@ -79,6 +88,6 @@ def timer_callback(_obj, _event): showm.render() -showm.add_timer_callback(True, 50, timer_callback) +showm.add_timer_callback(True, 20, timer_callback) showm.start() diff --git a/fury/gltf.py b/fury/gltf.py index c4116d90a..8eb89bd04 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -128,8 +128,8 @@ def inspect_scene(self, scene_id=0): for node_id in nodes: self.transverse_node(node_id, self.init_transform) - for animation in self.gltf.animations[:1]: - self.transverse_channels(animation) + for i, animation in enumerate(self.gltf.animations): + self.transverse_channels(animation, i) def transverse_node(self, nextnode_id, matrix, parent=None, isJoint=False): """Load mesh and generates transformation matrix. @@ -477,7 +477,7 @@ def load_camera(self, camera_id, transform_mat): self.cameras[camera_id] = vtk_cam - def transverse_channels(self, animation: gltflib.Animation): + def transverse_channels(self, animation: gltflib.Animation, count: int): """Loops over animation channels and sets animation data. Parameters @@ -486,6 +486,8 @@ def transverse_channels(self, animation: gltflib.Animation): pygltflib animation object. """ name = animation.name + if name is None: + name = str(count) anim_channel = {} for channel in animation.channels: @@ -494,8 +496,8 @@ def transverse_channels(self, animation: gltflib.Animation): path = channel.target.path anim_data = self.get_sampler_data(sampler, node_id, path) self.node_transform.append(anim_data) - sampler_data = self.get_matrix_from_sampler(path, node_id, - name, sampler) + sampler_data = self.get_matrix_from_sampler(path, node_id, name, + anim_channel, sampler) anim_channel[node_id] = sampler_data self.animation_channels[name] = anim_channel @@ -529,14 +531,16 @@ def get_sampler_data(self, sampler: gltflib.Sampler, node_id: int, 'interpolation': interpolation, 'property': transform_type} - def get_matrix_from_sampler(self, prop, node, name, sampler: gltflib.Sampler): + def get_matrix_from_sampler(self, prop, node, name, + anim_channel, sampler: gltflib.Sampler): time_array = self.get_acc_data(sampler.input) tran_array = self.get_acc_data(sampler.output) tran_matrix = [] - if node in self.sampler_matrices: - prev_arr = self.sampler_matrices[node]['matrix'] + if node in anim_channel: + prev_arr = anim_channel[node]['matrix'] else: prev_arr = [np.identity(4) for i in range(len(time_array))] + for i, arr in enumerate(tran_array): temp = self.generate_tmatrix(arr, prop) tran_matrix.append(np.dot(prev_arr[i], temp)) @@ -579,7 +583,6 @@ def generate_tmatrix(self, transf, prop): def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): """Applies the skinnig matrix, that transforms the vertices. - NOTE: vertices has joint_matrix applied already. Parameters ---------- @@ -596,8 +599,6 @@ def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): clone = np.copy(vertices) weights = self.weights_0[actor_index] joints = self.joints_0[actor_index] - # print(weights) - # print(joints) for i, xyz in enumerate(clone): a_joint = joints[i] @@ -609,15 +610,13 @@ def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): np.multiply(a_weight[1], joint_matrices[a_joint[1]]) +\ np.multiply(a_weight[2], joint_matrices[a_joint[2]]) +\ np.multiply(a_weight[3], joint_matrices[a_joint[3]]) - # print(skin_mat) xyz = np.dot(skin_mat, np.append(xyz, [1.0])) - # xyz = np.dot(np.append(xyz, [1.0]), skin_mat) clone[i] = xyz[:3] return clone - def transverse_bones(self, bone_id, parent_timeline: Timeline): + def transverse_bones(self, bone_id, channel_name, parent_timeline: Timeline): """ bone_id : int Index of the bone. @@ -626,8 +625,8 @@ def transverse_bones(self, bone_id, parent_timeline: Timeline): """ node = self.gltf.nodes[bone_id] timeline = Timeline(playback_panel=False) - if bone_id in self.sampler_matrices: - transforms = self.sampler_matrices[bone_id] + if bone_id in self.animation_channels[channel_name]: + transforms = self.animation_channels[channel_name][bone_id] timestamps = transforms['timestamps'] metrices = transforms['matrix'] @@ -640,24 +639,24 @@ def transverse_bones(self, bone_id, parent_timeline: Timeline): self.timeline_order.append(bone_id) if node.children: for child_bone in node.children: - self.transverse_bones(child_bone, timeline) - # else: - # self.child_timelines.append(timeline) + self.transverse_bones(child_bone, channel_name, timeline) def get_skin_timeline(self): """One timeline for each bone, contains parent transforms. Returns ------- - root_timeline : Timeline + root_timelines : Dict A timeline containing all the child timelines for bones. """ - root_timeline = Timeline(playback_panel=True) - root_bone = self.gltf.skins[0].skeleton - root_bone = root_bone if root_bone else self.bones[0] - print(f'root bone: {root_bone}') - self.transverse_bones(root_bone, root_timeline) - return root_timeline + root_timelines = {} + for name in self.animation_channels.keys(): + root_timeline = Timeline(playback_panel=True) + root_bone = self.gltf.skins[0].skeleton + root_bone = root_bone if root_bone else self.bones[0] + self.transverse_bones(root_bone, name, root_timeline) + root_timelines[name] = root_timeline + return root_timelines def get_joint_actors(self, length=0.5, with_transforms=False): """Creates an arrow actor for each bone in a skinned model. From e74bc69d600796f01e59e6aabbc705a5ea393a30 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Tue, 27 Sep 2022 18:46:59 +0530 Subject: [PATCH 13/25] set initial transform of bone to bone_transform --- docs/tutorials/01_introductory/viz_skinning.py | 6 +++--- fury/gltf.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index 9e8dcce99..ecc48f067 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -6,7 +6,7 @@ from fury.data import fetch_gltf, read_viz_gltf scene = window.Scene() -bone = False +show_bones = False fetch_gltf('RiggedFigure', 'glTF') filename = read_viz_gltf('RiggedFigure') @@ -26,7 +26,7 @@ showm.initialize() scene.add(timeline) -if bone: +if show_bones: bactors = gltf_obj.get_joint_actors(length=0.2, with_transforms=False) bverts = {} for bone, joint_actor in bactors.items(): @@ -50,7 +50,7 @@ def transverse_timelines(timeline, bone_id, timestamp, joint_matrices, node = gltf_obj.gltf.nodes[bone_id] - if bone: + if show_bones: actor_transform = gltf_obj.transformations[0] bone_transform = np.dot(actor_transform, new_deform) bverts[bone_id][:] = transform.apply_transfomation(bvert_copy[bone_id], diff --git a/fury/gltf.py b/fury/gltf.py index 8eb89bd04..8bc31d535 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -625,15 +625,15 @@ def transverse_bones(self, bone_id, channel_name, parent_timeline: Timeline): """ node = self.gltf.nodes[bone_id] timeline = Timeline(playback_panel=False) + orig_transform = self.bone_tranforms[bone_id] if bone_id in self.animation_channels[channel_name]: transforms = self.animation_channels[channel_name][bone_id] timestamps = transforms['timestamps'] metrices = transforms['matrix'] - for time, matrix in zip(timestamps, metrices): timeline.set_keyframe('transform', time[0], matrix) else: - timeline.set_keyframe('transform', 0.0, np.identity(4)) + timeline.set_keyframe('transform', 0.0, orig_transform) parent_timeline.add(timeline) self.timeline_order.append(bone_id) @@ -680,7 +680,7 @@ def get_joint_actors(self, length=0.5, with_transforms=False): parent_transforms = self.bone_tranforms for bone in self.bones: - arrow = actor.arrow(origin, [0, 1, 0], [1, 0, 0], scales=length) + arrow = actor.arrow(origin, [0, 1, 0], [1, 1, 1], scales=length) if with_transforms: verts = utils.vertices_from_actor(arrow) actor_transf = self.transformations[0] From 64e11f374a17c4dc1e5108ebfb6c686983b893fa Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Wed, 28 Sep 2022 20:30:29 +0530 Subject: [PATCH 14/25] fixing merge conflicts with tutorials --- docs/tutorials/01_introductory/viz_gltf.py | 2 +- docs/tutorials/01_introductory/viz_gltf_animated.py | 11 +++++++++-- fury/gltf.py | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_gltf.py b/docs/tutorials/01_introductory/viz_gltf.py index 46de7ca47..d615eef95 100644 --- a/docs/tutorials/01_introductory/viz_gltf.py +++ b/docs/tutorials/01_introductory/viz_gltf.py @@ -18,7 +18,7 @@ ############################################################################## # Retrieving the gltf model. fetch_gltf('Duck', 'glTF') -filename = read_viz_gltf('BrainStem') +filename = read_viz_gltf('Duck') ############################################################################## # Initialize the glTF object and get actors using `actors` method. diff --git a/docs/tutorials/01_introductory/viz_gltf_animated.py b/docs/tutorials/01_introductory/viz_gltf_animated.py index f6d14bdf9..5f0877cb0 100644 --- a/docs/tutorials/01_introductory/viz_gltf_animated.py +++ b/docs/tutorials/01_introductory/viz_gltf_animated.py @@ -1,3 +1,4 @@ + """ ======================= Visualizing a glTF file @@ -31,7 +32,7 @@ # Get the main_timeline (which contains multiple Timeline objects). gltf_obj = glTF(filename) -timeline = gltf_obj.get_main_timeline() +timeline = gltf_obj.main_timeline() ############################################################################## # Add the timeline to the scene (No need to add actors seperately). @@ -41,6 +42,8 @@ ############################################################################## # define a timer_callback that updates the timeline. +interactive = False + def timer_callback(_obj, _event): timeline.update_animation() @@ -49,4 +52,8 @@ def timer_callback(_obj, _event): showm.add_timer_callback(True, 10, timer_callback) -showm.start() +if interactive: + showm.start() + +window.record(scene, out_path='viz_gltf_animated.png', + size=(900, 768)) diff --git a/fury/gltf.py b/fury/gltf.py index 8bc31d535..922d39b74 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -765,7 +765,7 @@ def get_animation_timelines(self): timelines.append(timeline) return timelines - def get_main_timeline(self): + def main_timeline(self): """Returns main timeline with all animations. """ main_timeline = Timeline(playback_panel=True) From 6d5434f7db052c1c03856268a44d49cfc34c2387 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Wed, 28 Sep 2022 20:38:04 +0530 Subject: [PATCH 15/25] changing animation name to anim_count --- docs/tutorials/01_introductory/viz_skinning.py | 2 +- fury/gltf.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index ecc48f067..143a8bd4a 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -17,7 +17,7 @@ vertices = [vertices_from_actor(actor) for actor in actors] clone = [np.copy(vert) for vert in vertices] -timeline = gltf_obj.get_skin_timeline()['0'] +timeline = gltf_obj.get_skin_timeline()['anim_0'] timeline.add_actor(actors) scene = window.Scene() diff --git a/fury/gltf.py b/fury/gltf.py index 922d39b74..8c4787d32 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -487,7 +487,7 @@ def transverse_channels(self, animation: gltflib.Animation, count: int): """ name = animation.name if name is None: - name = str(count) + name = str(f'anim_{count}') anim_channel = {} for channel in animation.channels: From f6d63bdb58fa7b93f505670c0af703f6937c85e4 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Thu, 29 Sep 2022 23:34:36 +0530 Subject: [PATCH 16/25] fixing is `skeleton` is not in joints --- docs/tutorials/01_introductory/viz_skinning.py | 4 ++-- fury/gltf.py | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index 143a8bd4a..69a0b8281 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -6,10 +6,10 @@ from fury.data import fetch_gltf, read_viz_gltf scene = window.Scene() -show_bones = False +show_bones = True fetch_gltf('RiggedFigure', 'glTF') -filename = read_viz_gltf('RiggedFigure') +filename = read_viz_gltf('RiggedSimple') gltf_obj = glTF(filename, apply_normals=False) actors = gltf_obj.actors() diff --git a/fury/gltf.py b/fury/gltf.py index 8c4787d32..24e9ff8b0 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -625,7 +625,10 @@ def transverse_bones(self, bone_id, channel_name, parent_timeline: Timeline): """ node = self.gltf.nodes[bone_id] timeline = Timeline(playback_panel=False) - orig_transform = self.bone_tranforms[bone_id] + if bone_id in self.bone_tranforms.keys(): + orig_transform = self.bone_tranforms[bone_id] + else: + orig_transform = np.identity(4) if bone_id in self.animation_channels[channel_name]: transforms = self.animation_channels[channel_name][bone_id] timestamps = transforms['timestamps'] From 8eaf4513df37a4abf5f8ab22f6997f22be426fde Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Fri, 30 Sep 2022 14:01:55 +0530 Subject: [PATCH 17/25] removing simple animation functions --- .../01_introductory/viz_gltf_animated.py | 59 --------- fury/gltf.py | 123 ------------------ fury/tests/test_gltf.py | 28 +--- 3 files changed, 1 insertion(+), 209 deletions(-) delete mode 100644 docs/tutorials/01_introductory/viz_gltf_animated.py diff --git a/docs/tutorials/01_introductory/viz_gltf_animated.py b/docs/tutorials/01_introductory/viz_gltf_animated.py deleted file mode 100644 index 5f0877cb0..000000000 --- a/docs/tutorials/01_introductory/viz_gltf_animated.py +++ /dev/null @@ -1,59 +0,0 @@ - -""" -======================= -Visualizing a glTF file -======================= -In this tutorial, we will show how to display a simple animated glTF in a -scene. -""" - -from fury import window -from fury.gltf import glTF -from fury.data import fetch_gltf, read_viz_gltf - -############################################################################## -# Create a scene. - -scene = window.Scene() - -showm = window.ShowManager(scene, - size=(900, 768), reset_camera=False, - order_transparent=True) -showm.initialize() - - -############################################################################## -# Retrieving the gltf model. -fetch_gltf('InterpolationTest', 'glTF') -filename = read_viz_gltf('InterpolationTest') - -############################################################################## -# Initialize the glTF object and get actors using `actors` method. -# Get the main_timeline (which contains multiple Timeline objects). - -gltf_obj = glTF(filename) -timeline = gltf_obj.main_timeline() - -############################################################################## -# Add the timeline to the scene (No need to add actors seperately). - -scene.add(timeline) - -############################################################################## -# define a timer_callback that updates the timeline. - -interactive = False - - -def timer_callback(_obj, _event): - timeline.update_animation() - showm.render() - - -showm.add_timer_callback(True, 10, timer_callback) - -if interactive: - showm.start() - -window.record(scene, out_path='viz_gltf_animated.png', - size=(900, 768)) diff --git a/fury/gltf.py b/fury/gltf.py index 24e9ff8b0..42f70ed0e 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -694,129 +694,6 @@ def get_joint_actors(self, length=0.5, with_transforms=False): actors[bone] = arrow return actors - def get_animation_timelines(self): - """Returns list of animation timeline. - - Returns - ------- - timelines : List - List of timelines containing actors. - """ - actors = self.actors() - interpolators = { - 'LINEAR': linear_interpolator, - 'STEP': step_interpolator, - 'CUBICSPLINE': tan_cubic_spline_interpolator - } - - rotation_interpolators = { - 'LINEAR': slerp, - 'STEP': step_interpolator, - 'CUBICSPLINE': tan_cubic_spline_interpolator - } - - timelines = [] - for transforms in self.node_transform: - target_node = transforms['node'] - - for i, nodes in enumerate(self.nodes): - timeline = Timeline() - - if target_node in nodes: - timeline.add_actor(actors[i]) - timestamp = transforms['input'] - transform = transforms['output'] - prop = transforms['property'] - - interpolation_type = transforms['interpolation'] - - interpolator = interpolators.get(interpolation_type) - rot_interp = rotation_interpolators.get( - interpolation_type) - timeshape = timestamp.shape - transhape = transform.shape - if transforms['interpolation'] == 'CUBICSPLINE': - transform = transform.reshape( - (timeshape[0], -1, transhape[1])) - - for time, trs in zip(timestamp, transform): - in_tan, out_tan = None, None - if trs.ndim == 2: - cubicspline = trs - in_tan = cubicspline[0] - trs = cubicspline[1] - out_tan = cubicspline[2] - - if prop == 'rotation': - timeline.set_rotation(time[0], trs, - in_tangent=in_tan, - out_tangent=out_tan) - timeline.set_rotation_interpolator(rot_interp) - if prop == 'translation': - timeline.set_position(time[0], trs, - in_tangent=in_tan, - out_tangent=out_tan) - timeline.set_position_interpolator(interpolator) - if prop == 'scale': - timeline.set_scale(time[0], trs, - in_tangent=in_tan, - out_tangent=out_tan) - timeline.set_scale_interpolator(interpolator) - else: - timeline.add_static_actor(actors[i]) - - timelines.append(timeline) - return timelines - - def main_timeline(self): - """Returns main timeline with all animations. - """ - main_timeline = Timeline(playback_panel=True) - timelines = self.get_animation_timelines() - for timeline in timelines: - main_timeline.add_timeline(timeline) - return main_timeline - - def skinning_interpolator(self, keyframes): - - timestamps = helpers.get_timestamps_from_keyframes(keyframes) - for time in keyframes: - data = keyframes.get(time) - if data.get('value') is None: - data['value'] = np.identity(4) - - def interpolate(t): - actor = self.actors()[0] - vertices = utils.vertices_from_actor(actor) - clone = np.copy(vertices) - bones = self.bones[0] - inverse_binds = [] - parent_transforms = self.bone_tranforms - t0 = helpers.get_previous_timestamp(timestamps, t) - t1 = helpers.get_next_timestamp(timestamps, t) - - joint_matrices = [] - - for i, bone in enumerate(bones): - in_mat = keyframes.get(t0).get('value') - out_mat = keyframes.get(t1).get('value') - - deform = lerp(in_mat, out_mat, t0, t1, t) - parent_transform = parent_transforms[bone] - ibm = self.ibms[0][i].T - inverse_binds.append(ibm) - - joint_mat = np.dot(parent_transform, deform) - joint_mat = np.dot(joint_mat, ibm) - joint_matrices.append(joint_mat) - - vertices[:] = self.apply_skin_matrix(clone, joint_matrices) - utils.update_actor(actor) - utils.compute_bounds(actor) - return vertices - - return interpolate - def export_scene(scene, filename='default.gltf'): """Generate gltf from FURY scene. diff --git a/fury/tests/test_gltf.py b/fury/tests/test_gltf.py index d160d0086..294edb581 100644 --- a/fury/tests/test_gltf.py +++ b/fury/tests/test_gltf.py @@ -143,38 +143,12 @@ def test_export_gltf(): npt.assert_equal(res.colors_found, [True, True]) -def test_simple_animation(): - fetch_gltf('BoxAnimated', 'glTF') - file = read_viz_gltf('BoxAnimated') - gltf_obj = glTF(file) - timeline = gltf_obj.get_main_timeline() - - scene = window.Scene() - showm = window.ShowManager(scene, size=(900, 768)) - showm.initialize() - - scene.add(timeline) - - # timestamp animation seek - timeline.seek(0.0) - showm.save_screenshot('keyframe1.png') - - timeline.seek(2.57) - showm.save_screenshot('keyframe2.png') - res1 = window.analyze_snapshot('keyframe1.png', colors=(255, 255, 255)) - res2 = window.analyze_snapshot('keyframe2.png', colors=(255, 255, 255)) - - assert_greater(res2.objects, res1.objects) - npt.assert_equal(res1.colors_found, [True]) - npt.assert_equal(res2.colors_found, [True]) - - def test_skinning(): # animation test fetch_gltf('SimpleSkin', 'glTF') file = read_viz_gltf('SimpleSkin') gltf_obj = glTF(file) - timeline = gltf_obj.get_skin_timeline() + timeline = gltf_obj.get_skin_timeline()['anim_0'] # checking weights and joints weights = np.array([[1.00, 0.00, 0.0, 0.0], From a9fe19a30772a3c47b1cbba27cf6fa1ef62d402e Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Fri, 30 Sep 2022 18:17:21 +0530 Subject: [PATCH 18/25] fixing variable names after merge --- .../tutorials/01_introductory/viz_skinning.py | 6 +++--- fury/gltf.py | 20 +++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index 69a0b8281..47cf75ad0 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -9,7 +9,7 @@ show_bones = True fetch_gltf('RiggedFigure', 'glTF') -filename = read_viz_gltf('RiggedSimple') +filename = read_viz_gltf('RiggedFigure') gltf_obj = glTF(filename, apply_normals=False) actors = gltf_obj.actors() @@ -53,8 +53,8 @@ def transverse_timelines(timeline, bone_id, timestamp, joint_matrices, if show_bones: actor_transform = gltf_obj.transformations[0] bone_transform = np.dot(actor_transform, new_deform) - bverts[bone_id][:] = transform.apply_transfomation(bvert_copy[bone_id], - bone_transform) + bverts[bone_id][:] = transform.apply_transformation(bvert_copy[bone_id], + bone_transform) update_actor(bactors[bone_id]) if node.children: diff --git a/fury/gltf.py b/fury/gltf.py index 620478261..634ae457f 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -130,7 +130,8 @@ def inspect_scene(self, scene_id=0): for i, animation in enumerate(self.gltf.animations): self.transverse_channels(animation, i) - def transverse_node(self, nextnode_id, matrix, parent=None, is_joint=False): + def transverse_node(self, nextnode_id, matrix, parent=None, + is_joint=False): """Load mesh and generates transformation matrix. Parameters @@ -180,7 +181,7 @@ def transverse_node(self, nextnode_id, matrix, parent=None, is_joint=False): nextnode_id not in self.bone_tranforms): self.bone_tranforms[nextnode_id] = next_matrix[:] - if isJoint: + if is_joint: if not (nextnode_id in self.bone_tranforms): self.bone_tranforms[nextnode_id] = next_matrix[:] @@ -195,7 +196,7 @@ def transverse_node(self, nextnode_id, matrix, parent=None, is_joint=False): self.bones.append(bone) self.ibms[bone] = ibm self.transverse_node(joints[0], np.identity(4), parent, - isJoint=True) + is_joint=True) if node.camera is not None: camera_id = node.camera @@ -230,7 +231,6 @@ def load_mesh(self, mesh_id, transform_mat, parent): if attributes.NORMAL is not None and self.apply_normals: normals = self.get_acc_data(attributes.NORMAL) - normals = transform.apply_transformation(normals, transform_mat) utils.set_polydata_normals(polydata, normals) if attributes.TEXCOORD_0 is not None: @@ -532,13 +532,16 @@ def get_matrix_from_sampler(self, prop, node, name, anim_channel, sampler: gltflib.Sampler): time_array = self.get_acc_data(sampler.input) tran_array = self.get_acc_data(sampler.output) + print(time_array.shape) + print(tran_array) tran_matrix = [] if node in anim_channel: prev_arr = anim_channel[node]['matrix'] else: - prev_arr = [np.identity(4) for i in range(len(time_array))] + prev_arr = [np.identity(4) for i in range(len(tran_array))] for i, arr in enumerate(tran_array): + print(i) temp = self.generate_tmatrix(arr, prop) tran_matrix.append(np.dot(prev_arr[i], temp)) data = { @@ -613,7 +616,8 @@ def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): return clone - def transverse_bones(self, bone_id, channel_name, parent_timeline: Timeline): + def transverse_bones(self, bone_id, channel_name, + parent_timeline: Timeline): """ bone_id : int Index of the bone. @@ -683,7 +687,7 @@ def get_joint_actors(self, length=0.5, with_transforms=False): verts = utils.vertices_from_actor(arrow) actor_transf = self.transformations[0] arrow_transf = np.dot(parent_transforms[bone], actor_transf) - verts[:] = transform.apply_transfomation( + verts[:] = transform.apply_transformation( verts, parent_transforms[bone]) utils.update_actor(arrow) actors[bone] = arrow @@ -691,7 +695,7 @@ def get_joint_actors(self, length=0.5, with_transforms=False): def get_animation_timelines(self): """Returns list of animation timeline. - + Returns ------- timelines: List From e6bb4cf0bf59e3ea73caa00de0276a2cd3b8e879 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Sat, 1 Oct 2022 15:17:05 +0530 Subject: [PATCH 19/25] fixing simple animation issues after hirearc animation --- .../tutorials/01_introductory/viz_skinning.py | 14 ++++++++++--- fury/gltf.py | 21 +++++++++++-------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index 47cf75ad0..2d58e942a 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -1,6 +1,6 @@ import copy import numpy as np -from fury import window, transform +from fury import window, transform, actor from fury.utils import vertices_from_actor, update_actor, compute_bounds from fury.gltf import glTF from fury.data import fetch_gltf, read_viz_gltf @@ -66,6 +66,12 @@ def transverse_timelines(timeline, bone_id, timestamp, joint_matrices, def timer_callback(_obj, _event): + update_skinning() + showm.render() + + +def update_skinning(): + # copy everything above timeline.update_animation() timestamp = timeline.current_timestamp joint_matrices = {} @@ -83,11 +89,13 @@ def timer_callback(_obj, _event): joint_matrices, parent_transform) for i, vertex in enumerate(vertices): vertex[:] = gltf_obj.apply_skin_matrix(clone[i], joint_matrices, i) + actor_transf = gltf_obj.transformations[i] + vertex[:] = transform.apply_transformation(vertex, actor_transf) update_actor(actors[i]) compute_bounds(actors[i]) - showm.render() showm.add_timer_callback(True, 20, timer_callback) - +update_skinning() +scene.reset_camera() showm.start() diff --git a/fury/gltf.py b/fury/gltf.py index 634ae457f..7549edccf 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -5,8 +5,9 @@ import pygltflib as gltflib from pygltflib.utils import glb2gltf, gltf2glb from PIL import Image -from fury.lib import Texture, Camera, numpy_support +from fury.lib import Texture, Camera, numpy_support, Transform, Matrix4x4 from fury import transform, utils, io, actor +from fury import transform as ftrans from fury.animation.timeline import Timeline from fury.animation.interpolator import (linear_interpolator, step_interpolator, slerp, @@ -96,12 +97,13 @@ def actors(self): for i, polydata in enumerate(self.polydatas): actor = utils.get_actor_from_polydata(polydata) transform_mat = self.transformations[i] - position, rot, scale = transform.transform_from_matrix( - transform_mat) - actor.SetPosition(position) - actor.SetScale(scale) - actor.RotateWXYZ(*rot) + _transform = Transform() + _matrix = Matrix4x4() + _matrix.DeepCopy(transform_mat.ravel()) + + _transform.SetMatrix(_matrix) + actor.SetUserTransform(_transform) if self.materials[i] is not None: base_col_tex = self.materials[i]['baseColorTexture'] @@ -532,8 +534,6 @@ def get_matrix_from_sampler(self, prop, node, name, anim_channel, sampler: gltflib.Sampler): time_array = self.get_acc_data(sampler.input) tran_array = self.get_acc_data(sampler.output) - print(time_array.shape) - print(tran_array) tran_matrix = [] if node in anim_channel: prev_arr = anim_channel[node]['matrix'] @@ -541,7 +541,6 @@ def get_matrix_from_sampler(self, prop, node, name, prev_arr = [np.identity(4) for i in range(len(tran_array))] for i, arr in enumerate(tran_array): - print(i) temp = self.generate_tmatrix(arr, prop) tran_matrix.append(np.dot(prev_arr[i], temp)) data = { @@ -720,6 +719,10 @@ def get_animation_timelines(self): for i, nodes in enumerate(self.nodes): timeline = Timeline() + transform_mat = self.transformations[i] + position, rot, scale = ftrans.transform_from_matrix( + transform_mat) + timeline.set_keyframe('position', 0.0, position) if target_node in nodes: timeline.add_actor(actors[i]) From 36dcab74eee15c6e55121c1d119c9a4dcc45840e Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Sun, 2 Oct 2022 00:41:38 +0530 Subject: [PATCH 20/25] Moving skinning functions inside gltf.py --- .../tutorials/01_introductory/viz_skinning.py | 83 ++-------------- fury/gltf.py | 98 +++++++++++++++---- 2 files changed, 86 insertions(+), 95 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index 2d58e942a..52b51347a 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -1,101 +1,30 @@ -import copy -import numpy as np -from fury import window, transform, actor -from fury.utils import vertices_from_actor, update_actor, compute_bounds +from fury import window from fury.gltf import glTF from fury.data import fetch_gltf, read_viz_gltf scene = window.Scene() -show_bones = True fetch_gltf('RiggedFigure', 'glTF') -filename = read_viz_gltf('RiggedFigure') +filename = read_viz_gltf('RiggedSimple') gltf_obj = glTF(filename, apply_normals=False) -actors = gltf_obj.actors() -vertices = [vertices_from_actor(actor) for actor in actors] -clone = [np.copy(vert) for vert in vertices] - -timeline = gltf_obj.get_skin_timeline()['anim_0'] -timeline.add_actor(actors) +timeline = gltf_obj.skin_timeline()['anim_0'] scene = window.Scene() showm = window.ShowManager(scene, size=(900, 768), reset_camera=True, order_transparent=True) + +gltf_obj.initialise_skin(timeline, bones=False) showm.initialize() scene.add(timeline) -if show_bones: - bactors = gltf_obj.get_joint_actors(length=0.2, with_transforms=False) - bverts = {} - for bone, joint_actor in bactors.items(): - bverts[bone] = vertices_from_actor(joint_actor) - bvert_copy = copy.deepcopy(bverts) - scene.add(* bactors.values()) - -bones = gltf_obj.bones -parent_transforms = gltf_obj.bone_tranforms - - -def transverse_timelines(timeline, bone_id, timestamp, joint_matrices, - parent_bone_deform=np.identity(4)): - deform = timeline.get_value('transform', timestamp) - new_deform = np.dot(parent_bone_deform, deform) - - # calculating skinning matrix - ibm = gltf_obj.ibms[bone_id].T - skin_matrix = np.dot(new_deform, ibm) - joint_matrices[bone_id] = skin_matrix - - node = gltf_obj.gltf.nodes[bone_id] - - if show_bones: - actor_transform = gltf_obj.transformations[0] - bone_transform = np.dot(actor_transform, new_deform) - bverts[bone_id][:] = transform.apply_transformation(bvert_copy[bone_id], - bone_transform) - update_actor(bactors[bone_id]) - - if node.children: - c_timelines = timeline.timelines - c_bones = node.children - for c_timeline, c_bone in zip(c_timelines, c_bones): - transverse_timelines(c_timeline, c_bone, timestamp, - joint_matrices, new_deform) - def timer_callback(_obj, _event): - update_skinning() + gltf_obj.update_skin(timeline) showm.render() -def update_skinning(): - # copy everything above - timeline.update_animation() - timestamp = timeline.current_timestamp - joint_matrices = {} - root_bone = gltf_obj.gltf.skins[0].skeleton - root_bone = root_bone if root_bone else gltf_obj.bones[0] - - if not root_bone == bones[0]: - _timeline = timeline.timelines[0] - parent_transform = gltf_obj.transformations[root_bone].T - else: - _timeline = timeline - parent_transform = np.identity(4) - for child in _timeline.timelines: - transverse_timelines(child, bones[0], timestamp, - joint_matrices, parent_transform) - for i, vertex in enumerate(vertices): - vertex[:] = gltf_obj.apply_skin_matrix(clone[i], joint_matrices, i) - actor_transf = gltf_obj.transformations[i] - vertex[:] = transform.apply_transformation(vertex, actor_transf) - update_actor(actors[i]) - compute_bounds(actors[i]) - - showm.add_timer_callback(True, 20, timer_callback) -update_skinning() scene.reset_camera() showm.start() diff --git a/fury/gltf.py b/fury/gltf.py index 7549edccf..76ddead6c 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -2,15 +2,17 @@ import base64 import os import numpy as np +import copy import pygltflib as gltflib from pygltflib.utils import glb2gltf, gltf2glb from PIL import Image from fury.lib import Texture, Camera, numpy_support, Transform, Matrix4x4 from fury import transform, utils, io, actor from fury import transform as ftrans +from fury.utils import (update_actor, compute_bounds, vertices_from_actor,) from fury.animation.timeline import Timeline -from fury.animation.interpolator import (linear_interpolator, - step_interpolator, slerp, +from fury.animation.interpolator import (linear_interpolator, slerp, + step_interpolator, tan_cubic_spline_interpolator) from fury.animation import helpers @@ -79,11 +81,16 @@ def __init__(self, filename, apply_normals=False): self.weights_0 = [] self.bones = [] self.ibms = {} - self.vertices = [] - self.child_timelines = [] - self.timeline_order = [] + + self._vertices = None + self._vcopy = None + self._bvertices = {} + self._bvert_copy = {} + self.show_bones = False self.inspect_scene(0) + self._actors = self.actors() + self._bactors = {} def actors(self): """Generate actors from glTF file. @@ -233,6 +240,8 @@ def load_mesh(self, mesh_id, transform_mat, parent): if attributes.NORMAL is not None and self.apply_normals: normals = self.get_acc_data(attributes.NORMAL) + normals = transform.apply_transformation(normals, + transform_mat) utils.set_polydata_normals(polydata, normals) if attributes.TEXCOORD_0 is not None: @@ -579,6 +588,63 @@ def generate_tmatrix(self, transf, prop): elif prop == 'scale': matrix = transform.scale(transf) return matrix + + def transverse_timelines(self, timeline, bone_id, timestamp, + joint_matrices, + parent_bone_deform=np.identity(4)): + deform = timeline.get_value('transform', timestamp) + new_deform = np.dot(parent_bone_deform, deform) + + ibm = self.ibms[bone_id].T + skin_matrix = np.dot(new_deform, ibm) + joint_matrices[bone_id] = skin_matrix + + node = self.gltf.nodes[bone_id] + + if self.show_bones: + actor_transform = self.transformations[0] + bone_transform = np.dot(actor_transform, new_deform) + self._bvertices[bone_id][:] = transform.apply_transformation( + self._bvert_copy[bone_id], bone_transform) + utils.update_actor(self._bactors[bone_id]) + + if node.children: + c_timelines = timeline.timelines + c_bones = node.children + for c_timeline, c_bone in zip(c_timelines, c_bones): + self.transverse_timelines(c_timeline, c_bone, timestamp, + joint_matrices, new_deform) + + def update_skin(self, timeline): + timeline.update_animation() + timestamp = timeline.current_timestamp + joint_matrices = {} + root_bone = self.gltf.skins[0].skeleton + root_bone = root_bone if root_bone else self.bones[0] + + if not root_bone == self.bones[0]: + _timeline = timeline.timelines[0] + parent_transform = self.transformations[root_bone].T + else: + _timeline = timeline + parent_transform = np.identity(4) + for child in _timeline.timelines: + self.transverse_timelines(child, self.bones[0], timestamp, + joint_matrices, parent_transform) + for i, vertex in enumerate(self._vertices): + vertex[:] = self.apply_skin_matrix(self._vcopy[i], + joint_matrices, i) + actor_transf = self.transformations[i] + vertex[:] = transform.apply_transformation(vertex, actor_transf) + utils.update_actor(self._actors[i]) + utils.compute_bounds(self._actors[i]) + + def initialise_skin(self, timeline, bones=False): + self.show_bones = bones + if bones: + self.get_joint_actors(0.2, False) + timeline.add_actor(list(self._bactors.values())) + self.update_skin(timeline) def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): """Applies the skinnig matrix, that transforms the vertices. @@ -639,12 +705,12 @@ def transverse_bones(self, bone_id, channel_name, timeline.set_keyframe('transform', 0.0, orig_transform) parent_timeline.add(timeline) - self.timeline_order.append(bone_id) + # self.timeline_order.append(bone_id) if node.children: for child_bone in node.children: self.transverse_bones(child_bone, channel_name, timeline) - def get_skin_timeline(self): + def skin_timeline(self): """One timeline for each bone, contains parent transforms. Returns @@ -653,12 +719,15 @@ def get_skin_timeline(self): A timeline containing all the child timelines for bones. """ root_timelines = {} + self._vertices = [vertices_from_actor(act) for act in self._actors] + self._vcopy = [np.copy(vert) for vert in self._vertices] for name in self.animation_channels.keys(): root_timeline = Timeline(playback_panel=True) root_bone = self.gltf.skins[0].skeleton root_bone = root_bone if root_bone else self.bones[0] self.transverse_bones(root_bone, name, root_timeline) root_timelines[name] = root_timeline + root_timeline.add_actor(self._actors) return root_timelines def get_joint_actors(self, length=0.5, with_transforms=False): @@ -670,27 +739,20 @@ def get_joint_actors(self, length=0.5, with_transforms=False): with_transforms : bool (default = False) Applies respective transformations to bone. Bones will be at origin if set to `False`. - Returns - ------- - actors : dict - Dictionary conatining bones as keys and corresponding actor as - values. """ origin = np.zeros((3, 3)) - actors = {} parent_transforms = self.bone_tranforms for bone in self.bones: arrow = actor.arrow(origin, [0, 1, 0], [1, 1, 1], scales=length) + verts = utils.vertices_from_actor(arrow) if with_transforms: - verts = utils.vertices_from_actor(arrow) - actor_transf = self.transformations[0] - arrow_transf = np.dot(parent_transforms[bone], actor_transf) verts[:] = transform.apply_transformation( verts, parent_transforms[bone]) utils.update_actor(arrow) - actors[bone] = arrow - return actors + self._bactors[bone] = arrow + self._bvertices[bone] = verts + self._bvert_copy = copy.deepcopy(self._bvertices) def get_animation_timelines(self): """Returns list of animation timeline. From 25819f53772bcc1df828694c47fca4f06ea55ecb Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Sun, 2 Oct 2022 01:18:54 +0530 Subject: [PATCH 21/25] Adding docs for tutorials --- .../tutorials/01_introductory/viz_skinning.py | 57 +++++++++++++++++-- fury/gltf.py | 4 +- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/docs/tutorials/01_introductory/viz_skinning.py b/docs/tutorials/01_introductory/viz_skinning.py index 52b51347a..098e90bbd 100644 --- a/docs/tutorials/01_introductory/viz_skinning.py +++ b/docs/tutorials/01_introductory/viz_skinning.py @@ -1,30 +1,77 @@ +""" +================================= +Skeletal Animation in a glTF file +================================= +In this tutorial, we will show how to use skeletal animations (skinning) in a +glTF model in FURY. +""" + from fury import window from fury.gltf import glTF from fury.data import fetch_gltf, read_viz_gltf -scene = window.Scene() +############################################################################## +# Retrieving the model with skeletal animations. +# We're choosing the `RiggedFigure` model here. fetch_gltf('RiggedFigure', 'glTF') -filename = read_viz_gltf('RiggedSimple') +filename = read_viz_gltf('RiggedFigure') + +############################################################################## +# Initializing the glTF object, You can additionaly set `apply_normals=True`. +# Note: Normals might not work well as intended with skinning animations. gltf_obj = glTF(filename, apply_normals=False) +############################################################################## +# Get the skinning timeline using `skin_timeline` method, Choose the animation +# name you want to visualize. +# Note: If there's no name for animation, It's stored as `anim_0`, `anim_1` etc + timeline = gltf_obj.skin_timeline()['anim_0'] +# After we get the timeline object, We want to initialise the skinning process. +# You can set `bones=true` to visualize each bone transformation. Additionaly, +# you can set `lenght` of bones in the `initialise_skin` method. +# Note: Make sure to call this method before you initialize ShowManager, else +# bones won't be added to the scene. + +gltf_obj.initialize_skin(timeline, bones=False) + +############################################################################## +# Create a scene, and show manager. +# Initialize the show manager and add timeline to the scene (No need to add +# actors to the scene seperately). + scene = window.Scene() showm = window.ShowManager(scene, size=(900, 768), reset_camera=True, order_transparent=True) - -gltf_obj.initialise_skin(timeline, bones=False) showm.initialize() scene.add(timeline) +############################################################################## +# define a timer_callback. +# Use the `update_skin` method, It updates the timeline and applies skinning to +# actors (and bones). + def timer_callback(_obj, _event): gltf_obj.update_skin(timeline) showm.render() +############################################################################## +# Optional: `timeline.play()` auto plays the animations. + +timeline.play() + showm.add_timer_callback(True, 20, timer_callback) scene.reset_camera() -showm.start() + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_skinning.png', + size=(900, 768)) diff --git a/fury/gltf.py b/fury/gltf.py index 76ddead6c..037adb45e 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -639,10 +639,10 @@ def update_skin(self, timeline): utils.update_actor(self._actors[i]) utils.compute_bounds(self._actors[i]) - def initialise_skin(self, timeline, bones=False): + def initialize_skin(self, timeline, bones=False, length=0.2): self.show_bones = bones if bones: - self.get_joint_actors(0.2, False) + self.get_joint_actors(length, False) timeline.add_actor(list(self._bactors.values())) self.update_skin(timeline) From e62edfa432212919109af0bce2a999ebdeaf384d Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Sun, 2 Oct 2022 01:43:51 +0530 Subject: [PATCH 22/25] fixing tests --- fury/gltf.py | 9 ++++----- fury/tests/test_gltf.py | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/fury/gltf.py b/fury/gltf.py index 037adb45e..ba77774b2 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -64,7 +64,6 @@ def __init__(self, filename, apply_normals=False): self.apply_normals = apply_normals self.cameras = {} - self.actors_list = [] self.materials = [] self.nodes = [] self.transformations = [] @@ -89,7 +88,7 @@ def __init__(self, filename, apply_normals=False): self.show_bones = False self.inspect_scene(0) - self._actors = self.actors() + self._actors = [] self._bactors = {} def actors(self): @@ -118,9 +117,9 @@ def actors(self): base_color = self.materials[i]['baseColor'] actor.GetProperty().SetColor(tuple(base_color[:3])) - self.actors_list.append(actor) + self._actors.append(actor) - return self.actors_list + return self._actors def inspect_scene(self, scene_id=0): """Loop over nodes in a scene. @@ -719,7 +718,7 @@ def skin_timeline(self): A timeline containing all the child timelines for bones. """ root_timelines = {} - self._vertices = [vertices_from_actor(act) for act in self._actors] + self._vertices = [vertices_from_actor(act) for act in self.actors()] self._vcopy = [np.copy(vert) for vert in self._vertices] for name in self.animation_channels.keys(): root_timeline = Timeline(playback_panel=True) diff --git a/fury/tests/test_gltf.py b/fury/tests/test_gltf.py index 3f8f72b1d..1816e9eb3 100644 --- a/fury/tests/test_gltf.py +++ b/fury/tests/test_gltf.py @@ -190,7 +190,7 @@ def test_skinning(): fetch_gltf('SimpleSkin', 'glTF') file = read_viz_gltf('SimpleSkin') gltf_obj = glTF(file) - timeline = gltf_obj.get_skin_timeline()['anim_0'] + timeline = gltf_obj.skin_timeline()['anim_0'] # checking weights and joints weights = np.array([[1.00, 0.00, 0.0, 0.0], From fdac5a87eb63672b546f9f14b34161929e87bf0d Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Mon, 3 Oct 2022 19:12:06 +0530 Subject: [PATCH 23/25] adding docstring --- fury/gltf.py | 95 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 18 deletions(-) diff --git a/fury/gltf.py b/fury/gltf.py index ba77774b2..53528e80c 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -8,13 +8,10 @@ from PIL import Image from fury.lib import Texture, Camera, numpy_support, Transform, Matrix4x4 from fury import transform, utils, io, actor -from fury import transform as ftrans -from fury.utils import (update_actor, compute_bounds, vertices_from_actor,) from fury.animation.timeline import Timeline from fury.animation.interpolator import (linear_interpolator, slerp, step_interpolator, tan_cubic_spline_interpolator) -from fury.animation import helpers comp_type = { 5120: {'size': 1, 'dtype': np.byte}, @@ -491,6 +488,8 @@ def transverse_channels(self, animation: gltflib.Animation, count: int): ---------- animation : glTflib.Animation pygltflib animation object. + count : int + Animation count. """ name = animation.name if name is None: @@ -503,7 +502,7 @@ def transverse_channels(self, animation: gltflib.Animation, count: int): path = channel.target.path anim_data = self.get_sampler_data(sampler, node_id, path) self.node_transform.append(anim_data) - sampler_data = self.get_matrix_from_sampler(path, node_id, name, + sampler_data = self.get_matrix_from_sampler(path, node_id, anim_channel, sampler) anim_channel[node_id] = sampler_data self.animation_channels[name] = anim_channel @@ -532,14 +531,27 @@ def get_sampler_data(self, sampler: gltflib.Sampler, node_id: int, interpolation = sampler.interpolation return { - 'node': node_id, - 'input': time_array, + 'node': node_id, 'input': time_array, 'output': transform_array, 'interpolation': interpolation, 'property': transform_type} - def get_matrix_from_sampler(self, prop, node, name, - anim_channel, sampler: gltflib.Sampler): + def get_matrix_from_sampler(self, prop, node, anim_channel, + sampler: gltflib.Sampler): + """Returns transformation matrix for a given timestamp from Sampler + data. Combines matrices for a given common timestamp. + + Parameters + ---------- + prop : str + Property of the array ('translation', 'rotation' or 'scale') + node : int + Node index of the sampler data. + anim_channel : dict + Containing previous animations with node as keys. + sampler : gltflib.Sampler + Sampler object for an animation channel. + """ time_array = self.get_acc_data(sampler.input) tran_array = self.get_acc_data(sampler.output) tran_matrix = [] @@ -580,6 +592,16 @@ def get_skin_data(self, skin_id): return joint_nodes, inv_bind_matrix def generate_tmatrix(self, transf, prop): + """Creates transformation matrix from TRS array. + + Parameters + ---------- + transf : ndarray + Array containing translation, rotation or scale values. + prop : str + String that defines the type of array + (values: translation, rotation or scale). + """ if prop == 'translation': matrix = transform.translate(transf) elif prop == 'rotation': @@ -587,10 +609,27 @@ def generate_tmatrix(self, transf, prop): elif prop == 'scale': matrix = transform.scale(transf) return matrix - - def transverse_timelines(self, timeline, bone_id, timestamp, + + def transverse_timelines(self, timeline, bone_id, timestamp, joint_matrices, parent_bone_deform=np.identity(4)): + """Calculates skinning matrix (Joint Matrices) and transforms bone for + each timeline. + + Parameters + ---------- + timeline : Timeline + Timeline object. + bone_id : int + Bone index of the current transform. + timestamp : float + Current timestamp of the timeline. + joint_matrices : dict + Empty dictionary that will contain joint matrices. + parent_bone_transform : ndarray (4, 4) + Transformation matrix of the parent bone. + (default=np.identity(4)) + """ deform = timeline.get_value('transform', timestamp) new_deform = np.dot(parent_bone_deform, deform) @@ -615,6 +654,13 @@ def transverse_timelines(self, timeline, bone_id, timestamp, joint_matrices, new_deform) def update_skin(self, timeline): + """Updates the timeline and actors with skinning data. + + Parameters + ---------- + timeline : Timeline + Timeline object. + """ timeline.update_animation() timestamp = timeline.current_timestamp joint_matrices = {} @@ -637,8 +683,21 @@ def update_skin(self, timeline): vertex[:] = transform.apply_transformation(vertex, actor_transf) utils.update_actor(self._actors[i]) utils.compute_bounds(self._actors[i]) - + def initialize_skin(self, timeline, bones=False, length=0.2): + """Creates bones and adds to the timeline and initialises `update_skin` + + Parameters + ---------- + timeline : Timeline + timeline of the respective animation. + bones : bool + Switches the visibility of bones in scene. + (default=False) + length : float + Length of the bones. + (default=0.2) + """ self.show_bones = bones if bones: self.get_joint_actors(length, False) @@ -718,7 +777,7 @@ def skin_timeline(self): A timeline containing all the child timelines for bones. """ root_timelines = {} - self._vertices = [vertices_from_actor(act) for act in self.actors()] + self._vertices = [utils.vertices_from_actor(act) for act in self.actors()] self._vcopy = [np.copy(vert) for vert in self._vertices] for name in self.animation_channels.keys(): root_timeline = Timeline(playback_panel=True) @@ -781,14 +840,14 @@ def get_animation_timelines(self): for i, nodes in enumerate(self.nodes): timeline = Timeline() transform_mat = self.transformations[i] - position, rot, scale = ftrans.transform_from_matrix( - transform_mat) + position, rot, scale = transform.transform_from_matrix( + transform_mat) timeline.set_keyframe('position', 0.0, position) if target_node in nodes: timeline.add_actor(actors[i]) timestamp = transforms['input'] - transform = transforms['output'] + node_transform = transforms['output'] prop = transforms['property'] interpolation_type = transforms['interpolation'] @@ -797,12 +856,12 @@ def get_animation_timelines(self): rot_interp = rotation_interpolators.get( interpolation_type) timeshape = timestamp.shape - transhape = transform.shape + transhape = node_transform.shape if transforms['interpolation'] == 'CUBICSPLINE': - transform = transform.reshape( + node_transform = node_transform.reshape( (timeshape[0], -1, transhape[1])) - for time, trs in zip(timestamp, transform): + for time, trs in zip(timestamp, node_transform): in_tan, out_tan = None, None if trs.ndim == 2: cubicspline = trs From 0be47121d40845c831c229c53ab369855ec3ebfe Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Wed, 5 Oct 2022 01:13:10 +0530 Subject: [PATCH 24/25] fixing docstrings --- fury/gltf.py | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/fury/gltf.py b/fury/gltf.py index 53528e80c..ed12931bb 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -482,7 +482,7 @@ def load_camera(self, camera_id, transform_mat): self.cameras[camera_id] = vtk_cam def transverse_channels(self, animation: gltflib.Animation, count: int): - """Loops over animation channels and sets animation data. + """Loop over animation channels and sets animation data. Parameters ---------- @@ -509,7 +509,7 @@ def transverse_channels(self, animation: gltflib.Animation, count: int): def get_sampler_data(self, sampler: gltflib.Sampler, node_id: int, transform_type): - """Gets the timeline and transformation data from sampler. + """Get the timeline and transformation data from sampler. Parameters ---------- @@ -538,8 +538,8 @@ def get_sampler_data(self, sampler: gltflib.Sampler, node_id: int, def get_matrix_from_sampler(self, prop, node, anim_channel, sampler: gltflib.Sampler): - """Returns transformation matrix for a given timestamp from Sampler - data. Combines matrices for a given common timestamp. + """Return transformation matrix for a given timestamp from Sampler + data. Combine matrices for a given common timestamp. Parameters ---------- @@ -571,7 +571,7 @@ def get_matrix_from_sampler(self, prop, node, anim_channel, return data def get_skin_data(self, skin_id): - """Gets the inverse bind matrix for each bone in the skin. + """Get the inverse bind matrix for each bone in the skin. Parameters ---------- @@ -592,7 +592,7 @@ def get_skin_data(self, skin_id): return joint_nodes, inv_bind_matrix def generate_tmatrix(self, transf, prop): - """Creates transformation matrix from TRS array. + """Create transformation matrix from TRS array. Parameters ---------- @@ -613,7 +613,7 @@ def generate_tmatrix(self, transf, prop): def transverse_timelines(self, timeline, bone_id, timestamp, joint_matrices, parent_bone_deform=np.identity(4)): - """Calculates skinning matrix (Joint Matrices) and transforms bone for + """Calculate skinning matrix (Joint Matrices) and transform bone for each timeline. Parameters @@ -654,7 +654,7 @@ def transverse_timelines(self, timeline, bone_id, timestamp, joint_matrices, new_deform) def update_skin(self, timeline): - """Updates the timeline and actors with skinning data. + """Update the timeline and actors with skinning data. Parameters ---------- @@ -685,7 +685,7 @@ def update_skin(self, timeline): utils.compute_bounds(self._actors[i]) def initialize_skin(self, timeline, bones=False, length=0.2): - """Creates bones and adds to the timeline and initialises `update_skin` + """Create bones and add to the timeline and initialise `update_skin` Parameters ---------- @@ -705,7 +705,7 @@ def initialize_skin(self, timeline, bones=False, length=0.2): self.update_skin(timeline) def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): - """Applies the skinnig matrix, that transforms the vertices. + """Applie the skinnig matrix, that transform the vertices. Parameters ---------- @@ -741,9 +741,15 @@ def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): def transverse_bones(self, bone_id, channel_name, parent_timeline: Timeline): - """ + """Loop over the bones and add child bone timeline to their parent + timeline. + + Parameters + ---------- bone_id : int Index of the bone. + channel_name : str + Animation name. parent_timeline : Timeline timeline of the parent bone. Should be `root_timeline` by default. """ @@ -763,7 +769,6 @@ def transverse_bones(self, bone_id, channel_name, timeline.set_keyframe('transform', 0.0, orig_transform) parent_timeline.add(timeline) - # self.timeline_order.append(bone_id) if node.children: for child_bone in node.children: self.transverse_bones(child_bone, channel_name, timeline) @@ -789,7 +794,8 @@ def skin_timeline(self): return root_timelines def get_joint_actors(self, length=0.5, with_transforms=False): - """Creates an arrow actor for each bone in a skinned model. + """Create an arrow actor for each bone in a skinned model. + Parameters ---------- length : float (default = 0.5) @@ -813,7 +819,7 @@ def get_joint_actors(self, length=0.5, with_transforms=False): self._bvert_copy = copy.deepcopy(self._bvertices) def get_animation_timelines(self): - """Returns list of animation timeline. + """Return list of animation timeline. Returns ------- @@ -890,7 +896,13 @@ def get_animation_timelines(self): return timelines def main_timeline(self): - """Returns main timeline with all animations. + """Return main timeline with all animations. + + Returns + ------- + main_timeline : Timeline + A parent timeline containing all child timelines for simple + animation. """ main_timeline = Timeline(playback_panel=True) timelines = self.get_animation_timelines() From 5c980c7bc82a08ccf65e47ab012c4a0a12279844 Mon Sep 17 00:00:00 2001 From: Shivam Anand <74976752+xtanion@users.noreply.github.com> Date: Thu, 6 Oct 2022 03:51:01 +0530 Subject: [PATCH 25/25] fixing few docstring grammatical errors --- fury/gltf.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fury/gltf.py b/fury/gltf.py index ed12931bb..5e22d93ee 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -601,6 +601,11 @@ def generate_tmatrix(self, transf, prop): prop : str String that defines the type of array (values: translation, rotation or scale). + + Returns + ------- + matrix : ndarray (4, 4) + ransformation matrix of shape (4, 4) with respective transforms. """ if prop == 'translation': matrix = transform.translate(transf) @@ -705,7 +710,7 @@ def initialize_skin(self, timeline, bones=False, length=0.2): self.update_skin(timeline) def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): - """Applie the skinnig matrix, that transform the vertices. + """Apply the skinnig matrix, that transform the vertices. Parameters ---------- @@ -717,7 +722,7 @@ def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): Returns ------- vertices : ndarray - Modified vertices + Modified vertices. """ clone = np.copy(vertices) weights = self.weights_0[actor_index]