[Bf-blender-cvs] [4b0396695c6] master: UI/Assets: Support generating object preview images

Julian Eisel noreply at git.blender.org
Mon Dec 14 13:18:14 CET 2020


Commit: 4b0396695c622d1ac8669600fa820e80b1f0979f
Author: Julian Eisel
Date:   Mon Dec 14 12:48:16 2020 +0100
Branches: master
https://developer.blender.org/rB4b0396695c622d1ac8669600fa820e80b1f0979f

UI/Assets: Support generating object preview images

Object previews are really helpful for visual data-block selection, like asset
browsing. Having them be generative should also be quite handy and should work
well enough in many, if not most cases.

What this does is simple:
* Place the object (actually a deep copy of it, for thread safety) in a virtual
  .blend into an empty scene/view-layer.
* Add a camera, point it towards the front of the object, assuming that means
  pointing towards its +Y axis.
* Use "Camera Fit Frame to Selected" logic to put the object into frame.
* Create a threaded off-screen render.

Of course, such an automatic preview will not work in all situations. E.g. it
currently does a bad job capturing a single plane. We could add options for
more advanced automatic previews, but probably custom previews is more
important, which I committed already (812ea9184221).

Part of the first Asset Browser milestone. Check the #asset_browser_milestone_1
project milestone on developer.blender.org.

Reviewed as part of https://developer.blender.org/D9719.
Reviewed by: Bastien Montagne, Brecht Van Lommel

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

M	source/blender/blenkernel/intern/object.c
M	source/blender/editors/include/ED_view3d.h
M	source/blender/editors/render/render_preview.c
M	source/blender/editors/space_view3d/view3d_utils.c
M	source/blender/editors/space_view3d/view3d_view.c

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

diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index bdb907df1ac..f11e7bc429d 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -2208,7 +2208,9 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f
   BLI_listbase_clear(&psysn->childcachebufs);
 
   if (flag & LIB_ID_CREATE_NO_MAIN) {
-    BLI_assert((psys->flag & PSYS_SHARED_CACHES) == 0);
+    /* XXX Disabled, fails when evaluating depsgraph after copying ID with no main for preview
+     * creation. */
+    // BLI_assert((psys->flag & PSYS_SHARED_CACHES) == 0);
     psysn->flag |= PSYS_SHARED_CACHES;
     BLI_assert(psysn->pointcache != NULL);
   }
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 596533406c3..13687bf0450 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -141,6 +141,11 @@ void ED_view3d_to_object(const struct Depsgraph *depsgraph,
                          const float quat[4],
                          const float dist);
 
+bool ED_view3d_camera_to_view_selected(struct Main *bmain,
+                                       struct Depsgraph *depsgraph,
+                                       const struct Scene *scene,
+                                       struct Object *camera_ob);
+
 void ED_view3d_lastview_store(struct RegionView3D *rv3d);
 
 /* Depth buffer */
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index d67113083a3..4466d9f434d 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -68,6 +68,7 @@
 #include "BKE_main.h"
 #include "BKE_material.h"
 #include "BKE_node.h"
+#include "BKE_object.h"
 #include "BKE_scene.h"
 #include "BKE_texture.h"
 #include "BKE_world.h"
@@ -94,12 +95,16 @@
 #include "ED_datafiles.h"
 #include "ED_render.h"
 #include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_view3d_offscreen.h"
 
 #ifndef NDEBUG
 /* Used for database init assert(). */
 #  include "BLI_threads.h"
 #endif
 
+static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect);
+
 ImBuf *get_brush_icon(Brush *brush)
 {
   static const int flags = IB_rect | IB_multilayer | IB_metadata;
@@ -336,7 +341,7 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world)
   return sp->worldcopy;
 }
 
