Blender V4.3
eevee_velocity.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
14#include "BKE_duplilist.hh"
15#include "BKE_object.hh"
16#include "BLI_map.hh"
18#include "DNA_modifier_types.h"
19#include "DNA_particle_types.h"
20#include "DNA_rigidbody_types.h"
21
22#include "draw_cache_impl.hh"
23
24#include "eevee_instance.hh"
25// #include "eevee_renderpasses.hh"
26#include "eevee_shader.hh"
28#include "eevee_velocity.hh"
29
30#include "draw_common.hh"
31
32namespace blender::eevee {
33
34/* -------------------------------------------------------------------- */
40{
41 if (!inst_.is_viewport() && !inst_.is_baking() &&
44 {
45 /* No motion blur and the vector pass was requested. Do the steps sync here. */
46 const Scene *scene = inst_.scene;
47 float initial_time = scene->r.cfra + scene->r.subframe;
48 step_sync(STEP_PREVIOUS, initial_time - 1.0f);
49 step_sync(STEP_NEXT, initial_time + 1.0f);
50 /* Let the main sync loop handle the current step. */
51 inst_.set_time(initial_time);
52 step_ = STEP_CURRENT;
53 }
54
55 /* For viewport, only previous motion is supported.
56 * Still bind previous step to avoid undefined behavior. */
57 next_step_ = (inst_.is_viewport() || inst_.is_baking()) ? STEP_PREVIOUS : STEP_NEXT;
58}
59
60/* Similar to Instance::object_sync, but only syncs velocity. */
61static void step_object_sync_render(void *instance,
62 Object *ob,
63 RenderEngine * /*engine*/,
64 Depsgraph * /*depsgraph*/)
65{
66 Instance &inst = *reinterpret_cast<Instance *>(instance);
67
68 const bool is_velocity_type = ELEM(ob->type, OB_CURVES, OB_MESH, OB_POINTCLOUD);
69 const int ob_visibility = DRW_object_visibility_in_active_context(ob);
70 const bool partsys_is_visible = (ob_visibility & OB_VISIBLE_PARTICLES) != 0 &&
71 (ob->type == OB_MESH);
72 const bool object_is_visible = DRW_object_is_renderable(ob) &&
73 (ob_visibility & OB_VISIBLE_SELF) != 0;
74
75 if (!is_velocity_type || (!partsys_is_visible && !object_is_visible)) {
76 return;
77 }
78
79 /* NOTE: Dummy resource handle since this won't be used for drawing. */
80 ResourceHandle resource_handle(0);
81 ObjectRef ob_ref = DRW_object_ref_get(ob);
82 ObjectHandle &ob_handle = inst.sync.sync_object(ob_ref);
83
84 if (partsys_is_visible) {
85 auto sync_hair =
86 [&](ObjectHandle hair_handle, ModifierData &md, ParticleSystem &particle_sys) {
88 ob, hair_handle.object_key, resource_handle, hair_handle.recalc, &md, &particle_sys);
89 };
90 foreach_hair_particle_handle(ob, ob_handle, sync_hair);
91 };
92
93 if (object_is_visible) {
94 inst.velocity.step_object_sync(ob, ob_handle.object_key, resource_handle, ob_handle.recalc);
95 }
96}
97
99{
100 inst_.set_time(time);
101 step_ = step;
102 object_steps_usage[step_] = 0;
104
107
109
114
116}
117
119{
120 inst_.camera.sync();
121 *camera_steps[step_] = inst_.camera.data_get();
122 step_time[step_] = inst_.scene->r.cfra + inst_.scene->r.subframe;
123 /* Fix undefined camera steps when rendering is starting. */
124 if ((step_ == STEP_CURRENT) && (camera_steps[STEP_PREVIOUS]->initialized == false)) {
125 *camera_steps[STEP_PREVIOUS] = *static_cast<CameraData *>(camera_steps[step_]);
128 }
129}
130
132 ObjectKey &object_key,
133 ResourceHandle resource_handle,
134 int /*IDRecalcFlag*/ recalc,
135 ModifierData *modifier_data /*=nullptr*/,
136 ParticleSystem *particle_sys /*=nullptr*/)
137{
138 bool has_motion = object_has_velocity(ob) || (recalc & ID_RECALC_TRANSFORM);
139 /* NOTE: Fragile. This will only work with 1 frame of lag since we can't record every geometry
140 * just in case there might be an update the next frame. */
141 bool has_deform = object_is_deform(ob) || (recalc & ID_RECALC_GEOMETRY);
142
143 if (!has_motion && !has_deform) {
144 return false;
145 }
146
147 /* Object motion. */
148 /* FIXME(fclem) As we are using original objects pointers, there is a chance the previous
149 * object key matches a totally different object if the scene was changed by user or python
150 * callback. In this case, we cannot correctly match objects between updates.
151 * What this means is that there will be incorrect motion vectors for these objects.
152 * We live with that until we have a correct way of identifying new objects. */
153 VelocityObjectData &vel = velocity_map.lookup_or_add_default(object_key);
154 vel.obj.ofs[step_] = object_steps_usage[step_]++;
155 vel.obj.resource_id = resource_handle.resource_index();
156 /* While VelocityObjectData is unique for each object/instance, multiple VelocityObjectDatas can
157 * point to the same offset in VelocityGeometryData, since geometry is stored local space. */
158 vel.id = particle_sys ? uint64_t(particle_sys) : uint64_t(ob->data);
159 object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = ob->object_to_world();
160 if (step_ == STEP_CURRENT) {
161 /* Replace invalid steps. Can happen if object was hidden in one of those steps. */
162 if (vel.obj.ofs[STEP_PREVIOUS] == -1) {
164 object_steps[STEP_PREVIOUS]->get_or_resize(
165 vel.obj.ofs[STEP_PREVIOUS]) = ob->object_to_world();
166 }
167 if (vel.obj.ofs[STEP_NEXT] == -1) {
169 object_steps[STEP_NEXT]->get_or_resize(vel.obj.ofs[STEP_NEXT]) = ob->object_to_world();
170 }
171 }
172
173 /* Geometry motion. */
174 if (has_deform) {
175 auto add_cb = [&]() {
177 if (particle_sys) {
178 if (inst_.is_viewport()) {
179 data.pos_buf = DRW_hair_pos_buffer_get(ob, particle_sys, modifier_data);
180 }
181 else {
182 data.pos_buf = draw::hair_pos_buffer_get(inst_.scene, ob, particle_sys, modifier_data);
183 }
184 return data;
185 }
186 switch (ob->type) {
187 case OB_CURVES:
188 if (inst_.is_viewport()) {
189 data.pos_buf = DRW_curves_pos_buffer_get(ob);
190 }
191 else {
192 data.pos_buf = draw::curves_pos_buffer_get(inst_.scene, ob);
193 }
194 break;
195 case OB_POINTCLOUD:
197 break;
198 default:
199 data.pos_buf = DRW_cache_object_pos_vertbuf_get(ob);
200 break;
201 }
202 return data;
203 };
204
205 const VelocityGeometryData &data = geometry_map.lookup_or_add_cb(vel.id, add_cb);
206
207 if (data.pos_buf == nullptr) {
208 has_deform = false;
209 }
210 }
211
212 /* Avoid drawing object that has no motions but were tagged as such. */
213 if (step_ == STEP_CURRENT && has_motion == true && has_deform == false) {
214 const float4x4 &obmat_curr = (*object_steps[STEP_CURRENT])[vel.obj.ofs[STEP_CURRENT]];
215 const float4x4 &obmat_prev = (*object_steps[STEP_PREVIOUS])[vel.obj.ofs[STEP_PREVIOUS]];
216 const float4x4 &obmat_next = (*object_steps[STEP_NEXT])[vel.obj.ofs[STEP_NEXT]];
217 if (inst_.is_viewport()) {
218 has_motion = (obmat_curr != obmat_prev);
219 }
220 else {
221 has_motion = (obmat_curr != obmat_prev || obmat_curr != obmat_next);
222 }
223 }
224
225#if 0
226 if (!has_motion && !has_deform) {
227 std::cout << "Detected no motion on " << ob->id.name << std::endl;
228 }
229 if (has_deform) {
230 std::cout << "Geometry Motion on " << ob->id.name << std::endl;
231 }
232 if (has_motion) {
233 std::cout << "Object Motion on " << ob->id.name << std::endl;
234 }
235#endif
236
237 if (!has_motion && !has_deform) {
238 return false;
239 }
240
241 return true;
242}
243
245{
246 uint dst_ofs = 0;
247 for (VelocityGeometryData &geom : geometry_map.values()) {
248 if (!geom.pos_buf) {
249 continue;
250 }
251 uint src_len = GPU_vertbuf_get_vertex_len(geom.pos_buf);
252 geom.len = src_len;
253 geom.ofs = dst_ofs;
254 dst_ofs += src_len;
255 }
256 /* TODO(@fclem): Fail gracefully (disable motion blur + warning print) if
257 * `tot_len * sizeof(float4)` is greater than max SSBO size. */
258 geometry_steps[step_]->resize(max_ii(16, dst_ofs));
259
260 PassSimple copy_ps("Velocity Copy Pass");
261 copy_ps.init();
264 copy_ps.bind_ssbo("out_buf", *geometry_steps[step_]);
265
266 for (VelocityGeometryData &geom : geometry_map.values()) {
267 if (!geom.pos_buf || geom.len == 0) {
268 continue;
269 }
270 const GPUVertFormat *format = GPU_vertbuf_get_format(geom.pos_buf);
271 if (format->stride == 16) {
273 geom.pos_buf,
274 geom.ofs * sizeof(float4),
275 0,
276 geom.len * sizeof(float4));
277 }
278 else {
279 BLI_assert(format->stride % 4 == 0);
280 copy_ps.bind_ssbo("in_buf", geom.pos_buf);
281 copy_ps.push_constant("start_offset", geom.ofs);
282 copy_ps.push_constant("vertex_stride", int(format->stride / 4));
283 copy_ps.push_constant("vertex_count", geom.len);
284 uint group_len_x = divide_ceil_u(geom.len, VERTEX_COPY_GROUP_SIZE);
285 uint verts_per_thread = divide_ceil_u(group_len_x, GPU_max_work_group_count(0));
286 copy_ps.dispatch(int3(group_len_x / verts_per_thread, 1, 1));
287 }
288 }
289
291 inst_.manager->submit(copy_ps);
292
293 /* Copy back the #VelocityGeometryIndex into #VelocityObjectData which are
294 * indexed using persistent keys (unlike geometries which are indexed by volatile ID). */
295 for (VelocityObjectData &vel : velocity_map.values()) {
296 const VelocityGeometryData &geom = geometry_map.lookup_default(vel.id, VelocityGeometryData());
297 vel.geo.len[step_] = geom.len;
298 vel.geo.ofs[step_] = geom.ofs;
299 /* Avoid reuse. */
300 vel.id = 0;
301 }
302
303 geometry_map.clear();
304}
305
307{
308 auto swap_steps = [&](eVelocityStep step_a, eVelocityStep step_b) {
309 std::swap(object_steps[step_a], object_steps[step_b]);
310 std::swap(geometry_steps[step_a], geometry_steps[step_b]);
311 std::swap(camera_steps[step_a], camera_steps[step_b]);
312 std::swap(step_time[step_a], step_time[step_b]);
313
314 for (VelocityObjectData &vel : velocity_map.values()) {
315 vel.obj.ofs[step_a] = vel.obj.ofs[step_b];
316 vel.obj.ofs[step_b] = uint(-1);
317 vel.geo.ofs[step_a] = vel.geo.ofs[step_b];
318 vel.geo.len[step_a] = vel.geo.len[step_b];
319 vel.geo.ofs[step_b] = uint(-1);
320 vel.geo.len[step_b] = uint(-1);
321 }
322 };
323
324 if (inst_.is_viewport()) {
326 /* For viewport we only use the last rendered redraw as previous frame.
327 * We swap current with previous step at the end of a redraw.
328 * We do not support motion blur as it is rendered to avoid conflicting motions
329 * for temporal reprojection. */
331 }
332 else {
333 /* Render case: The STEP_CURRENT is left untouched. */
335 }
336}
337
339{
340 step_ = STEP_CURRENT;
342 object_steps_usage[step_] = 0;
343}
344
346{
347 Vector<ObjectKey, 0> deleted_obj;
348
349 uint32_t max_resource_id_ = 0u;
350
352 if (item.value.obj.resource_id == uint32_t(-1)) {
353 deleted_obj.append(item.key);
354 }
355 else {
356 max_resource_id_ = max_uu(max_resource_id_, item.value.obj.resource_id);
357 }
358 }
359
360 for (auto &key : deleted_obj) {
361 velocity_map.remove(key);
362 }
363
364 indirection_buf.resize(ceil_to_multiple_u(max_resource_id_ + 1, 128));
365
366 /* Avoid uploading more data to the GPU as well as an extra level of
367 * indirection on the GPU by copying back offsets the to VelocityIndex. */
368 for (VelocityObjectData &vel : velocity_map.values()) {
369 /* Disable deform if vertex count mismatch. */
370 if (inst_.is_viewport()) {
371 /* Current geometry step will be copied at the end of the frame.
372 * Thus vel.geo.len[STEP_CURRENT] is not yet valid and the current length is manually
373 * retrieved. */
374 gpu::VertBuf *pos_buf = geometry_map.lookup_default(vel.id, VelocityGeometryData()).pos_buf;
375 vel.geo.do_deform = pos_buf != nullptr &&
376 (vel.geo.len[STEP_PREVIOUS] == GPU_vertbuf_get_vertex_len(pos_buf));
377 }
378 else {
379 vel.geo.do_deform = (vel.geo.len[STEP_CURRENT] != 0) &&
380 (vel.geo.len[STEP_CURRENT] == vel.geo.len[STEP_PREVIOUS]) &&
381 (vel.geo.len[STEP_CURRENT] == vel.geo.len[STEP_NEXT]);
382 }
383 indirection_buf[vel.obj.resource_id] = vel;
384 /* Reset for next sync. */
385 vel.obj.resource_id = uint(-1);
386 }
387
388 object_steps[STEP_PREVIOUS]->push_update();
389 object_steps[STEP_NEXT]->push_update();
390 camera_steps[STEP_PREVIOUS]->push_update();
391 camera_steps[STEP_CURRENT]->push_update();
392 camera_steps[STEP_NEXT]->push_update();
394}
395
396bool VelocityModule::object_has_velocity(const Object *ob)
397{
398#if 0
399 RigidBodyOb *rbo = ob->rigidbody_object;
400 /* Active rigidbody objects only, as only those are affected by sim. */
401 const bool has_rigidbody = (rbo && (rbo->type == RBO_TYPE_ACTIVE));
402 /* For now we assume dupli objects are moving. */
403 const bool is_dupli = (ob->base_flag & BASE_FROM_DUPLI) != 0;
404 const bool object_moves = is_dupli || has_rigidbody || BKE_object_moves_in_time(ob, true);
405#else
406 UNUSED_VARS(ob);
407 /* BKE_object_moves_in_time does not work in some cases.
408 * Better detect non moving object after evaluation. */
409 const bool object_moves = true;
410#endif
411 return object_moves;
412}
413
414bool VelocityModule::object_is_deform(const Object *ob)
415{
416 RigidBodyOb *rbo = ob->rigidbody_object;
417 /* Active rigidbody objects only, as only those are affected by sim. */
418 const bool has_rigidbody = (rbo && (rbo->type == RBO_TYPE_ACTIVE));
419 const bool is_deform = BKE_object_is_deform_modified(inst_.scene, (Object *)ob) ||
420 (has_rigidbody && (rbo->flag & RBO_FLAG_USE_DEFORM) != 0);
421
422 return is_deform;
423}
424
426{
427 /* For viewport, only previous motion is supported.
428 * Still bind previous step to avoid undefined behavior. */
430 DRW_shgroup_storage_block_ref(grp, "velocity_obj_prev_buf", &(*object_steps[STEP_PREVIOUS]));
431 DRW_shgroup_storage_block_ref(grp, "velocity_obj_next_buf", &(*object_steps[next]));
432 DRW_shgroup_storage_block_ref(grp, "velocity_geo_prev_buf", &(*geometry_steps[STEP_PREVIOUS]));
433 DRW_shgroup_storage_block_ref(grp, "velocity_geo_next_buf", &(*geometry_steps[next]));
436 DRW_shgroup_uniform_block_ref(grp, "camera_next", &(*camera_steps[next]));
437 DRW_shgroup_storage_block_ref(grp, "velocity_indirection_buf", &indirection_buf);
438}
439
441{
442 /* Only valid after sync. */
443 if (inst_.is_viewport()) {
444 /* Viewport has no next step. */
446 }
449}
450
452{
453 /* Only valid after sync. */
454 if (inst_.is_viewport()) {
455 return camera_steps[STEP_PREVIOUS]->type != camera_steps[STEP_CURRENT]->type;
456 }
457 /* Cannot happen in render mode since we set the type during the init phase. */
458 return false;
459}
460
462{
463 return step_time[end] - step_time[start];
464}
465
468} // namespace blender::eevee
General operations, lookup, etc. for blender objects.
@ OB_VISIBLE_SELF
@ OB_VISIBLE_PARTICLES
int BKE_object_is_deform_modified(Scene *scene, Object *ob)
bool BKE_object_moves_in_time(const Object *object, bool recurse_parent)
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE uint ceil_to_multiple_u(uint a, uint b)
MINLINE uint divide_ceil_u(uint a, uint b)
MINLINE uint max_uu(uint a, uint b)
MINLINE int max_ii(int a, int b)
unsigned int uint
#define UNUSED_VARS(...)
#define ELEM(...)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ BASE_FROM_DUPLI
@ EEVEE_RENDER_PASS_VECTOR
@ OB_MESH
@ OB_POINTCLOUD
@ 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)
#define DRW_shgroup_storage_block_ref(shgroup, name, ssbo)
int GPU_max_work_group_count(int index)
@ GPU_BARRIER_SHADER_STORAGE
Definition GPU_state.hh:48
void GPU_storagebuf_copy_sub_from_vertbuf(GPUStorageBuf *ssbo, blender::gpu::VertBuf *src, uint dst_offset, uint src_offset, uint copy_size)
Copy a part of a vertex buffer to a storage buffer.
const GPUVertFormat * GPU_vertbuf_get_format(const blender::gpu::VertBuf *verts)
uint GPU_vertbuf_get_vertex_len(const blender::gpu::VertBuf *verts)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object instance
void append(const T &value)
void submit(PassSimple &pass, View &view)
void dispatch(int group_len)
Definition draw_pass.hh:874
void barrier(eGPUBarrier type)
Definition draw_pass.hh:943
void state_set(DRWState state, int clip_plane_count=0)
Definition draw_pass.hh:954
void push_constant(const char *name, const float &data)
void bind_ssbo(const char *name, GPUStorageBuf *buffer)
void shader_set(GPUShader *shader)
Definition draw_pass.hh:971
const CameraData & data_get() const
eViewLayerEEVEEPassType enabled_passes_get() const
A running instance of the engine.
MotionBlurModule motion_blur
GPUShader * static_shader_get(eShaderType shader_type)
ObjectHandle & sync_object(const ObjectRef &ob_ref)
Definition eevee_sync.cc:37
float step_time_delta_get(eVelocityStep start, eVelocityStep end) const
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)
bool step_object_sync(Object *ob, ObjectKey &object_key, ResourceHandle resource_handle, int recalc=0, ModifierData *modifier_data=nullptr, ParticleSystem *particle_sys=nullptr)
void step_sync(eVelocityStep step, float time)
Map< uint64_t, VelocityGeometryData > geometry_map
blender::gpu::VertBuf * DRW_cache_object_pos_vertbuf_get(Object *ob)
blender::gpu::VertBuf * DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, ModifierData *md)
Definition draw_hair.cc:130
blender::draw::ObjectRef DRW_object_ref_get(Object *object)
bool DRW_object_is_renderable(const Object *ob)
int DRW_object_visibility_in_active_context(const Object *ob)
void DRW_render_object_iter(void *vedata, RenderEngine *engine, Depsgraph *depsgraph, void(*callback)(void *vedata, Object *ob, RenderEngine *engine, Depsgraph *depsgraph))
@ DRW_STATE_NO_DRAW
Definition draw_state.hh:27
#define VERTEX_COPY_GROUP_SIZE
static bool initialized
format
static ulong * next
gpu::VertBuf * curves_pos_buffer_get(Scene *scene, Object *object)
void hair_update(Manager &manager)
Definition draw_hair.cc:338
void curves_update(Manager &manager)
gpu::VertBuf * hair_pos_buffer_get(Scene *scene, Object *object, ParticleSystem *psys, ModifierData *md)
Definition draw_hair.cc:324
void hair_free()
Definition draw_hair.cc:344
void hair_init()
Definition draw_hair.cc:272
gpu::VertBuf * DRW_pointcloud_position_and_radius_buffer_get(Object *ob)
gpu::VertBuf * DRW_curves_pos_buffer_get(Object *object)
static void step_object_sync_render(void *instance, Object *ob, RenderEngine *, Depsgraph *)
void foreach_hair_particle_handle(Object *ob, ObjectHandle ob_handle, HairHandleCallback callback)
T step(const T &edge, const T &value)
VecBase< int32_t, 3 > int3
unsigned int uint32_t
Definition stdint.h:80
unsigned __int64 uint64_t
Definition stdint.h:90
char name[66]
Definition DNA_ID.h:425
short base_flag
struct RigidBodyOb * rigidbody_object
struct RenderData r