Blender V4.3
eevee_motion_blur.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
9// #include "BLI_map.hh"
10#include "BKE_colortools.hh"
12
13#include "eevee_instance.hh"
14#include "eevee_motion_blur.hh"
15// #include "eevee_sampling.hh"
16// #include "eevee_shader_shared.hh"
17// #include "eevee_velocity.hh"
18
19namespace blender::eevee {
20
21/* -------------------------------------------------------------------- */
27{
28 const Scene *scene = inst_.scene;
29 const ViewLayer *view_layer = inst_.view_layer;
30
31 /* Disable on viewport outside of animation playback,
32 * since it can get distracting while editing the scene. */
33 enabled_ = (scene->r.mode & R_MBLUR) != 0 && (inst_.is_image_render() || inst_.is_playback());
34 if (enabled_) {
35 enabled_ = (view_layer->layflag & SCE_LAY_MOTION_BLUR) != 0;
36 }
37
38 if (!enabled_) {
39 motion_blur_fx_enabled_ = false;
40 return;
41 }
42
43 /* Take into account the steps needed for fx motion blur. */
44 int steps_count = max_ii(1, scene->eevee.motion_blur_steps) * 2 + 1;
45
46 time_steps_.resize(steps_count);
47
48 initial_frame_ = scene->r.cfra;
49 initial_subframe_ = scene->r.subframe;
50 frame_time_ = initial_frame_ + initial_subframe_;
51 shutter_position_ = scene->r.motion_blur_position;
52 shutter_time_ = scene->r.motion_blur_shutter;
53
54 data_.depth_scale = scene->eevee.motion_blur_depth_scale;
55 motion_blur_fx_enabled_ = true; /* TODO(fclem): UI option. */
56
57 /* Viewport stops here. We only do Post-FX motion blur. */
58 if (inst_.is_viewport()) {
59 enabled_ = false;
60 return;
61 }
62
63 /* Without this there is the possibility of the curve table not being allocated. */
64 BKE_curvemapping_changed((CurveMapping *)&scene->r.mblur_shutter_curve, false);
65
67 Sampling::cdf_from_curvemapping(scene->r.mblur_shutter_curve, cdf);
68 Sampling::cdf_invert(cdf, time_steps_);
69
70 for (float &time : time_steps_) {
71 time = this->shutter_time_to_scene_time(time);
72 }
73
74 step_id_ = 1;
75
76 if (motion_blur_fx_enabled_) {
77 /* A bit weird but we have to sync the first 2 steps here because the step()
78 * function is only called after rendering a sample. */
79 inst_.velocity.step_sync(STEP_PREVIOUS, time_steps_[0]);
80 inst_.velocity.step_sync(STEP_NEXT, time_steps_[2]);
81 /* Let the main sync loop handle the current step. */
82 }
83 inst_.set_time(time_steps_[1]);
84}
85
86/* Runs after rendering a sample. */
88{
89 if (!enabled_) {
90 return;
91 }
92
93 if (inst_.sampling.finished()) {
94 /* Restore original frame number. This is because the render pipeline expects it. */
95 RE_engine_frame_set(inst_.render, initial_frame_, initial_subframe_);
96 }
97 else if (inst_.sampling.do_render_sync()) {
98 /* Time to change motion step. */
99 BLI_assert(time_steps_.size() > step_id_ + 2);
100 step_id_ += 2;
101
102 if (motion_blur_fx_enabled_) {
103 inst_.velocity.step_swap();
104 inst_.velocity.step_sync(eVelocityStep::STEP_NEXT, time_steps_[step_id_ + 1]);
105 }
106 inst_.set_time(time_steps_[step_id_]);
107 }
108}
109
110float MotionBlurModule::shutter_time_to_scene_time(float time)
111{
112 switch (shutter_position_) {
113 case SCE_MB_START:
114 /* No offset. */
115 break;
116 case SCE_MB_CENTER:
117 time -= 0.5f;
118 break;
119 case SCE_MB_END:
120 time -= 1.0;
121 break;
122 default:
123 BLI_assert_msg(false, "Invalid motion blur position enum!");
124 break;
125 }
126 time *= shutter_time_;
127 time += frame_time_;
128 return time;
129}
130
132{
133 /* Disable motion blur in viewport when changing camera projection type.
134 * Avoids really high velocities. */
136 (inst_.is_viewport() && (inst_.camera.overscan_changed() || inst_.camera.camera_changed())))
137 {
138 motion_blur_fx_enabled_ = false;
139 }
140
141 if (!motion_blur_fx_enabled_) {
142 return;
143 }
144
146 RenderBuffers &render_buffers = inst_.render_buffers;
147
148 motion_blur_ps_.init();
149 motion_blur_ps_.bind_resources(inst_.velocity);
150 motion_blur_ps_.bind_resources(inst_.sampling);
151 {
152 /* Create max velocity tiles. */
153 PassSimple::Sub &sub = motion_blur_ps_.sub("TilesFlatten");
154 eGPUTextureFormat vector_tx_format = inst_.render_buffers.vector_tx_format();
155 eShaderType shader = vector_tx_format == GPU_RG16F ? MOTION_BLUR_TILE_FLATTEN_RG :
157 sub.shader_set(inst_.shaders.static_shader_get(shader));
158 sub.bind_ubo("motion_blur_buf", data_);
159 sub.bind_texture("depth_tx", &render_buffers.depth_tx);
160 sub.bind_image("velocity_img", &render_buffers.vector_tx);
161 sub.bind_image("out_tiles_img", &tiles_tx_);
162 sub.dispatch(&dispatch_flatten_size_);
164 }
165 {
166 /* Expand max velocity tiles by spreading them in their neighborhood. */
167 PassSimple::Sub &sub = motion_blur_ps_.sub("TilesDilate");
169 sub.bind_ssbo("tile_indirection_buf", tile_indirection_buf_);
170 sub.bind_image("in_tiles_img", &tiles_tx_);
171 sub.dispatch(&dispatch_dilate_size_);
173 }
174 {
175 /* Do the motion blur gather algorithm. */
176 PassSimple::Sub &sub = motion_blur_ps_.sub("ConvolveGather");
178 sub.bind_ubo("motion_blur_buf", data_);
179 sub.bind_ssbo("tile_indirection_buf", tile_indirection_buf_);
180 sub.bind_texture("depth_tx", &render_buffers.depth_tx, no_filter);
181 sub.bind_texture("velocity_tx", &render_buffers.vector_tx, no_filter);
182 sub.bind_texture("in_color_tx", &input_color_tx_, no_filter);
183 sub.bind_image("in_tiles_img", &tiles_tx_);
184 sub.bind_image("out_color_img", &output_color_tx_);
185
186 sub.dispatch(&dispatch_gather_size_);
188 }
189}
190
191void MotionBlurModule::render(View &view, GPUTexture **input_tx, GPUTexture **output_tx)
192{
193 if (!motion_blur_fx_enabled_) {
194 return;
195 }
196
197 const Texture &depth_tx = inst_.render_buffers.depth_tx;
198
199 int2 extent = {depth_tx.width(), depth_tx.height()};
200 int2 tiles_extent = math::divide_ceil(extent, int2(MOTION_BLUR_TILE_SIZE));
201
202 if (inst_.is_viewport()) {
203 float frame_delta = fabsf(inst_.velocity.step_time_delta_get(STEP_PREVIOUS, STEP_CURRENT));
204 /* Avoid highly disturbing blurs, during navigation with high shutter time. */
205 if (frame_delta > 0.0f && !inst_.is_navigating()) {
206 /* Rescale motion blur intensity to be shutter time relative and avoid long streak when we
207 * have frame skipping. Always try to stick to what the render frame would look like. */
208 data_.motion_scale = float2(shutter_time_ / frame_delta);
209 }
210 else {
211 /* There is no time change. Motion only comes from viewport navigation and object transform.
212 * Apply motion blur as smoothing and only blur towards last frame. */
213 data_.motion_scale = float2(1.0f, 0.0f);
214
215 if (was_navigating_ != inst_.is_navigating()) {
216 /* Special case for navigation events that only last for one frame (for instance mouse
217 * scroll for zooming). For this case we have to wait for the next frame before enabling
218 * the navigation motion blur. */
219 was_navigating_ = inst_.is_navigating();
220 return;
221 }
222 }
223 was_navigating_ = inst_.is_navigating();
224 }
225 else {
226 data_.motion_scale = float2(1.0f);
227 }
228 /* Second motion vector is stored inverted. */
229 data_.motion_scale.y = -data_.motion_scale.y;
230 data_.target_size_inv = 1.0f / float2(extent);
231 data_.push_update();
232
233 input_color_tx_ = *input_tx;
234 output_color_tx_ = *output_tx;
235
236 dispatch_flatten_size_ = int3(tiles_extent, 1);
237 dispatch_dilate_size_ = int3(math::divide_ceil(tiles_extent, int2(MOTION_BLUR_GROUP_SIZE)), 1);
238 dispatch_gather_size_ = int3(math::divide_ceil(extent, int2(MOTION_BLUR_GROUP_SIZE)), 1);
239
240 DRW_stats_group_start("Motion Blur");
241
242 tiles_tx_.acquire(tiles_extent, GPU_RGBA16F);
243
244 tile_indirection_buf_.clear_to_zero();
245
246 const bool do_motion_vectors_swizzle = inst_.render_buffers.vector_tx_format() == GPU_RG16F;
247 if (do_motion_vectors_swizzle) {
248 /* Change texture swizzling to avoid complexity in gather pass shader. */
250 }
251
252 inst_.manager->submit(motion_blur_ps_, view);
253
254 if (do_motion_vectors_swizzle) {
255 /* Reset swizzle since this texture might be reused in other places. */
257 }
258
259 tiles_tx_.release();
260
262
263 /* Swap buffers so that next effect has the right input. */
264 *input_tx = output_color_tx_;
265 *output_tx = input_color_tx_;
266}
267
270} // namespace blender::eevee
void BKE_curvemapping_changed(CurveMapping *cumap, bool rem_doubles)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
MINLINE int max_ii(int a, int b)
#define MOTION_BLUR_TILE_SIZE
#define CM_TABLE
@ SCE_MB_START
@ SCE_MB_END
@ SCE_MB_CENTER
@ R_MBLUR
@ SCE_LAY_MOTION_BLUR
@ GPU_BARRIER_SHADER_STORAGE
Definition GPU_state.hh:48
@ GPU_BARRIER_TEXTURE_FETCH
Definition GPU_state.hh:37
@ GPU_BARRIER_SHADER_IMAGE_ACCESS
Definition GPU_state.hh:35
eGPUTextureFormat
void GPU_texture_swizzle_set(GPUTexture *texture, const char swizzle[4])
int64_t size() const
void resize(const int64_t new_size)
void submit(PassSimple &pass, View &view)
void acquire(int2 extent, eGPUTextureFormat format, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL)
void bind_texture(const char *name, GPUTexture *texture, GPUSamplerState state=sampler_auto)
void bind_resources(U &resources)
Definition draw_pass.hh:426
void bind_image(const char *name, GPUTexture *image)
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:616
void dispatch(int group_len)
Definition draw_pass.hh:874
void barrier(eGPUBarrier type)
Definition draw_pass.hh:943
void bind_ubo(const char *name, GPUUniformBuf *buffer)
void bind_ssbo(const char *name, GPUStorageBuf *buffer)
void shader_set(GPUShader *shader)
Definition draw_pass.hh:971
bool overscan_changed() const
bool camera_changed() const
void render(View &view, GPUTexture **input_tx, GPUTexture **output_tx)
static void cdf_invert(Vector< float > &cdf, Vector< float > &inverted_cdf)
static void cdf_from_curvemapping(const CurveMapping &curve, Vector< float > &cdf)
GPUShader * static_shader_get(eShaderType shader_type)
float step_time_delta_get(eVelocityStep start, eVelocityStep end) const
void step_sync(eVelocityStep step, float time)
double time
#define fabsf(x)
void DRW_stats_group_start(const char *name)
void DRW_stats_group_end()
#define MOTION_BLUR_GROUP_SIZE
void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
constexpr GPUSamplerState no_filter
VecBase< T, Size > divide_ceil(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
static constexpr GPUSamplerState default_sampler()