-static ID *duplicate_ids(ID *id)
+static ID *duplicate_ids(ID *id, const bool allow_failure)
 {
   if (id == NULL) {
     /* Non-ID preview render. */
@@ -344,6 +349,7 @@ static ID *duplicate_ids(ID *id)
   }
 
   switch (GS(id->name)) {
+    case ID_OB:
     case ID_MA:
     case ID_TE:
     case ID_LA:
@@ -357,7 +363,9 @@ static ID *duplicate_ids(ID *id)
     case ID_SCR:
       return NULL;
     default:
-      BLI_assert(!"ID type preview not supported.");
+      if (!allow_failure) {
+        BLI_assert(!"ID type preview not supported.");
+      }
       return NULL;
   }
 }
@@ -698,6 +706,132 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
   }
 }
 
+/* **************************** Object preview ****************** */
+
+struct ObjectPreviewData {
+  /* The main for the preview, not of the current file. */
+  Main *pr_main;
+  /* Copy of the object to create the preview for. The copy is for thread safety (and to insert it
+   * into an own main). */
+  Object *object;
+  int sizex;
+  int sizey;
+};
+
+static Object *object_preview_camera_create(
+    Main *preview_main, ViewLayer *view_layer, Object *preview_object, int sizex, int sizey)
+{
+  Object *camera = BKE_object_add(preview_main, view_layer, OB_CAMERA, "Preview Camera");
+
+  float rotmat[3][3];
+  float dummyscale[3];
+  mat4_to_loc_rot_size(camera->loc, rotmat, dummyscale, preview_object->obmat);
+
+  /* Camera is Y up, so needs additional 90deg rotation around X to match object's Z up. */
+  float drotmat[3][3];
+  axis_angle_to_mat3_single(drotmat, 'X', M_PI_2);
+  mul_m3_m3_post(rotmat, drotmat);
+
+  camera->rotmode = ROT_MODE_QUAT;
+  mat3_to_quat(camera->quat, rotmat);
+
+  /* shader_preview_render() does this too. */
+  if (sizex > sizey) {
+    ((Camera *)camera->data)->lens *= (float)sizey / (float)sizex;
+  }
+
+  return camera;
+}
+
+static Scene *object_preview_scene_create(const struct ObjectPreviewData *preview_data,
+                                          Depsgraph **r_depsgraph)
+{
+  Scene *scene = BKE_scene_add(preview_data->pr_main, "Object preview scene");
+  ViewLayer *view_layer = scene->view_layers.first;
+  Depsgraph *depsgraph = DEG_graph_new(
+      preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT);
+
+  BLI_assert(preview_data->object != NULL);
+  BLI_addtail(&preview_data->pr_main->objects, preview_data->object);
+
+  BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object);
+
+  Object *camera_object = object_preview_camera_create(preview_data->pr_main,
+                                                       view_layer,
+                                                       preview_data->object,
+                                                       preview_data->sizex,
+                                                       preview_data->sizey);
+
+  scene->camera = camera_object;
+  scene->r.xsch = preview_data->sizex;
+  scene->r.ysch = preview_data->sizey;
+  scene->r.size = 100;
+
+  Base *preview_base = BKE_view_layer_base_find(view_layer, preview_data->object);
+  /* For 'view selected' below. */
+  preview_base->flag |= BASE_SELECTED;
+
+  DEG_graph_build_from_view_layer(depsgraph);
+  DEG_evaluate_on_refresh(depsgraph);
+
+  ED_view3d_camera_to_view_selected(preview_data->pr_main, depsgraph, scene, camera_object);
+
+  BKE_scene_graph_update_tagged(depsgraph, preview_data->pr_main);
+
+  *r_depsgraph = depsgraph;
+  return scene;
+}
+
+static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
+{
+  Main *preview_main = BKE_main_new();
+  const float pixelsize_old = U.pixelsize;
+  char err_out[256] = "unknown";
+
+  BLI_assert(preview->id_copy && (preview->id_copy != preview->id));
+
+  struct ObjectPreviewData preview_data = {
+      .pr_main = preview_main,
+      /* Act on a copy. */
+      .object = (Object *)preview->id_copy,
+      .sizex = preview_sized->sizex,
+      .sizey = preview_sized->sizey,
+  };
+  Depsgraph *depsgraph;
+  Scene *scene = object_preview_scene_create(&preview_data, &depsgraph);
+
+  /* Ownership is now ours. */
+  preview->id_copy = NULL;
+
+  U.pixelsize = 2.0f;
+
+  ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple(
+      depsgraph,
+      DEG_get_evaluated_scene(depsgraph),
+      NULL,
+      OB_SOLID,
+      DEG_get_evaluated_object(depsgraph, scene->camera),
+      preview_sized->sizex,
+      preview_sized->sizey,
+      IB_rect,
+      V3D_OFSDRAW_NONE,
+      R_ALPHAPREMUL,
+      NULL,
+      NULL,
+      err_out);
+  /* TODO color-management? */
+
+  U.pixelsize = pixelsize_old;
+
+  if (ibuf) {
+    icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
+    IMB_freeImBuf(ibuf);
+  }
+
+  DEG_graph_free(depsgraph);
+  BKE_main_free(preview_main);
+}
+
 /* **************************** new shader preview system ****************** */
 
 /* inside thread, called by renderer, sets job update value */
