Files
test2/source/blender/depsgraph/intern/depsgraph_query_iter.cc
Dalai Felinto e75c04898f Fix duplicator visibility logic
Cycles old behaviour is to hide the duplicator on rendering at all times.

We have since a few months an option in 2.8 to control the duplicator
visibility on its own. However when the duplicator is also duplicated, things
were not working properly.

What we do now is, in addition to the duplicator visibility control, is to not
have the source collection of the duplicator object to ever influence its
visibility when the object is been duplicated.

So if the user wants to reproduce Cycles old behaviour all that is required is
to have different collections, one for the original to-be duplicated objects
that you hide in for the view layer used in the final render. And another
collection with only the first duplicator (which in turn duplicates other
duplicators).

I know this all may sound confusing, so please just give it a try, it's simpler
than it sounds.
2018-02-05 19:01:27 -02:00

283 lines
8.2 KiB
C++

/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2017 Blender Foundation.
* All rights reserved.
*
* Original Author: Dalai Felinto
* Contributor(s): Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/depsgraph/intern/depsgraph_query_iter.cc
* \ingroup depsgraph
*
* Implementation of Querying and Filtering API's
*/
#include "MEM_guardedalloc.h"
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BKE_anim.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
#include "BKE_object.h"
} /* extern "C" */
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
#include "intern/nodes/deg_node_id.h"
#ifndef NDEBUG
# include "intern/eval/deg_eval_copy_on_write.h"
#endif
/* ************************ DEG ITERATORS ********************* */
static void verify_id_proeprties_freed(DEGObjectIterData *data)
{
if (data->dupli_object_current == NULL) {
// We didn't enter duplication yet, so we can't have any dangling
// pointers.
return;
}
const Object *dupli_object = data->dupli_object_current->ob;
Object *temp_dupli_object = &data->temp_dupli_object;
if (temp_dupli_object->id.properties == NULL) {
// No ID proeprties in temp datablock -- no leak is possible.
return;
}
if (temp_dupli_object->id.properties == dupli_object->id.properties) {
// Temp copy of object did not modify ID properties.
return;
}
// Free memory which is owned by temporary storage which is about to
// get overwritten.
IDP_FreeProperty(temp_dupli_object->id.properties);
MEM_freeN(temp_dupli_object->id.properties);
temp_dupli_object->id.properties = NULL;
}
static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
{
DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
while (data->dupli_object_next != NULL) {
DupliObject *dob = data->dupli_object_next;
Object *obd = dob->ob;
data->dupli_object_next = data->dupli_object_next->next;
/* Group duplis need to set ob matrices correct, for deform. so no_draw
* is part handled.
*/
if ((obd->transflag & OB_RENDER_DUPLI) == 0 && dob->no_draw) {
continue;
}
if (obd->type == OB_MBALL) {
continue;
}
verify_id_proeprties_freed(data);
data->dupli_object_current = dob;
/* Temporary object to evaluate. */
Object *dupli_parent = data->dupli_parent;
Object *temp_dupli_object = &data->temp_dupli_object;
*temp_dupli_object = *dob->ob;
temp_dupli_object->select_color = dupli_parent->select_color;
temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROMDUPLI;
/* Duplicated elements shouldn't care whether their original collection is visible or not. */
temp_dupli_object->base_flag |= BASE_VISIBLED;
if (BKE_object_is_visible(temp_dupli_object, (eObjectVisibilityCheck)data->visibility_check) == false) {
continue;
}
temp_dupli_object->transflag &= ~OB_DUPLI;
if (dob->collection_properties != NULL) {
temp_dupli_object->base_collection_properties = dob->collection_properties;
IDP_MergeGroup(temp_dupli_object->base_collection_properties,
dupli_parent->base_collection_properties,
false);
}
else {
temp_dupli_object->base_collection_properties =
dupli_parent->base_collection_properties;
}
copy_m4_m4(data->temp_dupli_object.obmat, dob->mat);
iter->current = &data->temp_dupli_object;
BLI_assert(
DEG::deg_validate_copy_on_write_datablock(
&data->temp_dupli_object.id));
return true;
}
return false;
}
static void DEG_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node)
{
/* Set it early in case we need to exit and we are running from within a loop. */
iter->skip = true;
DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
const ID_Type id_type = GS(id_node->id_orig->name);
if (id_type != ID_OB) {
return;
}
switch (id_node->linked_state) {
case DEG::DEG_ID_LINKED_DIRECTLY:
if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY) == 0) {
return;
}
break;
case DEG::DEG_ID_LINKED_VIA_SET:
if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) == 0) {
return;
}
break;
case DEG::DEG_ID_LINKED_INDIRECTLY:
if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY) == 0) {
return;
}
break;
}
Object *object = (Object *)id_node->id_cow;
BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id));
if ((BKE_object_is_visible(object, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) == false) &&
((data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) != 0))
{
return;
}
if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) &&
(object->transflag & OB_DUPLI))
{
data->dupli_parent = object;
data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, object);
data->dupli_object_next = (DupliObject *)data->dupli_list->first;
if (BKE_object_is_visible(object, (eObjectVisibilityCheck)data->visibility_check) == false) {
return;
}
}
iter->current = object;
iter->skip = false;
}
void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
{
Depsgraph *depsgraph = data->graph;
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
const size_t num_id_nodes = deg_graph->id_nodes.size();
if (num_id_nodes == 0) {
iter->valid = false;
return;
}
/* TODO(sergey): What evaluation type we want here? */
/* 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;
data->dupli_parent = NULL;
data->dupli_list = NULL;
data->dupli_object_next = NULL;
data->dupli_object_current = NULL;
data->scene = DEG_get_evaluated_scene(depsgraph);
data->id_node_index = 0;
data->num_id_nodes = num_id_nodes;
data->visibility_check = (data->mode == DEG_ITER_OBJECT_MODE_RENDER)
? OB_VISIBILITY_CHECK_FOR_RENDER
: OB_VISIBILITY_CHECK_FOR_VIEWPORT;
DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index];
DEG_iterator_objects_step(iter, id_node);
if (iter->skip) {
DEG_iterator_objects_next(iter);
}
}
void DEG_iterator_objects_next(BLI_Iterator *iter)
{
DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
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;
}
else {
verify_id_proeprties_freed(data);
free_object_duplilist(data->dupli_list);
data->dupli_parent = NULL;
data->dupli_list = NULL;
data->dupli_object_next = NULL;
data->dupli_object_current = NULL;
}
}
++data->id_node_index;
if (data->id_node_index == data->num_id_nodes) {
iter->valid = false;
return;
}
DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index];
DEG_iterator_objects_step(iter, id_node);
} while (iter->skip);
}
void DEG_iterator_objects_end(BLI_Iterator *iter)
{
#ifndef NDEBUG
DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
/* Force crash in case the iterator data is referenced and accessed down
* the line. (T51718)
*/
memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object));
#else
(void) iter;
#endif
}