Blender V5.0
gpencil_antialiasing.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_rand.h"
10#include "BLI_smaa_textures.h"
11
12#include "DNA_scene_types.h"
13#include "DRW_render.hh"
14
16
18
19void Instance::antialiasing_init()
20{
21 const float2 size_f = this->draw_ctx->viewport_size_get();
22 const int2 size(size_f[0], size_f[1]);
23 const float4 metrics = {1.0f / size[0], 1.0f / size[1], float(size[0]), float(size[1])};
24
25 if (this->simplify_antialias) {
26 /* No AA fallback. */
27 PassSimple &pass = this->smaa_resolve_ps;
28 pass.init();
30 pass.shader_set(ShaderCache::get().antialiasing[2].get());
31 pass.bind_texture("blend_tx", &this->color_tx);
32 pass.bind_texture("color_tx", &this->color_tx);
33 pass.bind_texture("reveal_tx", &this->reveal_tx);
34 pass.push_constant("do_anti_aliasing", false);
35 pass.push_constant("only_alpha", this->draw_wireframe);
36 pass.push_constant("viewport_metrics", metrics);
38 return;
39 }
40
41 if (!this->smaa_search_tx.is_valid()) {
44 gpu::TextureFormat::UNORM_8, int2(SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT), usage);
46
48 gpu::TextureFormat::UNORM_8_8, int2(AREATEX_WIDTH, AREATEX_HEIGHT), usage);
50
53 }
54
55 {
57 this->smaa_edge_tx.acquire(size, gpu::TextureFormat::UNORM_8_8, usage);
58 this->smaa_weight_tx.acquire(size, gpu::TextureFormat::UNORM_8_8_8_8, usage);
59
62 }
63
64 SceneGpencil gpencil_settings = this->scene->grease_pencil_settings;
65 const float luma_weight = this->is_viewport ? gpencil_settings.smaa_threshold :
66 gpencil_settings.smaa_threshold_render;
67
68 {
69 /* Stage 1: Edge detection. */
70 PassSimple &pass = this->smaa_edge_ps;
71 pass.init();
73 pass.shader_set(ShaderCache::get().antialiasing[0].get());
74 pass.bind_texture("color_tx", &this->color_tx);
75 pass.bind_texture("reveal_tx", &this->reveal_tx);
76 pass.push_constant("viewport_metrics", metrics);
77 pass.push_constant("luma_weight", luma_weight);
78 pass.clear_color(float4(0.0f));
80 }
81 {
82 /* Stage 2: Blend Weight/Coord. */
83 PassSimple &pass = this->smaa_weight_ps;
84 pass.init();
86 pass.shader_set(ShaderCache::get().antialiasing[1].get());
87 pass.bind_texture("edges_tx", &this->smaa_edge_tx);
88 pass.bind_texture("area_tx", &this->smaa_area_tx);
89 pass.bind_texture("search_tx", &this->smaa_search_tx);
90 pass.push_constant("viewport_metrics", metrics);
91 pass.clear_color(float4(0.0f));
93 }
94 {
95 /* Stage 3: Resolve. */
96 PassSimple &pass = this->smaa_resolve_ps;
97 pass.init();
99 pass.shader_set(ShaderCache::get().antialiasing[2].get());
100 pass.bind_texture("blend_tx", &this->smaa_weight_tx);
101 pass.bind_texture("color_tx", &this->color_tx);
102 pass.bind_texture("reveal_tx", &this->reveal_tx);
103 pass.push_constant("do_anti_aliasing", true);
104 pass.push_constant("only_alpha", this->draw_wireframe);
105 pass.push_constant("viewport_metrics", metrics);
106 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
107 }
108}
109
110void Instance::antialiasing_draw(Manager &manager)
111{
112 if (!this->simplify_antialias) {
114 manager.submit(this->smaa_edge_ps);
115
117 manager.submit(this->smaa_weight_ps);
118 }
119
121 manager.submit(this->smaa_resolve_ps);
122
123 if (this->use_separate_pass) {
126 manager.submit(this->smaa_resolve_ps);
127 }
128}
129
130static float erfinv_approx(const float x)
131{
132 /* From: Approximating the `erfinv` function by Mike Giles. */
133 /* To avoid trouble at the limit, clamp input to 1-epsilon. */
134 const float a = math::min(fabsf(x), 0.99999994f);
135 float w = -logf((1.0f - a) * (1.0f + a));
136 float p;
137 if (w < 5.0f) {
138 w = w - 2.5f;
139 p = 2.81022636e-08f;
140 p = p * w + 3.43273939e-07f;
141 p = p * w + -3.5233877e-06f;
142 p = p * w + -4.39150654e-06f;
143 p = p * w + 0.00021858087f;
144 p = p * w + -0.00125372503f;
145 p = p * w + -0.00417768164f;
146 p = p * w + 0.246640727f;
147 p = p * w + 1.50140941f;
148 }
149 else {
150 w = sqrtf(w) - 3.0f;
151 p = -0.000200214257f;
152 p = p * w + 0.000100950558f;
153 p = p * w + 0.00134934322f;
154 p = p * w + -0.00367342844f;
155 p = p * w + 0.00573950773f;
156 p = p * w + -0.0076224613f;
157 p = p * w + 0.00943887047f;
158 p = p * w + 1.00167406f;
159 p = p * w + 2.83297682f;
160 }
161 return p * x;
162}
163
164float2 Instance::antialiasing_sample_get(const int sample_index, const int sample_count)
165{
166 if (sample_count < 2) {
167 return float2(0.0f);
168 }
169
170 double halton[2];
171 {
172 uint primes[2] = {2, 3};
173 double ofs[2] = {0, 0};
174 BLI_halton_2d(primes, ofs, sample_index, halton);
175 }
176 /* Uniform distribution [0..1]. */
177 const float2 rand = float2(halton[0], halton[1]);
178 /* Uniform distribution [-1..1]. */
179 const float2 rand_remap = rand * 2.0f - 1.0f;
180 /* Limit sampling region to avoid outliers. */
181 const float2 rand_adjusted = rand_remap * 0.93f;
182 /* Gaussian distribution [-1..1]. */
183 const float2 offset = float2(erfinv_approx(rand_adjusted.x), erfinv_approx(rand_adjusted.y));
184 /* Gaussian fitted to Blackman-Harris (follows EEVEE). */
185 const float sigma = 0.284f;
186 /* NOTE(fclem): Not sure where this sqrt comes from but is needed to match EEVEE. */
187 return offset * sqrt(sigma);
188}
189
190void Instance::antialiasing_accumulate(Manager &manager, const float alpha)
191{
192 BLI_assert_msg(this->render_color_tx.gpu_texture() != nullptr,
193 "This should only be called during render");
194 const int2 size = this->render_color_tx.size().xy();
195
198 accumulation_tx.ensure_2d(gpu::TextureFormat::GPENCIL_ACCUM_FORMAT, size, usage);
199
200 {
201 PassSimple &pass = this->accumulate_ps;
202 pass.init();
203 pass.state_set(DRW_STATE_WRITE_DEPTH /* There is no depth, but avoid blank state. */);
204 pass.shader_set(ShaderCache::get().accumulation.get());
205 pass.bind_image("src_img", &this->render_color_tx);
206 pass.bind_image("dst_img", &this->accumulation_tx);
207 pass.push_constant("weight_src", alpha);
208 pass.push_constant("weight_dst", 1.0f - alpha);
209 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
210 }
211
212 accumulation_fb.ensure(size);
214 manager.submit(this->accumulate_ps);
215}
216
217} // namespace blender::draw::gpencil
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
Random number functions.
void BLI_halton_2d(const unsigned int prime[2], double offset[2], int n, double *r)
Definition rand.cc:237
#define SEARCHTEX_HEIGHT
const unsigned char searchTexBytes[]
#define SEARCHTEX_WIDTH
#define AREATEX_HEIGHT
const unsigned char areaTexBytes[]
#define AREATEX_WIDTH
@ GPU_COLOR_BIT
#define GPU_ATTACHMENT_TEXTURE(_texture)
#define GPU_ATTACHMENT_NONE
void GPU_framebuffer_clear(blender::gpu::FrameBuffer *fb, GPUFrameBufferBits buffers, const float clear_col[4], float clear_depth, unsigned int clear_stencil)
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
@ GPU_PRIM_TRIS
@ GPU_DATA_UBYTE
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_SHADER_WRITE
@ GPU_TEXTURE_USAGE_HOST_READ
@ GPU_TEXTURE_USAGE_ATTACHMENT
void GPU_texture_filter_mode(blender::gpu::Texture *texture, bool use_filter)
void GPU_texture_update(blender::gpu::Texture *texture, eGPUDataFormat data_format, const void *data)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
void ensure(GPUAttachment depth=GPU_ATTACHMENT_NONE, GPUAttachment color1=GPU_ATTACHMENT_NONE, GPUAttachment color2=GPU_ATTACHMENT_NONE, GPUAttachment color3=GPU_ATTACHMENT_NONE, GPUAttachment color4=GPU_ATTACHMENT_NONE, GPUAttachment color5=GPU_ATTACHMENT_NONE, GPUAttachment color6=GPU_ATTACHMENT_NONE, GPUAttachment color7=GPU_ATTACHMENT_NONE, GPUAttachment color8=GPU_ATTACHMENT_NONE)
void submit(PassSimple &pass, View &view)
void acquire(int2 extent, blender::gpu::TextureFormat format, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL)
bool ensure_2d(blender::gpu::TextureFormat format, int2 extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
void shader_set(gpu::Shader *shader)
void bind_texture(const char *name, gpu::Texture *texture, GPUSamplerState state=sampler_auto)
void clear_color(float4 color)
void bind_image(const char *name, gpu::Texture *image)
void draw_procedural(GPUPrimType primitive, uint instance_len, uint vertex_len, uint vertex_first=-1, ResourceIndexRange res_index={}, uint custom_id=0)
Definition draw_pass.hh:964
void state_set(DRWState state, int clip_plane_count=0)
void push_constant(const char *name, const float &data)
nullptr float
#define logf(x)
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_BLEND_CUSTOM
Definition draw_state.hh:63
#define sqrt
static float erfinv_approx(const float x)
detail::Pass< command::DrawCommandBuf > PassSimple
T min(const T &a, const T &b)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
#define fabsf
#define sqrtf
blender::float2 viewport_size_get() const
float smaa_threshold_render
struct SceneGpencil grease_pencil_settings
static float2 antialiasing_sample_get(int sample_index, int sample_count)
void antialiasing_accumulate(Manager &manager, float alpha)