Implement glow/bloom on compatibility renderer

This commit is contained in:
Bastiaan Olij 2024-01-19 16:14:36 +11:00
parent ab4c5a594a
commit aa260e5f3d
23 changed files with 1313 additions and 221 deletions

View File

@ -155,12 +155,14 @@ void CopyEffects::copy_to_and_from_rect(const Rect2 &p_rect) {
draw_screen_quad();
}
void CopyEffects::copy_screen() {
bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT);
void CopyEffects::copy_screen(float p_multiply) {
bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SCREEN);
if (!success) {
return;
}
copy.shader.version_set_uniform(CopyShaderGLES3::MULTIPLY, p_multiply, copy.shader_version, CopyShaderGLES3::MODE_SCREEN);
draw_screen_triangle();
}

View File

@ -33,7 +33,7 @@
#ifdef GLES3_ENABLED
#include "drivers/gles3/shaders/copy.glsl.gen.h"
#include "drivers/gles3/shaders/effects/copy.glsl.gen.h"
namespace GLES3 {
@ -64,7 +64,7 @@ public:
void copy_to_rect(const Rect2 &p_rect);
void copy_to_rect_3d(const Rect2 &p_rect, float p_layer, int p_type, float p_lod = 0.0f);
void copy_to_and_from_rect(const Rect2 &p_rect);
void copy_screen();
void copy_screen(float p_multiply = 1.0);
void copy_cube_to_rect(const Rect2 &p_rect);
void copy_cube_to_panorama(float p_mip_level);
void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);

View File