@@ -1188,27 +1322,54 @@ static void common_preview_startjob(void *customdata,
   }
 }
 
-/* exported functions */
-
-static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey)
+/**
+ * Some ID types already have their own, more focused rendering (only objects right now). This is
+ * for the other ones, which all share #ShaderPreview and some functions.
+ */
+static void other_id_types_preview_render(IconPreview *ip,
+                                          IconPreviewSize *cur_size,
+                                          const bool is_deferred,
+                                          short *stop,
+                                          short *do_update,
+                                          float *progress)
 {
-  IconPreviewSize *cur_size = ip->sizes.first, *new_size;
+  ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
+  const bool is_render = !is_deferred;
+
+  /* These types don't use the ShaderPreview mess, they have their own types and functions. */
+  BLI_assert(!ELEM(GS(ip->id->name), ID_OB));
+
+  /* construct shader preview from image size and previewcustomdata */
+  sp->scene = ip->scene;
+  sp->owner = ip->owner;
+  sp->sizex = cur_size->sizex;
+  sp->sizey = cur_size->sizey;
+  sp->pr_method = is_render ? PR_ICON_RENDER : PR_ICON_DEFERRED;
+  sp->pr_rect = cur_size->rect;
+  sp->id = ip->id;
+  sp->id_copy = ip->id_copy;
+  sp->bmain = ip->bmain;
+  sp->own_id_copy = false;
+  Material *ma = NULL;
 
-  while (cur_size) {
-    if (cur_size->sizex == sizex && cur_size->sizey == sizey) {
-      /* requested size is already in list, no need to add it again */
-      return;
+  if (is_render) {
+    BLI_assert(ip->id);
+
+    /* grease pencil use its own preview file */
+    if (GS(ip->id->name) == ID_MA) {
+      ma = (Material *)ip->id;
     }
 
-    cur_size = cur_size->next;
+    if ((ma == NULL) || (ma->gp_style == NULL)) {
+      sp->pr_main = G_pr_main;
+    }
+    else {
+      sp->pr_main = G_pr_main_grease_pencil;
+    }
   }
 
-  new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize");
-  new_size->sizex = sizex;
-  new_size->sizey = sizey;
-  new_size->rect = rect;
-
-  BLI_addtail(&ip->sizes, new_size);
+  common_preview_startjob(sp, stop, do_update, progress);
+  shader_preview_free(sp);
 }
 
 static void icon_preview_startjob_all_sizes(void *customdata,
@@ -1235,41 +1396,36 @@ static void icon_preview_startjob_all_sizes(void *customdata,
       continue;
     }
 
-    ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
-    const bool is_render = !(prv->tag & PRV_TAG_DEFFERED);
-
-    /* construct shader preview from image size and previewcustomdata */
-    sp->scene = i

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list