Image Empties: More visibility settings
authorJacques Lucke <mail@jlucke.com>
Wed, 31 Oct 2018 12:35:53 +0000 (13:35 +0100)
committerJacques Lucke <mail@jlucke.com>
Wed, 31 Oct 2018 12:42:33 +0000 (13:42 +0100)
Support for showing images in background/foreground and only in perspective/orthographic view.

Internally the depth of the image is modified in the fragment shader by setting `gl_FragDepth` explicitly.

The UI still needs some work to improve usability, see D3863 for details.
Currently there is one duplicated function, not sure how to best deduplicate it yet. (`is_image_empty_visible`)

Reviewer: fclem, brecht, campbellbarton

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

release/scripts/startup/bl_ui/properties_data_empty.py
source/blender/blenkernel/intern/object.c
source/blender/blenloader/intern/versioning_280.c
source/blender/draw/modes/object_mode.c
source/blender/draw/modes/shaders/object_empty_image_frag.glsl
source/blender/editors/space_view3d/view3d_gizmo_empty.c
source/blender/makesdna/DNA_object_types.h
source/blender/makesrna/intern/rna_object.c

index 9cd5a5909ce91e2a0925f4d8c413af0c877532df..36295eb4b7ef85da4db87f71a27559364299eb1b 100644 (file)
@@ -56,6 +56,10 @@ class DATA_PT_empty(DataButtonsPanel, Panel):
         layout.separator()
 
         layout.prop(ob, "empty_display_size", text="Size")
+        layout.prop(ob, "empty_image_depth", text="Depth", expand=True)
+
+        layout.prop(ob, "show_empty_image_orthographic", text="Display Orthographic")
+        layout.prop(ob, "show_empty_image_perspective", text="Display Perspective")
 
 
 classes = (
index 00031b2611c88e4b46e3e1724c24aeb4ddff3326..60d800f19a810a1c7040f451fa35e7981f680ed9 100644 (file)
@@ -832,6 +832,10 @@ void BKE_object_init(Object *ob)
        ob->dt = OB_TEXTURE;
        ob->empty_drawtype = OB_PLAINAXES;
        ob->empty_drawsize = 1.0;
+       ob->empty_image_depth = OB_EMPTY_IMAGE_DEPTH_DEFAULT;
+       ob->empty_image_visibility_flag = (
+                 OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE
+               | OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC);
        if (ob->type == OB_EMPTY) {
                copy_v2_fl(ob->ima_ofs, -0.5f);
        }
index 75818a3075145416f5df327c124f26b1645698d0..a726b32166bcd983eb110c36496af63baeb04d55 100644 (file)
@@ -2220,5 +2220,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
                        }
                }
 
+               for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+                       ob->empty_image_visibility_flag = (
+                                 OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE
+                               | OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC);
+               }
        }
 }
index dc26b09183218cd2fca3210f9dfcde1ddb6f93bd..53f128463fe67f10d306934647c09d93e5de63f4 100644 (file)
@@ -419,14 +419,23 @@ static void OBJECT_engine_init(void *vedata)
                e_data.outline_fade_sh = DRW_shader_create_fullscreen(datatoc_object_outline_expand_frag_glsl, NULL);
 
                /* Empty images */
+#              define EMPTY_IMAGE_SHADER_DEFINES \
+                       "#define DEPTH_UNCHANGED " STRINGIFY(OB_EMPTY_IMAGE_DEPTH_DEFAULT) "\n" \
+                       "#define DEPTH_FRONT " STRINGIFY(OB_EMPTY_IMAGE_DEPTH_FRONT) "\n" \
+                       "#define DEPTH_BACK " STRINGIFY(OB_EMPTY_IMAGE_DEPTH_BACK) "\n"
+
                e_data.object_empty_image_sh = DRW_shader_create(
-                          datatoc_object_empty_image_vert_glsl, NULL,
-                          datatoc_object_empty_image_frag_glsl, NULL);
+                           datatoc_object_empty_image_vert_glsl, NULL,
+                           datatoc_object_empty_image_frag_glsl,
+                           EMPTY_IMAGE_SHADER_DEFINES);
 
                e_data.object_empty_image_wire_sh = DRW_shader_create(
-                          datatoc_object_empty_image_vert_glsl, NULL,
-                          datatoc_object_empty_image_frag_glsl,
-                          "#define USE_WIRE\n");
+                           datatoc_object_empty_image_vert_glsl, NULL,
+                           datatoc_object_empty_image_frag_glsl,
+                           EMPTY_IMAGE_SHADER_DEFINES
+                           "#define USE_WIRE\n");
+
+#              undef EMPTY_IMAGE_SHADER_DEFINES
 
                /* Grid */
                e_data.grid_sh = DRW_shader_create_with_lib(
@@ -847,6 +856,17 @@ static void image_calc_aspect(Image *ima, ImageUser *iuser, float r_image_aspect
        }
 }
 