@ -0,0 +1,172 @@
/**************************************************************************/
/* glow.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifdef GLES3_ENABLED
#include "glow.h"
using namespace GLES3;
Glow *Glow::singleton = nullptr;
Glow *Glow::get_singleton() {
return singleton;
}
Glow::Glow() {
singleton = this;
glow.shader.initialize();
glow.shader_version = glow.shader.version_create();
{ // Screen Triangle.
glGenBuffers(1, &screen_triangle);
glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
const float qv[6] = {
-1.0f,
-1.0f,
3.0f,
-1.0f,
-1.0f,
3.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
glGenVertexArrays(1, &screen_triangle_array);
glBindVertexArray(screen_triangle_array);
glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
}
}
Glow::~Glow() {
glDeleteBuffers(1, &screen_triangle);
glDeleteVertexArrays(1, &screen_triangle_array);
glow.shader.version_free(glow.shader_version);
singleton = nullptr;
}
void Glow::_draw_screen_triangle() {
glBindVertexArray(screen_triangle_array);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
}
void Glow::process_glow(GLuint p_source_color, Size2i p_size, const Glow::GLOWLEVEL *p_glow_buffers, uint32_t p_view, bool p_use_multiview) {
ERR_FAIL_COND(p_source_color == 0);
ERR_FAIL_COND(p_glow_buffers[3].color == 0);
// Reset some OpenGL state...
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
// Start with our filter pass
{
glBindFramebuffer(GL_FRAMEBUFFER, p_glow_buffers[0].fbo);
glViewport(0, 0, p_glow_buffers[0].size.x, p_glow_buffers[0].size.y);
glActiveTexture(GL_TEXTURE0);
glBindTexture(p_use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D, p_source_color);
uint64_t specialization = p_use_multiview ? GlowShaderGLES3::USE_MULTIVIEW : 0;
bool success = glow.shader.version_bind_shader(glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
if (!success) {
return;
}
glow.shader.version_set_uniform(GlowShaderGLES3::PIXEL_SIZE, 1.0 / p_glow_buffers[0].size.x, 1.0 / p_glow_buffers[0].size.y, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
glow.shader.version_set_uniform(GlowShaderGLES3::VIEW, float(p_view), glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
glow.shader.version_set_uniform(GlowShaderGLES3::LUMINANCE_MULTIPLIER, luminance_multiplier, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
glow.shader.version_set_uniform(GlowShaderGLES3::GLOW_BLOOM, glow_bloom, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
glow.shader.version_set_uniform(GlowShaderGLES3::GLOW_HDR_THRESHOLD, glow_hdr_bleed_threshold, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
glow.shader.version_set_uniform(GlowShaderGLES3::GLOW_HDR_SCALE, glow_hdr_bleed_scale, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
glow.shader.version_set_uniform(GlowShaderGLES3::GLOW_LUMINANCE_CAP, glow_hdr_luminance_cap, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
_draw_screen_triangle();
}
// Continue with downsampling
{
bool success = glow.shader.version_bind_shader(glow.shader_version, GlowShaderGLES3::MODE_DOWNSAMPLE, 0);
if (!success) {
return;
}
for (int i = 1; i < 4; i++) {
glBindFramebuffer(GL_FRAMEBUFFER, p_glow_buffers[i].fbo);
glViewport(0, 0, p_glow_buffers[i].size.x, p_glow_buffers[i].size.y);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, p_glow_buffers[i - 1].color);
glow.shader.version_set_uniform(GlowShaderGLES3::PIXEL_SIZE, 1.0 / p_glow_buffers[i].size.x, 1.0 / p_glow_buffers[i].size.y, glow.shader_version, GlowShaderGLES3::MODE_DOWNSAMPLE);
_draw_screen_triangle();
}
}
// Now upsample
{
bool success = glow.shader.version_bind_shader(glow.shader_version, GlowShaderGLES3::MODE_UPSAMPLE, 0);
if (!success) {
return;
}
for (int i = 2; i >= 0; i--) {
glBindFramebuffer(GL_FRAMEBUFFER, p_glow_buffers[i].fbo);
glViewport(0, 0, p_glow_buffers[i].size.x, p_glow_buffers[i].size.y);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, p_glow_buffers[i + 1].color);
glow.shader.version_set_uniform(GlowShaderGLES3::PIXEL_SIZE, 1.0 / p_glow_buffers[i].size.x, 1.0 / p_glow_buffers[i].size.y, glow.shader_version, GlowShaderGLES3::MODE_UPSAMPLE);
_draw_screen_triangle();
}
}
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
#endif // GLES3_ENABLED

View File

@ -0,0 +1,89 @@
/**************************************************************************/
/* glow.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GLOW_GLES3_H
#define GLOW_GLES3_H
#ifdef GLES3_ENABLED
#include "drivers/gles3/shaders/effects/glow.glsl.gen.h"
namespace GLES3 {
class Glow {
private:
static Glow *singleton;
struct GLOW {
GlowShaderGLES3 shader;
RID shader_version;
} glow;
float luminance_multiplier = 1.0;
float glow_intensity = 1.0;
float glow_bloom = 0.0;
float glow_hdr_bleed_threshold = 1.0;
float glow_hdr_bleed_scale = 2.0;
float glow_hdr_luminance_cap = 12.0;
// Use for full-screen effects. Slightly more efficient than screen_quad as this eliminates pixel overdraw along the diagonal.
GLuint screen_triangle = 0;
GLuint screen_triangle_array = 0;
void _draw_screen_triangle();
public:
struct GLOWLEVEL {
Size2i size;
GLuint color = 0;
GLuint fbo = 0;
};
static Glow *get_singleton();
Glow();
~Glow();
void set_intensity(float p_value) { glow_intensity = p_value; }
void set_luminance_multiplier(float p_luminance_multiplier) { luminance_multiplier = p_luminance_multiplier; }
void set_glow_bloom(float p_bloom) { glow_bloom = p_bloom; }
void set_glow_hdr_bleed_threshold(float p_threshold) { glow_hdr_bleed_threshold = p_threshold; }
void set_glow_hdr_bleed_scale(float p_scale) { glow_hdr_bleed_scale = p_scale; }
void set_glow_hdr_luminance_cap(float p_cap) { glow_hdr_luminance_cap = p_cap; }
void process_glow(GLuint p_source_color, Size2i p_size, const GLOWLEVEL *p_glow_buffers, uint32_t p_view = 0, bool p_use_multiview = false);
};
} //namespace GLES3
#endif // GLES3_ENABLED
#endif // GLOW_GLES3_H

View File

@ -0,0 +1,152 @@
/**************************************************************************/
/* post_effects.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifdef GLES3_ENABLED
#include "post_effects.h"
using namespace GLES3;
PostEffects *PostEffects::singleton = nullptr;
PostEffects *PostEffects::get_singleton() {
return singleton;
}
PostEffects::PostEffects() {
singleton = this;
post.shader.initialize();
post.shader_version = post.shader.version_create();
post.shader.version_bind_shader(post.shader_version, PostShaderGLES3::MODE_DEFAULT);
{ // Screen Triangle.
glGenBuffers(1, &screen_triangle);
glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
const float qv[6] = {
-1.0f,
-1.0f,
3.0f,
-1.0f,
-1.0f,
3.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
glGenVertexArrays(1, &screen_triangle_array);
glBindVertexArray(screen_triangle_array);
glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
}
}
PostEffects::~PostEffects() {
singleton = nullptr;
glDeleteBuffers(1, &screen_triangle);
glDeleteVertexArrays(1, &screen_triangle_array);
post.shader.version_free(post.shader_version);
}
void PostEffects::_draw_screen_triangle() {
glBindVertexArray(screen_triangle_array);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
}
void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view, bool p_use_multiview) {
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_BLEND);
glBindFramebuffer(GL_FRAMEBUFFER, p_dest_framebuffer);
glViewport(0, 0, p_dest_size.x, p_dest_size.y);
PostShaderGLES3::ShaderVariant mode = PostShaderGLES3::MODE_DEFAULT;
uint64_t flags = 0;
if (p_use_multiview) {
flags |= PostShaderGLES3::USE_MULTIVIEW;
}
if (p_glow_buffers != nullptr) {
flags |= PostShaderGLES3::USE_GLOW;
}
if (p_luminance_multiplier != 1.0) {
flags |= PostShaderGLES3::USE_LUMINANCE_MULTIPLIER;
}
bool success = post.shader.version_bind_shader(post.shader_version, mode, flags);
if (!success) {
return;
}
GLenum texture_target = p_use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture_target, p_source_color);
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (p_glow_buffers != nullptr) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, p_glow_buffers[0].color);
post.shader.version_set_uniform(PostShaderGLES3::PIXEL_SIZE, 1.0 / p_source_size.x, 1.0 / p_source_size.y, post.shader_version, mode, flags);
post.shader.version_set_uniform(PostShaderGLES3::GLOW_INTENSITY, p_glow_intensity, post.shader_version, mode, flags);
}
post.shader.version_set_uniform(PostShaderGLES3::VIEW, float(p_view), post.shader_version, mode, flags);
post.shader.version_set_uniform(PostShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, post.shader_version, mode, flags);
_draw_screen_triangle();
// Reset state
if (p_glow_buffers != nullptr) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
}
// Return back to nearest
glActiveTexture(GL_TEXTURE0);
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(texture_target, 0);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
#endif // GLES3_ENABLED

View File

@ -0,0 +1,69 @@
/**************************************************************************/
/* post_effects.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef POST_EFFECTS_GLES3_H
#define POST_EFFECTS_GLES3_H
#ifdef GLES3_ENABLED
#include "drivers/gles3/shaders/effects/post.glsl.gen.h"
#include "glow.h"
namespace GLES3 {
class PostEffects {
private:
struct Post {
PostShaderGLES3 shader;
RID shader_version;
} post;
static PostEffects *singleton;
// Use for full-screen effects. Slightly more efficient than screen_quad as this eliminates pixel overdraw along the diagonal.
GLuint screen_triangle = 0;
GLuint screen_triangle_array = 0;
void _draw_screen_triangle();
public:
static PostEffects *get_singleton();
PostEffects();
~PostEffects();
void post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view = 0, bool p_use_multiview = false);
};
} //namespace GLES3
#endif // GLES3_ENABLED
#endif // POST_EFFECTS_GLES3_H

View File

@ -201,6 +201,8 @@ void RasterizerGLES3::finalize() {
memdelete(canvas);
memdelete(gi);
memdelete(fog);
memdelete(post_effects);
memdelete(glow);
memdelete(copy_effects);
memdelete(light_storage);
memdelete(particles_storage);
@ -347,6 +349,8 @@ RasterizerGLES3::RasterizerGLES3() {
particles_storage = memnew(GLES3::ParticlesStorage);
light_storage = memnew(GLES3::LightStorage);
copy_effects = memnew(GLES3::CopyEffects);
glow = memnew(GLES3::Glow);
post_effects = memnew(GLES3::PostEffects);
gi = memnew(GLES3::GI);
fog = memnew(GLES3::Fog);
canvas = memnew(RasterizerCanvasGLES3());

View File

@ -34,6 +34,8 @@
#ifdef GLES3_ENABLED
#include "effects/copy_effects.h"
#include "effects/glow.h"
#include "effects/post_effects.h"
#include "environment/fog.h"
#include "environment/gi.h"
#include "rasterizer_canvas_gles3.h"
@ -67,6 +69,8 @@ protected:
GLES3::GI *gi = nullptr;
GLES3::Fog *fog = nullptr;
GLES3::CopyEffects *copy_effects = nullptr;
GLES3::Glow *glow = nullptr;
GLES3::PostEffects *post_effects = nullptr;
RasterizerCanvasGLES3 *canvas = nullptr;
RasterizerSceneGLES3 *scene = nullptr;
static RasterizerGLES3 *singleton;

View File

@ -764,7 +764,7 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
}
}
void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier, bool p_use_multiview, bool p_flip_y) {
void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_sky_energy_multiplier, float p_luminance_multiplier, bool p_use_multiview, bool p_flip_y, bool p_apply_color_adjustments_in_post) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
@ -778,6 +778,10 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
if (p_flip_y) {
spec_constants |= SkyShaderGLES3::USE_INVERTED_Y;
}
if (!p_apply_color_adjustments_in_post) {
spec_constants |= SkyShaderGLES3::APPLY_TONEMAPPING;
// TODO add BCS and color corrections once supported.
}
RS::EnvironmentBG background = environment_get_background(p_env);
@ -832,6 +836,7 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.columns[2][0], camera.columns[0][0], camera.columns[2][1], camera.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::SKY_ENERGY_MULTIPLIER, p_sky_energy_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
if (p_use_multiview) {
@ -843,7 +848,7 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
glDrawArrays(GL_TRIANGLES, 0, 3);
}
void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier) {
void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_sky_energy_multiplier) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
@ -939,20 +944,17 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, cm.columns[2][0], cm.columns[0][0], cm.columns[2][1], cm.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::SKY_ENERGY_MULTIPLIER, p_sky_energy_multiplier, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, 1.0, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
glBindVertexArray(sky_globals.screen_triangle_array);
glViewport(0, 0, sky->radiance_size, sky->radiance_size);
glBindFramebuffer(GL_FRAMEBUFFER, sky->radiance_framebuffer);
glDisable(GL_BLEND);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_DISABLED;
glDisable(GL_SCISSOR_TEST);
glDisable(GL_CULL_FACE);
scene_state.cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
scene_state.reset_gl_state();
scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_DISABLED);
scene_state.enable_gl_blend(false);
for (int i = 0; i < 6; i++) {
Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
@ -969,17 +971,13 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
_filter_sky_radiance(sky, 0); //Just copy over the first mipmap
}
sky->processing_layer = 1;
sky->baked_exposure = p_luminance_multiplier;
sky->baked_exposure = p_sky_energy_multiplier;
sky->reflection_dirty = false;
} else {
if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
glDisable(GL_BLEND);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_DISABLED;
glDisable(GL_SCISSOR_TEST);
glDisable(GL_CULL_FACE);
scene_state.cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
scene_state.reset_gl_state();
scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_DISABLED);
scene_state.enable_gl_blend(false);
_filter_sky_radiance(sky, sky->processing_layer);
sky->processing_layer++;
@ -1584,6 +1582,8 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
scene_state.ubo.luminance_multiplier = p_render_data->luminance_multiplier;
scene_state.ubo.shadow_bias = p_shadow_bias;
scene_state.ubo.pancake_shadows = p_pancake_shadows;
@ -2271,14 +2271,10 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
scene_state.reset_gl_state();
scene_state.enable_gl_depth_test(true);
scene_state.enable_gl_depth_draw(true);
glDepthFunc(GL_LESS);
glDisable(GL_SCISSOR_TEST);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
glColorMask(0, 0, 0, 0);
glDrawBuffers(0, nullptr);
@ -2303,8 +2299,8 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
_render_list_template<PASS_MODE_SHADOW>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_SECONDARY].elements.size());
glColorMask(1, 1, 1, 1);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
scene_state.enable_gl_depth_test(false);
scene_state.enable_gl_depth_draw(true);
glDisable(GL_CULL_FACE);
scene_state.cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -2315,15 +2311,32 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
GLES3::Config *config = GLES3::Config::get_singleton();
RENDER_TIMESTAMP("Setup 3D Scene");
bool apply_color_adjustments_in_post = false;
Ref<RenderSceneBuffersGLES3> rb;
if (p_render_buffers.is_valid()) {
rb = p_render_buffers;
ERR_FAIL_COND(rb.is_null());
if (rb->get_scaling_3d_mode() != RS::VIEWPORT_SCALING_3D_MODE_OFF) {
// If we're scaling, we apply tonemapping etc. in post, so disable it during rendering
apply_color_adjustments_in_post = true;
}
}
GLES3::RenderTarget *rt = texture_storage->get_render_target(rb->render_target);
ERR_FAIL_NULL(rt);
bool glow_enabled = false;
if (p_environment.is_valid() && rb.is_valid()) {
glow_enabled = environment_get_glow_enabled(p_environment);
rb->set_glow_enabled(glow_enabled); // ensure our intermediate buffer is available if glow is enabled
if (glow_enabled) {
// If glow is enabled, we apply tonemapping etc. in post, so disable it during rendering
apply_color_adjustments_in_post = true;
}
}
// Assign render data
// Use the format from rendererRD
RenderDataGLES3 render_data;
@ -2359,6 +2372,13 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
// this should be the same for all cameras..
render_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier();
if (rt->color_type == GL_UNSIGNED_INT_2_10_10_10_REV && glow_enabled) {
// As our output is in sRGB and we're using 10bit color space, we can fake a little HDR to do glow...
render_data.luminance_multiplier = 0.25;
} else {
render_data.luminance_multiplier = 1.0;
}
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
render_data.screen_mesh_lod_threshold = 0.0;
} else {
@ -2519,9 +2539,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, rb->internal_size.x, rb->internal_size.y);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
scene_state.reset_gl_state();
// Do depth prepass if it's explicitly enabled
bool use_depth_prepass = config->use_depth_prepass;
@ -2533,11 +2551,11 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
RENDER_TIMESTAMP("Depth Prepass");
//pre z pass
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
scene_state.enable_gl_depth_test(true);
scene_state.enable_gl_depth_draw(true);
scene_state.enable_gl_blend(false);
glDepthFunc(GL_LEQUAL);
glDisable(GL_SCISSOR_TEST);
scene_state.enable_gl_scissor_test(false);
glColorMask(0, 0, 0, 0);
RasterizerGLES3::clear_depth(1.0);
@ -2560,21 +2578,19 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
}
glBlendEquation(GL_FUNC_ADD);
if (render_data.transparent_bg) {
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
scene_state.enable_gl_blend(true);
} else {
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
glDisable(GL_BLEND);
scene_state.enable_gl_blend(false);
}
scene_state.current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
glEnable(GL_DEPTH_TEST);
scene_state.enable_gl_scissor_test(false);
scene_state.enable_gl_depth_test(true);
scene_state.enable_gl_depth_draw(true);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS;
{
GLuint db = GL_COLOR_ATTACHMENT0;
@ -2589,7 +2605,19 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
if (!keep_color) {
clear_color.a = render_data.transparent_bg ? 0.0f : 1.0f;
glClearBufferfv(GL_COLOR, 0, clear_color.components);
} else if (fbo != rt->fbo) {
// Need to copy our current contents to our intermediate/MSAA buffer
GLES3::CopyEffects *copy_effects = GLES3::CopyEffects::get_singleton();
scene_state.enable_gl_depth_test(false);
scene_state.enable_gl_depth_draw(false);
glActiveTexture(GL_TEXTURE0);
glBindTexture(rt->view_count > 1 ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D, rt->color);
copy_effects->copy_screen(render_data.luminance_multiplier);
}
RENDER_TIMESTAMP("Render Opaque Pass");
uint64_t spec_constant_base_flags = 0;
@ -2606,26 +2634,28 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
if (render_data.environment.is_valid() && environment_get_fog_mode(render_data.environment) == RS::EnvironmentFogMode::ENV_FOG_MODE_DEPTH) {
spec_constant_base_flags |= SceneShaderGLES3::USE_DEPTH_FOG;
}
if (!apply_color_adjustments_in_post) {
spec_constant_base_flags |= SceneShaderGLES3::APPLY_TONEMAPPING;
// TODO add BCS and Color corrections here once supported.
}
}
// Render Opaque Objects.
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, spec_constant_base_flags, use_wireframe);
_render_list_template<PASS_MODE_COLOR>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
glDepthMask(GL_FALSE);
scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_DISABLED;
scene_state.enable_gl_depth_draw(false);
if (draw_sky) {
RENDER_TIMESTAMP("Render Sky");
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
scene_state.enable_gl_depth_test(true);
scene_state.enable_gl_blend(false);
scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_BACK);
_draw_sky(render_data.environment, render_data.cam_projection, render_data.cam_transform, sky_energy_multiplier, p_camera_data->view_count > 1, flip_y);
_draw_sky(render_data.environment, render_data.cam_projection, render_data.cam_transform, sky_energy_multiplier, render_data.luminance_multiplier, p_camera_data->view_count > 1, flip_y, apply_color_adjustments_in_post);
}
if (scene_state.used_screen_texture || scene_state.used_depth_texture) {
@ -2674,7 +2704,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
}
RENDER_TIMESTAMP("Render 3D Transparent Pass");
glEnable(GL_BLEND);
scene_state.enable_gl_blend(true);
//Render transparent pass
RenderListParameters render_list_params_alpha(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, spec_constant_base_flags, use_wireframe);
@ -2689,7 +2719,10 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
if (rb.is_valid()) {
_render_buffers_debug_draw(rb, p_shadow_atlas, fbo);
}
glDisable(GL_BLEND);
// Reset stuff that may trip up the next process.
scene_state.reset_gl_state();
glUseProgram(0);
_render_post_processing(&render_data);
@ -2700,6 +2733,9 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_render_data) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::Glow *glow = GLES3::Glow::get_singleton();
GLES3::PostEffects *post_effects = GLES3::PostEffects::get_singleton();
Ref<RenderSceneBuffersGLES3> rb = p_render_data->render_buffers;
ERR_FAIL_COND(rb.is_null());
@ -2714,6 +2750,26 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
GLuint fbo_int = rb->get_internal_fbo();
GLuint fbo_rt = texture_storage->render_target_get_fbo(render_target); // TODO if MSAA 2D is enabled and we're not using rt_msaa, get 2D render target here.
// Check if we have glow enabled and if so, check if our buffers were allocated
bool glow_enabled = false;
float glow_intensity = 1.0;
float glow_bloom = 0.0;
float glow_hdr_bleed_threshold = 1.0;
float glow_hdr_bleed_scale = 2.0;
float glow_hdr_luminance_cap = 12.0;
if (p_render_data->environment.is_valid()) {
glow_enabled = environment_get_glow_enabled(p_render_data->environment);
glow_intensity = environment_get_glow_intensity(p_render_data->environment);
glow_bloom = environment_get_glow_bloom(p_render_data->environment);
glow_hdr_bleed_threshold = environment_get_glow_hdr_bleed_threshold(p_render_data->environment);
glow_hdr_bleed_scale = environment_get_glow_hdr_bleed_scale(p_render_data->environment);
glow_hdr_luminance_cap = environment_get_glow_hdr_luminance_cap(p_render_data->environment);
}
if (glow_enabled) {
rb->check_glow_buffers();
}
if (view_count == 1) {
// Resolve if needed.
if (fbo_msaa_3d != 0 && msaa3d_needs_resolve) {
@ -2729,23 +2785,41 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, internal_size.x, internal_size.y, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
}
// Rendered to intermediate buffer, must copy to our render target
if (fbo_int != 0) {
// TODO If we have glow or other post processing, we upscale only depth here, post processing will also do scaling.
// Apply glow/bloom if requested? then populate our glow buffers
GLuint color = fbo_int != 0 ? rb->get_internal_color() : texture_storage->render_target_get_color(render_target);
const GLES3::Glow::GLOWLEVEL *glow_buffers = nullptr;
if (glow_enabled) {
glow_buffers = rb->get_glow_buffers();
glow->set_luminance_multiplier(p_render_data->luminance_multiplier);
glow->set_intensity(glow_intensity);
glow->set_glow_bloom(glow_bloom);
glow->set_glow_hdr_bleed_threshold(glow_hdr_bleed_threshold);
glow->set_glow_hdr_bleed_scale(glow_hdr_bleed_scale);
glow->set_glow_hdr_luminance_cap(glow_hdr_luminance_cap);
glow->process_glow(color, internal_size, glow_buffers);
}
// Copy color buffer
post_effects->post_copy(fbo_rt, target_size, color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity);
// Copy depth buffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_int);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_rt);
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
}
glBindFramebuffer(GL_FRAMEBUFFER, fbo_rt);
} else if ((fbo_msaa_3d != 0 && msaa3d_needs_resolve) || (fbo_int != 0)) {
// TODO investigate if it's smarter to cache these FBOs
GLuint fbos[2]; // read and write
glGenFramebuffers(2, fbos);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
GLuint fbos[3]; // read, write and post
glGenFramebuffers(3, fbos);
// Resolve if needed.
if (fbo_msaa_3d != 0 && msaa3d_needs_resolve) {
GLuint read_color = rb->get_msaa3d_color();
GLuint read_depth = rb->get_msaa3d_depth();
@ -2760,6 +2834,9 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
write_depth = texture_storage->render_target_get_depth(render_target);
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
for (uint32_t v = 0; v < view_count; v++) {
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, read_color, 0, v);
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, read_depth, 0, v);
@ -2769,25 +2846,53 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
}
}
// Rendered to intermediate buffer, must copy to our render target
if (fbo_int != 0) {
GLuint read_color = rb->get_internal_color();
GLuint read_depth = rb->get_internal_depth();
// Apply glow/bloom if requested? then populate our glow buffers
const GLES3::Glow::GLOWLEVEL *glow_buffers = nullptr;
GLuint source_color = fbo_int != 0 ? rb->get_internal_color() : texture_storage->render_target_get_color(render_target);
if (glow_enabled) {
glow_buffers = rb->get_glow_buffers();
glow->set_luminance_multiplier(p_render_data->luminance_multiplier);
glow->set_intensity(glow_intensity);
glow->set_glow_bloom(glow_bloom);
glow->set_glow_hdr_bleed_threshold(glow_hdr_bleed_threshold);
glow->set_glow_hdr_bleed_scale(glow_hdr_bleed_scale);
glow->set_glow_hdr_luminance_cap(glow_hdr_luminance_cap);
}
GLuint write_color = texture_storage->render_target_get_color(render_target);
GLuint write_depth = texture_storage->render_target_get_depth(render_target);
for (uint32_t v = 0; v < view_count; v++) {
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, read_color, 0, v);
if (glow_enabled) {
glow->process_glow(source_color, internal_size, glow_buffers, v, true);
}
glBindFramebuffer(GL_FRAMEBUFFER, fbos[2]);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v);
post_effects->post_copy(fbos[2], target_size, source_color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity, v, true);
}
// Copy depth
GLuint read_depth = rb->get_internal_depth();
GLuint write_depth = texture_storage->render_target_get_depth(render_target);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
for (uint32_t v = 0; v < view_count; v++) {
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, read_depth, 0, v);
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v);
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, write_depth, 0, v);
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
}
}
glBindFramebuffer(GL_FRAMEBUFFER, fbo_rt);
glDeleteFramebuffers(2, fbos);
glDeleteFramebuffers(3, fbos);
}
}
@ -2884,33 +2989,15 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
if constexpr (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
if (scene_state.current_depth_test != shader->depth_test) {
if (shader->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED) {
glDisable(GL_DEPTH_TEST);
} else {
glEnable(GL_DEPTH_TEST);
}
scene_state.current_depth_test = shader->depth_test;
}
scene_state.enable_gl_depth_test(shader->depth_test == GLES3::SceneShaderData::DEPTH_TEST_ENABLED);
}
if constexpr (p_pass_mode != PASS_MODE_SHADOW) {
if (scene_state.current_depth_draw != shader->depth_draw) {
switch (shader->depth_draw) {
case GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE: {
glDepthMask((p_pass_mode == PASS_MODE_COLOR && !GLES3::Config::get_singleton()->use_depth_prepass) ||
p_pass_mode == PASS_MODE_DEPTH);
} break;
case GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS: {
glDepthMask(GL_TRUE);
} break;
case GLES3::SceneShaderData::DEPTH_DRAW_DISABLED: {
glDepthMask(GL_FALSE);
} break;
}
if (shader->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE) {
scene_state.enable_gl_depth_draw((p_pass_mode == PASS_MODE_COLOR && !GLES3::Config::get_singleton()->use_depth_prepass) || p_pass_mode == PASS_MODE_DEPTH);
} else {
scene_state.enable_gl_depth_draw(shader->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS);
}
scene_state.current_depth_draw = shader->depth_draw;
}
bool uses_additive_lighting = (inst->light_passes.size() + p_render_data->directional_shadow_count) > 0;
@ -2937,7 +3024,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
if (uses_additive_lighting && pass == 1 && !p_render_data->transparent_bg) {
// Enable blending if in opaque pass and not already enabled.
glEnable(GL_BLEND);
scene_state.enable_gl_blend(true);
}
if (pass < int32_t(inst->light_passes.size())) {
RID light_instance_rid = inst->light_passes[pass].light_instance_rid;
@ -3017,18 +3104,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
}
if (scene_state.cull_mode != cull_mode) {
if (cull_mode == GLES3::SceneShaderData::CULL_DISABLED) {
glDisable(GL_CULL_FACE);
} else {
if (scene_state.cull_mode == GLES3::SceneShaderData::CULL_DISABLED) {
// Last time was disabled, so enable and set proper face.
glEnable(GL_CULL_FACE);
}
glCullFace(cull_mode == GLES3::SceneShaderData::CULL_FRONT ? GL_FRONT : GL_BACK);
}
scene_state.cull_mode = cull_mode;
}
scene_state.set_gl_cull_mode(cull_mode);
RS::PrimitiveType primitive = surf->primitive;
if (shader->uses_point_size) {
@ -3417,7 +3493,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
if constexpr (p_pass_mode == PASS_MODE_COLOR) {
if (uses_additive_lighting && !p_render_data->transparent_bg) {
// Disable additive blending if enabled for additive lights.
glDisable(GL_BLEND);
scene_state.enable_gl_blend(false);
}
}
}
@ -3480,14 +3556,10 @@ void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider,
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
scene_state.reset_gl_state();
scene_state.enable_gl_depth_test(true);
scene_state.enable_gl_depth_draw(true);
glDepthFunc(GL_LESS);
glDisable(GL_SCISSOR_TEST);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
glDrawBuffers(0, nullptr);
@ -3530,14 +3602,10 @@ void RasterizerSceneGLES3::_render_uv2(const PagedArray<RenderGeometryInstance *
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
scene_state.reset_gl_state();
scene_state.enable_gl_depth_test(true);
scene_state.enable_gl_depth_draw(true);
glDepthFunc(GL_LESS);
glDisable(GL_SCISSOR_TEST);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
TightLocalVector<GLenum> draw_buffers;
draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
@ -3629,10 +3697,9 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES
glBindFramebuffer(GL_FRAMEBUFFER, shadow_atlas_fb);
glViewport(0, 0, shadow_atlas_size, shadow_atlas_size);
glActiveTexture(GL_TEXTURE0);
glDepthMask(GL_TRUE);
scene_state.enable_gl_depth_draw(true);
glDepthFunc(GL_ALWAYS);
glDisable(GL_CULL_FACE);
scene_state.cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_DISABLED);
// Loop through quadrants and copy shadows over.
for (int quadrant = 0; quadrant < 4; quadrant++) {
@ -3706,8 +3773,8 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
scene_state.enable_gl_depth_test(false);
scene_state.enable_gl_depth_draw(false);
copy_effects->copy_to_rect(Rect2(Vector2(), Vector2(0.5, 0.5)));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);

View File

@ -127,6 +127,8 @@ struct RenderDataGLES3 {
uint32_t spot_light_count = 0;
uint32_t omni_light_count = 0;
float luminance_multiplier = 1.0;
RenderingMethod::RenderInfo *render_info = nullptr;
/* Shadow data */
@ -404,15 +406,14 @@ private:
float fog_height_density;
float fog_depth_curve;
float pad;
float fog_sun_scatter;
float fog_depth_begin;
float fog_light_color[3];
float fog_depth_end;
float fog_sun_scatter;
float shadow_bias;
float luminance_multiplier;
uint32_t camera_visible_layers;
bool pancake_shadows;
};
@ -442,10 +443,85 @@ private:
bool used_depth_prepass = false;
GLES3::SceneShaderData::BlendMode current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
GLES3::SceneShaderData::DepthDraw current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE;
GLES3::SceneShaderData::DepthTest current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_DISABLED;
GLES3::SceneShaderData::Cull cull_mode = GLES3::SceneShaderData::CULL_BACK;
bool current_blend_enabled = false;
bool current_depth_draw_enabled = false;
bool current_depth_test_enabled = false;
bool current_scissor_test_enabled = false;
void reset_gl_state() {
glDisable(GL_BLEND);
current_blend_enabled = false;
glDisable(GL_SCISSOR_TEST);
current_scissor_test_enabled = false;
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
cull_mode = GLES3::SceneShaderData::CULL_BACK;
glDepthMask(GL_FALSE);
current_depth_draw_enabled = false;
glDisable(GL_DEPTH_TEST);
current_depth_test_enabled = false;
}
void set_gl_cull_mode(GLES3::SceneShaderData::Cull p_mode) {
if (cull_mode != p_mode) {
if (p_mode == GLES3::SceneShaderData::CULL_DISABLED) {
glDisable(GL_CULL_FACE);
} else {
if (cull_mode == GLES3::SceneShaderData::CULL_DISABLED) {
// Last time was disabled, so enable and set proper face.
glEnable(GL_CULL_FACE);
}
glCullFace(p_mode == GLES3::SceneShaderData::CULL_FRONT ? GL_FRONT : GL_BACK);
}
cull_mode = p_mode;
}
}
void enable_gl_blend(bool p_enabled) {
if (current_blend_enabled != p_enabled) {
if (p_enabled) {
glEnable(GL_BLEND);
} else {
glDisable(GL_BLEND);
}
current_blend_enabled = p_enabled;
}
}
void enable_gl_scissor_test(bool p_enabled) {
if (current_scissor_test_enabled != p_enabled) {
if (p_enabled) {
glEnable(GL_SCISSOR_TEST);
} else {
glDisable(GL_SCISSOR_TEST);
}
current_scissor_test_enabled = p_enabled;
}
}
void enable_gl_depth_draw(bool p_enabled) {
if (current_depth_draw_enabled != p_enabled) {
glDepthMask(p_enabled ? GL_TRUE : GL_FALSE);
current_depth_draw_enabled = p_enabled;
}
}
void enable_gl_depth_test(bool p_enabled) {
if (current_depth_test_enabled != p_enabled) {
if (p_enabled) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
current_depth_test_enabled = p_enabled;
}
}
bool texscreen_copied = false;
bool used_screen_texture = false;
bool used_normal_texture = false;
@ -656,9 +732,9 @@ protected:
void _setup_sky(const RenderDataGLES3 *p_render_data, const PagedArray<RID> &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size);
void _invalidate_sky(Sky *p_sky);
void _update_dirty_skys();
void _update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier);
void _update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_sky_energy_multiplier);
void _filter_sky_radiance(Sky *p_sky, int p_base_layer);
void _draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier, bool p_use_multiview, bool p_flip_y);
void _draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_sky_energy_multiplier, float p_luminance_multiplier, bool p_use_multiview, bool p_flip_y, bool p_apply_color_adjustments_in_post);
void _free_sky_data(Sky *p_sky);
// Needed for a single argument calls (material and uv2).

View File

@ -12,8 +12,10 @@ if "GLES3_GLSL" in env["BUILDERS"]:
# make sure we recompile shaders if include files change
env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#gles3_builders.py"])
# compile shaders
# as we have a few, not yet, converted files we name the ones we want to include:
env.GLES3_GLSL("canvas.glsl")
env.GLES3_GLSL("copy.glsl")
env.GLES3_GLSL("scene.glsl")
env.GLES3_GLSL("sky.glsl")
env.GLES3_GLSL("cubemap_filter.glsl")
@ -22,3 +24,10 @@ if "GLES3_GLSL" in env["BUILDERS"]:
env.GLES3_GLSL("particles.glsl")
env.GLES3_GLSL("particles_copy.glsl")
env.GLES3_GLSL("skeleton.glsl")
# once we finish conversion we can introduce this to cover all files:
# for glsl_file in glsl_files:
# env.GLES3_GLSL(glsl_file)
SConscript("effects/SCsub")

View File

@ -0,0 +1,17 @@
#!/usr/bin/env python
Import("env")
if "GLES3_GLSL" in env["BUILDERS"]:
# find all include files
gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
# find all shader code(all glsl files excluding our include files)
glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
# make sure we recompile shaders if include files change
env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#gles3_builders.py"])
# compile shaders
for glsl_file in glsl_files:
env.GLES3_GLSL(glsl_file)

