Implement duplicator viewport/render visibility options

This allows a duplicator (as known as dupli parent) to be in a visible
collection so its duplicated objects are visible, however while being
invisible for the final render.

An object that is a particle emitter is also considered a duplicator.

Many thanks for the reviewers for the extense feedback.

Reviewers: sergey, campbellbarton

Differential Revision: https://developer.blender.org/D2966
This commit is contained in:
Dalai Felinto 2017-12-21 13:29:14 -02:00
parent 103dd66057
commit b89f2276e5
21 changed files with 215 additions and 69 deletions

View File

@ -469,6 +469,7 @@ static bool object_render_hide(BL::Object& b_ob,
BL::Object::particle_systems_iterator b_psys;
bool hair_present = false;
bool has_particles = false;
bool show_emitter = false;
bool hide_emitter = false;
bool hide_as_dupli_parent = false;
@ -478,20 +479,17 @@ static bool object_render_hide(BL::Object& b_ob,
if((b_psys->settings().render_type() == BL::ParticleSettings::render_type_PATH) &&
(b_psys->settings().type()==BL::ParticleSettings::type_HAIR))
hair_present = true;
if(b_psys->settings().use_render_emitter())
show_emitter = true;
else
hide_emitter = true;
has_particles = true;
}
if(show_emitter)
hide_emitter = false;
/* duplicators hidden by default, except dupliframes which duplicate self */
if(b_ob.is_duplicator())
if(top_level || b_ob.dupli_type() != BL::Object::dupli_type_FRAMES)
if(has_particles) {
show_emitter = b_ob.show_duplicator_for_render();
hide_emitter = !show_emitter;
} else if(b_ob.is_duplicator()) {
if(top_level || b_ob.show_duplicator_for_render()) {
hide_as_dupli_parent = true;
}
}
/* hide original object for duplis */
BL::Object parent = b_ob.parent();

View File

@ -278,6 +278,13 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
col.label(text="Object Color:")
col.prop(obj, "color", text="")
col = layout.column()
col.active = bool(is_dupli or obj.particle_systems)
col.label(text="Duplicator Visibility:")
row = col.row(align=True)
row.prop(obj, "show_duplicator_for_viewport", text="Viewport")
row.prop(obj, "show_duplicator_for_render", text="Render")
class OBJECT_PT_duplication(ObjectButtonsPanel, Panel):
bl_label = "Duplication"

View File

@ -926,7 +926,6 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel):
split = layout.split()
col = split.column()
col.prop(part, "use_render_emitter")
col.prop(part, "use_parent_particles")
col = split.column()

View File

@ -82,7 +82,14 @@ bool BKE_object_exists_check(struct Object *obtest);
bool BKE_object_is_in_editmode(struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(struct Object *ob);
bool BKE_object_is_in_wpaint_select_vert(struct Object *ob);
bool BKE_object_is_visible(struct Object *ob);
typedef enum eObjectVisibilityCheck {
OB_VISIBILITY_CHECK_FOR_VIEWPORT,
OB_VISIBILITY_CHECK_FOR_RENDER,
OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE,
} eObjectVisibilityCheck;
bool BKE_object_is_visible(struct Object *ob, const eObjectVisibilityCheck mode);
void BKE_object_init(struct Object *ob);
struct Object *BKE_object_add_only_object(

View File

@ -552,11 +552,32 @@ bool BKE_object_is_in_wpaint_select_vert(Object *ob)
/**
* Return if the object is visible, as evaluated by depsgraph
* Keep in sync with rna_object.c (object.is_visible).
*/
bool BKE_object_is_visible(Object *ob)
bool BKE_object_is_visible(Object *ob, const eObjectVisibilityCheck mode)
{
return (ob->base_flag & BASE_VISIBLED) != 0;
if ((ob->base_flag & BASE_VISIBLED) == 0) {
return false;
}
if (mode == OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) {
return true;
}
if (((ob->transflag & OB_DUPLI) == 0) &&
(ob->particlesystem.first == NULL))
{
return true;
}
switch (mode) {
case OB_VISIBILITY_CHECK_FOR_VIEWPORT:
return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT) != 0);
case OB_VISIBILITY_CHECK_FOR_RENDER:
return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0);
default:
BLI_assert(!"Object visible test mode not supported.");
return false;
}
}
bool BKE_object_exists_check(Object *obtest)
@ -684,6 +705,7 @@ void BKE_object_init(Object *ob)
ob->col_group = 0x01;
ob->col_mask = 0xffff;
ob->preview = NULL;
ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
/* NT fluid sim defaults */
ob->fluidsimSettings = NULL;

