EEVEE-Next: Fix DupliObject ObjectKey

Fixed version of #112544 (reverted).

`DRW_drawdata_get` reuses the same `DrawData` for all duplis,
so they all end up using the same `ObjectHandle` and `ObjectKey`,
which breaks motion vectors.

* Don't rely on `DRW_drawdata_get` for storing `ObjectKey`s.
* Simplify `ObjectKey`.

This also solves the issue of objects created "on the fly" always having
the `ID_RECALC_ALL` flag.

Pull Request: https://projects.blender.org/blender/blender/pulls/113252
This commit is contained in:
Miguel Pozo 2023-10-06 15:29:50 +02:00
parent 1aca58cf16
commit 57cfe20e5b
4 changed files with 58 additions and 75 deletions

View File

@ -169,7 +169,7 @@ ReflectionProbe &ReflectionProbeModule::find_or_insert(ObjectHandle &ob_handle,
int subdivision_level)
{
ReflectionProbe &reflection_probe = probes_.lookup_or_add_cb(
ob_handle.object_key.hash_value, [this, subdivision_level]() {
ob_handle.object_key.hash(), [this, subdivision_level]() {
ReflectionProbe probe;
ReflectionProbeData probe_data = find_empty_reflection_probe_data(subdivision_level,
false);

View File

@ -40,25 +40,28 @@ static void draw_data_init_cb(DrawData *dd)
ObjectHandle &SyncModule::sync_object(Object *ob)
{
DrawEngineType *owner = (DrawEngineType *)&DRW_engine_viewport_eevee_next_type;
DrawData *dd = DRW_drawdata_ensure(
(ID *)ob, owner, sizeof(eevee::ObjectHandle), draw_data_init_cb, nullptr);
ObjectHandle &eevee_dd = *reinterpret_cast<ObjectHandle *>(dd);
ObjectKey key(ob);
if (eevee_dd.object_key.ob == nullptr) {
ob = DEG_get_original_object(ob);
eevee_dd.object_key = ObjectKey(ob);
}
ObjectHandle &handle = ob_handles.lookup_or_add_cb(key, [&]() {
ObjectHandle new_handle;
new_handle.object_key = key;
new_handle.recalc = ID_RECALC_ALL;
return new_handle;
});
/** TODO(Miguel Pozo): DrawData is the only way of retrieving the correct recalc flags.
* We should find a more optimal way to handle this. */
DrawEngineType *owner = (DrawEngineType *)&DRW_engine_viewport_eevee_next_type;
DrawData *dd = DRW_drawdata_ensure((ID *)ob, owner, sizeof(DrawData), nullptr, nullptr);
handle.recalc |= dd->recalc;
const int recalc_flags = ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_SHADING |
ID_RECALC_GEOMETRY;
if ((eevee_dd.recalc & recalc_flags) != 0) {
/** WARNING: Some objects are always created "on the fly" (ie. Geometry Nodes volumes),
* so this causes to redraw the sample 1 forever. */
if ((handle.recalc & recalc_flags) != 0) {
inst_.sampling.reset();
}
return eevee_dd;
return handle;
}
WorldHandle &SyncModule::sync_world(::World *world)
@ -512,8 +515,8 @@ void foreach_hair_particle_handle(Object *ob, ObjectHandle ob_handle, HairHandle
continue;
}
ObjectHandle particle_sys_handle = {{nullptr}};
particle_sys_handle.object_key = ObjectKey(ob_handle.object_key.ob, sub_key++);
ObjectHandle particle_sys_handle = ob_handle;
particle_sys_handle.object_key = ObjectKey(ob, sub_key++);
particle_sys_handle.recalc = particle_sys->recalc;
callback(particle_sys_handle, *md, *particle_sys);

View File

@ -14,6 +14,7 @@
#include "BKE_duplilist.h"
#include "BLI_ghash.h"
#include "BLI_map.hh"
#include "DEG_depsgraph_query.hh"
#include "DNA_object_types.h"
#include "DRW_render.h"
#include "GPU_material.h"
@ -31,87 +32,60 @@ class Instance;
* Note that we get a unique key for each object component.
* \{ */
struct ObjectKey {
class ObjectKey {
/** Hash value of the key. */
uint64_t hash_value;
uint64_t hash_value_;
/** Original Object or source object for duplis. */
Object *ob;
Object *ob_;
/** Original Parent object for duplis. */
Object *parent;
Object *parent_;
/** Dupli objects recursive unique identifier */
int id[MAX_DUPLI_RECUR];
int id_[MAX_DUPLI_RECUR];
/** Used for particle system hair. */
int sub_key_;
#ifdef DEBUG
char name[64];
#endif
ObjectKey() : ob(nullptr), parent(nullptr){};
ObjectKey(Object *ob_, Object *parent_, int id_[MAX_DUPLI_RECUR], int sub_key_ = 0)
: ob(ob_), parent(parent_), sub_key_(sub_key_)
public:
ObjectKey() = default;
ObjectKey(Object *ob, int sub_key = 0) : sub_key_(sub_key)
{
if (id_) {
memcpy(id, id_, sizeof(id));
ob_ = DEG_get_original_object(ob);
hash_value_ = BLI_ghashutil_ptrhash(ob_);
if (DupliObject *dupli = DRW_object_get_dupli(ob)) {
parent_ = DRW_object_get_dupli_parent(ob);
hash_value_ = BLI_ghashutil_combine_hash(hash_value_, BLI_ghashutil_ptrhash(parent_));
memcpy(id_, dupli->persistent_id, sizeof(id_));
for (int id : id_) {
if (id == INT_MAX) {
break;
}
hash_value_ = BLI_ghashutil_combine_hash(hash_value_, BLI_ghashutil_inthash(id));
}
}
else {
memset(id, 0, sizeof(id));
}
/* Compute hash on creation so we avoid the cost of it for every sync. */
hash_value = BLI_ghashutil_ptrhash(ob);
hash_value = BLI_ghashutil_combine_hash(hash_value, BLI_ghashutil_ptrhash(parent));
for (int i = 0; i < MAX_DUPLI_RECUR; i++) {
if (id[i] != 0) {
hash_value = BLI_ghashutil_combine_hash(hash_value, BLI_ghashutil_inthash(id[i]));
}
else {
break;
}
parent_ = nullptr;
memset(id_, 0, sizeof(id_));
}
if (sub_key_ != 0) {
hash_value = BLI_ghashutil_combine_hash(hash_value, sub_key_);
hash_value_ = BLI_ghashutil_combine_hash(hash_value_, BLI_ghashutil_inthash(sub_key_));
}
#ifdef DEBUG
STRNCPY(name, ob->id.name);
#endif
}
ObjectKey(Object *ob, DupliObject *dupli, Object *parent, int sub_key_ = 0)
: ObjectKey(ob, parent, dupli ? dupli->persistent_id : nullptr, sub_key_){};
ObjectKey(Object *ob, int sub_key_ = 0)
: ObjectKey(ob, DRW_object_get_dupli(ob), DRW_object_get_dupli_parent(ob), sub_key_){};
uint64_t hash() const
{
return hash_value;
return hash_value_;
}
bool operator<(const ObjectKey &k) const
{
if (ob != k.ob) {
return (ob < k.ob);
}
if (parent != k.parent) {
return (parent < k.parent);
}
if (sub_key_ != k.sub_key_) {
return (sub_key_ < k.sub_key_);
}
return memcmp(id, k.id, sizeof(id)) < 0;
return memcmp(this, &k, sizeof(*this)) < 0;
}
bool operator==(const ObjectKey &k) const
{
if (ob != k.ob) {
return false;
}
if (parent != k.parent) {
return false;
}
if (sub_key_ != k.sub_key_) {
return false;
}
return memcmp(id, k.id, sizeof(id)) == 0;
return memcmp(this, &k, sizeof(*this)) == 0;
}
};
@ -122,9 +96,9 @@ struct ObjectKey {
*
* \{ */
struct ObjectHandle : public DrawData {
ObjectKey object_key;
struct BaseHandle {
/* Accumulated recalc flags, which corresponds to ID->recalc flags. */
unsigned int recalc;
void reset_recalc_flag()
{
if (recalc != 0) {
@ -133,6 +107,10 @@ struct ObjectHandle : public DrawData {
}
};
struct ObjectHandle : public BaseHandle {
ObjectKey object_key;
};
struct WorldHandle : public DrawData {
void reset_recalc_flag()
{
@ -155,6 +133,8 @@ class SyncModule {
private:
Instance &inst_;
Map<ObjectKey, ObjectHandle> ob_handles = {};
public:
SyncModule(Instance &inst) : inst_(inst){};
~SyncModule(){};

View File

@ -154,7 +154,7 @@ bool VelocityModule::step_object_sync(Object *ob,
VelocityObjectData &vel = velocity_map.lookup_or_add_default(object_key);
vel.obj.ofs[step_] = object_steps_usage[step_]++;
vel.obj.resource_id = resource_handle.resource_index();
vel.id = object_key.hash_value;
vel.id = object_key.hash();
object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = float4x4_view(ob->object_to_world);
if (step_ == STEP_CURRENT) {
/* Replace invalid steps. Can happen if object was hidden in one of those steps. */