View File

@ -6,6 +6,7 @@ mode_copy_section = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY
mode_copy_section_source = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define MODE_COPY_FROM
mode_copy_section_3d = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define USE_TEXTURE_3D
mode_copy_section_2d_array = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define USE_TEXTURE_2D_ARRAY
mode_screen = #define MODE_SIMPLE_COPY \n#define MODE_MULTIPLY
mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
mode_mipmap = #define MODE_MIPMAP
mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
@ -55,6 +56,10 @@ uniform float lod;
uniform vec4 color_in;
#endif
#ifdef MODE_MULTIPLY
uniform float multiply;
#endif
#ifdef MODE_GAUSSIAN_BLUR
// Defined in 0-1 coords.
uniform highp vec2 pixel_size;
@ -105,10 +110,14 @@ void main() {
vec4 color = textureLod(source_2d_array, vec3(uv_interp, layer), lod);
#else
vec4 color = texture(source, uv_interp);
#endif
#endif // USE_TEXTURE_3D
#ifdef MODE_MULTIPLY
color *= multiply;
#endif // MODE_MULTIPLY
frag_color = color;
#endif
#endif // MODE_SIMPLE_COPY
#ifdef MODE_SIMPLE_COLOR
frag_color = color_in;

View File

@ -0,0 +1,113 @@
/* clang-format off */
#[modes]
// Based on Dual filtering glow as explained in Marius Bjørge presentation at Siggraph 2015 "Bandwidth-Efficient Rendering"
mode_filter = #define MODE_FILTER
mode_downsample = #define MODE_DOWNSAMPLE
mode_upsample = #define MODE_UPSAMPLE
#[specializations]
USE_MULTIVIEW = false
#[vertex]
layout(location = 0) in vec2 vertex_attrib;
/* clang-format on */
out vec2 uv_interp;
void main() {
uv_interp = vertex_attrib * 0.5 + 0.5;
gl_Position = vec4(vertex_attrib, 1.0, 1.0);
}
/* clang-format off */
#[fragment]
/* clang-format on */
#ifdef MODE_FILTER
#ifdef USE_MULTIVIEW
uniform sampler2DArray source_color; // texunit:0
#else
uniform sampler2D source_color; // texunit:0
#endif // USE_MULTIVIEW
uniform float view;
uniform vec2 pixel_size;
uniform float luminance_multiplier;
uniform float glow_bloom;
uniform float glow_hdr_threshold;
uniform float glow_hdr_scale;
uniform float glow_luminance_cap;
#endif // MODE_FILTER
#ifdef MODE_DOWNSAMPLE
uniform sampler2D source_color; // texunit:0
uniform vec2 pixel_size;
#endif // MODE_DOWNSAMPLE
#ifdef MODE_UPSAMPLE
uniform sampler2D source_color; // texunit:0
uniform vec2 pixel_size;
#endif // MODE_UPSAMPLE
in vec2 uv_interp;
layout(location = 0) out vec4 frag_color;
void main() {
#ifdef MODE_FILTER
// Note, we read from an image with double resolution, so we average those out
#ifdef USE_MULTIVIEW
vec2 half_pixel = pixel_size * 0.5;
vec3 uv = vec3(uv_interp, view);
vec3 color = textureLod(source_color, uv, 0.0).rgb * 4.0;
color += textureLod(source_color, uv - vec3(half_pixel, 0.0), 0.0).rgb;
color += textureLod(source_color, uv + vec3(half_pixel, 0.0), 0.0).rgb;
color += textureLod(source_color, uv - vec3(half_pixel.x, -half_pixel.y, 0.0), 0.0).rgb;
color += textureLod(source_color, uv + vec3(half_pixel.x, -half_pixel.y, 0.0), 0.0).rgb;
#else
vec2 half_pixel = pixel_size * 0.5;
vec2 uv = uv_interp;
vec3 color = textureLod(source_color, uv, 0.0).rgb * 4.0;
color += textureLod(source_color, uv - half_pixel, 0.0).rgb;
color += textureLod(source_color, uv + half_pixel, 0.0).rgb;
color += textureLod(source_color, uv - vec2(half_pixel.x, -half_pixel.y), 0.0).rgb;
color += textureLod(source_color, uv + vec2(half_pixel.x, -half_pixel.y), 0.0).rgb;
#endif // USE_MULTIVIEW
color /= luminance_multiplier * 8.0;
float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
float feedback = max(smoothstep(glow_hdr_threshold, glow_hdr_threshold + glow_hdr_scale, luminance), glow_bloom);
color = min(color * feedback, vec3(glow_luminance_cap));
frag_color = vec4(luminance_multiplier * color, 1.0);
#endif // MODE_FILTER
#ifdef MODE_DOWNSAMPLE
vec2 half_pixel = pixel_size * 0.5;
vec4 color = textureLod(source_color, uv_interp, 0.0) * 4.0;
color += textureLod(source_color, uv_interp - half_pixel, 0.0);
color += textureLod(source_color, uv_interp + half_pixel, 0.0);
color += textureLod(source_color, uv_interp - vec2(half_pixel.x, -half_pixel.y), 0.0);
color += textureLod(source_color, uv_interp + vec2(half_pixel.x, -half_pixel.y), 0.0);
frag_color = color / 8.0;
#endif // MODE_DOWNSAMPLE
#ifdef MODE_UPSAMPLE
vec2 half_pixel = pixel_size * 0.5;
vec4 color = textureLod(source_color, uv_interp + vec2(-half_pixel.x * 2.0, 0.0), 0.0);
color += textureLod(source_color, uv_interp + vec2(-half_pixel.x, half_pixel.y), 0.0) * 2.0;
color += textureLod(source_color, uv_interp + vec2(0.0, half_pixel.y * 2.0), 0.0);
color += textureLod(source_color, uv_interp + vec2(half_pixel.x, half_pixel.y), 0.0) * 2.0;
color += textureLod(source_color, uv_interp + vec2(half_pixel.x * 2.0, 0.0), 0.0);
color += textureLod(source_color, uv_interp + vec2(half_pixel.x, -half_pixel.y), 0.0) * 2.0;
color += textureLod(source_color, uv_interp + vec2(0.0, -half_pixel.y * 2.0), 0.0);
color += textureLod(source_color, uv_interp + vec2(-half_pixel.x, -half_pixel.y), 0.0) * 2.0;
frag_color = color / 12.0;
#endif // MODE_UPSAMPLE
}

View File

@ -0,0 +1,96 @@
/* clang-format off */
#[modes]
mode_default = #define MODE_DEFAULT
// mode_glow = #define MODE_GLOW
#[specializations]
USE_MULTIVIEW = false
USE_GLOW = false
USE_LUMINANCE_MULTIPLIER = false
#[vertex]
layout(location = 0) in vec2 vertex_attrib;
/* clang-format on */
out vec2 uv_interp;
void main() {
uv_interp = vertex_attrib * 0.5 + 0.5;
gl_Position = vec4(vertex_attrib, 1.0, 1.0);
}
/* clang-format off */
#[fragment]
/* clang-format on */
#include "../tonemap_inc.glsl"
#ifdef USE_MULTIVIEW
uniform sampler2DArray source_color; // texunit:0
#else
uniform sampler2D source_color; // texunit:0
#endif // USE_MULTIVIEW
uniform float view;
uniform float luminance_multiplier;
#ifdef USE_GLOW
uniform sampler2D glow_color; // texunit:1
uniform vec2 pixel_size;
uniform float glow_intensity;
vec4 get_glow_color(vec2 uv) {
vec2 half_pixel = pixel_size * 0.5;
vec4 color = textureLod(glow_color, uv + vec2(-half_pixel.x * 2.0, 0.0), 0.0);
color += textureLod(glow_color, uv + vec2(-half_pixel.x, half_pixel.y), 0.0) * 2.0;
color += textureLod(glow_color, uv + vec2(0.0, half_pixel.y * 2.0), 0.0);
color += textureLod(glow_color, uv + vec2(half_pixel.x, half_pixel.y), 0.0) * 2.0;
color += textureLod(glow_color, uv + vec2(half_pixel.x * 2.0, 0.0), 0.0);
color += textureLod(glow_color, uv + vec2(half_pixel.x, -half_pixel.y), 0.0) * 2.0;
color += textureLod(glow_color, uv + vec2(0.0, -half_pixel.y * 2.0), 0.0);
color += textureLod(glow_color, uv + vec2(-half_pixel.x, -half_pixel.y), 0.0) * 2.0;
return color / 12.0;
}
#endif // USE_GLOW
in vec2 uv_interp;
layout(location = 0) out vec4 frag_color;
void main() {
#ifdef USE_MULTIVIEW
vec4 color = texture(source_color, vec3(uv_interp, view));
#else
vec4 color = texture(source_color, uv_interp);
#endif
#ifdef USE_GLOW
vec4 glow = get_glow_color(uv_interp) * glow_intensity;
// Just use softlight...
glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f));
color.rgb = max((color.rgb + glow.rgb) - (color.rgb * glow.rgb), vec3(0.0));
#endif // USE_GLOW
#ifdef USE_LUMINANCE_MULTIPLIER
color = color / luminance_multiplier;
#endif
color.rgb = srgb_to_linear(color.rgb);
color.rgb = apply_tonemapping(color.rgb, white);
color.rgb = linear_to_srgb(color.rgb);
#ifdef USE_BCS
color.rgb = apply_bcs(color.rgb, bcs);
#endif
#ifdef USE_COLOR_CORRECTION
color.rgb = apply_color_correction(color.rgb, color_correction);
#endif
frag_color = color;
}