View File

@ -3279,7 +3279,7 @@ static void default_particle_settings(ParticleSettings *part)
part->clength = 1.0f;
part->clength_thres = 0.0f;
part->draw = PART_DRAW_EMITTER;
part->draw = 0;
part->draw_line[0] = 0.5;
part->path_start = 0.0f;
part->path_end = 1.0f;

View File

@ -45,6 +45,7 @@
#include "DNA_lightprobe_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
@ -855,4 +856,28 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
{
if (!DNA_struct_elem_find(fd->filesdna, "Object", "char", "duplicator_visibility_flag")) {
for (Object *object = main->object.first; object; object = object->id.next) {
if (object->particlesystem.first) {
bool show_emitter = false;
for (ParticleSystem *psys = object->particlesystem.first; psys; psys=psys->next) {
show_emitter |= (psys->part->draw & PART_DRAW_EMITTER) != 0;
}
object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT;
if (show_emitter) {
object->duplicator_visibility_flag |= OB_DUPLI_FLAG_RENDER;
}
}
else if (object->transflag & OB_DUPLI){
object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT;
}
else {
object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
}
}
}
}
}

View File

@ -77,12 +77,18 @@ enum {
DEG_ITER_OBJECT_FLAG_DUPLI = (1 << 4),
};
typedef enum eDepsObjectIteratorMode {
DEG_ITER_OBJECT_MODE_VIEWPORT = 0,
DEG_ITER_OBJECT_MODE_RENDER = 1,
} eDepsObjectIteratorMode;
typedef struct DEGObjectIterData {
struct Depsgraph *graph;
struct Scene *scene;
struct EvaluationContext eval_ctx;
int flag;
eDepsObjectIteratorMode mode;
/* **** Iteration over dupli-list. *** */
@ -115,10 +121,11 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter);
* Although they are available they have no overrides (collection_properties)
* and will crash if you try to access it.
*/
#define DEG_OBJECT_ITER(graph_, instance_, flag_) \
#define DEG_OBJECT_ITER(graph_, instance_, mode_, flag_) \
{ \
DEGObjectIterData data_ = { \
.graph = (graph_), \
.mode = (mode_), \
.flag = (flag_), \
}; \
\
@ -134,8 +141,8 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter);
/**
* Depsgraph objects iterator for draw manager and final render
*/
#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph_, instance_) \
DEG_OBJECT_ITER(graph_, instance_, \
#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph_, instance_, mode_) \
DEG_OBJECT_ITER(graph_, instance_, mode_, \
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | \
DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | \
DEG_ITER_OBJECT_FLAG_VISIBLE | \

View File

@ -84,6 +84,7 @@ static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
Object *dupli_parent = data->dupli_parent;
Object *temp_dupli_object = &data->temp_dupli_object;
*temp_dupli_object = *dob->ob;
temp_dupli_object->transflag &= ~OB_DUPLI;
temp_dupli_object->select_color = dupli_parent->select_color;
temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROMDUPLI;
@ -139,7 +140,7 @@ static void DEG_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_no
Object *object = (Object *)id_node->id_cow;
BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id));
if ((BKE_object_is_visible(object) == false) &&
if ((BKE_object_is_visible(object, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) == false) &&
((data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) != 0))
{
return;
@ -149,6 +150,14 @@ static void DEG_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_no
data->dupli_parent = object;
data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, object);
data->dupli_object_next = (DupliObject *)data->dupli_list->first;
const eObjectVisibilityCheck mode = (data->mode == DEG_ITER_OBJECT_MODE_RENDER) ?
OB_VISIBILITY_CHECK_FOR_RENDER :
OB_VISIBILITY_CHECK_FOR_VIEWPORT;
if (BKE_object_is_visible(object, mode) == false) {
return;
}
}
iter->current = object;
@ -167,7 +176,10 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
}
/* TODO(sergey): What evaluation type we want here? */
DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_RENDER);
/* TODO(dfelinto): Get rid of evaluation context here, it's only used to do
* direct dupli-objects update in group.c. Which is terribly bad, and all
* objects are expected to be evaluated already. */
DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_VIEWPORT);
data->eval_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph);
iter->data = data;
@ -193,6 +205,7 @@ void DEG_iterator_objects_next(BLI_Iterator *iter)
Depsgraph *depsgraph = data->graph;
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
do {
iter->skip = false;
if (data->dupli_list) {
if (deg_objects_dupli_iterator_next(iter)) {
return;

View File

@ -746,12 +746,45 @@ static void clay_cache_init(void *vedata)
}
}
static void clay_cache_populate_particles(void *vedata, Object *ob)
{
CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
Object *obedit = scene->obedit;
if (ob != obedit) {
for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
if (psys_check_enabled(ob, psys, false)) {
ParticleSettings *part = psys->part;
int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) {
draw_as = PART_DRAW_DOT;
}
static float mat[4][4];
unit_m4(mat);
if (draw_as == PART_DRAW_PATH) {
struct Gwn_Batch *geom = DRW_cache_particles_get_hair(psys, NULL);
DRWShadingGroup *hair_shgrp = CLAY_hair_shgrp_get(vedata, ob, stl, psl);
DRW_shgroup_call_add(hair_shgrp, geom, mat);
}
}
}
}
}
static void clay_cache_populate(void *vedata, Object *ob)
{
CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
DRWShadingGroup *clay_shgrp, *hair_shgrp;
DRWShadingGroup *clay_shgrp;
if (!DRW_object_is_renderable(ob))
return;
@ -764,6 +797,15 @@ static void clay_cache_populate(void *vedata, Object *ob)
}
}
/* Handle particles first in case the emitter itself shouldn't be rendered. */
if (ob->type == OB_MESH) {
clay_cache_populate_particles(vedata, ob);
}
if (DRW_check_object_visible_within_active_context(ob) == false) {
return;
}
struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob);
if (geom) {
IDProperty *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, "");
@ -797,33 +839,6 @@ static void clay_cache_populate(void *vedata, Object *ob)
DRW_shgroup_call_add(clay_shgrp, geom, ob->obmat);
}
}
if (ob->type == OB_MESH) {
Scene *scene = draw_ctx->scene;
Object *obedit = scene->obedit;
if (ob != obedit) {
for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
if (psys_check_enabled(ob, psys, false)) {
ParticleSettings *part = psys->part;
int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) {
draw_as = PART_DRAW_DOT;
}
static float mat[4][4];
unit_m4(mat);
if (draw_as == PART_DRAW_PATH) {
geom = DRW_cache_particles_get_hair(psys, NULL);
hair_shgrp = CLAY_hair_shgrp_get(vedata, ob, stl, psl);
DRW_shgroup_call_add(hair_shgrp, geom, mat);
}
}
}
}
}
}
static void clay_cache_finish(void *vedata)

