[Bf-blender-cvs] [7dd6e034f1c] master: Animation: Added option to playblast only keyframes of selected objects

Sybren A. Stüvel noreply at git.blender.org
Thu Dec 19 16:01:18 CET 2019


Commit: 7dd6e034f1ca5a9628b40de1c664161d83a3546b
Author: Sybren A. Stüvel
Date:   Wed Dec 18 15:19:59 2019 +0100
Branches: master
https://developer.blender.org/rB7dd6e034f1ca5a9628b40de1c664161d83a3546b

Animation: Added option to playblast only keyframes of selected objects

This feature makes it possible to do a viewport render (a.k.a.
playblast) by only rendering those frames on which the selected objects
have a keyframe.

The frames to render are stored in a `BLI_bitmap`, which has a bit for
each frame set to 0 (skip) or 1 (render). An alternative approach would
be to construct a set of all keyframes to render, but that would make
both constructing the list and looking up frames in the list more
complex.

The only thing this feature does is skip OpenGL rendering of a frame. As
a result, 'skipped' frames are still included in the output, but just
use the render result of the last-rendered frame. This is exactly what's
described in T72229.

Differential Revision: https://developer.blender.org/D6443

Reviewed By: zeddb

Design task: T72229

===================================================================

M	release/scripts/startup/bl_ui/space_view3d.py
M	source/blender/editors/render/render_opengl.c

===================================================================

diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 34d22877fa1..868ee738127 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1115,6 +1115,12 @@ class VIEW3D_MT_view(Menu):
 
         layout.operator("render.opengl", text="Viewport Render Image", icon='RENDER_STILL')
         layout.operator("render.opengl", text="Viewport Render Animation", icon='RENDER_ANIMATION').animation = True
+        props = layout.operator("render.opengl",
+                                text="Viewport Render Keyframes",
+                                icon='RENDER_ANIMATION',
+        )
+        props.animation = True
+        props.render_keyed_only = True
 
         layout.separator()
 
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index b46b8cdda89..c7a93e371fb 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -28,6 +28,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "DNA_camera_types.h"
+#include "BLI_bitmap.h"
 #include "BLI_math.h"
 #include "BLI_math_color_blend.h"
 #include "BLI_blenlib.h"
@@ -35,13 +36,18 @@
 #include "BLI_threads.h"
 #include "BLI_task.h"
 
+#include "DNA_anim_types.h"
+#include "DNA_action_types.h"
+#include "DNA_curve_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_object_types.h"
 #include "DNA_gpencil_types.h"
 
+#include "BKE_animsys.h"
 #include "BKE_camera.h"
 #include "BKE_context.h"
 #include "BKE_customdata.h"
+#include "BKE_fcurve.h"
 #include "BKE_global.h"
 #include "BKE_image.h"
 #include "BKE_main.h"
@@ -123,6 +129,9 @@ typedef struct OGLRender {
 
   int totvideos;
 
+  /* For only rendering frames that have a key in animation data. */
+  unsigned int *render_frames; /* BLI_bitmap */
+
   /* quick lookup */
   int view_id;
 
@@ -517,6 +526,69 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
   }
 }
 