+static bool is_image_empty_visible(Object *ob, RegionView3D *rv3d)
+{
+       int visibility_flag = ob->empty_image_visibility_flag;
+       if (rv3d->is_persp) {
+               return visibility_flag & OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE;
+       }
+       else {
+               return visibility_flag & OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC;
+       }
+}
+
 /* per-image shading groups for image-type empty objects */
 struct EmptyImageShadingGroupData {
        DRWShadingGroup *shgrp_image;
@@ -855,10 +875,12 @@ struct EmptyImageShadingGroupData {
 };
 
 static void DRW_shgroup_empty_image(
-        OBJECT_ShadingGroupList *sgl, Object *ob, const float color[3])
+        OBJECT_ShadingGroupList *sgl, Object *ob, const float color[3], RegionView3D *rv3d)
 {
        /* TODO: 'StereoViews', see draw_empty_image. */
 
+       if (!is_image_empty_visible(ob, rv3d)) return;
+
        if (sgl->image_plane_map == NULL) {
                sgl->image_plane_map = BLI_ghash_ptr_new(__func__);
        }
@@ -891,6 +913,7 @@ static void DRW_shgroup_empty_image(
                                e_data.object_empty_image_sh, sgl->non_meshes, geom, e_data.empty_image_format);
                        DRW_shgroup_uniform_texture(grp, "image", tex);
                        DRW_shgroup_uniform_vec2(grp, "aspect", empty_image_data->image_aspect, 1);
+                       DRW_shgroup_uniform_int_copy(grp, "depthMode", ob->empty_image_depth);
 
                        empty_image_data->shgrp_image = grp;
                }
@@ -910,6 +933,7 @@ static void DRW_shgroup_empty_image(
                        DRWShadingGroup *grp = DRW_shgroup_instance_create(
                                e_data.object_empty_image_wire_sh, sgl->non_meshes, geom, e_data.empty_image_wire_format);
                        DRW_shgroup_uniform_vec2(grp, "aspect", empty_image_data->image_aspect, 1);
+                       DRW_shgroup_uniform_int_copy(grp, "depthMode", ob->empty_image_depth);
 
                        empty_image_data->shgrp_wire = grp;
                }
@@ -1853,7 +1877,7 @@ static void DRW_shgroup_empty_ex(
        }
 }
 
-static void DRW_shgroup_empty(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer)
+static void DRW_shgroup_empty(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer, RegionView3D *rv3d)
 {
        float *color;
        DRW_object_wire_theme_get(ob, view_layer, &color);
@@ -1869,7 +1893,7 @@ static void DRW_shgroup_empty(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye
                        DRW_shgroup_empty_ex(sgl, ob->obmat, &ob->empty_drawsize, ob->empty_drawtype, color);
                        break;
                case OB_EMPTY_IMAGE:
-                       DRW_shgroup_empty_image(sgl, ob, color);
+                       DRW_shgroup_empty_image(sgl, ob, color, rv3d);
                        break;
        }
 }
@@ -2756,7 +2780,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
                        if (hide_object_extra) {
                                break;
                        }