View File

@ -113,6 +113,10 @@ static void eevee_cache_populate(void *vedata, Object *ob)
}
}
if (DRW_check_object_visible_within_active_context(ob) == false) {
return;
}
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
EEVEE_materials_cache_populate(vedata, sldata, ob);

View File

@ -396,6 +396,7 @@ void DRW_lamp_engine_data_free(struct LampEngineData *led);
/* Settings */
bool DRW_object_is_renderable(struct Object *ob);
bool DRW_check_object_visible_within_active_context(struct Object *ob);
bool DRW_object_is_flat_normal(const struct Object *ob);
int DRW_object_is_mode_shade(const struct Object *ob);
@ -433,6 +434,8 @@ bool DRW_state_show_text(void);
bool DRW_state_draw_support(void);
bool DRW_state_draw_background(void);
enum eDepsObjectIteratorMode DRW_iterator_mode_get(void);
struct DRWTextStore *DRW_state_text_cache_get(void);
/* Avoid too many lookups while drawing */

View File

@ -2215,7 +2215,7 @@ bool DRW_object_is_renderable(Object *ob)
Scene *scene = DST.draw_ctx.scene;
Object *obedit = scene->obedit;
BLI_assert(BKE_object_is_visible(ob));
BLI_assert(BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE));
if (ob->type == OB_MESH) {
if (ob == obedit) {
@ -2234,6 +2234,18 @@ bool DRW_object_is_renderable(Object *ob)
return true;
}
/**
* Return whether this object is visible depending if
* we are rendering or drawing in the viewport.
*/
bool DRW_check_object_visible_within_active_context(Object *ob)
{
const eObjectVisibilityCheck mode = DRW_state_is_scene_render() ?
OB_VISIBILITY_CHECK_FOR_RENDER :
OB_VISIBILITY_CHECK_FOR_VIEWPORT;
return BKE_object_is_visible(ob, mode);
}
bool DRW_object_is_flat_normal(const Object *ob)
{
if (ob->type == OB_MESH) {
@ -2245,7 +2257,6 @@ bool DRW_object_is_flat_normal(const Object *ob)
return true;
}
/**
* Return true if the object has its own draw mode.
* Caller must check this is active */
@ -3403,7 +3414,7 @@ void DRW_draw_render_loop_ex(
PROFILE_START(stime);
drw_engines_cache_init();
DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph, ob)
DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph, ob, DRW_iterator_mode_get())
{
drw_engines_cache_populate(ob);
}
@ -3620,7 +3631,7 @@ void DRW_draw_select_loop(
drw_engines_cache_populate(scene->obedit);
}
else {
DEG_OBJECT_ITER(graph, ob,
DEG_OBJECT_ITER(graph, ob, DRW_iterator_mode_get(),
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
DEG_ITER_OBJECT_FLAG_VISIBLE |
DEG_ITER_OBJECT_FLAG_DUPLI)
@ -3715,7 +3726,7 @@ void DRW_draw_depth_loop(
if (cache_is_dirty) {
drw_engines_cache_init();
DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph, ob)
DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph, ob, DRW_iterator_mode_get())
{
drw_engines_cache_populate(ob);
}
@ -3800,6 +3811,15 @@ bool DRW_state_is_scene_render(void)
return DST.options.is_scene_render;
}
/**
* Gives you the iterator mode to use for depsgraph.
*/
eDepsObjectIteratorMode DRW_iterator_mode_get(void)
{
return DRW_state_is_scene_render() ? DEG_ITER_OBJECT_MODE_RENDER :
DEG_ITER_OBJECT_MODE_VIEWPORT;
}
/**
* Should text draw in this mode?
*/

View File

@ -1648,7 +1648,7 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl
static void DRW_shgroup_relationship_lines(OBJECT_StorageList *stl, Object *ob)
{
if (ob->parent && BKE_object_is_visible(ob->parent)) {
if (ob->parent && DRW_check_object_visible_within_active_context(ob->parent)) {
DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->obmat[3]);
DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->parent->obmat[3]);
}
@ -1763,6 +1763,15 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
View3D *v3d = draw_ctx->v3d;
int theme_id = TH_UNDEFINED;
/* Handle particles first in case the emitter itself shouldn't be rendered. */
if (ob->type == OB_MESH) {
OBJECT_cache_populate_particles(ob, psl);
}
if (DRW_check_object_visible_within_active_context(ob) == false) {
return;
}
//CollectionEngineSettings *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, "");
//bool do_wire = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_wire");
@ -1800,8 +1809,6 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
}
}
}
OBJECT_cache_populate_particles(ob, psl);
break;
}
case OB_SURF:

