Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keyframe reintroduction #48

Merged
merged 7 commits into from
Mar 24, 2021
Merged

Keyframe reintroduction #48

merged 7 commits into from
Mar 24, 2021

Conversation

thomgrand
Copy link

Overview

This feature branch reintroduces keyframes from the standard Blender API back into the node tree. Every exposed property on any node should be animatable this way. This feature uses the fcurve feature along with the Global Time Keeper node to keep track and update the keyframes. It has been tested in limited ways, but looks to bring back a lot of animation functionality usable in other parts of blender. I'm looking forward on your thoughts.

Features

  • Keyframes can be easily inserted using the hotkey I (default) when hovering over a property.
  • Alternatively, one can hover and right-click -> Insert Keyframe.
  • Keyframes can be also deleted this way by right-click -> Clear Keyframes
  • All animated attributes and their keyframes are displayed in the Global Time Keeper
  • Keyframe are saved in the current blender version in the .blend file
  • The Global Time Keeper will dynamically update properties in each frame (if necessary) and backtrack all converter nodes to be updated. This is done by comparing the new fcurve value with the current property value and if the value has changed, looking up all output links from this node recursively until it ends up in one of the following nodes:
    • VTK To Blender (Mesh)
    • VTK To Blender Volume
    • VTK To Blender Particles
  • The Time Selector node now has an optional flag "Use Scene Time" for backwards compatibility. If true, the time selector node's time step is always equal to the current frame. If disabled, the property can be animated using the Global Time Keeper

Preview

grafik
grafik

Limitations

  • Keyframes are not accessible and editable over the dope sheet or graph editor
  • The interpolation mode will always be set to LINEAR currently and can not be changed. This could be implemented using enum properties, but would need to be dynamic.

Related Issues

… branch.

The Global Time Keeper node updates all keyframed properties using the fcurve feature.
Not yet tested with the TimeSelector node.
Code needs a bit of cleanup.
@tkeskita
Copy link
Owner

Hi Thomas,
this is very interesting, since missing animation possibility in custom nodes is a long standing sore issue in Blender. I'll try to check this out this week!

connected_converter_nodes = backtrack_converter_nodes(node)
#Append, ignoring duplicates
nodes_2b_updated = nodes_2b_updated.union(set(connected_converter_nodes))

Copy link
Owner

@tkeskita tkeskita Mar 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add break here? Disabled Scene Time does not seem to work when frame is changed..?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem comes probably from the ordering of the node tree. I will fix this by ignoring Time Selector nodes with active scene time directly in the AnimationHelper. Otherwise the Global Time Keeper can potentially overwrite the changes in these lines.

@@ -0,0 +1,18 @@

class BVTKException(Exception):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here comes now the question: Do we need a custom exception handler? Is it beneficial and justified, or could we use standard exception handlers?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found the custom handler helpful down the line to distinguish between expected and unexpected errors, but I'm not very attached to the idea. I'll leave this decision up to you.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, maybe leave custom exception out now and add later on if needed. My aim is to try to make also error handling clearer in #45. Thanks!

time/animation.py Outdated Show resolved Hide resolved
current_frame = invalid_frame
vtk_time = invalid_vtk_time
def setup(self):
self.current_frame = int(-1e6)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

=invalid_frame ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix

self.current_frame = int(-1e6)
self.animated_properties = None

def get_animated_property_list(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhat long and indented function, can it be split?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I can extract common submethods with update_animated_properties to shorten the method

for f_curve in self.f_curves:
prop_path = f_curve.data_path
delimiter_index = prop_path.rindex(".")
node_name = prop_path[7:delimiter_index-2]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add comment what is happening here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix

animated_properties = {k: (v[0], v[1], v[2], [tmp for tmp in zip(*v[3])], v[4], v[5]) for k, v in animated_properties.items()}
return animated_properties

def update_animated_properties(self, scene):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar code here and in get_animated_property_list(), maybe refactor common parts to own function possible?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try to refactor the methods

customfilter.py Outdated
return self.get_persistent_storage()["updated_nodes"]

def setup(self):
if self.bl_label in persistent_storage["nodes"]:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add from .cache import persistent_storage needed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix

@@ -0,0 +1,170 @@
'''
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lonesome file in own directory. Move to root and rename to animation_helper.py?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll move it to the main directory as suggested.

@tkeskita
Copy link
Owner

OK I've added comments to code, please check them in github (I edited some comments). Overall this feature looks very promising! It also allows to keyframe Time Step value in Time Selector, so it should be possible to get arbitrary time point data from reader in, which I think was the idea in #44 .

@thomgrand
Copy link
Author

Many thanks for the thorough review and bug-checking. About the error handler, I'll await your decision and otherwise replace the exception thrown in assert_bvtk with a generic one.
I'll try to implement the changes this week, then only the documentation would be missing. Do you have any recommendations where the feature should be promoted in the documentation?

@tkeskita
Copy link
Owner

OK, so let's leave error handler out for now.
For docs I think there could be a new special node section for Global Time Keeper right after Time Selector.
Thanks!

- Invalid frame correctly referenced
- Fixed a missing import in setup of Global Time Keeper
- Removed the custom BVTKException and moved bvtk_assert to the core
- animation.py moved to the main directory and renamed animation_helper.py
- Fixed a bug where the Global Time Keeper could overwrite changes in Time Selector nodes with active 'Use Scene Time'
@thomgrand
Copy link
Author

thomgrand commented Mar 23, 2021

The new commits should resolve the issues and leave only the documentation to be done.
Edit: The documentation is also now finished.

@thomgrand thomgrand marked this pull request as ready for review March 23, 2021 13:04
@tkeskita
Copy link
Owner

Found few bugs:

  • getting this error in customfilter.py line 495 when changing frame number: return self.get_persistent_storage()["updated_nodes"]
    KeyError: 'updated_nodes'
  • raise BVTKException in customfilter.py
  • persistent storage is not cleaned if: open file with empty node tree --> add Global Time Keeper -> reload same file without saving -> add Global Time Keeper -> error about second Global Time Keeper node.

@thomgrand
Copy link
Author

The last two commits should hopefully fix the bugs you mentioned.

@tkeskita tkeskita merged commit 8b09ab1 into tkeskita:master Mar 24, 2021
@tkeskita
Copy link
Owner

Thank you so much! This feature addition is great! Everything I tried worked nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants