summaryrefslogtreecommitdiff
path: root/servers/rendering/rasterizer_rd
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/rasterizer_rd')
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp39
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h8
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl110
3 files changed, 144 insertions, 13 deletions
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
index 35b0591289..3fff593598 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
@@ -51,6 +51,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {
int blend_mode = BLEND_MODE_MIX;
int depth_testi = DEPTH_TEST_ENABLED;
+ int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
int cull = CULL_BACK;
uses_point_size = false;
@@ -82,6 +83,9 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {
actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
+ actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
+ actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
+
actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
@@ -154,6 +158,11 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {
//blend modes
+ // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
+ if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
+ blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
+ }
+
RD::PipelineColorBlendState::Attachment blend_attachment;
switch (blend_mode) {
@@ -199,6 +208,15 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
uses_blend_alpha = true; //force alpha used because of blend
} break;
+ case BLEND_MODE_ALPHA_TO_COVERAGE: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+ }
}
RD::PipelineColorBlendState blend_state_blend;
@@ -245,8 +263,17 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {
RD::PipelineColorBlendState blend_state;
RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
+ RD::PipelineMultisampleState multisample_state;
if (uses_alpha || uses_blend_alpha) {
+ // only allow these flags to go through if we have some form of msaa
+ if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
+ multisample_state.enable_alpha_to_coverage = true;
+ } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
+ multisample_state.enable_alpha_to_coverage = true;
+ multisample_state.enable_alpha_to_one = true;
+ }
+
if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
blend_state = blend_state_blend;
if (depth_draw == DEPTH_DRAW_OPAQUE) {
@@ -286,7 +313,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {
}
RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k);
- pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, RD::PipelineMultisampleState(), depth_stencil, blend_state, 0);
+ pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);
}
}
}
@@ -2725,6 +2752,11 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
actions.renames["POINT_SIZE"] = "gl_PointSize";
actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
+ actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
+ actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
+ actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge";
+ actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate";
+
//builtins
actions.renames["TIME"] = "scene_data.time";
@@ -2793,6 +2825,11 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
+ actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n";
+ actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n";
+ actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n";
+ actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE";
+
actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
index 566022ae5b..db083a75cc 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
@@ -83,6 +83,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
+ BLEND_MODE_ALPHA_TO_COVERAGE
};
enum DepthDraw {
@@ -110,6 +111,12 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
};
+ enum AlphaAntiAliasing {
+ ALPHA_ANTIALIASING_OFF,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
+ };
+
bool valid;
RID version;
uint32_t vertex_input_mask;
@@ -132,6 +139,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
bool uses_point_size;
bool uses_alpha;
bool uses_blend_alpha;
+ bool uses_alpha_clip;
bool uses_depth_pre_pass;
bool uses_discard;
bool uses_roughness;
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
index 455a3d4a3a..da3c60af04 100644
--- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
@@ -361,6 +361,65 @@ layout(location = 0) out vec4 frag_color;
#endif // RENDER DEPTH
+#ifdef ALPHA_HASH_USED
+
+float hash_2d(vec2 p) {
+ return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) *
+ (0.1 + abs(sin(13.0 * p.y + p.x))));
+}
+
+float hash_3d(vec3 p) {
+ return hash_2d(vec2(hash_2d(p.xy), p.z));
+}
+
+float compute_alpha_hash_threshold(vec3 pos, float hash_scale) {
+ vec3 dx = dFdx(pos);
+ vec3 dy = dFdx(pos);
+ float delta_max_sqr = max(length(dx), length(dy));
+ float pix_scale = 1.0 / (hash_scale * delta_max_sqr);
+
+ vec2 pix_scales =
+ vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale))));
+
+ vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)),
+ hash_3d(floor(pix_scales.y * pos.xyz)));
+
+ float lerp_factor = fract(log2(pix_scale));
+
+ float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y;
+
+ float min_lerp = min(lerp_factor, 1.0 - lerp_factor);
+
+ vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)),
+ (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp),
+ 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) /
+ (2.0 * min_lerp * (1.0 - min_lerp))));
+
+ float alpha_hash_threshold =
+ (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z;
+
+ return clamp(alpha_hash_threshold, 0.0, 1.0);
+}
+
+#endif // ALPHA_HASH_USED
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+
+float calc_mip_level(vec2 texture_coord) {
+ vec2 dx = dFdx(texture_coord);
+ vec2 dy = dFdy(texture_coord);
+ float delta_max_sqr = max(dot(dx, dx), dot(dy, dy));
+ return max(0.0, 0.5 * log2(delta_max_sqr));
+}
+
+float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) {
+ input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number
+ input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5;
+ return clamp(input_alpha, 0.0, 1.0);
+}
+
+#endif // ALPHA_ANTIALIASING_USED
+
// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V.
// We're dividing this factor off because the overall term we'll end up looks like
// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012):
@@ -1709,10 +1768,6 @@ void main() {
float alpha = 1.0;
-#if defined(ALPHA_SCISSOR_USED)
- float alpha_scissor = 0.5;
-#endif
-
#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
vec3 binormal = normalize(binormal_interp);
vec3 tangent = normalize(tangent_interp);
@@ -1749,6 +1804,19 @@ void main() {
float sss_strength = 0.0;
+#ifdef ALPHA_SCISSOR_USED
+ float alpha_scissor_threshold = 1.0;
+#endif // ALPHA_SCISSOR_USED
+
+#ifdef ALPHA_HASH_USED
+ float alpha_hash_scale = 1.0;
+#endif // ALPHA_HASH_USED
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+ float alpha_antialiasing_edge = 0.0;
+ vec2 alpha_texture_coordinate = vec2(0.0, 0.0);
+#endif // ALPHA_ANTIALIASING_EDGE_USED
+
{
/* clang-format off */
@@ -1757,7 +1825,7 @@ FRAGMENT_SHADER_CODE
/* clang-format on */
}
-#if defined(LIGHT_TRANSMITTANCE_USED)
+#ifdef LIGHT_TRANSMITTANCE_USED
#ifdef SSS_MODE_SKIN
transmittance_color.a = sss_strength;
#else
@@ -1765,25 +1833,43 @@ FRAGMENT_SHADER_CODE
#endif
#endif
-#if !defined(USE_SHADOW_TO_OPACITY)
+#ifndef USE_SHADOW_TO_OPACITY
-#if defined(ALPHA_SCISSOR_USED)
- if (alpha < alpha_scissor) {
+#ifdef ALPHA_SCISSOR_USED
+ if (alpha < alpha_scissor_threshold) {
discard;
}
#endif // ALPHA_SCISSOR_USED
-#ifdef USE_OPAQUE_PREPASS
+// alpha hash can be used in unison with alpha antialiasing
+#ifdef ALPHA_HASH_USED
+ if (alpha < compute_alpha_hash_threshold(vertex, alpha_hash_scale)) {
+ discard;
+ }
+#endif // ALPHA_HASH_USED
+
+// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash
+#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED)
+ alpha = 1.0;
+#endif
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather
+#ifdef ALPHA_SCISSOR_USED
+ alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0);
+#endif
+ alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge);
+#endif // ALPHA_ANTIALIASING_EDGE_USED
+#ifdef USE_OPAQUE_PREPASS
if (alpha < opaque_prepass_threshold) {
discard;
}
-
#endif // USE_OPAQUE_PREPASS
#endif // !USE_SHADOW_TO_OPACITY
-#if defined(NORMALMAP_USED)
+#ifdef NORMALMAP_USED
normalmap.xy = normalmap.xy * 2.0 - 1.0;
normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc.
@@ -1792,7 +1878,7 @@ FRAGMENT_SHADER_CODE
#endif
-#if defined(LIGHT_ANISOTROPY_USED)
+#ifdef LIGHT_ANISOTROPY_USED
if (anisotropy > 0.01) {
//rotation matrix