-                       DRW_shgroup_empty(sgl, ob, view_layer);
+                       DRW_shgroup_empty(sgl, ob, view_layer, rv3d);
                        break;
                case OB_GPENCIL:
                        if (hide_object_extra) {
index eab107354d1ff2ddd36f71f7a399bbea6cab37c5..e47b28d80c633377dff9eda22c1374cfe4d9bb80 100644 (file)
@@ -11,6 +11,8 @@ out vec4 fragColor;
 uniform sampler2D image;
 #endif
 
+uniform int depthMode;
+
 void main()
 {
 #ifdef USE_WIRE
@@ -18,4 +20,14 @@ void main()
 #else
        fragColor = finalColor * texture(image, texCoord_interp);
 #endif
+
+       if (depthMode == DEPTH_BACK) {
+               gl_FragDepth = 0.999999;
+       }
+       else if (depthMode == DEPTH_FRONT) {
+               gl_FragDepth = 0.000001;
+       }
+       else if (depthMode == DEPTH_UNCHANGED) {
+               gl_FragDepth = gl_FragCoord.z;
+       }
 }
index fe1129f8028bf0db37470d542d60ee98fd601ccf..bc190355ea6e7bac79f97c00318e4eef582d7809 100644 (file)
@@ -107,9 +107,21 @@ static void gizmo_empty_image_prop_matrix_set(
        ob->ima_ofs[1] = (matrix[3][1] - (0.5f * dims[1])) / dims[1];
 }
 
+static bool is_image_empty_visible(Object *ob, RegionView3D *rv3d)
+{
+       int visibility_flag = ob->empty_image_visibility_flag;
+       if (rv3d->is_persp) {
+               return visibility_flag & OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE;
+       }
+       else {
+               return visibility_flag & OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC;
+       }
+}
+
 static bool WIDGETGROUP_empty_image_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
 {
        View3D *v3d = CTX_wm_view3d(C);
+       RegionView3D *rv3d = CTX_wm_region_view3d(C);
 
        if ((v3d->flag2 & V3D_RENDER_OVERRIDE) ||
            (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)))
@@ -120,7 +132,9 @@ static bool WIDGETGROUP_empty_image_poll(const bContext *C, wmGizmoGroupType *UN
        Object *ob = CTX_data_active_object(C);
 
        if (ob && ob->type == OB_EMPTY) {
-               return (ob->empty_drawtype == OB_EMPTY_IMAGE);
+               if (ob->empty_drawtype == OB_EMPTY_IMAGE){
+                       return is_image_empty_visible(ob, rv3d);
+               }
        }
        return false;
 }
index d19c29574b67867901601b9990534d6088d269eb..fca6a8767bed6c49e8e38c76086266329eae5b0e 100644 (file)
@@ -296,6 +296,9 @@ typedef struct Object {
 
        float ima_ofs[2];               /* offset for image empties */
        ImageUser *iuser;               /* must be non-null when object is an empty image */
+       char empty_image_visibility_flag;
+       char empty_image_depth;
+       char pad11[6];
 
        ListBase lodlevels;             /* contains data for levels of detail */
        LodLevel *currentlod;
@@ -596,6 +599,17 @@ enum {
        OB_DUPLI_FLAG_RENDER   = 1 << 1,
 };
 
+/* ob->empty_image_depth */
+#define OB_EMPTY_IMAGE_DEPTH_DEFAULT 0
+#define OB_EMPTY_IMAGE_DEPTH_FRONT 1
+#define OB_EMPTY_IMAGE_DEPTH_BACK 2
+
+/* ob->empty_image_visibility_flag */
+enum {
+       OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE  = 1 << 0,
+       OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC = 1 << 1,
+};
+
 #define MAX_DUPLI_RECUR 8
 
 #ifdef __cplusplus
index f2df147e90fdb52682dbe242db91464abefb54ad..2883543a2e3f2932baa643eb31cc8f1ae70cc3f2 100644 (file)
@@ -110,6 +110,13 @@ const EnumPropertyItem rna_enum_object_empty_drawtype_items[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
+const EnumPropertyItem rna_enum_object_empty_image_depth_items[] = {
+       {OB_EMPTY_IMAGE_DEPTH_DEFAULT, "DEFAULT", 0, "Default", ""},
+       {OB_EMPTY_IMAGE_DEPTH_FRONT, "FRONT", 0, "Front", ""},
+       {OB_EMPTY_IMAGE_DEPTH_BACK, "BACK", 0, "Back", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
 const EnumPropertyItem rna_enum_object_gpencil_type_items[] = {
        {GP_EMPTY, "EMPTY", ICON_GP_EMPTY, "Blank", "Create an empty grease pencil object"},
        {GP_STROKE, "STROKE", ICON_GP_STROKE, "Stroke", "Create a simple stroke with basic colors"},
@@ -2488,6 +2495,21 @@ static void rna_def_object(BlenderRNA *brna)
                                 "Parameters defining which layer, pass and frame of the image is displayed");
        RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
 
+       prop = RNA_def_property(srna, "empty_image_depth", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_items(prop, rna_enum_object_empty_image_depth_items);
+       RNA_def_property_ui_text(prop, "Empty Image Depth", "Determine which other objects will occlude the image");
+       RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+       prop = RNA_def_property(srna, "show_empty_image_perspective", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "empty_image_visibility_flag", OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE);
+       RNA_def_property_ui_text(prop, "Display in Perspective Mode", "Display image in perspective mode");
+       RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+       prop = RNA_def_property(srna, "show_empty_image_orthographic", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "empty_image_visibility_flag", OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC);
+       RNA_def_property_ui_text(prop, "Display in Orthographic Mode", "Display image in orthographic mode");
+       RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
        /* render */
        prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
        RNA_def_property_int_sdna(prop, NULL, "index");