View File

@ -9217,7 +9217,10 @@ afterdraw:
/* help lines and so */
if (ob != scene->obedit && ob->parent) {
if (BKE_object_is_visible(ob->parent)) {
const eObjectVisibilityCheck mode = eval_ctx->mode != DAG_EVAL_VIEWPORT ?
OB_VISIBILITY_CHECK_FOR_RENDER :
OB_VISIBILITY_CHECK_FOR_VIEWPORT;
if (BKE_object_is_visible(ob->parent, mode)) {
setlinestyle(3);
immBegin(GWN_PRIM_LINES, 2);
immVertex3fv(pos, ob->obmat[3]);

View File

@ -208,7 +208,7 @@ typedef struct Object {
/* did last modifier stack generation need mapping support? */
char lastNeedMapping; /* bool */
char pad;
char duplicator_visibility_flag;
/* dupli-frame settings */
int dupon, dupoff, dupsta, dupend;
@ -708,6 +708,12 @@ enum {
OB_LOCK_ROT4D = 1 << 10,
};
/* ob->duplicator_visibility_flag */
enum {
OB_DUPLI_FLAG_VIEWPORT = 1 << 0,
OB_DUPLI_FLAG_RENDER = 1 << 1,
};
/* ob->mode */
typedef enum eObjectMode {
OB_MODE_OBJECT = 0,

View File

@ -168,6 +168,7 @@ static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, Pointe
data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
DEG_ITER_OBJECT_FLAG_VISIBLE |
DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
data->mode = DEG_ITER_OBJECT_MODE_RENDER;
((BLI_Iterator *)iter->internal.custom)->valid = true;
DEG_iterator_objects_begin(iter->internal.custom, data);
@ -208,6 +209,7 @@ static void rna_Depsgraph_duplis_begin(CollectionPropertyIterator *iter, Pointer
DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
DEG_ITER_OBJECT_FLAG_VISIBLE |
DEG_ITER_OBJECT_FLAG_DUPLI;
data->mode = DEG_ITER_OBJECT_MODE_RENDER;
((BLI_Iterator *)iter->internal.custom)->valid = true;
DEG_iterator_objects_begin(iter->internal.custom, data);

View File

@ -870,7 +870,7 @@ static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, Po
static void rna_ViewLayer_update_tagged(ViewLayer *UNUSED(view_layer), bContext *C)
{
Depsgraph *graph = CTX_data_depsgraph(C);
DEG_OBJECT_ITER(graph, ob,
DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_MODE_VIEWPORT,
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY |

View File

@ -232,7 +232,13 @@ static void rna_Object_hide_update(Main *bmain, Scene *UNUSED(scene), PointerRNA
static int rna_Object_is_visible_get(PointerRNA *ptr)
{
Object *ob = ptr->id.data;
return BKE_object_is_visible(ob);
/* The duplicators final visibility is not evaluated by depsgraph, so it's
* in ob->base_flag & VISIBLED. Instead we need to take into account whether
* we are rendering or not, and the ob->duplicator_visibility_flag.
* However for this assessor we don't know if we are rendering, so we just
* ignore the duplicator visibility
*/
return BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE);
}
static void rna_Object_collection_properties_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@ -2798,6 +2804,14 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update");
prop = RNA_def_property(srna, "show_duplicator_for_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_RENDER);
RNA_def_property_ui_text(prop, "Render Duplicator", "Make duplicator visible when rendering");
prop = RNA_def_property(srna, "show_duplicator_for_viewport", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_VIEWPORT);
RNA_def_property_ui_text(prop, "Show Duplicator", "Make duplicator visible in the viewport");
prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_Object_is_visible_get", NULL);
RNA_def_property_ui_text(prop, "Visible", "Visible to camera rays, set only on objects evaluated by depsgraph");

View File

@ -2292,11 +2292,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Size", "Show particle size");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "use_render_emitter", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_EMITTER);
RNA_def_property_ui_text(prop, "Emitter", "Render emitter Object also");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "show_health", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_HEALTH);
RNA_def_property_ui_text(prop, "Health", "Draw boid health");

View File

@ -4668,9 +4668,8 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
/* the emitter has to be processed first (render levels of modifiers) */
/* so here we only check if the emitter should be rendered */
if (ob->particlesystem.first) {
show_emitter= 0;
show_emitter = (ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0;
for (psys=ob->particlesystem.first; psys; psys=psys->next) {
show_emitter += psys->part->draw & PART_DRAW_EMITTER;
if (!(re->r.scemode & R_VIEWPORT_PREVIEW)) {
psys_has_renderdata |= (psys->renderdata != NULL);
psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset);