Grease Pencil: Accumulation Anti-aliasing
This adds a new more accurate antialiasing to the Grease Pencil render engine. This is only available for render. This Accumulation AA doesn't replace the SMAA. SMAA is still used by the viewport and for removing aliasing from the depth buffer. However, using both at the same time can lead to overblurred result. Here are some measurements for how much the render time increases compared to the baseline with different (SSAA) sample counts (using an example production file, rendered at 1080p, results might vary depending on the scene complexity): * 8 samples: +0.14 s * 16 samples +0.36 s * 32 samples: +0.58 s Co-authored-by: Falk David <falk@blender.org> Pull Request: https://projects.blender.org/blender/blender/pulls/136551
This commit is contained in:
committed by
Falk David
parent
3064906eb7
commit
299a581b1b
@@ -845,6 +845,7 @@ class RENDER_PT_eevee_performance_viewport(RenderButtonsPanel, Panel):
|
||||
col.prop(rd, "preview_pixel_size", text="Pixel Size")
|
||||
|
||||
|
||||
# TODO(falk): To rename for 5.0
|
||||
class RENDER_PT_gpencil(RenderButtonsPanel, Panel):
|
||||
bl_label = "Grease Pencil"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
@@ -855,6 +856,24 @@ class RENDER_PT_gpencil(RenderButtonsPanel, Panel):
|
||||
'BLENDER_WORKBENCH',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
pass
|
||||
|
||||
|
||||
class RENDER_PT_grease_pencil_viewport(RenderButtonsPanel, Panel):
|
||||
bl_label = "Viewport"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_parent_id = "RENDER_PT_gpencil"
|
||||
COMPAT_ENGINES = {
|
||||
'BLENDER_RENDER',
|
||||
'BLENDER_EEVEE_NEXT',
|
||||
'BLENDER_WORKBENCH',
|
||||
}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
@@ -864,7 +883,30 @@ class RENDER_PT_gpencil(RenderButtonsPanel, Panel):
|
||||
props = scene.grease_pencil_settings
|
||||
|
||||
col = layout.column()
|
||||
col.prop(props, "antialias_threshold")
|
||||
col.prop(props, "antialias_threshold", text="SMAA Threshold")
|
||||
|
||||
|
||||
class RENDER_PT_grease_pencil_render(RenderButtonsPanel, Panel):
|
||||
bl_label = "Render"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_parent_id = "RENDER_PT_gpencil"
|
||||
COMPAT_ENGINES = {
|
||||
'BLENDER_RENDER',
|
||||
'BLENDER_EEVEE_NEXT',
|
||||
'BLENDER_WORKBENCH',
|
||||
}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
scene = context.scene
|
||||
props = scene.grease_pencil_settings
|
||||
|
||||
col = layout.column()
|
||||
col.prop(props, "antialias_threshold_render", text="SMAA Threshold")
|
||||
col.prop(props, "aa_samples", text="SSAA Samples")
|
||||
|
||||
|
||||
class RENDER_PT_opengl_sampling(RenderButtonsPanel, Panel):
|
||||
@@ -1081,6 +1123,8 @@ classes = (
|
||||
|
||||
|
||||
RENDER_PT_gpencil,
|
||||
RENDER_PT_grease_pencil_viewport,
|
||||
RENDER_PT_grease_pencil_render,
|
||||
RENDER_PT_opengl_sampling,
|
||||
RENDER_PT_opengl_lighting,
|
||||
RENDER_PT_opengl_color,
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 15
|
||||
#define BLENDER_FILE_SUBVERSION 16
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
||||
@@ -195,9 +195,6 @@ static void scene_init_data(ID *id)
|
||||
scene->unit.temperature_unit = uchar(
|
||||
BKE_unit_base_of_type_get(USER_UNIT_METRIC, B_UNIT_TEMPERATURE));
|
||||
|
||||
/* Anti-Aliasing threshold. */
|
||||
scene->grease_pencil_settings.smaa_threshold = 1.0f;
|
||||
|
||||
{
|
||||
ParticleEditSettings *pset;
|
||||
pset = &scene->toolsettings->particle;
|
||||
|
||||
@@ -6634,6 +6634,14 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 16)) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
scene->grease_pencil_settings.smaa_threshold_render =
|
||||
scene->grease_pencil_settings.smaa_threshold;
|
||||
scene->grease_pencil_settings.aa_samples = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Always run this versioning; meshes are written with the legacy format which always needs to
|
||||
* be converted to the new format on file load. Can be moved to a subversion check in a larger
|
||||
* breaking release. */
|
||||
|
||||
@@ -584,6 +584,7 @@ set(GLSL_SRC
|
||||
|
||||
engines/gpencil/shaders/gpencil_frag.glsl
|
||||
engines/gpencil/shaders/gpencil_vert.glsl
|
||||
engines/gpencil/shaders/gpencil_antialiasing_accumulation_frag.glsl
|
||||
engines/gpencil/shaders/gpencil_antialiasing_frag.glsl
|
||||
engines/gpencil/shaders/gpencil_antialiasing_vert.glsl
|
||||
engines/gpencil/shaders/gpencil_common_lib.glsl
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#include "BLI_rand.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DRW_render.hh"
|
||||
|
||||
@@ -58,6 +59,10 @@ void Instance::antialiasing_init()
|
||||
this->smaa_weight_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(this->smaa_weight_tx));
|
||||
}
|
||||
|
||||
SceneGpencil gpencil_settings = this->scene->grease_pencil_settings;
|
||||
const float luma_weight = this->is_viewport ? gpencil_settings.smaa_threshold :
|
||||
gpencil_settings.smaa_threshold_render;
|
||||
|
||||
{
|
||||
/* Stage 1: Edge detection. */
|
||||
PassSimple &pass = this->smaa_edge_ps;
|
||||
@@ -67,7 +72,7 @@ void Instance::antialiasing_init()
|
||||
pass.bind_texture("colorTex", &this->color_tx);
|
||||
pass.bind_texture("revealTex", &this->reveal_tx);
|
||||
pass.push_constant("viewportMetrics", metrics);
|
||||
pass.push_constant("lumaWeight", this->scene->grease_pencil_settings.smaa_threshold);
|
||||
pass.push_constant("lumaWeight", luma_weight);
|
||||
pass.clear_color(float4(0.0f));
|
||||
pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
}
|
||||
@@ -114,4 +119,91 @@ void Instance::antialiasing_draw(Manager &manager)
|
||||
manager.submit(this->smaa_resolve_ps);
|
||||
}
|
||||
|
||||
static float erfinv_approx(const float x)
|
||||
{
|
||||
/* From: Approximating the `erfinv` function by Mike Giles. */
|
||||
/* To avoid trouble at the limit, clamp input to 1-epsilon. */
|
||||
const float a = math::min(fabsf(x), 0.99999994f);
|
||||
float w = -logf((1.0f - a) * (1.0f + a));
|
||||
float p;
|
||||
if (w < 5.0f) {
|
||||
w = w - 2.5f;
|
||||
p = 2.81022636e-08f;
|
||||
p = p * w + 3.43273939e-07f;
|
||||
p = p * w + -3.5233877e-06f;
|
||||
p = p * w + -4.39150654e-06f;
|
||||
p = p * w + 0.00021858087f;
|
||||
p = p * w + -0.00125372503f;
|
||||
p = p * w + -0.00417768164f;
|
||||
p = p * w + 0.246640727f;
|
||||
p = p * w + 1.50140941f;
|
||||
}
|
||||
else {
|
||||
w = sqrtf(w) - 3.0f;
|
||||
p = -0.000200214257f;
|
||||
p = p * w + 0.000100950558f;
|
||||
p = p * w + 0.00134934322f;
|
||||
p = p * w + -0.00367342844f;
|
||||
p = p * w + 0.00573950773f;
|
||||
p = p * w + -0.0076224613f;
|
||||
p = p * w + 0.00943887047f;
|
||||
p = p * w + 1.00167406f;
|
||||
p = p * w + 2.83297682f;
|
||||
}
|
||||
return p * x;
|
||||
}
|
||||
|
||||
float2 Instance::antialiasing_sample_get(const int sample_index, const int sample_count)
|
||||
{
|
||||
if (sample_count < 2) {
|
||||
return float2(0.0f);
|
||||
}
|
||||
|
||||
double halton[2];
|
||||
{
|
||||
uint primes[2] = {2, 3};
|
||||
double ofs[2] = {0, 0};
|
||||
BLI_halton_2d(primes, ofs, sample_index, halton);
|
||||
}
|
||||
/* Uniform distribution [0..1]. */
|
||||
const float2 rand = float2(halton[0], halton[1]);
|
||||
/* Uniform distribution [-1..1]. */
|
||||
const float2 rand_remap = rand * 2.0f - 1.0f;
|
||||
/* Limit sampling region to avoid outliers. */
|
||||
const float2 rand_adjusted = rand_remap * 0.93f;
|
||||
/* Gaussian distribution [-1..1]. */
|
||||
const float2 offset = float2(erfinv_approx(rand_adjusted.x), erfinv_approx(rand_adjusted.y));
|
||||
/* Gaussian fitted to Blackman-Harris (follows EEVEE). */
|
||||
const float sigma = 0.284f;
|
||||
/* NOTE(fclem): Not sure where this sqrt comes from but is needed to match EEVEE. */
|
||||
return offset * sqrt(sigma);
|
||||
}
|
||||
|
||||
void Instance::antialiasing_accumulate(Manager &manager, const float alpha)
|
||||
{
|
||||
BLI_assert_msg(this->render_color_tx.gpu_texture() != nullptr,
|
||||
"This should only be called during render");
|
||||
const int2 size = this->render_color_tx.size().xy();
|
||||
|
||||
const eGPUTextureUsage usage = GPU_TEXTURE_USAGE_HOST_READ | GPU_TEXTURE_USAGE_SHADER_READ |
|
||||
GPU_TEXTURE_USAGE_SHADER_WRITE | GPU_TEXTURE_USAGE_ATTACHMENT;
|
||||
accumulation_tx.ensure_2d(GPENCIL_ACCUM_FORMAT, size, usage);
|
||||
|
||||
{
|
||||
PassSimple &pass = this->accumulate_ps;
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_DEPTH /* There is no depth, but avoid blank state. */);
|
||||
pass.shader_set(ShaderCache::get().accumulation.get());
|
||||
pass.bind_image("src_img", &this->render_color_tx);
|
||||
pass.bind_image("dst_img", &this->accumulation_tx);
|
||||
pass.push_constant("weight_src", alpha);
|
||||
pass.push_constant("weight_dst", 1.0f - alpha);
|
||||
pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
}
|
||||
|
||||
accumulation_fb.ensure(size);
|
||||
GPU_framebuffer_bind(this->accumulation_fb);
|
||||
manager.submit(this->accumulate_ps);
|
||||
}
|
||||
|
||||
} // namespace blender::draw::gpencil
|
||||
|
||||
@@ -21,3 +21,6 @@
|
||||
#define GPENCIL_LIGHT_SLOT 3
|
||||
/* UBOs */
|
||||
#define GPENCIL_SCENE_SLOT 2
|
||||
|
||||
#define GPENCIL_RENDER_FORMAT GPU_RGBA16F
|
||||
#define GPENCIL_ACCUM_FORMAT GPU_RGBA16F
|
||||
|
||||
@@ -124,6 +124,7 @@ struct Instance final : public DrawEngine {
|
||||
PassSimple smaa_edge_ps = {"smaa_edge"};
|
||||
PassSimple smaa_weight_ps = {"smaa_weight"};
|
||||
PassSimple smaa_resolve_ps = {"smaa_resolve"};
|
||||
PassSimple accumulate_ps = {"aa_accumulate"};
|
||||
/* Composite the object depth to the default depth buffer to occlude overlays. */
|
||||
PassSimple merge_depth_ps = {"merge_depth_ps"};
|
||||
/* Invert mask buffer content. */
|
||||
@@ -206,6 +207,9 @@ struct Instance final : public DrawEngine {
|
||||
/* Pointer to dtxl->depth */
|
||||
GPUTexture *scene_depth_tx;
|
||||
GPUFrameBuffer *scene_fb;
|
||||
/* Used for render accumulation antialiasing. */
|
||||
Texture accumulation_tx = {"gp_accumulation_tx"};
|
||||
Framebuffer accumulation_fb = {"gp_accumulation_fb"};
|
||||
/* Copy of txl->dummy_tx */
|
||||
GPUTexture *dummy_tx;
|
||||
/* Copy of v3d->shading.single_color. */
|
||||
@@ -314,6 +318,10 @@ struct Instance final : public DrawEngine {
|
||||
|
||||
void draw(Manager &manager) final;
|
||||
|
||||
void antialiasing_accumulate(Manager &manager, float alpha);
|
||||
|
||||
static float2 antialiasing_sample_get(int sample_index, int sample_count);
|
||||
|
||||
private:
|
||||
tObject *object_sync_do(Object *ob, ResourceHandle res_handle);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_rect.h"
|
||||
|
||||
@@ -23,26 +24,52 @@
|
||||
|
||||
namespace blender::draw::gpencil {
|
||||
|
||||
static void render_init(const DRWContext *draw_ctx,
|
||||
Instance &inst,
|
||||
RenderEngine *engine,
|
||||
RenderLayer *render_layer,
|
||||
const Depsgraph *depsgraph,
|
||||
const rcti *rect)
|
||||
/* Remap depth from viewspace to [0..1] to be able to use it with as GPU depth buffer. */
|
||||
static void remap_depth(const View &view, MutableSpan<float> pix_z)
|
||||
{
|
||||
if (view.is_persp()) {
|
||||
const float4x4 &winmat = view.winmat();
|
||||
for (auto &pix : pix_z) {
|
||||
pix = (-winmat[3][2] / -pix) - winmat[2][2];
|
||||
pix = clamp_f(pix * 0.5f + 0.5f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Keep in mind, near and far distance are negatives. */
|
||||
const float near = view.near_clip();
|
||||
const float far = view.far_clip();
|
||||
const float range_inv = 1.0f / fabsf(far - near);
|
||||
for (auto &pix : pix_z) {
|
||||
pix = (pix + near) * range_inv;
|
||||
pix = clamp_f(pix, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void render_set_view(RenderEngine *engine,
|
||||
const Depsgraph *depsgraph,
|
||||
float2 aa_offset = float2{0.0f})
|
||||
{
|
||||
Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
|
||||
|
||||
float4x4 winmat, viewinv;
|
||||
RE_GetCameraWindow(engine->re, camera, winmat.ptr());
|
||||
RE_GetCameraModelMatrix(engine->re, camera, viewinv.ptr());
|
||||
|
||||
window_translate_m4(winmat.ptr(), winmat.ptr(), UNPACK2(aa_offset));
|
||||
|
||||
View::default_set(math::invert(viewinv), winmat);
|
||||
}
|
||||
|
||||
static void render_init_buffers(const DRWContext *draw_ctx,
|
||||
Instance &inst,
|
||||
RenderEngine *engine,
|
||||
RenderLayer *render_layer,
|
||||
const Depsgraph *depsgraph,
|
||||
const rcti *rect)
|
||||
{
|
||||
Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
||||
const int2 size = int2(draw_ctx->viewport_size_get());
|
||||
|
||||
/* Set the perspective & view matrix. */
|
||||
float winmat[4][4], viewmat[4][4], viewinv[4][4];
|
||||
|
||||
Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
|
||||
RE_GetCameraWindow(engine->re, camera, winmat);
|
||||
RE_GetCameraModelMatrix(engine->re, camera, viewinv);
|
||||
|
||||
invert_m4_m4(viewmat, viewinv);
|
||||
|
||||
View::default_set(float4x4(viewmat), float4x4(winmat));
|
||||
View &view = View::default_get();
|
||||
|
||||
/* Create depth texture & color texture from render result. */
|
||||
@@ -61,25 +88,7 @@ static void render_init(const DRWContext *draw_ctx,
|
||||
if (pix_z) {
|
||||
/* Depth need to be remapped to [0..1] range. */
|
||||
pix_z = static_cast<float *>(MEM_dupallocN(pix_z));
|
||||
|
||||
int pix_num = rpass_z_src->rectx * rpass_z_src->recty;
|
||||
|
||||
if (view.is_persp()) {
|
||||
for (int i = 0; i < pix_num; i++) {
|
||||
pix_z[i] = (-winmat[3][2] / -pix_z[i]) - winmat[2][2];
|
||||
pix_z[i] = clamp_f(pix_z[i] * 0.5f + 0.5f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Keep in mind, near and far distance are negatives. */
|
||||
float near = view.near_clip();
|
||||
float far = view.far_clip();
|
||||
float range_inv = 1.0f / fabsf(far - near);
|
||||
for (int i = 0; i < pix_num; i++) {
|
||||
pix_z[i] = (pix_z[i] + near) * range_inv;
|
||||
pix_z[i] = clamp_f(pix_z[i], 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
remap_depth(view, {pix_z, rpass_z_src->rectx * rpass_z_src->recty});
|
||||
}
|
||||
|
||||
const bool do_region = (scene->r.mode & R_BORDER) != 0;
|
||||
@@ -203,8 +212,10 @@ static void render_result_combined(RenderLayer *rl,
|
||||
{
|
||||
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
|
||||
|
||||
GPU_framebuffer_bind(instance.render_fb);
|
||||
GPU_framebuffer_read_color(instance.render_fb,
|
||||
Framebuffer read_fb;
|
||||
read_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(instance.accumulation_tx));
|
||||
GPU_framebuffer_bind(read_fb);
|
||||
GPU_framebuffer_read_color(read_fb,
|
||||
rect->xmin,
|
||||
rect->ymin,
|
||||
BLI_rcti_size_x(rect),
|
||||
@@ -226,7 +237,8 @@ void Engine::render_to_image(RenderEngine *engine, RenderLayer *render_layer, co
|
||||
|
||||
Manager &manager = *DRW_manager_get();
|
||||
|
||||
render_init(draw_ctx, inst, engine, render_layer, depsgraph, &rect);
|
||||
render_set_view(engine, depsgraph);
|
||||
render_init_buffers(draw_ctx, inst, engine, render_layer, depsgraph, &rect);
|
||||
inst.init();
|
||||
|
||||
inst.camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
|
||||
@@ -248,8 +260,24 @@ void Engine::render_to_image(RenderEngine *engine, RenderLayer *render_layer, co
|
||||
|
||||
manager.end_sync();
|
||||
|
||||
/* Render the gpencil object and merge the result to the underlying render. */
|
||||
inst.draw(manager);
|
||||
const float aa_radius = clamp_f(draw_ctx->scene->r.gauss, 0.0f, 100.0f);
|
||||
const int sample_count = draw_ctx->scene->grease_pencil_settings.aa_samples;
|
||||
for (auto i : IndexRange(sample_count)) {
|
||||
float2 aa_offset = Instance::antialiasing_sample_get(i, sample_count) * aa_radius;
|
||||
aa_offset = 2.0f * aa_offset / float2(inst.render_color_tx.size());
|
||||
render_set_view(engine, depsgraph, aa_offset);
|
||||
render_init_buffers(draw_ctx, inst, engine, render_layer, depsgraph, &rect);
|
||||
|
||||
/* Render the gpencil object and merge the result to the underlying render. */
|
||||
inst.draw(manager);
|
||||
|
||||
/* Weight of this render SSAA sample. The sum of previous samples is weighted by `1 - weight`.
|
||||
* This diminishes after each new sample as we want all samples to be equally weighted inside
|
||||
* the final result (inside the combined buffer). This weighting scheme allows to always store
|
||||
* the resolved result making it ready for in-progress display or readback. */
|
||||
const float weight = 1.0f / (1.0f + i);
|
||||
inst.antialiasing_accumulate(manager, weight);
|
||||
}
|
||||
|
||||
render_result_combined(render_layer, viewname, inst, &rect);
|
||||
render_result_z(draw_ctx, render_layer, viewname, inst, &rect);
|
||||
|
||||
@@ -36,6 +36,8 @@ class ShaderCache {
|
||||
StaticShader antialiasing[3] = {{"gpencil_antialiasing_stage_0"},
|
||||
{"gpencil_antialiasing_stage_1"},
|
||||
{"gpencil_antialiasing_stage_2"}};
|
||||
/* Accumulation antialiasing */
|
||||
StaticShader accumulation = {"gpencil_antialiasing_accumulation"};
|
||||
/* GPencil Object rendering */
|
||||
StaticShader geometry = {"gpencil_geometry"};
|
||||
/* All layer blend types in one shader! */
|
||||
|
||||
@@ -26,6 +26,7 @@ set(SRC_GLSL_VERT
|
||||
)
|
||||
|
||||
set(SRC_GLSL_FRAG
|
||||
gpencil_antialiasing_accumulation_frag.glsl
|
||||
gpencil_antialiasing_frag.glsl
|
||||
gpencil_depth_merge_frag.glsl
|
||||
gpencil_frag.glsl
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2020-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpencil_info.hh"
|
||||
|
||||
FRAGMENT_SHADER_CREATE_INFO(gpencil_antialiasing_accumulation)
|
||||
|
||||
vec4 colorspace_scene_to_perceptual(vec4 color)
|
||||
{
|
||||
return vec4(log2(color.rgb + 0.5), color.a);
|
||||
}
|
||||
|
||||
vec4 colorspace_perceptual_to_scene(vec4 color)
|
||||
{
|
||||
return vec4(exp2(color.rgb) - 0.5, color.a);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
vec4 data_src = colorspace_scene_to_perceptual(max(vec4(0.0), imageLoadFast(src_img, texel)));
|
||||
vec4 data_dst = colorspace_scene_to_perceptual(max(vec4(0.0), imageLoadFast(dst_img, texel)));
|
||||
vec4 result = data_src * weight_src;
|
||||
if (weight_dst > 0.0) {
|
||||
/* Avoid uncleared data to mess with the result value. */
|
||||
result += data_dst * weight_dst;
|
||||
}
|
||||
if (data_src.a == 1.0 && data_dst.a == 1.0) {
|
||||
/* Avoid float imprecision leading to non fully opaque renders. */
|
||||
result.a = 1.0;
|
||||
}
|
||||
imageStoreFast(dst_img, texel, colorspace_perceptual_to_scene(result));
|
||||
}
|
||||
@@ -181,4 +181,14 @@ ADDITIONAL_INFO(gpencil_antialiasing)
|
||||
DO_STATIC_COMPILATION()
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpencil_antialiasing_accumulation)
|
||||
IMAGE(0, GPENCIL_RENDER_FORMAT, READ, FLOAT_2D, src_img)
|
||||
IMAGE(1, GPENCIL_ACCUM_FORMAT, READ_WRITE, FLOAT_2D, dst_img)
|
||||
PUSH_CONSTANT(FLOAT, weight_src)
|
||||
PUSH_CONSTANT(FLOAT, weight_dst)
|
||||
FRAGMENT_SOURCE("gpencil_antialiasing_accumulation_frag.glsl")
|
||||
ADDITIONAL_INFO(draw_fullscreen)
|
||||
DO_STATIC_COMPILATION()
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -236,6 +236,13 @@
|
||||
.flag = SCE_EEVEE_TAA_REPROJECTION, \
|
||||
}
|
||||
|
||||
#define _DNA_DEFAULT_SceneGreasePencil \
|
||||
{ \
|
||||
.smaa_threshold = 1.0f, \
|
||||
.smaa_threshold_render = 0.25f, \
|
||||
.aa_samples = 8, \
|
||||
}
|
||||
|
||||
#define _DNA_DEFAULT_SceneHydra \
|
||||
{ \
|
||||
.export_method = SCE_HYDRA_EXPORT_HYDRA, \
|
||||
@@ -254,6 +261,8 @@
|
||||
.safe_areas = _DNA_DEFAULT_DisplaySafeAreas, \
|
||||
\
|
||||
.eevee = _DNA_DEFAULT_SceneEEVEE, \
|
||||
\
|
||||
.grease_pencil_settings = _DNA_DEFAULT_SceneGreasePencil, \
|
||||
\
|
||||
.hydra = _DNA_DEFAULT_SceneHydra, \
|
||||
.simulation_frame_start = 1, \
|
||||
|
||||
@@ -1966,7 +1966,9 @@ typedef struct SceneEEVEE {
|
||||
|
||||
typedef struct SceneGpencil {
|
||||
float smaa_threshold;
|
||||
char _pad[4];
|
||||
float smaa_threshold_render;
|
||||
int aa_samples;
|
||||
char _pad0[4];
|
||||
} SceneGpencil;
|
||||
|
||||
typedef struct SceneHydra {
|
||||
|
||||
@@ -496,6 +496,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
|
||||
SDNA_DEFAULT_DECL_EX(SceneDisplay, Scene.display),
|
||||
SDNA_DEFAULT_DECL_EX(SceneEEVEE, Scene.eevee),
|
||||
SDNA_DEFAULT_DECL_EX(RaytraceEEVEE, Scene.eevee.ray_tracing_options),
|
||||
SDNA_DEFAULT_DECL_EX(SceneGpencil, Scene.grease_pencil_settings),
|
||||
|
||||
SDNA_DEFAULT_DECL(ToolSettings),
|
||||
SDNA_DEFAULT_DECL_EX(CurvePaintSettings, ToolSettings.curve_paint_settings),
|
||||
|
||||
@@ -8491,13 +8491,35 @@ static void rna_def_scene_gpencil(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "antialias_threshold", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "smaa_threshold");
|
||||
RNA_def_property_float_default(prop, 1.0f);
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 2.0f, 1, 3);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Anti-Aliasing Threshold",
|
||||
"SMAA Threshold Viewport",
|
||||
"Threshold for edge detection algorithm (higher values might over-blur "
|
||||
"some part of the image)");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "antialias_threshold_render", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "smaa_threshold_render");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 2.0f, 1, 3);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"SMAA Threshold Render",
|
||||
"Threshold for edge detection algorithm (higher values might over-blur "
|
||||
"some part of the image). Only applies to final render");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "aa_samples", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Anti-Aliasing Samples",
|
||||
"Number of supersampling anti-aliasing samples per pixel for final render");
|
||||
RNA_def_property_range(prop, 1, INT_MAX);
|
||||
RNA_def_property_ui_range(prop, 1, 256, 1, 3);
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);
|
||||
RNA_def_property_flag(prop, PROP_ANIMATABLE);
|
||||
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user