View File

@ -28,6 +28,7 @@ LIGHT_USE_PSSM4 = false
LIGHT_USE_PSSM_BLEND = false
BASE_PASS = true
USE_ADDITIVE_LIGHTING = false
APPLY_TONEMAPPING = true
// We can only use one type of light per additive pass. This means that if USE_ADDITIVE_LIGHTING is defined, and
// these are false, we are doing a directional light pass.
ADDITIVE_OMNI = false
@ -185,18 +186,17 @@ layout(std140) uniform SceneData { // ubo:2
uint fog_mode;
float fog_density;
float fog_height;
float fog_height_density;
float fog_height_density;
float fog_depth_curve;
float pad;
float fog_sun_scatter;
float fog_depth_begin;
vec3 fog_light_color;
float fog_depth_end;
float fog_sun_scatter;
float shadow_bias;
float luminance_multiplier;
uint camera_visible_layers;
bool pancake_shadows;
}
@ -676,18 +676,17 @@ layout(std140) uniform SceneData { // ubo:2
uint fog_mode;
float fog_density;
float fog_height;
float fog_height_density;
float fog_height_density;
float fog_depth_curve;
float pad;
float fog_sun_scatter;
float fog_depth_begin;
vec3 fog_light_color;
float fog_depth_end;
float fog_sun_scatter;
float shadow_bias;
float luminance_multiplier;
uint camera_visible_layers;
bool pancake_shadows;
}
@ -1758,7 +1757,9 @@ void main() {
// Tonemap before writing as we are writing to an sRGB framebuffer
frag_color.rgb *= exposure;
#ifdef APPLY_TONEMAPPING
frag_color.rgb = apply_tonemapping(frag_color.rgb, white);
#endif
frag_color.rgb = linear_to_srgb(frag_color.rgb);
#ifdef USE_BCS
@ -1973,7 +1974,9 @@ void main() {
// Tonemap before writing as we are writing to an sRGB framebuffer
additive_light_color *= exposure;
#ifdef APPLY_TONEMAPPING
additive_light_color = apply_tonemapping(additive_light_color, white);
#endif
additive_light_color = linear_to_srgb(additive_light_color);
#ifdef USE_BCS
@ -1986,6 +1989,9 @@ void main() {
frag_color.rgb += additive_light_color;
#endif // USE_ADDITIVE_LIGHTING
frag_color.rgb *= scene_data.luminance_multiplier;
#endif // !RENDER_MATERIAL
#endif //!MODE_RENDER_DEPTH
#endif // !MODE_RENDER_DEPTH
}

View File

@ -12,6 +12,7 @@ mode_cubemap_quarter_res = #define USE_CUBEMAP_PASS \n#define USE_QUARTER_RES_PA
USE_MULTIVIEW = false
USE_INVERTED_Y = true
APPLY_TONEMAPPING = true
#[vertex]
@ -103,6 +104,7 @@ uniform mat4 orientation;
uniform vec4 projection;
uniform vec3 position;
uniform float time;
uniform float sky_energy_multiplier;
uniform float luminance_multiplier;
uniform float fog_aerial_perspective;
@ -195,12 +197,14 @@ void main() {
}
color *= luminance_multiplier;
color *= sky_energy_multiplier;
// Convert to Linear for tonemapping so color matches scene shader better
color = srgb_to_linear(color);
color *= exposure;
#ifdef APPLY_TONEMAPPING
color = apply_tonemapping(color, white);
#endif
color = linear_to_srgb(color);
#ifdef USE_BCS
@ -211,10 +215,10 @@ void main() {
color = apply_color_correction(color, color_correction);
#endif
frag_color.rgb = color;
frag_color.rgb = color * luminance_multiplier;
frag_color.a = alpha;
#ifdef USE_DEBANDING
frag_color.rgb += interleaved_gradient_noise(gl_FragCoord.xy) * luminance_multiplier;
frag_color.rgb += interleaved_gradient_noise(gl_FragCoord.xy) * sky_energy_multiplier * luminance_multiplier;
#endif
}

View File

@ -47,6 +47,13 @@
#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
#endif
RenderSceneBuffersGLES3::RenderSceneBuffersGLES3() {
for (int i = 0; i < 4; i++) {
glow.levels[i].color = 0;
glow.levels[i].fbo = 0;
}
}
RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
free_render_buffer_data();
}
@ -137,9 +144,22 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
//use_debanding = p_config->get_use_debanding();
view_count = config->multiview_supported ? p_config->get_view_count() : 1;
ERR_FAIL_COND(view_count == 0);
bool use_multiview = view_count > 1;
// Get color format data from our render target so we match those
if (render_target.is_valid()) {
color_internal_format = texture_storage->render_target_get_color_internal_format(render_target);
color_format = texture_storage->render_target_get_color_format(render_target);
color_type = texture_storage->render_target_get_color_type(render_target);
color_format_size = texture_storage->render_target_get_color_format_size(render_target);
} else {
// reflection probe? or error?
color_internal_format = GL_RGBA8;
color_format = GL_RGBA;
color_type = GL_UNSIGNED_BYTE;
color_format_size = 4;
}
// Check our scaling mode
if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && internal_size.x == 0 && internal_size.y == 0) {
// Disable, no size set.
@ -153,14 +173,38 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
}
bool use_internal_buffer = scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF; // TODO also need this if doing post processing like glow
// Check if we support MSAA.
if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && internal_size.x == 0 && internal_size.y == 0) {
// Disable, no size set.
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
} else if (!use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_supported && !config->rt_msaa_supported) {
WARN_PRINT_ONCE("MSAA is not supported on this device.");
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
} else if (use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_multiview_supported && !config->rt_msaa_multiview_supported) {
WARN_PRINT_ONCE("Multiview MSAA is not supported on this device.");
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
}
// We don't create our buffers right away because post effects can be made active at any time and change our buffer configuration.
}
void RenderSceneBuffersGLES3::_check_render_buffers() {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
ERR_FAIL_COND(view_count == 0);
bool use_internal_buffer = scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF || glow.glow_enabled;
uint32_t depth_format_size = 3;
bool use_multiview = view_count > 1;
if ((!use_internal_buffer || internal3d.color != 0) && (msaa3d.mode == RS::VIEWPORT_MSAA_DISABLED || msaa3d.color != 0)) {
// already setup!
return;
}
if (use_internal_buffer) {
// Setup our internal buffer.
bool is_transparent = texture_storage->render_target_get_transparent(render_target);
GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
GLuint color_format = GL_RGBA;
GLuint color_type = is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
// Create our color buffer.
@ -178,7 +222,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.color, internal_size.x * internal_size.y * view_count * 4, "3D color texture");
GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.color, internal_size.x * internal_size.y * view_count * color_format_size, "3D color texture");
// Create our depth buffer.
glGenTextures(1, &internal3d.depth);
@ -195,7 +239,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.depth, internal_size.x * internal_size.y * view_count * 3, "3D depth texture");
GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size, "3D depth texture");
// Create our internal 3D FBO.
// Note that if MSAA is used and our rt_msaa_* extensions are available, this is only used for blitting and effects.
@ -224,18 +268,6 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// Check if we support MSAA.
if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && internal_size.x == 0 && internal_size.y == 0) {
// Disable, no size set.
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
} else if (!use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_supported && !config->rt_msaa_supported) {
WARN_PRINT_ONCE("MSAA is not supported on this device.");
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
} else if (use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_multiview_supported && !config->rt_msaa_multiview_supported) {
WARN_PRINT_ONCE("Multiview MSAA is not supported on this device.");
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
}
if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED) {
// Setup MSAA.
const GLsizei samples[] = { 1, 2, 4, 8 };
@ -255,9 +287,6 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
msaa3d.needs_resolve = true;
msaa3d.check_fbo_cache = false;
bool is_transparent = texture_storage->render_target_get_transparent(render_target);
GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
// Create our color buffer.
glGenRenderbuffers(1, &msaa3d.color);
glBindRenderbuffer(GL_RENDERBUFFER, msaa3d.color);
@ -282,6 +311,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
_clear_msaa3d_buffers();
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
WARN_PRINT("Could not create 3D MSAA buffers, status: " + texture_storage->get_framebuffer_error(status));
}
@ -293,9 +323,6 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
msaa3d.needs_resolve = true;
msaa3d.check_fbo_cache = false;
bool is_transparent = texture_storage->render_target_get_transparent(render_target);
GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
// Create our color buffer.
glGenTextures(1, &msaa3d.color);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.color);
@ -306,7 +333,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, color_internal_format, internal_size.x, internal_size.y, view_count, GL_TRUE);
#endif
GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.color, internal_size.x * internal_size.y * view_count * 4 * msaa3d.samples, "MSAA 3D color texture");
GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.color, internal_size.x * internal_size.y * view_count * color_format_size * msaa3d.samples, "MSAA 3D color texture");
// Create our depth buffer.
glGenTextures(1, &msaa3d.depth);
@ -318,7 +345,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, GL_TRUE);
#endif
GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * msaa3d.samples, "MSAA 3D depth texture");
GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size * msaa3d.samples, "MSAA 3D depth texture");
// Create our MSAA 3D FBO.
glGenFramebuffers(1, &msaa3d.fbo);
@ -330,6 +357,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
_clear_msaa3d_buffers();
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
WARN_PRINT("Could not create 3D MSAA buffers, status: " + texture_storage->get_framebuffer_error(status));
}
@ -358,6 +386,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
_clear_msaa3d_buffers();
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
WARN_PRINT("Could not create 3D MSAA framebuffer, status: " + texture_storage->get_framebuffer_error(status));
}
@ -435,13 +464,9 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de
glBindFramebuffer(GL_FRAMEBUFFER, backbuffer3d.fbo);
bool is_transparent = texture_storage->render_target_get_transparent(render_target);
GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
GLuint color_format = GL_RGBA;
GLuint color_type = is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
bool use_multiview = view_count > 1 && GLES3::Config::get_singleton()->multiview_supported;
GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
uint32_t depth_format_size = 3;
if (backbuffer3d.color == 0 && p_need_color) {
glGenTextures(1, &backbuffer3d.color);
@ -458,7 +483,7 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.color, internal_size.x * internal_size.y * view_count * 4, "3D Back buffer color texture");
GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.color, internal_size.x * internal_size.y * view_count * color_format_size, "3D Back buffer color texture");
#ifndef IOS_ENABLED
if (use_multiview) {
@ -486,7 +511,7 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.depth, internal_size.x * internal_size.y * view_count * 3, "3D back buffer depth texture");
GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size, "3D back buffer depth texture");
#ifndef IOS_ENABLED
if (use_multiview) {
@ -526,21 +551,101 @@ void RenderSceneBuffersGLES3::_clear_back_buffers() {
}
}
void RenderSceneBuffersGLES3::set_glow_enabled(bool p_glow_enabled) {
if (glow.glow_enabled != p_glow_enabled) {
glow.glow_enabled = p_glow_enabled;
// Clear our main buffers, this can impact them.
_clear_msaa3d_buffers();
_clear_intermediate_buffers();
}
}
void RenderSceneBuffersGLES3::check_glow_buffers() {
if (glow.levels[0].color != 0) {
// already have these setup..
return;
}
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
Size2i level_size = internal_size;
for (int i = 0; i < 4; i++) {
level_size.x = MAX(level_size.x >> 1, 4);
level_size.y = MAX(level_size.y >> 1, 4);
glow.levels[i].size = level_size;
// Create our texture
glGenTextures(1, &glow.levels[i].color);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, glow.levels[i].color);
glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, level_size.x, level_size.y, 0, color_format, color_type, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
GLES3::Utilities::get_singleton()->texture_allocated_data(glow.levels[i].color, level_size.x * level_size.y * color_format_size, String("Glow buffer ") + String::num_int64(i));
// Create our FBO
glGenFramebuffers(1, &glow.levels[i].fbo);
glBindFramebuffer(GL_FRAMEBUFFER, glow.levels[i].fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glow.levels[i].color, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
WARN_PRINT("Could not create glow buffers, status: " + texture_storage->get_framebuffer_error(status));
_clear_glow_buffers();
break;
}
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void RenderSceneBuffersGLES3::_clear_glow_buffers() {
for (int i = 0; i < 4; i++) {
if (glow.levels[i].fbo != 0) {
glDeleteFramebuffers(1, &glow.levels[i].fbo);
glow.levels[i].fbo = 0;
}
if (glow.levels[i].color != 0) {
GLES3::Utilities::get_singleton()->texture_free_data(glow.levels[i].color);
glow.levels[i].color = 0;
}
}
}
void RenderSceneBuffersGLES3::free_render_buffer_data() {
_clear_msaa3d_buffers();
_clear_intermediate_buffers();
_clear_back_buffers();
_clear_glow_buffers();
}
GLuint RenderSceneBuffersGLES3::get_render_fbo() {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLuint rt_fbo = 0;
_check_render_buffers();
if (msaa3d.check_fbo_cache) {
GLuint color = texture_storage->render_target_get_color(render_target);
GLuint depth = texture_storage->render_target_get_depth(render_target);
rt_fbo = _rt_get_cached_fbo(color, depth, msaa3d.samples, view_count);
if (rt_fbo == 0) {
// Somehow couldn't obtain this? Just render without MSAA.
rt_fbo = texture_storage->render_target_get_fbo(render_target);
}
} else if (msaa3d.fbo != 0) {
// We have an MSAA fbo, render to our MSAA buffer
return msaa3d.fbo;

View File

@ -33,6 +33,7 @@
#ifdef GLES3_ENABLED
#include "drivers/gles3/effects/glow.h"
#include "servers/rendering/storage/render_scene_buffers.h"
#include "platform_gl.h"
@ -52,6 +53,12 @@ public:
RID render_target;
// Color format details from our render target
GLuint color_internal_format = GL_RGBA8;
GLuint color_format = GL_RGBA;
GLuint color_type = GL_UNSIGNED_BYTE;
uint32_t color_format_size = 4;
struct FBDEF {
GLuint color = 0;
GLuint depth = 0;
@ -74,31 +81,24 @@ public:
FBDEF backbuffer3d; // our back buffer
// Built-in textures used for ping pong image processing and blurring.
struct Blur {
RID texture;
struct Mipmap {
RID texture;
int width;
int height;
GLuint fbo;
};
Vector<Mipmap> mipmaps;
};
Blur blur[2]; //the second one starts from the first mipmap
// Buffers for our glow implementation
struct GLOW {
bool glow_enabled = false;
GLES3::Glow::GLOWLEVEL levels[4];
} glow;
private:
void _check_render_buffers();
void _clear_msaa3d_buffers();
void _clear_intermediate_buffers();
void _clear_back_buffers();
void _clear_glow_buffers();
void _rt_attach_textures(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count);
GLuint _rt_get_cached_fbo(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count);
public:
RenderSceneBuffersGLES3();
virtual ~RenderSceneBuffersGLES3();
virtual void configure(const RenderSceneBuffersConfiguration *p_config) override;
@ -109,19 +109,45 @@ public:
void free_render_buffer_data();
void check_backbuffer(bool p_need_color, bool p_need_depth); // Check if we need to initialize our backbuffer.
void check_glow_buffers(); // Check if we need to initialise our glow buffers.
GLuint get_render_fbo();
GLuint get_msaa3d_fbo() const { return msaa3d.fbo; }
GLuint get_msaa3d_color() const { return msaa3d.color; }
GLuint get_msaa3d_depth() const { return msaa3d.depth; }
bool get_msaa_needs_resolve() const { return msaa3d.needs_resolve; }
GLuint get_internal_fbo() const { return internal3d.fbo; }
GLuint get_internal_color() const { return internal3d.color; }
GLuint get_internal_depth() const { return internal3d.depth; }
GLuint get_msaa3d_fbo() {
_check_render_buffers();
return msaa3d.fbo;
}
GLuint get_msaa3d_color() {
_check_render_buffers();
return msaa3d.color;
}
GLuint get_msaa3d_depth() {
_check_render_buffers();
return msaa3d.depth;
}
bool get_msaa_needs_resolve() {
_check_render_buffers();
return msaa3d.needs_resolve;
}
GLuint get_internal_fbo() {
_check_render_buffers();
return internal3d.fbo;
}
GLuint get_internal_color() {
_check_render_buffers();
return internal3d.color;
}
GLuint get_internal_depth() {
_check_render_buffers();
return internal3d.depth;
}
GLuint get_backbuffer_fbo() const { return backbuffer3d.fbo; }
GLuint get_backbuffer() const { return backbuffer3d.color; }
GLuint get_backbuffer_depth() const { return backbuffer3d.depth; }
bool get_glow_enabled() const { return glow.glow_enabled; }
void set_glow_enabled(bool p_glow_enabled);
const GLES3::Glow::GLOWLEVEL *get_glow_buffers() const { return &glow.levels[0]; }
// Getters
_FORCE_INLINE_ RID get_render_target() const { return render_target; }

View File

@ -1981,10 +1981,25 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
Config *config = Config::get_singleton();
rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2;
rt->color_format = GL_RGBA;
rt->color_type = rt->is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
rt->image_format = Image::FORMAT_RGBA8;
if (rt->hdr) {
rt->color_internal_format = GL_RGBA16F;
rt->color_format = GL_RGBA;
rt->color_type = GL_FLOAT;
rt->color_format_size = 8;
rt->image_format = Image::FORMAT_RGBAF;
} else if (rt->is_transparent) {
rt->color_internal_format = GL_RGBA8;
rt->color_format = GL_RGBA;
rt->color_type = GL_UNSIGNED_BYTE;
rt->color_format_size = 4;
rt->image_format = Image::FORMAT_RGBA8;
} else {
rt->color_internal_format = GL_RGB10_A2;
rt->color_format = GL_RGBA;
rt->color_type = GL_UNSIGNED_INT_2_10_10_10_REV;
rt->color_format_size = 4;
rt->image_format = Image::FORMAT_RGBA8;
}
glDisable(GL_SCISSOR_TEST);
glColorMask(1, 1, 1, 1);
@ -2023,7 +2038,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
texture->gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
texture->gl_set_repeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->color, rt->size.x * rt->size.y * rt->view_count * 4, "Render target color texture");
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->color, rt->size.x * rt->size.y * rt->view_count * rt->color_format_size, "Render target color texture");
}
#ifndef IOS_ENABLED
if (use_multiview) {
@ -2194,7 +2209,7 @@ void GLES3::TextureStorage::check_backbuffer(RenderTarget *rt, const bool uses_s
} else {
glTexImage2D(texture_target, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
}
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer, rt->size.x * rt->size.y * rt->view_count * 4, "Render target backbuffer color texture (3D)");
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer, rt->size.x * rt->size.y * rt->view_count * rt->color_format_size, "Render target backbuffer color texture (3D)");
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -2548,6 +2563,54 @@ RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) con
return rt->msaa;
}
void TextureStorage::render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL(rt);
ERR_FAIL_COND(rt->direct_to_screen);
if (p_use_hdr_2d == rt->hdr) {
return;
}
_clear_render_target(rt);
rt->hdr = p_use_hdr_2d;
_update_render_target(rt);
}
bool TextureStorage::render_target_is_using_hdr(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL_V(rt, false);
return rt->hdr;
}
GLuint TextureStorage::render_target_get_color_internal_format(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL_V(rt, GL_RGBA8);
return rt->color_internal_format;
}
GLuint TextureStorage::render_target_get_color_format(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL_V(rt, GL_RGBA);
return rt->color_format;
}
GLuint TextureStorage::render_target_get_color_type(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL_V(rt, GL_UNSIGNED_BYTE);
return rt->color_type;
}
uint32_t TextureStorage::render_target_get_color_format_size(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL_V(rt, 4);
return rt->color_format_size;
}
void TextureStorage::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL(rt);

