Blender  V3.3
eevee_velocity.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2021 Blender Foundation.
3  */
4 
14 #include "BKE_duplilist.h"
15 #include "BKE_object.h"
16 #include "BLI_map.hh"
17 #include "DEG_depsgraph_query.h"
18 #include "DNA_rigidbody_types.h"
19 
20 #include "eevee_instance.hh"
21 // #include "eevee_renderpasses.hh"
22 #include "eevee_shader.hh"
23 #include "eevee_shader_shared.hh"
24 #include "eevee_velocity.hh"
25 
26 namespace blender::eevee {
27 
28 /* -------------------------------------------------------------------- */
34 {
35  if (inst_.render && (inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR)) {
36  /* No motion blur and the vector pass was requested. Do the step sync here. */
37  const Scene *scene = inst_.scene;
38  float initial_time = scene->r.cfra + scene->r.subframe;
39  step_sync(STEP_PREVIOUS, initial_time - 1.0f);
40  step_sync(STEP_NEXT, initial_time + 1.0f);
41  inst_.set_time(initial_time);
42  }
43 }
44 
45 static void step_object_sync_render(void *velocity,
46  Object *ob,
47  RenderEngine *UNUSED(engine),
49 {
50  ObjectKey object_key(ob);
51  reinterpret_cast<VelocityModule *>(velocity)->step_object_sync(ob, object_key);
52 }
53 
54 void VelocityModule::step_sync(eVelocityStep step, float time)
55 {
56  inst_.set_time(time);
57  step_ = step;
58  object_steps_usage[step_] = 0;
61 }
62 
64 {
65  inst_.camera.sync();
66  *camera_steps[step_] = inst_.camera.data_get();
67  /* Fix undefined camera steps when rendering is starting. */
68  if ((step_ == STEP_CURRENT) && (camera_steps[STEP_PREVIOUS]->initialized == false)) {
69  *camera_steps[STEP_PREVIOUS] = *static_cast<CameraData *>(camera_steps[step_]);
70  camera_steps[STEP_PREVIOUS]->initialized = true;
71  }
72 }
73 
75  ObjectKey &object_key,
76  int /*IDRecalcFlag*/ recalc)
77 {
78  bool has_motion = object_has_velocity(ob) || (recalc & ID_RECALC_TRANSFORM);
79  /* NOTE: Fragile. This will only work with 1 frame of lag since we can't record every geometry
80  * just in case there might be an update the next frame. */
81  bool has_deform = object_is_deform(ob) || (recalc & ID_RECALC_GEOMETRY);
82 
83  if (!has_motion && !has_deform) {
84  return false;
85  }
86 
87  uint32_t resource_id = DRW_object_resource_id_get(ob);
88 
89  /* Object motion. */
90  /* FIXME(fclem) As we are using original objects pointers, there is a chance the previous
91  * object key matches a totally different object if the scene was changed by user or python
92  * callback. In this case, we cannot correctly match objects between updates.
93  * What this means is that there will be incorrect motion vectors for these objects.
94  * We live with that until we have a correct way of identifying new objects. */
95  VelocityObjectData &vel = velocity_map.lookup_or_add_default(object_key);
96  vel.obj.ofs[step_] = object_steps_usage[step_]++;
97  vel.obj.resource_id = resource_id;
98  vel.id = (ID *)ob->data;
99  object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = ob->obmat;
100  if (step_ == STEP_CURRENT) {
101  /* Replace invalid steps. Can happen if object was hidden in one of those steps. */
102  if (vel.obj.ofs[STEP_PREVIOUS] == -1) {
103  vel.obj.ofs[STEP_PREVIOUS] = object_steps_usage[STEP_PREVIOUS]++;
104  object_steps[STEP_PREVIOUS]->get_or_resize(vel.obj.ofs[STEP_PREVIOUS]) = ob->obmat;
105  }
106  if (vel.obj.ofs[STEP_NEXT] == -1) {
107  vel.obj.ofs[STEP_NEXT] = object_steps_usage[STEP_NEXT]++;
108  object_steps[STEP_NEXT]->get_or_resize(vel.obj.ofs[STEP_NEXT]) = ob->obmat;
109  }
110  }
111 
112  /* Geometry motion. */
113  if (has_deform) {
114  auto add_cb = [&]() {
116  switch (ob->type) {
117  case OB_CURVES:
118  data.pos_buf = DRW_curves_pos_buffer_get(ob);
119  break;
120  default:
122  break;
123  }
124  return data;
125  };
126 
127  const VelocityGeometryData &data = geometry_map.lookup_or_add_cb(vel.id, add_cb);
128 
129  if (data.pos_buf == nullptr) {
130  has_deform = false;
131  }
132  }
133 
134  /* Avoid drawing object that has no motions but were tagged as such. */
135  if (step_ == STEP_CURRENT && has_motion == true && has_deform == false) {
136  float4x4 &obmat_curr = (*object_steps[STEP_CURRENT])[vel.obj.ofs[STEP_CURRENT]];
137  float4x4 &obmat_prev = (*object_steps[STEP_PREVIOUS])[vel.obj.ofs[STEP_PREVIOUS]];
138  float4x4 &obmat_next = (*object_steps[STEP_NEXT])[vel.obj.ofs[STEP_NEXT]];
139  if (inst_.is_viewport()) {
140  has_motion = (obmat_curr != obmat_prev);
141  }
142  else {
143  has_motion = (obmat_curr != obmat_prev || obmat_curr != obmat_next);
144  }
145  }
146 
147 #if 0
148  if (!has_motion && !has_deform) {
149  std::cout << "Detected no motion on " << ob->id.name << std::endl;
150  }
151  if (has_deform) {
152  std::cout << "Geometry Motion on " << ob->id.name << std::endl;
153  }
154  if (has_motion) {
155  std::cout << "Object Motion on " << ob->id.name << std::endl;
156  }
157 #endif
158 
159  if (!has_motion && !has_deform) {
160  return false;
161  }
162 
163  /* TODO(@fclem): Reset sampling here? Should ultimately be covered by depsgraph update tags. */
164  inst_.sampling.reset();
165 
166  return true;
167 }
168 
175 {
176  {
177  /* Now that vertex buffers are guaranteed to be updated, proceed with
178  * offset computation and copy into the geometry step buffer. */
179  uint dst_ofs = 0;
180  for (VelocityGeometryData &geom : geometry_map.values()) {
181  uint src_len = GPU_vertbuf_get_vertex_len(geom.pos_buf);
182  geom.len = src_len;
183  geom.ofs = dst_ofs;
184  dst_ofs += src_len;
185  }
186  /* TODO(@fclem): Fail gracefully (disable motion blur + warning print) if
187  * `tot_len * sizeof(float4)` is greater than max SSBO size. */
188  geometry_steps[step_]->resize(max_ii(16, dst_ofs));
189 
190  for (VelocityGeometryData &geom : geometry_map.values()) {
192  geom.pos_buf,
193  geom.ofs * sizeof(float4),
194  0,
195  geom.len * sizeof(float4));
196  }
197  /* Copy back the #VelocityGeometryIndex into #VelocityObjectData which are
198  * indexed using persistent keys (unlike geometries which are indexed by volatile ID). */
199  for (VelocityObjectData &vel : velocity_map.values()) {
200  const VelocityGeometryData &geom = geometry_map.lookup_default(vel.id,
202  vel.geo.len[step_] = geom.len;
203  vel.geo.ofs[step_] = geom.ofs;
204  /* Avoid reuse. */
205  vel.id = nullptr;
206  }
207 
208  geometry_map.clear();
209  }
210 
211  auto swap_steps = [&](eVelocityStep step_a, eVelocityStep step_b) {
212  SWAP(VelocityObjectBuf *, object_steps[step_a], object_steps[step_b]);
213  SWAP(VelocityGeometryBuf *, geometry_steps[step_a], geometry_steps[step_b]);
214  SWAP(CameraDataBuf *, camera_steps[step_a], camera_steps[step_b]);
215 
216  for (VelocityObjectData &vel : velocity_map.values()) {
217  vel.obj.ofs[step_a] = vel.obj.ofs[step_b];
218  vel.obj.ofs[step_b] = (uint)-1;
219  vel.geo.ofs[step_a] = vel.geo.ofs[step_b];
220  vel.geo.len[step_a] = vel.geo.len[step_b];
221  vel.geo.ofs[step_b] = (uint)-1;
222  vel.geo.len[step_b] = (uint)-1;
223  }
224  };
225 
226  if (inst_.is_viewport()) {
227  /* For viewport we only use the last rendered redraw as previous frame.
228  * We swap current with previous step at the end of a redraw.
229  * We do not support motion blur as it is rendered to avoid conflicting motions
230  * for temporal reprojection. */
231  swap_steps(eVelocityStep::STEP_PREVIOUS, eVelocityStep::STEP_CURRENT);
232  }
233  else {
234  /* Render case: The STEP_CURRENT is left untouched. */
235  swap_steps(eVelocityStep::STEP_PREVIOUS, eVelocityStep::STEP_NEXT);
236  }
237 }
238 
240 {
241  if (inst_.is_viewport()) {
242  /* Viewport always evaluate current step. */
243  step_ = STEP_CURRENT;
244  }
246  object_steps_usage[step_] = 0;
247 }
248 
249 /* This is the end of the current frame sync. Not the step_sync. */
251 {
252  Vector<ObjectKey, 0> deleted_obj;
253 
254  uint32_t max_resource_id_ = 0u;
255 
257  if (item.value.obj.resource_id == (uint)-1) {
258  deleted_obj.append(item.key);
259  }
260  else {
261  max_resource_id_ = max_uu(max_resource_id_, item.value.obj.resource_id);
262  }
263  }
264 
265  if (deleted_obj.size() > 0) {
266  inst_.sampling.reset();
267  }
268 
269  if (inst_.is_viewport() && camera_has_motion()) {
270  inst_.sampling.reset();
271  }
272 
273  for (auto key : deleted_obj) {
274  velocity_map.remove(key);
275  }
276 
277  indirection_buf.resize(power_of_2_max_u(max_resource_id_ + 1));
278 
279  /* Avoid uploading more data to the GPU as well as an extra level of
280  * indirection on the GPU by copying back offsets the to VelocityIndex. */
281  for (VelocityObjectData &vel : velocity_map.values()) {
282  /* Disable deform if vertex count mismatch. */
283  if (inst_.is_viewport()) {
284  /* Current geometry step will be copied at the end of the frame.
285  * Thus vel.geo.len[STEP_CURRENT] is not yet valid and the current length is manually
286  * retrieved. */
287  GPUVertBuf *pos_buf = geometry_map.lookup_default(vel.id, VelocityGeometryData()).pos_buf;
288  vel.geo.do_deform = pos_buf != nullptr &&
289  (vel.geo.len[STEP_PREVIOUS] == GPU_vertbuf_get_vertex_len(pos_buf));
290  }
291  else {
292  vel.geo.do_deform = (vel.geo.len[STEP_PREVIOUS] == vel.geo.len[STEP_CURRENT]) &&
293  (vel.geo.len[STEP_NEXT] == vel.geo.len[STEP_CURRENT]);
294  }
295  indirection_buf[vel.obj.resource_id] = vel;
296  /* Reset for next sync. */
297  vel.obj.resource_id = (uint)-1;
298  }
299 
300  object_steps[STEP_PREVIOUS]->push_update();
301  object_steps[STEP_NEXT]->push_update();
302  camera_steps[STEP_PREVIOUS]->push_update();
303  camera_steps[STEP_CURRENT]->push_update();
304  camera_steps[STEP_NEXT]->push_update();
305  indirection_buf.push_update();
306 }
307 
308 bool VelocityModule::object_has_velocity(const Object *ob)
309 {
310 #if 0
311  RigidBodyOb *rbo = ob->rigidbody_object;
312  /* Active rigidbody objects only, as only those are affected by sim. */
313  const bool has_rigidbody = (rbo && (rbo->type == RBO_TYPE_ACTIVE));
314  /* For now we assume dupli objects are moving. */
315  const bool is_dupli = (ob->base_flag & BASE_FROM_DUPLI) != 0;
316  const bool object_moves = is_dupli || has_rigidbody || BKE_object_moves_in_time(ob, true);
317 #else
318  UNUSED_VARS(ob);
319  /* BKE_object_moves_in_time does not work in some cases.
320  * Better detect non moving object after evaluation. */
321  const bool object_moves = true;
322 #endif
323  return object_moves;
324 }
325 
326 bool VelocityModule::object_is_deform(const Object *ob)
327 {
328  RigidBodyOb *rbo = ob->rigidbody_object;
329  /* Active rigidbody objects only, as only those are affected by sim. */
330  const bool has_rigidbody = (rbo && (rbo->type == RBO_TYPE_ACTIVE));
331  const bool is_deform = BKE_object_is_deform_modified(inst_.scene, (Object *)ob) ||
332  (has_rigidbody && (rbo->flag & RBO_FLAG_USE_DEFORM) != 0);
333 
334  return is_deform;
335 }
336 
338 {
339  /* For viewport, only previous motion is supported.
340  * Still bind previous step to avoid undefined behavior. */
341  eVelocityStep next = inst_.is_viewport() ? STEP_PREVIOUS : STEP_NEXT;
342  DRW_shgroup_storage_block_ref(grp, "velocity_obj_prev_buf", &(*object_steps[STEP_PREVIOUS]));
343  DRW_shgroup_storage_block_ref(grp, "velocity_obj_next_buf", &(*object_steps[next]));
344  DRW_shgroup_storage_block_ref(grp, "velocity_geo_prev_buf", &(*geometry_steps[STEP_PREVIOUS]));
345  DRW_shgroup_storage_block_ref(grp, "velocity_geo_next_buf", &(*geometry_steps[next]));
346  DRW_shgroup_uniform_block_ref(grp, "camera_prev", &(*camera_steps[STEP_PREVIOUS]));
347  DRW_shgroup_uniform_block_ref(grp, "camera_curr", &(*camera_steps[STEP_CURRENT]));
348  DRW_shgroup_uniform_block_ref(grp, "camera_next", &(*camera_steps[next]));
349  DRW_shgroup_storage_block_ref(grp, "velocity_indirection_buf", &indirection_buf);
350 }
351 
353 {
354  /* Only valid after sync. */
355  if (inst_.is_viewport()) {
356  /* Viewport has no next step. */
357  return *camera_steps[STEP_PREVIOUS] != *camera_steps[STEP_CURRENT];
358  }
359  return *camera_steps[STEP_PREVIOUS] != *camera_steps[STEP_CURRENT] &&
360  *camera_steps[STEP_NEXT] != *camera_steps[STEP_CURRENT];
361 }
362 
365 } // namespace blender::eevee
General operations, lookup, etc. for blender objects.
int BKE_object_is_deform_modified(struct Scene *scene, struct Object *ob)
Definition: object.cc:4982
bool BKE_object_moves_in_time(const struct Object *object, bool recurse_parent)
MINLINE unsigned int power_of_2_max_u(unsigned int x)
MINLINE uint max_uu(uint a, uint b)
MINLINE int max_ii(int a, int b)
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED_VARS(...)
#define SWAP(type, a, b)
#define UNUSED(x)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:771
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ EEVEE_RENDER_PASS_VECTOR
@ BASE_FROM_DUPLI
@ OB_CURVES
Types and defines for representing Rigid Body entities.
@ RBO_TYPE_ACTIVE
@ RBO_FLAG_USE_DEFORM
#define DRW_shgroup_uniform_block_ref(shgroup, name, ubo)
Definition: DRW_render.h:653
#define DRW_shgroup_storage_block_ref(shgroup, name, ssbo)
Definition: DRW_render.h:657
void GPU_storagebuf_copy_sub_from_vertbuf(GPUStorageBuf *ssbo, GPUVertBuf *src, uint dst_offset, uint src_offset, uint copy_size)
Copy a part of a vertex buffer to a storage buffer.
uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts)
struct GPUVertBuf GPUVertBuf
int64_t size() const
Definition: BLI_vector.hh:694
void append(const T &value)
Definition: BLI_vector.hh:433
const CameraData & data_get() const
Definition: eevee_camera.hh:98
eViewLayerEEVEEPassType enabled_passes_get() const
Definition: eevee_film.cc:459
Map< ID *, VelocityGeometryData > geometry_map
Map< ObjectKey, VelocityObjectData > velocity_map
std::array< CameraDataBuf *, 3 > camera_steps
std::array< VelocityObjectBuf *, 3 > object_steps
std::array< VelocityGeometryBuf *, 3 > geometry_steps
void bind_resources(DRWShadingGroup *grp)
void step_sync(eVelocityStep step, float time)
bool step_object_sync(Object *ob, ObjectKey &object_key, int recalc=0)
double time
Scene scene
const Depsgraph * depsgraph
GPUVertBuf * DRW_cache_object_pos_vertbuf_get(Object *ob)
Definition: draw_cache.c:911
struct GPUVertBuf * DRW_curves_pos_buffer_get(struct Object *object)
Definition: draw_curves.cc:269
void DRW_render_object_iter(void *vedata, RenderEngine *engine, struct Depsgraph *depsgraph, void(*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph))
uint32_t DRW_object_resource_id_get(Object *UNUSED(ob))
smooth(Type::VEC3, "prev") .smooth(Type CameraData
static bool initialized
Definition: gpu_init_exit.c:22
static ulong * next
static void step_object_sync_render(void *velocity, Object *ob, RenderEngine *UNUSED(engine), Depsgraph *UNUSED(depsgraph))
unsigned int uint32_t
Definition: stdint.h:80
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
short base_flag
struct RigidBodyOb * rigidbody_object
float obmat[4][4]
void * data
struct RenderData r