Image Empties: More visibility settings

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
This commit is contained in:
Jacques Lucke 2018-10-31 13:35:53 +01:00
parent 0727abf1bc
commit a3802f66e2
8 changed files with 109 additions and 10 deletions

View 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 = (

View 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);
}

View 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);
}
}
}

View 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) {

View 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;
}
}

View 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;
}

View 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

View 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");