View File

@ -347,9 +347,11 @@ struct RenderTarget {
GLuint backbuffer = 0;
GLuint backbuffer_depth = 0;
bool hdr = false; // For Compatibility this effects both 2D and 3D rendering!
GLuint color_internal_format = GL_RGBA8;
GLuint color_format = GL_RGBA;
GLuint color_type = GL_UNSIGNED_BYTE;
uint32_t color_format_size = 4;
Image::Format image_format = Image::FORMAT_RGBA8;
GLuint sdf_texture_write = 0;
@ -631,14 +633,19 @@ public:
virtual void render_target_set_msaa_needs_resolve(RID p_render_target, bool p_needs_resolve) override {}
virtual bool render_target_get_msaa_needs_resolve(RID p_render_target) const override { return false; }
virtual void render_target_do_msaa_resolve(RID p_render_target) override {}
virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) override {}
virtual bool render_target_is_using_hdr(RID p_render_target) const override { return false; }
virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) override;
virtual bool render_target_is_using_hdr(RID p_render_target) const override;
// new
void render_target_set_as_unused(RID p_render_target) override {
render_target_clear_used(p_render_target);
}
GLuint render_target_get_color_internal_format(RID p_render_target) const;
GLuint render_target_get_color_format(RID p_render_target) const;
GLuint render_target_get_color_type(RID p_render_target) const;
uint32_t render_target_get_color_format_size(RID p_render_target) const;
void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override;
bool render_target_is_clear_requested(RID p_render_target) override;
Color render_target_get_clear_request_color(RID p_render_target) override;

View File

@ -1131,8 +1131,15 @@ void Environment::_validate_property(PropertyInfo &p_property) const {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
if (p_property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
// Hide glow properties we do not support in GL Compatibility.
if (p_property.name.begins_with("glow_levels") || p_property.name == "glow_normalized" || p_property.name == "glow_strength" || p_property.name == "glow_mix" || p_property.name == "glow_blend_mode" || p_property.name == "glow_map_strength" || p_property.name == "glow_map") {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
} else {
if (p_property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
if (p_property.name == "background_color") {

View File

@ -417,11 +417,6 @@ void RendererEnvironmentStorage::environment_set_glow(RID p_env, bool p_enable,
Environment *env = environment_owner.get_or_null(p_env);
ERR_FAIL_NULL(env);
ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7");
#ifdef DEBUG_ENABLED
if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility" && p_enable) {
WARN_PRINT_ONCE_ED("Glow is not supported when using the GL Compatibility backend yet. Support will be added in a future release.");
}
#endif
env->glow_enabled = p_enable;
env->glow_levels = p_levels;
env->glow_intensity = p_intensity;