[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