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