Blender V5.0
gpencil_shader_fx.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2017 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8#include "DNA_camera_types.h"
10#include "DNA_shader_fx_types.h"
11#include "DNA_view3d_types.h"
12
13#include "BLI_link_utils.h"
14#include "BLI_math_matrix.h"
15#include "BLI_math_vector.h"
16
17#include "DRW_render.hh"
18
19#include "BKE_camera.h"
20
22
23namespace blender::draw::gpencil {
24
25/* verify if this fx is active */
26static bool effect_is_active(ShaderFxData *fx, bool is_edit, bool is_viewport)
27{
28 if (fx == nullptr) {
29 return false;
30 }
31
32 if (((fx->mode & eShaderFxMode_Editmode) == 0) && (is_edit) && (is_viewport)) {
33 return false;
34 }
35
36 if (((fx->mode & eShaderFxMode_Realtime) && (is_viewport == true)) ||
37 ((fx->mode & eShaderFxMode_Render) && (is_viewport == false)))
38 {
39 return true;
40 }
41
42 return false;
43}
44
45PassSimple &Instance::vfx_pass_create(
46 const char *name, DRWState state, gpu::Shader *sh, tObject *tgp_ob, GPUSamplerState sampler)
47{
49
51 tVfx &tgp_vfx = (*gp_vfx_pool)[id];
52 tgp_vfx.target_fb = vfx_swapchain_.next().fb;
53
54 PassSimple &pass = *tgp_vfx.vfx_ps;
55 pass.init();
56 pass.state_set(state);
57 pass.shader_set(sh);
58 pass.bind_texture("color_buf", vfx_swapchain_.current().color_tx, sampler);
59 pass.bind_texture("reveal_buf", vfx_swapchain_.current().reveal_tx, sampler);
60
61 vfx_swapchain_.swap();
62
63 BLI_LINKS_APPEND(&tgp_ob->vfx, &tgp_vfx);
64
65 return pass;
66}
67
68void Instance::vfx_blur_sync(BlurShaderFxData *fx, Object *ob, tObject *tgp_ob)
69{
70 if ((fx->samples == 0.0f) || (fx->radius[0] == 0.0f && fx->radius[1] == 0.0f)) {
71 return;
72 }
73
74 if ((fx->flag & FX_BLUR_DOF_MODE) && this->camera == nullptr) {
75 /* No blur outside camera view (or when DOF is disabled on the camera). */
76 return;
77 }
78
79 const float s = sin(fx->rotation);
80 const float c = cos(fx->rotation);
81
82 float4x4 winmat, persmat;
83 float blur_size[2] = {fx->radius[0], fx->radius[1]};
84 persmat = View::default_get().persmat();
85 const float w = fabsf(mul_project_m4_v3_zfac(persmat.ptr(), ob->object_to_world().location()));
86
87 if (fx->flag & FX_BLUR_DOF_MODE) {
88 /* Compute circle of confusion size. */
89 float coc = (this->dof_params[0] / -w) - this->dof_params[1];
90 copy_v2_fl(blur_size, fabsf(coc));
91 }
92 else {
93 /* Modify by distance to camera and object scale. */
94 winmat = View::default_get().winmat();
95 const float2 vp_size = this->draw_ctx->viewport_size_get();
96 float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
97 float scale = mat4_to_scale(ob->object_to_world().ptr());
98 float distance_factor = world_pixel_scale * scale * winmat[1][1] * vp_size[1] / w;
99 mul_v2_fl(blur_size, distance_factor);
100 }
101
102 gpu::Shader *sh = ShaderCache::get().fx_blur.get();
103
105 if (blur_size[0] > 0.0f) {
106 auto &grp = vfx_pass_create("Fx Blur H", state, sh, tgp_ob);
107 grp.push_constant("offset", float2(blur_size[0] * c, blur_size[0] * s));
108 grp.push_constant("samp_count", max_ii(1, min_ii(fx->samples, blur_size[0])));
109 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
110 }
111 if (blur_size[1] > 0.0f) {
112 auto &grp = vfx_pass_create("Fx Blur V", state, sh, tgp_ob);
113 grp.push_constant("offset", float2(-blur_size[1] * s, blur_size[1] * c));
114 grp.push_constant("samp_count", max_ii(1, min_ii(fx->samples, blur_size[1])));
115 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
116 }
117}
118
119void Instance::vfx_colorize_sync(ColorizeShaderFxData *fx, Object * /*ob*/, tObject *tgp_ob)
120{
121 gpu::Shader *sh = ShaderCache::get().fx_colorize.get();
122
124 auto &grp = vfx_pass_create("Fx Colorize", state, sh, tgp_ob);
125 grp.push_constant("low_color", float3(fx->low_color));
126 grp.push_constant("high_color", float3(fx->high_color));
127 grp.push_constant("factor", fx->factor);
128 grp.push_constant("mode", fx->mode);
129 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
130}
131
132void Instance::vfx_flip_sync(FlipShaderFxData *fx, Object * /*ob*/, tObject *tgp_ob)
133{
134 float axis_flip[2];
135 axis_flip[0] = (fx->flag & FX_FLIP_HORIZONTAL) ? -1.0f : 1.0f;
136 axis_flip[1] = (fx->flag & FX_FLIP_VERTICAL) ? -1.0f : 1.0f;
137
138 gpu::Shader *sh = ShaderCache::get().fx_transform.get();
139
141 auto &grp = vfx_pass_create("Fx Flip", state, sh, tgp_ob);
142 grp.push_constant("axis_flip", float2(axis_flip));
143 grp.push_constant("wave_offset", float2(0.0f, 0.0f));
144 grp.push_constant("swirl_radius", 0.0f);
145 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
146}
147
148void Instance::vfx_rim_sync(RimShaderFxData *fx, Object *ob, tObject *tgp_ob)
149{
150 float4x4 winmat, persmat;
151 float offset[2] = {float(fx->offset[0]), float(fx->offset[1])};
152 float blur_size[2] = {float(fx->blur[0]), float(fx->blur[1])};
153 winmat = View::default_get().winmat();
154 persmat = View::default_get().persmat();
155 const float2 vp_size = this->draw_ctx->viewport_size_get();
156 const float2 vp_size_inv = 1.0f / vp_size;
157
158 const float w = fabsf(mul_project_m4_v3_zfac(persmat.ptr(), ob->object_to_world().location()));
159
160 /* Modify by distance to camera and object scale. */
161 float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
162 float scale = mat4_to_scale(ob->object_to_world().ptr());
163 float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
164 mul_v2_fl(offset, distance_factor);
165 mul_v2_v2(offset, vp_size_inv);
166 mul_v2_fl(blur_size, distance_factor);
167
168 gpu::Shader *sh = ShaderCache::get().fx_rim.get();
169
170 {
172 auto &grp = vfx_pass_create("Fx Rim H", state, sh, tgp_ob);
173 grp.push_constant("blur_dir", float2(blur_size[0] * vp_size_inv[0], 0.0f));
174 grp.push_constant("uv_offset", float2(offset));
175 grp.push_constant("samp_count", max_ii(1, min_ii(fx->samples, blur_size[0])));
176 grp.push_constant("mask_color", float3(fx->mask_rgb));
177 grp.push_constant("is_first_pass", true);
178 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
179 }
180
181 {
183 switch (fx->mode) {
186 break;
189 break;
192 break;
197 break;
198 }
199
200 zero_v2(offset);
201
202 auto &grp = vfx_pass_create("Fx Rim V", state, sh, tgp_ob);
203 grp.push_constant("blur_dir", float2(0.0f, blur_size[1] * vp_size_inv[1]));
204 grp.push_constant("uv_offset", float2(offset));
205 grp.push_constant("rim_color", float3(fx->rim_rgb));
206 grp.push_constant("samp_count", max_ii(1, min_ii(fx->samples, blur_size[1])));
207 grp.push_constant("blend_mode", fx->mode);
208 grp.push_constant("is_first_pass", false);
209 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
210
211 if (fx->mode == eShaderFxRimMode_Overlay) {
212 /* We cannot do custom blending on multi-target frame-buffers.
213 * Workaround by doing 2 passes. */
215 grp.push_constant("blend_mode", 999);
216 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
217 }
218 }
219}
220
221void Instance::vfx_pixelize_sync(PixelShaderFxData *fx, Object *ob, tObject *tgp_ob)
222{
223 float4x4 persmat, winmat;
224 float ob_center[3], pixsize_uniform[2];
225 winmat = View::default_get().winmat();
226 persmat = View::default_get().persmat();
227 const float2 vp_size = this->draw_ctx->viewport_size_get();
228 const float2 vp_size_inv = 1.0f / vp_size;
229 float pixel_size[2] = {float(fx->size[0]), float(fx->size[1])};
230 mul_v2_v2(pixel_size, vp_size_inv);
231
232 /* Fixed pixelisation center from object center. */
233 const float w = fabsf(mul_project_m4_v3_zfac(persmat.ptr(), ob->object_to_world().location()));
234 mul_v3_m4v3(ob_center, persmat.ptr(), ob->object_to_world().location());
235 mul_v3_fl(ob_center, 1.0f / w);
236
237 const bool use_antialiasing = ((fx->flag & FX_PIXEL_FILTER_NEAREST) == 0);
238
239 /* Convert to uvs. */
240 mul_v2_fl(ob_center, 0.5f);
241 add_v2_fl(ob_center, 0.5f);
242
243 /* Modify by distance to camera and object scale. */
244 float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
245 float scale = mat4_to_scale(ob->object_to_world().ptr());
246 mul_v2_fl(pixel_size, (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w);
247
248 /* Center to texel */
249 madd_v2_v2fl(ob_center, pixel_size, -0.5f);
250
251 gpu::Shader *sh = ShaderCache::get().fx_pixelize.get();
252
254
255 /* Only if pixelated effect is bigger than 1px. */
256 if (pixel_size[0] > vp_size_inv[0]) {
257 copy_v2_fl2(pixsize_uniform, pixel_size[0], vp_size_inv[1]);
258 GPUSamplerState sampler = (use_antialiasing) ? GPUSamplerState::internal_sampler() :
260
261 auto &grp = vfx_pass_create("Fx Pixelize X", state, sh, tgp_ob, sampler);
262 grp.push_constant("target_pixel_size", float2(pixsize_uniform));
263 grp.push_constant("target_pixel_offset", float2(ob_center));
264 grp.push_constant("accum_offset", float2(pixel_size[0], 0.0f));
265 int samp_count = (pixel_size[0] / vp_size_inv[0] > 3.0) ? 2 : 1;
266 grp.push_constant("samp_count", (use_antialiasing ? samp_count : 0));
267 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
268 }
269
270 if (pixel_size[1] > vp_size_inv[1]) {
271 GPUSamplerState sampler = (use_antialiasing) ? GPUSamplerState::internal_sampler() :
273 copy_v2_fl2(pixsize_uniform, vp_size_inv[0], pixel_size[1]);
274 auto &grp = vfx_pass_create("Fx Pixelize Y", state, sh, tgp_ob, sampler);
275 grp.push_constant("target_pixel_size", float2(pixsize_uniform));
276 grp.push_constant("accum_offset", float2(0.0f, pixel_size[1]));
277 int samp_count = (pixel_size[1] / vp_size_inv[1] > 3.0) ? 2 : 1;
278 grp.push_constant("samp_count", (use_antialiasing ? samp_count : 0));
279 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
280 }
281}
282
283void Instance::vfx_shadow_sync(ShadowShaderFxData *fx, Object *ob, tObject *tgp_ob)
284{
285 const bool use_obj_pivot = (fx->flag & FX_SHADOW_USE_OBJECT) != 0;
286 const bool use_wave = (fx->flag & FX_SHADOW_USE_WAVE) != 0;
287
288 float4x4 uv_mat, winmat, persmat;
289 float rot_center[3];
290 float wave_ofs[3], wave_dir[3], wave_phase, blur_dir[2], tmp[2];
291 float offset[2] = {float(fx->offset[0]), float(fx->offset[1])};
292 float blur_size[2] = {float(fx->blur[0]), float(fx->blur[1])};
293 winmat = View::default_get().winmat();
294 persmat = View::default_get().persmat();
295 const float2 vp_size = this->draw_ctx->viewport_size_get();
296 const float2 vp_size_inv = 1.0f / vp_size;
297 const float ratio = vp_size_inv[1] / vp_size_inv[0];
298
299 copy_v3_v3(rot_center,
300 (use_obj_pivot && fx->object) ? fx->object->object_to_world().location() :
301 ob->object_to_world().location());
302
303 const float w = fabsf(mul_project_m4_v3_zfac(persmat.ptr(), rot_center));
304 mul_v3_m4v3(rot_center, persmat.ptr(), rot_center);
305 mul_v3_fl(rot_center, 1.0f / w);
306
307 /* Modify by distance to camera and object scale. */
308 float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
309 float scale = mat4_to_scale(ob->object_to_world().ptr());
310 float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
311 mul_v2_fl(offset, distance_factor);
312 mul_v2_v2(offset, vp_size_inv);
313 mul_v2_fl(blur_size, distance_factor);
314
315 rot_center[0] = rot_center[0] * 0.5f + 0.5f;
316 rot_center[1] = rot_center[1] * 0.5f + 0.5f;
317
318 /* UV transform matrix. (loc, rot, scale) Sent to shader as 2x3 matrix. */
319 unit_m4(uv_mat.ptr());
320 translate_m4(uv_mat.ptr(), rot_center[0], rot_center[1], 0.0f);
321 rescale_m4(uv_mat.ptr(), float3{1.0f / fx->scale[0], 1.0f / fx->scale[1], 1.0f});
322 translate_m4(uv_mat.ptr(), -offset[0], -offset[1], 0.0f);
323 rescale_m4(uv_mat.ptr(), float3{1.0f / ratio, 1.0f, 1.0f});
324 rotate_m4(uv_mat.ptr(), 'Z', fx->rotation);
325 rescale_m4(uv_mat.ptr(), float3{ratio, 1.0f, 1.0f});
326 translate_m4(uv_mat.ptr(), -rot_center[0], -rot_center[1], 0.0f);
327
328 if (use_wave) {
329 float dir[2];
330 if (fx->orientation == 0) {
331 /* Horizontal */
332 copy_v2_fl2(dir, 1.0f, 0.0f);
333 }
334 else {
335 /* Vertical */
336 copy_v2_fl2(dir, 0.0f, 1.0f);
337 }
338 /* This is applied after rotation. Counter the rotation to keep aligned with global axis. */
339 rotate_v2_v2fl(wave_dir, dir, fx->rotation);
340 /* Rotate 90 degrees. */
341 copy_v2_v2(wave_ofs, wave_dir);
342 std::swap(wave_ofs[0], wave_ofs[1]);
343 wave_ofs[1] *= -1.0f;
344 /* Keep world space scaling and aspect ratio. */
345 mul_v2_fl(wave_dir, 1.0f / (max_ff(1e-8f, fx->period) * distance_factor));
346 mul_v2_v2(wave_dir, vp_size);
347 mul_v2_fl(wave_ofs, fx->amplitude * distance_factor);
348 mul_v2_v2(wave_ofs, vp_size_inv);
349 /* Phase start at shadow center. */
350 wave_phase = fx->phase - dot_v2v2(rot_center, wave_dir);
351 }
352 else {
353 zero_v2(wave_dir);
354 zero_v2(wave_ofs);
355 wave_phase = 0.0f;
356 }
357
358 gpu::Shader *sh = ShaderCache::get().fx_shadow.get();
359
360 copy_v2_fl2(blur_dir, blur_size[0] * vp_size_inv[0], 0.0f);
361
362 {
364 auto &grp = vfx_pass_create("Fx Shadow H", state, sh, tgp_ob);
365 grp.push_constant("blur_dir", float2(blur_dir));
366 grp.push_constant("wave_dir", float2(wave_dir));
367 grp.push_constant("wave_offset", float2(wave_ofs));
368 grp.push_constant("wave_phase", wave_phase);
369 grp.push_constant("uv_rot_x", float2(uv_mat[0]));
370 grp.push_constant("uv_rot_y", float2(uv_mat[1]));
371 grp.push_constant("uv_offset", float2(uv_mat[3]));
372 grp.push_constant("samp_count", max_ii(1, min_ii(fx->samples, blur_size[0])));
373 grp.push_constant("is_first_pass", true);
374 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
375 }
376
377 unit_m4(uv_mat.ptr());
378 zero_v2(wave_ofs);
379
380 /* Reset the `uv_mat` to account for rotation in the Y-axis (Shadow-V parameter). */
381 copy_v2_fl2(tmp, 0.0f, blur_size[1]);
382 rotate_v2_v2fl(blur_dir, tmp, -fx->rotation);
383 mul_v2_v2(blur_dir, vp_size_inv);
384
385 {
387 auto &grp = vfx_pass_create("Fx Shadow V", state, sh, tgp_ob);
388 grp.push_constant("shadow_color", float4(fx->shadow_rgba));
389 grp.push_constant("blur_dir", float2(blur_dir));
390 grp.push_constant("wave_offset", float2(wave_ofs));
391 grp.push_constant("uv_rot_x", float2(uv_mat[0]));
392 grp.push_constant("uv_rot_y", float2(uv_mat[1]));
393 grp.push_constant("uv_offset", float2(uv_mat[3]));
394 grp.push_constant("samp_count", max_ii(1, min_ii(fx->samples, blur_size[1])));
395 grp.push_constant("is_first_pass", false);
396 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
397 }
398}
399
400void Instance::vfx_glow_sync(GlowShaderFxData *fx, Object * /*ob*/, tObject *tgp_ob)
401{
402 const bool use_glow_under = (fx->flag & FX_GLOW_USE_ALPHA) != 0;
403 const float s = sin(fx->rotation);
404 const float c = cos(fx->rotation);
405
406 gpu::Shader *sh = ShaderCache::get().fx_glow.get();
407
408 float ref_col[4];
409
411 /* Only pass in the first value for luminance. */
412 ref_col[0] = fx->threshold;
413 ref_col[1] = -1.0f;
414 ref_col[2] = -1.0f;
415 ref_col[3] = -1.0f;
416 }
417 else {
418 /* First three values are the RGB for the selected color, last value the threshold. */
419 copy_v3_v3(ref_col, fx->select_color);
420 ref_col[3] = fx->threshold;
421 }
422
424 auto &grp = vfx_pass_create("Fx Glow H", state, sh, tgp_ob);
425 grp.push_constant("offset", float2(fx->blur[0] * c, fx->blur[0] * s));
426 grp.push_constant("samp_count", max_ii(1, min_ii(fx->samples, fx->blur[0])));
427 grp.push_constant("threshold", float4(ref_col));
428 grp.push_constant("glow_color", float4(fx->glow_color));
429 grp.push_constant("glow_under", use_glow_under);
430 grp.push_constant("first_pass", true);
431 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
432
434 /* Blending: Force blending. */
435 switch (fx->blend_mode) {
438 break;
441 break;
444 break;
448 break;
449 }
450
451 /* Small Hack: We ask for RGBA16F buffer if using use_glow_under to store original
452 * revealage in alpha channel. */
453 if (fx->blend_mode == eGplBlendMode_Subtract || use_glow_under) {
454 /* For this effect to propagate, we need a signed floating point buffer. */
455 this->use_signed_fb = true;
456 }
457
458 {
459 auto &grp = vfx_pass_create("Fx Glow V", state, sh, tgp_ob);
460 grp.push_constant("offset", float2(-fx->blur[1] * s, fx->blur[1] * c));
461 grp.push_constant("samp_count", max_ii(1, min_ii(fx->samples, fx->blur[0])));
462 grp.push_constant("threshold", float4{-1.0f, -1.0f, -1.0f, -1.0});
463 grp.push_constant("glow_color", float4{1.0f, 1.0f, 1.0f, fx->glow_color[3]});
464 grp.push_constant("first_pass", false);
465 grp.push_constant("blend_mode", fx->blend_mode);
466 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
467 }
468}
469
470void Instance::vfx_wave_sync(WaveShaderFxData *fx, Object *ob, tObject *tgp_ob)
471{
472 float4x4 winmat, persmat;
473 float wave_center[3];
474 float wave_ofs[3], wave_dir[3], wave_phase;
475 winmat = View::default_get().winmat();
476 persmat = View::default_get().persmat();
477 const float2 vp_size = this->draw_ctx->viewport_size_get();
478 const float2 vp_size_inv = 1.0f / vp_size;
479
480 const float w = fabsf(mul_project_m4_v3_zfac(persmat.ptr(), ob->object_to_world().location()));
481 mul_v3_m4v3(wave_center, persmat.ptr(), ob->object_to_world().location());
482 mul_v3_fl(wave_center, 1.0f / w);
483
484 /* Modify by distance to camera and object scale. */
485 float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
486 float scale = mat4_to_scale(ob->object_to_world().ptr());
487 float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
488
489 wave_center[0] = wave_center[0] * 0.5f + 0.5f;
490 wave_center[1] = wave_center[1] * 0.5f + 0.5f;
491
492 if (fx->orientation == 0) {
493 /* Horizontal */
494 copy_v2_fl2(wave_dir, 1.0f, 0.0f);
495 }
496 else {
497 /* Vertical */
498 copy_v2_fl2(wave_dir, 0.0f, 1.0f);
499 }
500 /* Rotate 90 degrees. */
501 copy_v2_v2(wave_ofs, wave_dir);
502 std::swap(wave_ofs[0], wave_ofs[1]);
503 wave_ofs[1] *= -1.0f;
504 /* Keep world space scaling and aspect ratio. */
505 mul_v2_fl(wave_dir, 1.0f / (max_ff(1e-8f, fx->period) * distance_factor));
506 mul_v2_v2(wave_dir, vp_size);
507 mul_v2_fl(wave_ofs, fx->amplitude * distance_factor);
508 mul_v2_v2(wave_ofs, vp_size_inv);
509 /* Phase start at shadow center. */
510 wave_phase = fx->phase - dot_v2v2(wave_center, wave_dir);
511
512 gpu::Shader *sh = ShaderCache::get().fx_transform.get();
513
515 auto &grp = vfx_pass_create("Fx Wave", state, sh, tgp_ob);
516 grp.push_constant("axis_flip", float2(1.0f, 1.0f));
517 grp.push_constant("wave_dir", float2(wave_dir));
518 grp.push_constant("wave_offset", float2(wave_ofs));
519 grp.push_constant("wave_phase", wave_phase);
520 grp.push_constant("swirl_radius", 0.0f);
521 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
522}
523
524void Instance::vfx_swirl_sync(SwirlShaderFxData *fx, Object * /*ob*/, tObject *tgp_ob)
525{
526 if (fx->object == nullptr) {
527 return;
528 }
529
530 float4x4 winmat, persmat;
531 float swirl_center[3];
532 winmat = View::default_get().winmat();
533 persmat = View::default_get().persmat();
534 const float2 vp_size = this->draw_ctx->viewport_size_get();
535
536 copy_v3_v3(swirl_center, fx->object->object_to_world().location());
537
538 const float w = fabsf(mul_project_m4_v3_zfac(persmat.ptr(), swirl_center));
539 mul_v3_m4v3(swirl_center, persmat.ptr(), swirl_center);
540 mul_v3_fl(swirl_center, 1.0f / w);
541
542 /* Modify by distance to camera and object scale. */
543 float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
544 float scale = mat4_to_scale(fx->object->object_to_world().ptr());
545 float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
546
547 mul_v2_fl(swirl_center, 0.5f);
548 add_v2_fl(swirl_center, 0.5f);
549 mul_v2_v2(swirl_center, vp_size);
550
551 float radius = fx->radius * distance_factor;
552 if (radius < 1.0f) {
553 return;
554 }
555
556 gpu::Shader *sh = ShaderCache::get().fx_transform.get();
557
559 auto &grp = vfx_pass_create("Fx Flip", state, sh, tgp_ob);
560 grp.push_constant("axis_flip", float2(1.0f, 1.0f));
561 grp.push_constant("wave_offset", float2(0.0f, 0.0f));
562 grp.push_constant("swirl_center", float2(swirl_center));
563 grp.push_constant("swirl_angle", fx->angle);
564 grp.push_constant("swirl_radius", radius);
565 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
566}
567
568void Instance::vfx_sync(Object *ob, tObject *tgp_ob)
569{
570 const bool is_edit_mode = ELEM(
572
573 vfx_swapchain_.next().fb = &layer_fb;
574 vfx_swapchain_.next().color_tx = &color_layer_tx;
575 vfx_swapchain_.next().reveal_tx = &reveal_layer_tx;
576 vfx_swapchain_.current().fb = &object_fb;
577 vfx_swapchain_.current().color_tx = &color_object_tx;
578 vfx_swapchain_.current().reveal_tx = &reveal_object_tx;
579
580 /* If simplify enabled, nothing more to do. */
581 if (!this->simplify_fx) {
583 if (effect_is_active(fx, is_edit_mode, this->is_viewport)) {
584 switch (fx->type) {
586 vfx_blur_sync((BlurShaderFxData *)fx, ob, tgp_ob);
587 break;
589 vfx_colorize_sync((ColorizeShaderFxData *)fx, ob, tgp_ob);
590 break;
592 vfx_flip_sync((FlipShaderFxData *)fx, ob, tgp_ob);
593 break;
595 vfx_pixelize_sync((PixelShaderFxData *)fx, ob, tgp_ob);
596 break;
598 vfx_rim_sync((RimShaderFxData *)fx, ob, tgp_ob);
599 break;
601 vfx_shadow_sync((ShadowShaderFxData *)fx, ob, tgp_ob);
602 break;
604 vfx_glow_sync((GlowShaderFxData *)fx, ob, tgp_ob);
605 break;
607 vfx_swirl_sync((SwirlShaderFxData *)fx, ob, tgp_ob);
608 break;
610 vfx_wave_sync((WaveShaderFxData *)fx, ob, tgp_ob);
611 break;
612 default:
613 break;
614 }
615 }
616 }
617 }
618
619 if ((!this->simplify_fx && tgp_ob->vfx.first != nullptr) || tgp_ob->do_mat_holdout) {
620 /* We need an extra pass to combine result to main buffer. */
621 vfx_swapchain_.next().fb = &this->gpencil_fb;
622
623 gpu::Shader *sh = ShaderCache::get().fx_composite.get();
624
626 auto &grp = vfx_pass_create("GPencil Object Compose", state, sh, tgp_ob);
627 grp.push_constant("is_first_pass", true);
628 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
629
630 /* We cannot do custom blending on multi-target frame-buffers.
631 * Workaround by doing 2 passes. */
633 grp.push_constant("is_first_pass", false);
634 grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
635
636 this->use_object_fb = true;
637 this->use_layer_fb = true;
638 }
639}
640
641} // namespace blender::draw::gpencil
Camera data-block and utility functions.
#define LISTBASE_FOREACH(type, var, list)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
float mat4_to_scale(const float mat[4][4])
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void rescale_m4(float mat[4][4], const float scale[3])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
void rotate_m4(float mat[4][4], char axis, float angle)
void unit_m4(float m[4][4])
MINLINE void copy_v2_fl2(float v[2], float x, float y)
MINLINE void madd_v2_v2fl(float r[2], const float a[2], float f)
MINLINE void mul_v2_v2(float r[2], const float a[2])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v2_fl(float r[2], float f)
MINLINE void zero_v2(float r[2])
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
void rotate_v2_v2fl(float r[2], const float p[2], float angle)
MINLINE void copy_v2_fl(float r[2], float f)
#define UNUSED_VARS(...)
#define ELEM(...)
@ eGplBlendMode_Regular
@ eGplBlendMode_Multiply
@ eGplBlendMode_Subtract
@ OB_MODE_EDIT
@ OB_MODE_SCULPT_GREASE_PENCIL
@ OB_MODE_WEIGHT_GREASE_PENCIL
struct Object Object
@ FX_BLUR_DOF_MODE
struct RimShaderFxData RimShaderFxData
struct GlowShaderFxData GlowShaderFxData
@ FX_SHADOW_USE_OBJECT
@ FX_SHADOW_USE_WAVE
@ eShaderFxMode_Realtime
@ eShaderFxMode_Editmode
@ eShaderFxMode_Render
struct FlipShaderFxData FlipShaderFxData
@ eShaderFxGlowMode_Luminance
struct WaveShaderFxData WaveShaderFxData
struct SwirlShaderFxData SwirlShaderFxData
@ eShaderFxRimMode_Multiply
@ eShaderFxRimMode_Add
@ eShaderFxRimMode_Normal
@ eShaderFxRimMode_Overlay
@ eShaderFxRimMode_Subtract
@ eShaderFxRimMode_Divide
@ FX_PIXEL_FILTER_NEAREST
struct BlurShaderFxData BlurShaderFxData
struct ColorizeShaderFxData ColorizeShaderFxData
struct ShaderFxData ShaderFxData
@ FX_FLIP_HORIZONTAL
@ FX_FLIP_VERTICAL
@ FX_GLOW_USE_ALPHA
struct ShadowShaderFxData ShadowShaderFxData
@ eShaderFxType_Pixel
@ eShaderFxType_Rim
@ eShaderFxType_Swirl
@ eShaderFxType_Glow
@ eShaderFxType_Flip
@ eShaderFxType_Blur
@ eShaderFxType_Shadow
@ eShaderFxType_Colorize
@ eShaderFxType_Wave
struct PixelShaderFxData PixelShaderFxData
@ GPU_PRIM_TRIS
long long int int64_t
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
const float4x4 & winmat(int view_id=0) const
Definition draw_view.hh:148
const float4x4 persmat(int view_id=0) const
Definition draw_view.hh:161
static View & default_get()
Definition draw_view.cc:317
blender::gpu::Shader * get()
nullptr float
DRWState
Definition draw_state.hh:25
@ DRW_STATE_BLEND_SUB
Definition draw_state.hh:61
@ DRW_STATE_BLEND_ADD_FULL
Definition draw_state.hh:53
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_BLEND_ALPHA_PREMUL
Definition draw_state.hh:57
@ DRW_STATE_BLEND_MUL
Definition draw_state.hh:60
#define GPENCIL_PIXEL_FACTOR
#define sin
#define cos
static ulong state[N]
static bool effect_is_active(ShaderFxData *fx, bool is_edit, bool is_viewport)
detail::Pass< command::DrawCommandBuf > PassSimple
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
const char * name
#define fabsf
static constexpr GPUSamplerState internal_sampler()
static constexpr GPUSamplerState default_sampler()
ListBase shader_fx
const c_style_mat & ptr() const