EEVEE-Next: Fix DupliObject ObjectKey
`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 use `DRW_drawdata_get`. * 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/112544
This commit is contained in:
parent
68c69a99d3
commit
641dff8bf4
|
@ -155,7 +155,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);
|
||||
|
||||
|
|
|
@ -40,25 +40,24 @@ 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;
|
||||
});
|
||||
|
||||
handle.recalc |= ob->id.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 +511,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);
|
||||
|
|
|
@ -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(){};
|
||||
|
|
|
@ -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. */
|
||||
|
|
Loading…
Reference in New Issue