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

WIP, ENH: support frame bounds for movie renders #16

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

tylerjereddy
Copy link
Contributor

  • Fixes ENH, MAINT: control "dead time" at end of mp4 movie renders? #15

  • Add a new frame_bounds argument to render(), so that the start and end frame may be controlled conveniently by the user when producing a movie. I suppose the argument for why this should be available to the user vs. using raw bpy would be similar to the argument in favor of the original frame argument to render individual frames.

  • I can add some regression tests, but I'll wait to see if folks actually want this. The current testsuite still passes locally at least.

PR Checklist

  • Tests?
  • Docs?
  • CHANGELOG updated?
  • Issue raised/referenced?

* Fixes yuxuanzhuang#15

* Add a new `frame_bounds` argument to `render()`, so that the start
and end frame may be controlled conveniently by the user when producing
a movie. I suppose the argument for why this should be available to
the user vs. using raw `bpy` would be similar to the argument in favor
of the original `frame` argument to render individual frames.

* I can add some regression tests, but I'll wait to see if folks
actually want this. The current testsuite still passes locally at least.

def render(self):
# Render the movie
if self.frame_bounds is not None:
bpy.context.scene.frame_start = self.frame_bounds[0]
bpy.context.scene.frame_end = self.frame_bounds[1]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

if it is None, we might also consider defaulting to the trajectory bounds, similar to the MN initialization approach Brady mentioned? (since a new user may not know about the kwarg)

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree default / None should default to trajectory bounds. If a user is going to be rendering a subset / outside of that they'll have to explicit anyway.

@tylerjereddy
Copy link
Contributor Author

Should perhaps think about smoothing/averaging and their impacts on frame counts here too? Or at least how the API would play with those.

@BradyAJohnston
Copy link
Collaborator

I think the overall philosophy would be that the user doesn't even have to import bpy let along use it, unless they were wanting to do something out-of-scope or far more advanced, so I am all for exposing those options.

For averaging then this won't affect start / end frame, but for adding in subframes, I think that should be left to the user to be explicit with requesting. If the input is default / None then we do take it into account with setting the final frame number.

@tylerjereddy
Copy link
Contributor Author

Is there a straightforward adjustment a user should make when using subframes? For example, if you have 90 frames and normally set your range to something like (0, 90), and then you set subframes in ggmolvis to 2 (instead of default 0) for a given molecule that you use as a render "object," is there a guidance we could document/suggest for still capturing the same sim time bounds? Some internet searching suggests this is slightly tricky?

I'll paste the diff for the render code I was playing with to adjust subframes below the fold. I certainly observed that less of the trajectory motion was captured in the same Blender frame bounds, and it was certainly much smoother, so maybe just need to clarify/document it, especially for cases with long trajectories where you don't want to find out you underestimated your upper bound after N hours of rendering or something like that.

--- a/adk.yaml
+++ b/adk.yaml
@@ -25,3 +25,5 @@ background_color:
   alpha: 1.0
 # a larger focal length increases "zoom"
 focal_length: 80
+# subframes can be increased for "smoothing" of animation
+subframes: 2
diff --git a/probe.py b/probe.py
index 3dad198..62cf9df 100644
--- a/probe.py
+++ b/probe.py
@@ -43,6 +43,7 @@ def main(p_config: dict):
     mode = p_config["mode"]
     background_color = p_config["background_color"]
     focal_length = p_config["focal_length"]
+    subframes = p_config["subframes"]
 
     if mode == "movie":
         outfile_suffix = "mp4"
@@ -58,6 +59,7 @@ def main(p_config: dict):
     u = mda.Universe(topology_path, trajectory_path)
     system = u.select_atoms(sel_string)
     all_mol = ggmv.molecule(system, lens=focal_length)
+    all_mol.subframes = subframes

@BradyAJohnston
Copy link
Collaborator

The number of subframes just inserts that many extra frames between one frame and the next. So if a trajectory has between (0, 90) then with 1 subframe it will be [0, 180].

Yes this does need to be documented better somewhere.

@BradyAJohnston
Copy link
Collaborator

The alternative to subframes (which just adds intermediate frames to move through) is the averaging, which doesn't add any extra frames but does calculate the mean across multiple frames to remove a lot of the jittering. Looks like support for that hasn't been implemented in ggmolvis directly though, but is upstream in MN.

@yuxuanzhuang
Copy link
Owner

One can also add transformation in MDAnalysis https://docs.mdanalysis.org/1.1.0/documentation_pages/transformations/positionaveraging.html which also won't mess up the total number of frames.

@BradyAJohnston
Copy link
Collaborator

A limitation I ran into which is why I ended up implementing it myself is that once you add a transformation to a universe you can't undo it, which is why the UI / MN uses this. But yes you can always add arbitrary transformations to your universe before loading it (or after loading it) into Blender

@tylerjereddy
Copy link
Contributor Author

So averaging has the advantage of not rendering extra frames, but presumably paying the cost of the extra subframe renders could potentially get you something that looks a bit nicer if you can wait for it?

@BradyAJohnston
Copy link
Collaborator

Personally I think averaging looks nicer, because you get smoother movements overall whereas subframes just adds slower linear interpolation between positions (and lengthens the animation). Averaging can sometimes look weird though, if you have an AA side chain that spins 180 degrees from one frame to the next, then by averaging the positions they will all move through the midpoint and overlap with each other. Depends on what you are trying to show ultimately.

tylerjereddy added a commit to tylerjereddy/ggmolvis that referenced this pull request Feb 27, 2025
* Expose frame averaging as an alternative to the usage of subframes, as
discussed at: yuxuanzhuang#16 (comment).

* This mostly involved mimicking the infrastructure currently used to
set subframes, minus a few changes we don't seem to need since
the frame count remains unchanged.

* Although I usually try to keep PRs focused on one thing, I did take a
stab at trying to improve the docs for `subframes` while adding in new
docs for `average`. I believe the default value documented for
`subframes` was also incorrect. These are a bit more verbose than
the descriptions in the MN source at `molecularnodes/props.py`, just
because I wanted a bit more detail for non-developer folks.
@tylerjereddy tylerjereddy mentioned this pull request Feb 27, 2025
4 tasks
tylerjereddy added a commit to tylerjereddy/ggmolvis that referenced this pull request Feb 28, 2025
* Expose frame averaging as an alternative to the usage of subframes, as
discussed at: yuxuanzhuang#16 (comment).

* This mostly involved mimicking the infrastructure currently used to
set subframes, minus a few changes we don't seem to need since
the frame count remains unchanged.

* Although I usually try to keep PRs focused on one thing, I did take a
stab at trying to improve the docs for `subframes` while adding in new
docs for `average`. I believe the default value documented for
`subframes` was also incorrect. These are a bit more verbose than
the descriptions in the MN source at `molecularnodes/props.py`, just
because I wanted a bit more detail for non-developer folks.
BradyAJohnston pushed a commit that referenced this pull request Mar 1, 2025
* Expose frame averaging as an alternative to the usage of subframes, as
discussed at: #16 (comment).

* This mostly involved mimicking the infrastructure currently used to
set subframes, minus a few changes we don't seem to need since
the frame count remains unchanged.

* Although I usually try to keep PRs focused on one thing, I did take a
stab at trying to improve the docs for `subframes` while adding in new
docs for `average`. I believe the default value documented for
`subframes` was also incorrect. These are a bit more verbose than
the descriptions in the MN source at `molecularnodes/props.py`, just
because I wanted a bit more detail for non-developer folks.
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.

ENH, MAINT: control "dead time" at end of mp4 movie renders?
3 participants