+static void gather_frames_to_render_for_adt(OGLRender *oglrender,
+                                            int frame_start,
+                                            int frame_end,
+                                            const AnimData *adt)
+{
+  if (adt == NULL || adt->action == NULL) {
+    return;
+  }
+
+  LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
+    if (fcu->driver != NULL || fcu->fpt != NULL) {
+      /* Drivers have values for any point in time, so to get "the keyed frames" they are
+       * useless. Same for baked FCurves, they also have keys for every frame, which is not
+       * useful for rendering the keyed subset of the frames. */
+      continue;
+    }
+
+    bool found = false; /* Not interesting, we just want a starting point for the for-loop.*/
+    int key_index = binarysearch_bezt_index(fcu->bezt, frame_start, fcu->totvert, &found);
+    for (; key_index < fcu->totvert; key_index++) {
+      BezTriple *bezt = &fcu->bezt[key_index];
+      /* The frame range to render uses integer frame numbers, and the frame
+       * step is also an integer, so we always render on the frame. */
+      int frame_nr = round_fl_to_int(bezt->vec[1][0]);
+
+      /* (frame_nr < frame_start) cannot happen because of the binary search above. */
+      BLI_assert(frame_nr >= frame_start);
+      if (frame_nr > frame_end) {
+        break;
+      }
+      BLI_BITMAP_ENABLE(oglrender->render_frames, frame_nr - frame_start);
+    }
+  }
+}
+
+/* Collect the frame numbers for which selected objects have keys in the animation data.
+ * The frames ares tored in oglrender->render_frames. */
+static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
+{
+  Scene *scene = CTX_data_scene(C);
+  int frame_start = PSFRA;
+  int frame_end = PEFRA;
+
+  /* Will be freed in screen_opengl_render_end(). */
+  oglrender->render_frames = BLI_BITMAP_NEW(frame_end - frame_start + 1,
+                                            "OGLRender::render_frames");
+
+  /* The first frame should always be rendered, otherwise there is nothing to write to file. */
+  BLI_BITMAP_ENABLE(oglrender->render_frames, 0);
+
+  CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+    if (ob->adt != NULL) {
+      gather_frames_to_render_for_adt(oglrender, frame_start, frame_end, ob->adt);
+    }
+
+    AnimData *adt = BKE_animdata_from_id(ob->data);
+    if (adt != NULL) {
+      gather_frames_to_render_for_adt(oglrender, frame_start, frame_end, adt);
+    }
+  }
+  CTX_DATA_END;
+}
+
 static bool screen_opengl_render_init(bContext *C, wmOperator *op)
 {
   /* new render clears all callbacks */
@@ -532,6 +604,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
   int sizex, sizey;
   bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
   const bool is_animation = RNA_boolean_get(op->ptr, "animation");
+  const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
   const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
   const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
   const eImageFormatDepth color_depth = (is_animation) ? scene->r.im_format.depth :
@@ -665,6 +738,10 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
   oglrender->movie_ctx_arr = NULL;
 
   if (is_animation) {
+    if (is_render_keyed_only) {
+      gather_frames_to_render(C, oglrender);
+    }
+
     TaskScheduler *task_scheduler = BLI_task_scheduler_get();
     if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
       task_scheduler = BLI_task_scheduler_create(1);
@@ -731,6 +808,8 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
   printf("Total render time: %f\n", PIL_check_seconds_timer() - oglrender->time_start);
 #endif
 
+  MEM_SAFE_FREE(oglrender->render_frames);
+
   if (oglrender->mh) {
     if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
       for (i = 0; i < oglrender->totvideos; i++) {
@@ -995,8 +1074,11 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
     BKE_scene_camera_switch_update(scene);
   }
 
-  /* render into offscreen buffer */
-  screen_opengl_render_apply(C, oglrender);
+  if (oglrender->render_frames == NULL ||
+      BLI_BITMAP_TEST_BOOL(oglrender->render_frames, CFRA - PSFRA)) {
+    /* render into offscreen buffer */
+    screen_opengl_render_apply(C, oglrender);
+  }
 
   /* save to disk */
   rr = RE_AcquireResultRead(oglrender->re);
@@ -1132,6 +1214,12 @@ static char *screen_opengl_render_description(struct bContext *UNUSED(C),
     return NULL;
   }
 
+  if (RNA_boolean_get(ptr, "render_keyed_only")) {
+    return BLI_strdup(
+        "Render the viewport for the animation range of this scene, but only render keyframes of "
+        "selected objects");
+  }
+
   return BLI_strdup("Render the viewport for the animation range of this scene");
 }
 
@@ -1159,6 +1247,15 @@ void RENDER_OT_opengl(wmOperatorType *ot)
                          "Animation",
                          "Render files from the animation range of this scene");
   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+  prop = RNA_def_boolean(ot->srna,
+                         "render_keyed_only",
+                         0,
+                         "Render Keyframes Only",
+                         "Render only those frames where selected objects have a key in their "
+                         "animation data. Only used when rendering animation");
+  RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
   prop = RNA_def_boolean(
       ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display");
   RNA_def_property_flag(prop, PROP_SKIP_SAVE);



More information about the Bf-blender-cvs mailing list