summaryrefslogtreecommitdiff
path: root/drivers/gles3
diff options
context:
space:
mode:
authorclayjohn <claynjohn@gmail.com>2022-05-16 11:56:03 -0700
committerclayjohn <claynjohn@gmail.com>2022-05-16 15:07:09 -0700
commit9b61c855ef00e14925cfdf8a5d61f854c51d92f4 (patch)
tree8f4e02ccf198e5dfd0ad2ca156549f4da3dacfbd /drivers/gles3
parent23207fcfddf47f17a749c1fa8424c11769610b31 (diff)
Add basic lighting to GLES3 renderer.
This includes all three light types and IBL, but does not include shadows or any form of GI
Diffstat (limited to 'drivers/gles3')
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp1055
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h286
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp13
-rw-r--r--drivers/gles3/shader_gles3.h5
-rw-r--r--drivers/gles3/shaders/SCsub13
-rw-r--r--drivers/gles3/shaders/cubemap_filter.glsl216
-rw-r--r--drivers/gles3/shaders/scene.glsl384
-rw-r--r--drivers/gles3/shaders/sky.glsl35
-rw-r--r--drivers/gles3/shaders/stdlib_inc.glsl6
-rw-r--r--drivers/gles3/shaders/tonemap_inc.glsl16
-rw-r--r--drivers/gles3/storage/material_storage.cpp5
-rw-r--r--drivers/gles3/storage/material_storage.h5
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp8
-rw-r--r--drivers/gles3/storage/texture_storage.cpp5
-rw-r--r--drivers/gles3/storage/texture_storage.h11
15 files changed, 1537 insertions, 526 deletions
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 68657b9152..7937090862 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -30,11 +30,26 @@
#include "rasterizer_scene_gles3.h"
#include "core/config/project_settings.h"
+#include "core/templates/sort_array.h"
#include "servers/rendering/rendering_server_default.h"
#include "storage/config.h"
#ifdef GLES3_ENABLED
+void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type) {
+#ifdef GLES_OVER_GL
+
+ for (int i = 0; i < levels; i++) {
+ glTexImage2D(target, i, internalformat, width, height, 0, format, type, nullptr);
+ width = MAX(1, (width / 2));
+ height = MAX(1, (height / 2));
+ }
+
+#else
+ glTexStorage2D(target, levels, internalformat, width, height);
+#endif
+}
+
uint64_t RasterizerSceneGLES3::auto_exposure_counter = 2;
RasterizerSceneGLES3 *RasterizerSceneGLES3::singleton = nullptr;
@@ -196,16 +211,39 @@ void RasterizerSceneGLES3::geometry_instance_set_cast_double_sided_shadows(Geome
}
uint32_t RasterizerSceneGLES3::geometry_instance_get_pair_mask() {
- return 0; //(1 << RS::INSTANCE_LIGHT);
- // For now, nothing is paired
+ return (1 << RS::INSTANCE_LIGHT);
}
void RasterizerSceneGLES3::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
ginstance->omni_light_count = 0;
ginstance->spot_light_count = 0;
+ ginstance->omni_lights.clear();
+ ginstance->spot_lights.clear();
+
+ for (uint32_t i = 0; i < p_light_instance_count; i++) {
+ RS::LightType type = light_instance_get_type(p_light_instances[i]);
+ switch (type) {
+ case RS::LIGHT_OMNI: {
+ if (ginstance->omni_light_count < (uint32_t)config->max_lights_per_object) {
+ ginstance->omni_lights.push_back(p_light_instances[i]);
+ ginstance->omni_light_count++;
+ }
+ } break;
+ case RS::LIGHT_SPOT: {
+ if (ginstance->spot_light_count < (uint32_t)config->max_lights_per_object) {
+ ginstance->spot_lights.push_back(p_light_instances[i]);
+ ginstance->spot_light_count++;
+ }
+ } break;
+ default:
+ break;
+ }
+ }
}
void RasterizerSceneGLES3::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
@@ -495,8 +533,6 @@ void RasterizerSceneGLES3::_geometry_instance_update(GeometryInstance *p_geometr
}
}
- //Fill push constant
-
bool store_transform = true;
ginstance->base_flags = 0;
@@ -556,12 +592,12 @@ void RasterizerSceneGLES3::set_directional_shadow_count(int p_count) {
/* SKY API */
-void RasterizerSceneGLES3::Sky::free() {
- if (radiance != 0) {
- glDeleteTextures(1, &radiance);
- radiance = 0;
- glDeleteFramebuffers(1, &radiance_framebuffer);
- radiance_framebuffer = 0;
+void RasterizerSceneGLES3::_free_sky_data(Sky *p_sky) {
+ if (p_sky->radiance != 0) {
+ glDeleteTextures(1, &p_sky->radiance);
+ p_sky->radiance = 0;
+ glDeleteFramebuffers(1, &p_sky->radiance_framebuffer);
+ p_sky->radiance_framebuffer = 0;
}
}
@@ -584,7 +620,8 @@ void RasterizerSceneGLES3::sky_set_radiance_size(RID p_sky, int p_radiance_size)
sky->radiance_size = p_radiance_size;
- sky->free();
+ _free_sky_data(sky);
+ _invalidate_sky(sky);
}
void RasterizerSceneGLES3::sky_set_mode(RID p_sky, RS::SkyMode p_mode) {
@@ -596,10 +633,7 @@ void RasterizerSceneGLES3::sky_set_mode(RID p_sky, RS::SkyMode p_mode) {
}
sky->mode = p_mode;
-
- if (sky->mode == RS::SKY_MODE_REALTIME) {
- WARN_PRINT_ONCE("The OpenGL renderer does not support the Real Time Sky Update Mode yet. Please use High Quality Mode instead");
- }
+ _invalidate_sky(sky);
}
void RasterizerSceneGLES3::sky_set_material(RID p_sky, RID p_material) {
@@ -611,6 +645,7 @@ void RasterizerSceneGLES3::sky_set_material(RID p_sky, RID p_material) {
}
sky->material = p_material;
+ _invalidate_sky(sky);
}
void RasterizerSceneGLES3::_invalidate_sky(Sky *p_sky) {
@@ -626,13 +661,57 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
while (sky) {
if (sky->radiance == 0) {
- //int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1;
+ sky->mipmap_count = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8) + 1;
- //uint32_t w = sky->radiance_size, h = sky->radiance_size;
- //int layers = sky_globals.roughness_layers;
+ // Left uninitialized, will attach a texture at render time
glGenFramebuffers(1, &sky->radiance_framebuffer);
+ GLenum internal_format = GL_RGB10_A2;
+
glGenTextures(1, &sky->radiance);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance);
+
+#ifdef GLES_OVER_GL
+ GLenum format = GL_RGBA;
+ GLenum type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ //TODO, on low-end compare this to allocating each face of each mip individually
+ // see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml
+ for (int i = 0; i < 6; i++) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, sky->radiance_size, sky->radiance_size, 0, format, type, nullptr);
+ }
+
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+#else
+ glTexStorage2D(GL_TEXTURE_CUBE_MAP, sky->mipmap_count, internal_format, sky->radiance_size, sky->radiance_size);
+#endif
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count);
+
+ glGenTextures(1, &sky->raw_radiance);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, sky->raw_radiance);
+
+#ifdef GLES_OVER_GL
+ //TODO, on low-end compare this to allocating each face of each mip individually
+ // see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml
+ for (int i = 0; i < 6; i++) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, sky->radiance_size, sky->radiance_size, 0, format, type, nullptr);
+ }
+
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+#else
+ glTexStorage2D(GL_TEXTURE_CUBE_MAP, sky->mipmap_count, internal_format, sky->radiance_size, sky->radiance_size);
+#endif
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}
sky->reflection_dirty = true;
@@ -647,6 +726,152 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
dirty_sky_list = nullptr;
}
+void RasterizerSceneGLES3::_setup_sky(Environment *p_env, RID p_render_buffers, const PagedArray<RID> &p_lights, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size) {
+ GLES3::LightStorage *light_storage = GLES3::LightStorage::get_singleton();
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ ERR_FAIL_COND(!p_env);
+
+ GLES3::SkyMaterialData *material = nullptr;
+ Sky *sky = sky_owner.get_or_null(p_env->sky);
+
+ RID sky_material;
+
+ GLES3::SkyShaderData *shader_data = nullptr;
+
+ if (sky) {
+ sky_material = sky->material;
+
+ if (sky_material.is_valid()) {
+ material = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_globals.default_material;
+ material = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ }
+
+ ERR_FAIL_COND(!material);
+
+ shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
+ sky->prev_time = time;
+ sky->reflection_dirty = true;
+ RenderingServerDefault::redraw_request();
+ }
+
+ if (material != sky->prev_material) {
+ sky->prev_material = material;
+ sky->reflection_dirty = true;
+ }
+
+ if (material->uniform_set_updated) {
+ material->uniform_set_updated = false;
+ sky->reflection_dirty = true;
+ }
+
+ if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
+ sky->prev_position = p_transform.origin;
+ sky->reflection_dirty = true;
+ }
+
+ if (shader_data->uses_light) {
+ sky_globals.directional_light_count = 0;
+ for (int i = 0; i < (int)p_lights.size(); i++) {
+ LightInstance *li = light_instance_owner.get_or_null(p_lights[i]);
+ if (!li) {
+ continue;
+ }
+ RID base = li->light;
+
+ ERR_CONTINUE(base.is_null());
+
+ RS::LightType type = light_storage->light_get_type(base);
+ if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) {
+ DirectionalLightData &sky_light_data = sky_globals.directional_lights[sky_globals.directional_light_count];
+ Transform3D light_transform = li->transform;
+ Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
+
+ sky_light_data.direction[0] = world_direction.x;
+ sky_light_data.direction[1] = world_direction.y;
+ sky_light_data.direction[2] = world_direction.z;
+
+ float sign = light_storage->light_is_negative(base) ? -1 : 1;
+ sky_light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
+
+ Color linear_col = light_storage->light_get_color(base);
+ sky_light_data.color[0] = linear_col.r;
+ sky_light_data.color[1] = linear_col.g;
+ sky_light_data.color[2] = linear_col.b;
+
+ sky_light_data.enabled = true;
+
+ float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+ if (angular_diameter > 0.0) {
+ angular_diameter = Math::tan(Math::deg2rad(angular_diameter));
+ } else {
+ angular_diameter = 0.0;
+ }
+ sky_light_data.size = angular_diameter;
+ sky_globals.directional_light_count++;
+ if (sky_globals.directional_light_count >= sky_globals.max_directional_lights) {
+ break;
+ }
+ }
+ }
+ // Check whether the directional_light_buffer changes
+ bool light_data_dirty = false;
+
+ // Light buffer is dirty if we have fewer or more lights
+ // If we have fewer lights, make sure that old lights are disabled
+ if (sky_globals.directional_light_count != sky_globals.last_frame_directional_light_count) {
+ light_data_dirty = true;
+ for (uint32_t i = sky_globals.directional_light_count; i < sky_globals.max_directional_lights; i++) {
+ sky_globals.directional_lights[i].enabled = false;
+ }
+ }
+
+ if (!light_data_dirty) {
+ for (uint32_t i = 0; i < sky_globals.directional_light_count; i++) {
+ if (sky_globals.directional_lights[i].direction[0] != sky_globals.last_frame_directional_lights[i].direction[0] ||
+ sky_globals.directional_lights[i].direction[1] != sky_globals.last_frame_directional_lights[i].direction[1] ||
+ sky_globals.directional_lights[i].direction[2] != sky_globals.last_frame_directional_lights[i].direction[2] ||
+ sky_globals.directional_lights[i].energy != sky_globals.last_frame_directional_lights[i].energy ||
+ sky_globals.directional_lights[i].color[0] != sky_globals.last_frame_directional_lights[i].color[0] ||
+ sky_globals.directional_lights[i].color[1] != sky_globals.last_frame_directional_lights[i].color[1] ||
+ sky_globals.directional_lights[i].color[2] != sky_globals.last_frame_directional_lights[i].color[2] ||
+ sky_globals.directional_lights[i].enabled != sky_globals.last_frame_directional_lights[i].enabled ||
+ sky_globals.directional_lights[i].size != sky_globals.last_frame_directional_lights[i].size) {
+ light_data_dirty = true;
+ break;
+ }
+ }
+ }
+
+ if (light_data_dirty) {
+ glBindBufferBase(GL_UNIFORM_BUFFER, SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, sky_globals.directional_light_buffer);
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(DirectionalLightData) * sky_globals.directional_light_count, sky_globals.directional_lights);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ DirectionalLightData *temp = sky_globals.last_frame_directional_lights;
+ sky_globals.last_frame_directional_lights = sky_globals.directional_lights;
+ sky_globals.directional_lights = temp;
+ sky_globals.last_frame_directional_light_count = sky_globals.directional_light_count;
+ sky->reflection_dirty = true;
+ }
+ }
+
+ if (!sky->radiance) {
+ _update_dirty_skys();
+ }
+ }
+}
+
void RasterizerSceneGLES3::_draw_sky(Environment *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
ERR_FAIL_COND(!p_env);
@@ -686,8 +911,6 @@ void RasterizerSceneGLES3::_draw_sky(Environment *p_env, const CameraMatrix &p_p
ERR_FAIL_COND(!shader_data);
- //glBindBufferBase(GL_UNIFORM_BUFFER, 2, p_sky.directional light data); // Directional light data
-
// Camera
CameraMatrix camera;
@@ -709,11 +932,178 @@ void RasterizerSceneGLES3::_draw_sky(Environment *p_env, const CameraMatrix &p_p
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
- // Bind a vertex array or else OpenGL complains. We won't actually use it
- glBindVertexArray(sky_globals.quad_array);
+
+ glBindVertexArray(sky_globals.screen_triangle_array);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
+void RasterizerSceneGLES3::_update_sky_radiance(Environment *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform) {
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ ERR_FAIL_COND(!p_env);
+
+ Sky *sky = sky_owner.get_or_null(p_env->sky);
+ ERR_FAIL_COND(!sky);
+
+ GLES3::SkyMaterialData *material_data = nullptr;
+ RID sky_material;
+
+ RS::EnvironmentBG background = p_env->background;
+
+ if (sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky->material;
+
+ if (sky_material.is_valid()) {
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ if (!material_data || !material_data->shader_data->valid) {
+ material_data = nullptr;
+ }
+ }
+
+ if (!material_data) {
+ sky_material = sky_globals.default_material;
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ }
+ } else if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+ sky_material = sky_globals.fog_material;
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ }
+
+ ERR_FAIL_COND(!material_data);
+ material_data->bind_uniforms();
+
+ GLES3::SkyShaderData *shader_data = material_data->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY;
+ RS::SkyMode sky_mode = sky->mode;
+
+ if (sky_mode == RS::SKY_MODE_AUTOMATIC) {
+ if (shader_data->uses_time || shader_data->uses_position) {
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_REALTIME;
+ } else if (shader_data->uses_light || shader_data->ubo_size > 0) {
+ update_single_frame = false;
+ sky_mode = RS::SKY_MODE_INCREMENTAL;
+ } else {
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_QUALITY;
+ }
+ }
+
+ if (sky->processing_layer == 0 && sky_mode == RS::SKY_MODE_INCREMENTAL) {
+ // On the first frame after creating sky, rebuild in single frame
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_QUALITY;
+ }
+
+ int max_processing_layer = sky->mipmap_count;
+
+ // Update radiance cubemap
+ if (sky->reflection_dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) {
+ static const Vector3 view_normals[6] = {
+ Vector3(+1, 0, 0),
+ Vector3(-1, 0, 0),
+ Vector3(0, +1, 0),
+ Vector3(0, -1, 0),
+ Vector3(0, 0, +1),
+ Vector3(0, 0, -1)
+ };
+ static const Vector3 view_up[6] = {
+ Vector3(0, -1, 0),
+ Vector3(0, -1, 0),
+ Vector3(0, 0, +1),
+ Vector3(0, 0, -1),
+ Vector3(0, -1, 0),
+ Vector3(0, -1, 0)
+ };
+
+ CameraMatrix cm;
+ cm.set_perspective(90, 1, 0.01, 10.0);
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ cm = correction * cm;
+
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, cm.matrix[2][0], cm.matrix[0][0], cm.matrix[2][1], cm.matrix[1][1], shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+
+ // Bind a vertex array or else OpenGL complains. We won't actually use it
+ glBindVertexArray(sky_globals.screen_triangle_array);
+
+ glViewport(0, 0, sky->radiance_size, sky->radiance_size);
+ glBindFramebuffer(GL_FRAMEBUFFER, sky->radiance_framebuffer);
+
+ for (int i = 0; i < 6; i++) {
+ Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, local_view, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, sky->raw_radiance, 0);
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ }
+
+ if (update_single_frame) {
+ for (int i = 0; i < max_processing_layer; i++) {
+ _filter_sky_radiance(sky, i);
+ }
+ } else {
+ _filter_sky_radiance(sky, 0); //Just copy over the first mipmap
+ }
+ sky->processing_layer = 1;
+
+ sky->reflection_dirty = false;
+ } else {
+ if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
+ _filter_sky_radiance(sky, sky->processing_layer);
+ sky->processing_layer++;
+ }
+ }
+}
+
+void RasterizerSceneGLES3::_filter_sky_radiance(Sky *p_sky, int p_base_layer) {
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, p_sky->raw_radiance);
+ glBindFramebuffer(GL_FRAMEBUFFER, p_sky->radiance_framebuffer);
+
+ CubemapFilterShaderGLES3::ShaderVariant mode = CubemapFilterShaderGLES3::MODE_DEFAULT;
+
+ if (p_base_layer == 0) {
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+ mode = CubemapFilterShaderGLES3::MODE_COPY;
+
+ //Copy over base layer
+ }
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, sky_globals.radical_inverse_vdc_cache_tex);
+
+ int size = p_sky->radiance_size >> p_base_layer;
+ glViewport(0, 0, size, size);
+ glBindVertexArray(sky_globals.screen_triangle_array);
+
+ material_storage->shaders.cubemap_filter_shader.version_bind_shader(scene_globals.cubemap_filter_shader_version, mode);
+ material_storage->shaders.cubemap_filter_shader.version_set_uniform(CubemapFilterShaderGLES3::SAMPLE_COUNT, sky_globals.ggx_samples, scene_globals.cubemap_filter_shader_version, mode);
+ material_storage->shaders.cubemap_filter_shader.version_set_uniform(CubemapFilterShaderGLES3::ROUGHNESS, float(p_base_layer) / (p_sky->mipmap_count - 1.0), scene_globals.cubemap_filter_shader_version, mode);
+ material_storage->shaders.cubemap_filter_shader.version_set_uniform(CubemapFilterShaderGLES3::FACE_SIZE, float(size), scene_globals.cubemap_filter_shader_version, mode);
+
+ for (int i = 0; i < 6; i++) {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, p_sky->radiance, p_base_layer);
+#ifdef DEBUG_ENABLED
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE);
+#endif
+ material_storage->shaders.cubemap_filter_shader.version_set_uniform(CubemapFilterShaderGLES3::FACE_ID, i, scene_globals.cubemap_filter_shader_version, mode);
+
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ }
+ glBindVertexArray(0);
+ glViewport(0, 0, p_sky->screen_size.x, p_sky->screen_size.y);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
Ref<Image> RasterizerSceneGLES3::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) {
return Ref<Image>();
}
@@ -941,13 +1331,29 @@ void RasterizerSceneGLES3::directional_shadow_quality_set(RS::ShadowQuality p_qu
}
RID RasterizerSceneGLES3::light_instance_create(RID p_light) {
- return RID();
+ RID li = light_instance_owner.make_rid(LightInstance());
+
+ LightInstance *light_instance = light_instance_owner.get_or_null(li);
+
+ light_instance->self = li;
+ light_instance->light = p_light;
+ light_instance->light_type = RSG::light_storage->light_get_type(p_light);
+
+ return li;
}
void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->transform = p_transform;
}
void RasterizerSceneGLES3::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->aabb = p_aabb;
}
void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
@@ -1090,8 +1496,22 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
flags |= INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE;
}
- //Process lights here, determine if they need extra passes
+ // Sets the index values for lookup in the shader
+ // This has to be done after _setup_lights was called this frame
+ // TODO, check shadow status of lights here, if using shadows, skip here and add below
if (p_pass_mode == PASS_MODE_COLOR) {
+ if (inst->omni_light_count) {
+ inst->omni_light_gl_cache.resize(inst->omni_light_count);
+ for (uint32_t j = 0; j < inst->omni_light_count; j++) {
+ inst->omni_light_gl_cache[j] = light_instance_get_gl_id(inst->omni_lights[j]);
+ }
+ }
+ if (inst->spot_light_count) {
+ inst->spot_light_gl_cache.resize(inst->spot_light_count);
+ for (uint32_t j = 0; j < inst->spot_light_count; j++) {
+ inst->spot_light_gl_cache[j] = light_instance_get_gl_id(inst->spot_lights[j]);
+ }
+ }
}
inst->flags_cache = flags;
@@ -1197,6 +1617,7 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
}
}
+// Needs to be called after _setup_lights so that directional_light_count is accurate.
void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows) {
CameraMatrix correction;
correction.set_depth_correction(p_flip_y);
@@ -1205,15 +1626,13 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
RasterizerStorageGLES3::store_camera(projection, scene_state.ubo.projection_matrix);
RasterizerStorageGLES3::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
RasterizerStorageGLES3::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix);
- RasterizerStorageGLES3::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.view_matrix);
+ RasterizerStorageGLES3::store_transform(p_render_data->inv_cam_transform, scene_state.ubo.view_matrix);
- scene_state.ubo.directional_light_count = 1;
+ scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
scene_state.ubo.z_far = p_render_data->z_far;
scene_state.ubo.z_near = p_render_data->z_near;
- scene_state.ubo.pancake_shadows = p_pancake_shadows;
-
scene_state.ubo.viewport_size[0] = p_screen_size.x;
scene_state.ubo.viewport_size[1] = p_screen_size.y;
@@ -1242,6 +1661,8 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy;
scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy;
scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy;
+ scene_state.ubo.use_ambient_light = true;
+ scene_state.ubo.use_ambient_cubemap = false;
} else {
float energy = env->ambient_light_energy;
Color color = env->ambient_light;
@@ -1253,6 +1674,16 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
Basis sky_transform = env->sky_orientation;
sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis;
RasterizerStorageGLES3::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
+ scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
+ scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
+ }
+
+ //specular
+ RS::EnvironmentReflectionSource ref_src = env->reflection_source;
+ if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) {
+ scene_state.ubo.use_reflection_cubemap = true;
+ } else {
+ scene_state.ubo.use_reflection_cubemap = false;
}
scene_state.ubo.fog_enabled = env->fog_enabled;
@@ -1281,6 +1712,210 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
+// Puts lights into Uniform Buffers. Needs to be called before _fill_list as this caches the index of each light in the Uniform Buffer
+void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_omni_light_count, uint32_t &r_spot_light_count) {
+ GLES3::LightStorage *light_storage = GLES3::LightStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ const Transform3D inverse_transform = p_render_data->inv_cam_transform;
+
+ const PagedArray<RID> &lights = *p_render_data->lights;
+
+ r_directional_light_count = 0;
+ r_omni_light_count = 0;
+ r_spot_light_count = 0;
+
+ int num_lights = lights.size();
+
+ for (int i = 0; i < num_lights; i++) {
+ LightInstance *li = light_instance_owner.get_or_null(lights[i]);
+ if (!li) {
+ continue;
+ }
+ RID base = li->light;
+
+ ERR_CONTINUE(base.is_null());
+
+ RS::LightType type = light_storage->light_get_type(base);
+ switch (type) {
+ case RS::LIGHT_DIRECTIONAL: {
+ if (r_directional_light_count >= RendererSceneRender::MAX_DIRECTIONAL_LIGHTS || light_storage->light_directional_get_sky_mode(base) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) {
+ continue;
+ }
+
+ DirectionalLightData &light_data = scene_state.directional_lights[r_directional_light_count];
+
+ Transform3D light_transform = li->transform;
+
+ Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized();
+
+ light_data.direction[0] = direction.x;
+ light_data.direction[1] = direction.y;
+ light_data.direction[2] = direction.z;
+
+ float sign = light_storage->light_is_negative(base) ? -1 : 1;
+
+ light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI;
+
+ Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
+ light_data.color[0] = linear_col.r;
+ light_data.color[1] = linear_col.g;
+ light_data.color[2] = linear_col.b;
+
+ float size = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+ light_data.size = 1.0 - Math::cos(Math::deg2rad(size)); //angle to cosine offset
+
+ light_data.specular = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR);
+
+ r_directional_light_count++;
+ } break;
+ case RS::LIGHT_OMNI: {
+ if (r_omni_light_count >= (uint32_t)config->max_renderable_lights) {
+ continue;
+ }
+
+ const real_t distance = p_render_data->cam_transform.origin.distance_to(li->transform.origin);
+
+ if (light_storage->light_is_distance_fade_enabled(li->light)) {
+ const float fade_begin = light_storage->light_get_distance_fade_begin(li->light);
+ const float fade_length = light_storage->light_get_distance_fade_length(li->light);
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ // Out of range, don't draw this light to improve performance.
+ continue;
+ }
+ }
+ }
+
+ li->gl_id = r_omni_light_count;
+
+ scene_state.omni_light_sort[r_omni_light_count].instance = li;
+ scene_state.omni_light_sort[r_omni_light_count].depth = distance;
+ r_omni_light_count++;
+ } break;
+ case RS::LIGHT_SPOT: {
+ if (r_spot_light_count >= (uint32_t)config->max_renderable_lights) {
+ continue;
+ }
+
+ const real_t distance = p_render_data->cam_transform.origin.distance_to(li->transform.origin);
+
+ if (light_storage->light_is_distance_fade_enabled(li->light)) {
+ const float fade_begin = light_storage->light_get_distance_fade_begin(li->light);
+ const float fade_length = light_storage->light_get_distance_fade_length(li->light);
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ // Out of range, don't draw this light to improve performance.
+ continue;
+ }
+ }
+ }
+
+ li->gl_id = r_spot_light_count;
+
+ scene_state.spot_light_sort[r_spot_light_count].instance = li;
+ scene_state.spot_light_sort[r_spot_light_count].depth = distance;
+ r_spot_light_count++;
+ } break;
+ }
+ }
+
+ if (r_omni_light_count) {
+ SortArray<InstanceSort<LightInstance>> sorter;
+ sorter.sort(scene_state.omni_light_sort, r_omni_light_count);
+ }
+
+ if (r_spot_light_count) {
+ SortArray<InstanceSort<LightInstance>> sorter;
+ sorter.sort(scene_state.spot_light_sort, r_spot_light_count);
+ }
+
+ for (uint32_t i = 0; i < (r_omni_light_count + r_spot_light_count); i++) {
+ uint32_t index = (i < r_omni_light_count) ? i : i - (r_omni_light_count);
+ LightData &light_data = (i < r_omni_light_count) ? scene_state.omni_lights[index] : scene_state.spot_lights[index];
+ //RS::LightType type = (i < omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT;
+ LightInstance *li = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].instance : scene_state.spot_light_sort[index].instance;
+ RID base = li->light;
+
+ Transform3D light_transform = li->transform;
+ Vector3 pos = inverse_transform.xform(light_transform.origin);
+
+ light_data.position[0] = pos.x;
+ light_data.position[1] = pos.y;
+ light_data.position[2] = pos.z;
+
+ float radius = MAX(0.001, light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE));
+ light_data.inv_radius = 1.0 / radius;
+
+ Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized();
+
+ light_data.direction[0] = direction.x;
+ light_data.direction[1] = direction.y;
+ light_data.direction[2] = direction.z;
+
+ float size = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+
+ light_data.size = size;
+
+ float sign = light_storage->light_is_negative(base) ? -1 : 1;
+ Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
+
+ // Reuse fade begin, fade length and distance for shadow LOD determination later.
+ float fade_begin = 0.0;
+ float fade_length = 0.0;
+ real_t distance = 0.0;
+
+ float fade = 1.0;
+ if (light_storage->light_is_distance_fade_enabled(li->light)) {
+ fade_begin = light_storage->light_get_distance_fade_begin(li->light);
+ fade_length = light_storage->light_get_distance_fade_length(li->light);
+ distance = p_render_data->cam_transform.origin.distance_to(li->transform.origin);
+
+ if (distance > fade_begin) {
+ // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
+ fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length);
+ }
+ }
+
+ float energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI * fade;
+
+ light_data.color[0] = linear_col.r * energy;
+ light_data.color[1] = linear_col.g * energy;
+ light_data.color[2] = linear_col.b * energy;
+
+ light_data.attenuation = light_storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION);
+
+ light_data.inv_spot_attenuation = 1.0f / light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ float spot_angle = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE);
+ light_data.cos_spot_angle = Math::cos(Math::deg2rad(spot_angle));
+
+ light_data.specular_amount = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0;
+
+ light_data.shadow_enabled = false;
+ }
+
+ // TODO, to avoid stalls, should rotate between 3 buffers based on frame index.
+ // TODO, consider mapping the buffer as in 2D
+ if (r_omni_light_count) {
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_OMNILIGHT_UNIFORM_LOCATION, scene_state.omni_light_buffer);
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightData) * r_omni_light_count, scene_state.omni_lights);
+ }
+
+ if (r_spot_light_count) {
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_SPOTLIGHT_UNIFORM_LOCATION, scene_state.spot_light_buffer);
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightData) * r_spot_light_count, scene_state.spot_lights);
+ }
+
+ if (r_directional_light_count) {
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, scene_state.directional_light_buffer);
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(DirectionalLightData) * r_directional_light_count, scene_state.directional_lights);
+ }
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+}
+
void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
@@ -1300,6 +1935,7 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
render_data.transparent_bg = rb->is_transparent;
// Our first camera is used by default
render_data.cam_transform = p_camera_data->main_transform;
+ render_data.inv_cam_transform = render_data.cam_transform.affine_inverse();
render_data.cam_projection = p_camera_data->main_projection;
render_data.view_projection[0] = p_camera_data->main_projection;
render_data.cam_orthogonal = p_camera_data->is_orthogonal;
@@ -1317,8 +1953,6 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
render_data.reflection_probes = &p_reflection_probes;
render_data.environment = p_environment;
render_data.camera_effects = p_camera_effects;
- render_data.shadow_atlas = p_shadow_atlas;
- render_data.reflection_atlas = p_reflection_atlas;
render_data.reflection_probe = p_reflection_probe;
render_data.reflection_probe_pass = p_reflection_probe_pass;
@@ -1365,8 +1999,10 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
screen_size.x = rb->width;
screen_size.y = rb->height;
+ bool use_wireframe = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME;
+
SceneState::TonemapUBO tonemap_ubo;
- if (is_environment(p_environment)) {
+ if (env) {
tonemap_ubo.exposure = env->exposure;
tonemap_ubo.white = env->white;
tonemap_ubo.tonemapper = int32_t(env->tone_mapper);
@@ -1379,12 +2015,79 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_TONEMAP_UNIFORM_LOCATION, scene_state.tonemap_buffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::TonemapUBO), &tonemap_ubo, GL_STREAM_DRAW);
+ _setup_lights(&render_data, false, render_data.directional_light_count, render_data.omni_light_count, render_data.spot_light_count);
_setup_environment(&render_data, render_data.reflection_probe.is_valid(), screen_size, !render_data.reflection_probe.is_valid(), clear_color, false);
_fill_render_list(RENDER_LIST_OPAQUE, &render_data, PASS_MODE_COLOR);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
+ bool draw_sky = false;
+ bool draw_sky_fog_only = false;
+ bool keep_color = false;
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
+ clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
+ } else if (env) {
+ RS::EnvironmentBG bg_mode = env->background;
+ float bg_energy = env->bg_energy;
+ switch (bg_mode) {
+ case RS::ENV_BG_CLEAR_COLOR: {
+ clear_color.r *= bg_energy;
+ clear_color.g *= bg_energy;
+ clear_color.b *= bg_energy;
+ if (env->fog_enabled) {
+ draw_sky_fog_only = true;
+ GLES3::MaterialStorage::get_singleton()->material_set_param(sky_globals.fog_material, "clear_color", Variant(clear_color));
+ }
+ } break;
+ case RS::ENV_BG_COLOR: {
+ clear_color = env->bg_color;
+ clear_color.r *= bg_energy;
+ clear_color.g *= bg_energy;
+ clear_color.b *= bg_energy;
+ if (env->fog_enabled) {
+ draw_sky_fog_only = true;
+ GLES3::MaterialStorage::get_singleton()->material_set_param(sky_globals.fog_material, "clear_color", Variant(clear_color));
+ }
+ } break;
+ case RS::ENV_BG_SKY: {
+ draw_sky = true;
+ } break;
+ case RS::ENV_BG_CANVAS: {
+ keep_color = true;
+ } break;
+ case RS::ENV_BG_KEEP: {
+ keep_color = true;
+ } break;
+ case RS::ENV_BG_CAMERA_FEED: {
+ } break;
+ default: {
+ }
+ }
+ // setup sky if used for ambient, reflections, or background
+ if (draw_sky || draw_sky_fog_only || env->reflection_source == RS::ENV_REFLECTION_SOURCE_SKY || env->ambient_source == RS::ENV_AMBIENT_SOURCE_SKY) {
+ RENDER_TIMESTAMP("Setup Sky");
+ CameraMatrix projection = render_data.cam_projection;
+ if (render_data.reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ projection = correction * render_data.cam_projection;
+ }
+
+ _setup_sky(env, p_render_buffers, *render_data.lights, projection, render_data.cam_transform, screen_size);
+
+ if (env->sky.is_valid()) {
+ if (env->reflection_source == RS::ENV_REFLECTION_SOURCE_SKY || env->ambient_source == RS::ENV_AMBIENT_SOURCE_SKY || (env->reflection_source == RS::ENV_REFLECTION_SOURCE_BG && env->background == RS::ENV_BG_SKY)) {
+ _update_sky_radiance(env, projection, render_data.cam_transform);
+ }
+ } else {
+ // do not try to draw sky if invalid
+ draw_sky = false;
+ }
+ }
+ }
+
glBindFramebuffer(GL_FRAMEBUFFER, rb->framebuffer);
glViewport(0, 0, rb->width, rb->height);
@@ -1395,6 +2098,7 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
use_depth_prepass = use_depth_prepass && get_debug_draw_mode() != RS::VIEWPORT_DEBUG_DRAW_OVERDRAW;
if (use_depth_prepass) {
+ RENDER_TIMESTAMP("Depth Prepass");
//pre z pass
glDisable(GL_BLEND);
@@ -1410,9 +2114,7 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
glClearDepth(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
- uint32_t spec_constant_base_flags = 0;
-
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, render_data.lod_camera_plane, render_data.lod_distance_multiplier, render_data.screen_mesh_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, 0, use_wireframe);
_render_list_template<PASS_MODE_DEPTH>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
glColorMask(1, 1, 1, 1);
@@ -1429,7 +2131,7 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
} else {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
glDisable(GL_BLEND);
}
scene_state.current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
@@ -1445,54 +2147,29 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
glClear(GL_DEPTH_BUFFER_BIT);
}
- bool draw_sky = false;
- bool keep_color = false;
-
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
- clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
- } else if (is_environment(p_environment)) {
- RS::EnvironmentBG bg_mode = environment_get_background(p_environment);
- float bg_energy = env->bg_energy; //environment_get_bg_energy(p_environment);
- switch (bg_mode) {
- case RS::ENV_BG_CLEAR_COLOR: {
- clear_color.r *= bg_energy;
- clear_color.g *= bg_energy;
- clear_color.b *= bg_energy;
- } break;
- case RS::ENV_BG_COLOR: {
- clear_color = env->bg_color; //environment_get_bg_color(p_environment);
- clear_color.r *= bg_energy;
- clear_color.g *= bg_energy;
- clear_color.b *= bg_energy;
- } break;
- case RS::ENV_BG_SKY: {
- draw_sky = true;
- } break;
- case RS::ENV_BG_CANVAS: {
- keep_color = true;
- } break;
- case RS::ENV_BG_KEEP: {
- keep_color = true;
- } break;
- case RS::ENV_BG_CAMERA_FEED: {
- } break;
- default: {
- }
- }
- // Draw sky cubemap
- }
-
if (!keep_color) {
glClearBufferfv(GL_COLOR, 0, clear_color.components);
}
-
+ RENDER_TIMESTAMP("Render Opaque Pass");
uint32_t spec_constant_base_flags = 0;
- //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, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, render_data.lod_camera_plane, render_data.lod_distance_multiplier, render_data.screen_mesh_lod_threshold);
+
+ {
+ // Specialization Constants that apply for entire rendering pass.
+ if (render_data.directional_light_count == 0) {
+ spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS;
+ }
+
+ if (!env || (env && !env->fog_enabled)) {
+ spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_FOG;
+ }
+ }
+ // 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());
if (draw_sky) {
+ RENDER_TIMESTAMP("Render Sky");
if (scene_state.current_depth_test != GLES3::SceneShaderData::DEPTH_TEST_ENABLED) {
glEnable(GL_DEPTH_TEST);
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
@@ -1509,19 +2186,15 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
_draw_sky(env, render_data.cam_projection, render_data.cam_transform);
}
+ RENDER_TIMESTAMP("Render 3D Transparent Pass");
glEnable(GL_BLEND);
//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, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, render_data.lod_camera_plane, render_data.lod_distance_multiplier, render_data.screen_mesh_lod_threshold);
+ 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);
_render_list_template<PASS_MODE_COLOR_TRANSPARENT>(&render_list_params_alpha, &render_data, 0, render_list[RENDER_LIST_ALPHA].elements.size(), true);
if (p_render_buffers.is_valid()) {
- /*
- RENDER_TIMESTAMP("Tonemap");
- _render_buffers_post_process_and_tonemap(&render_data);
- */
-
_render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
}
glDisable(GL_BLEND);
@@ -1531,12 +2204,16 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
template <PassMode p_pass_mode>
void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass) {
GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
GLuint prev_vertex_array_gl = 0;
GLuint prev_index_array_gl = 0;
GLES3::SceneMaterialData *prev_material_data = nullptr;
GLES3::SceneShaderData *prev_shader = nullptr;
+ GeometryInstanceGLES3 *prev_inst = nullptr;
SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized.
@@ -1553,9 +2230,23 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
} break;
}
+ if (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
+ Environment *env = environment_owner.get_or_null(p_render_data->environment);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 2);
+ GLuint texture_to_bind = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_CUBEMAP_BLACK))->tex_id;
+ if (env) {
+ Sky *sky = sky_owner.get_or_null(env->sky);
+ if (sky && sky->radiance != 0) {
+ texture_to_bind = sky->radiance;
+ // base_spec_constant |= USE_RADIANCE_MAP;
+ }
+ glBindTexture(GL_TEXTURE_CUBE_MAP, texture_to_bind);
+ }
+ }
+
for (uint32_t i = p_from_element; i < p_to_element; i++) {
const GeometryInstanceSurface *surf = p_params->elements[i];
- const GeometryInstanceGLES3 *inst = surf->owner;
+ GeometryInstanceGLES3 *inst = surf->owner;
if (p_pass_mode == PASS_MODE_COLOR && !(surf->flags & GeometryInstanceSurface::FLAG_PASS_OPAQUE)) {
continue; // Objects with "Depth-prepass" transparency are included in both render lists, but should only be rendered in the transparent pass
@@ -1627,7 +2318,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
if (p_render_data->transparent_bg) {
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
} else {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
}
} break;
@@ -1639,6 +2330,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
case GLES3::SceneShaderData::BLEND_MODE_SUB: {
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
} break;
case GLES3::SceneShaderData::BLEND_MODE_MUL: {
glBlendEquation(GL_FUNC_ADD);
@@ -1718,8 +2410,6 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
prev_index_array_gl = index_array_gl;
}
- // Update pipeline information here
-
Transform3D world_transform;
if (inst->store_transform_cache) {
world_transform = inst->transform;
@@ -1727,13 +2417,40 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
if (prev_material_data != material_data) {
material_data->bind_uniforms();
+ prev_material_data = material_data;
}
if (prev_shader != shader) {
- GLES3::MaterialStorage::get_singleton()->shaders.scene_shader.version_bind_shader(shader->version, shader_variant);
+ material_storage->shaders.scene_shader.version_bind_shader(shader->version, shader_variant);
+ float opaque_prepass_threshold = 0.0;
+ if (p_pass_mode == PASS_MODE_DEPTH) {
+ opaque_prepass_threshold = 0.99;
+ } else if (p_pass_mode == PASS_MODE_SHADOW) {
+ opaque_prepass_threshold = 0.1;
+ }
+
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, shader_variant);
+
+ prev_shader = shader;
+ }
+
+ if (prev_inst != inst) {
+ // Rebind the light indices.
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, shader_variant);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, shader_variant);
+
+ if (inst->omni_light_count) {
+ glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, shader_variant), inst->omni_light_count, inst->omni_light_gl_cache.ptr());
+ }
+
+ if (inst->spot_light_count) {
+ glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, shader_variant), inst->spot_light_count, inst->spot_light_gl_cache.ptr());
+ }
+
+ prev_inst = inst;
}
- GLES3::MaterialStorage::get_singleton()->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, shader_variant);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, shader_variant);
if (use_index_buffer) {
glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), mesh_storage->mesh_surface_get_index_type(mesh_surface), 0);
@@ -1976,7 +2693,7 @@ bool RasterizerSceneGLES3::free(RID p_rid) {
} else if (sky_owner.owns(p_rid)) {
Sky *sky = sky_owner.get_or_null(p_rid);
ERR_FAIL_COND_V(!sky, false);
- sky->free();
+ _free_sky_data(sky);
sky_owner.free(p_rid);
} else if (render_buffers_owner.owns(p_rid)) {
RenderBuffers *rb = render_buffers_owner.get_or_null(p_rid);
@@ -1984,6 +2701,10 @@ bool RasterizerSceneGLES3::free(RID p_rid) {
_free_render_buffer_data(rb);
render_buffers_owner.free(p_rid);
+ } else if (light_instance_owner.owns(p_rid)) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_rid);
+ ERR_FAIL_COND_V(!light_instance, false);
+ light_instance_owner.free(p_rid);
} else {
return false;
}
@@ -2005,11 +2726,55 @@ void RasterizerSceneGLES3::light_projectors_set_filter(RS::LightProjectorFilter
RasterizerSceneGLES3::RasterizerSceneGLES3(RasterizerStorageGLES3 *p_storage) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
storage = p_storage;
{
+ // Setup Lights
+
+ config->max_renderable_lights = MIN(config->max_renderable_lights, config->max_uniform_buffer_size / (int)sizeof(RasterizerSceneGLES3::LightData));
+ config->max_lights_per_object = MIN(config->max_lights_per_object, config->max_renderable_lights);
+
+ uint32_t light_buffer_size = config->max_renderable_lights * sizeof(LightData);
+ scene_state.omni_lights = memnew_arr(LightData, config->max_renderable_lights);
+ scene_state.omni_light_sort = memnew_arr(InstanceSort<LightInstance>, config->max_renderable_lights);
+ glGenBuffers(1, &scene_state.omni_light_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, scene_state.omni_light_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);
+
+ scene_state.spot_lights = memnew_arr(LightData, config->max_renderable_lights);
+ scene_state.spot_light_sort = memnew_arr(InstanceSort<LightInstance>, config->max_renderable_lights);
+ glGenBuffers(1, &scene_state.spot_light_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, scene_state.spot_light_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);
+
+ uint32_t directional_light_buffer_size = MAX_DIRECTIONAL_LIGHTS * sizeof(DirectionalLightData);
+ scene_state.directional_lights = memnew_arr(DirectionalLightData, MAX_DIRECTIONAL_LIGHTS);
+ glGenBuffers(1, &scene_state.directional_light_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, scene_state.directional_light_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, directional_light_buffer_size, nullptr, GL_STREAM_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ }
+
+ {
+ sky_globals.max_directional_lights = 4;
+ uint32_t directional_light_buffer_size = sky_globals.max_directional_lights * sizeof(DirectionalLightData);
+ sky_globals.directional_lights = memnew_arr(DirectionalLightData, sky_globals.max_directional_lights);
+ sky_globals.last_frame_directional_lights = memnew_arr(DirectionalLightData, sky_globals.max_directional_lights);
+ sky_globals.last_frame_directional_light_count = sky_globals.max_directional_lights + 1;
+ glGenBuffers(1, &sky_globals.directional_light_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, sky_globals.directional_light_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, directional_light_buffer_size, nullptr, GL_STREAM_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ }
+
+ {
String global_defines;
global_defines += "#define MAX_GLOBAL_VARIABLES 256\n"; // TODO: this is arbitrary for now
+ global_defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(config->max_renderable_lights) + "\n";
+ global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
+ global_defines += "\n#define MAX_FORWARD_LIGHTS " + itos(config->max_lights_per_object) + "\n";
material_storage->shaders.scene_shader.initialize(global_defines);
scene_globals.shader_default_version = material_storage->shaders.scene_shader.version_create();
material_storage->shaders.scene_shader.version_bind_shader(scene_globals.shader_default_version, SceneShaderGLES3::MODE_COLOR);
@@ -2050,6 +2815,10 @@ void fragment() {
material_storage->shaders.sky_shader.initialize(global_defines);
sky_globals.shader_default_version = material_storage->shaders.sky_shader.version_create();
material_storage->shaders.sky_shader.version_bind_shader(sky_globals.shader_default_version, SkyShaderGLES3::MODE_BACKGROUND);
+
+ material_storage->shaders.cubemap_filter_shader.initialize();
+ scene_globals.cubemap_filter_shader_version = material_storage->shaders.cubemap_filter_shader.version_create();
+ material_storage->shaders.cubemap_filter_shader.version_bind_shader(scene_globals.cubemap_filter_shader_version, CubemapFilterShaderGLES3::MODE_DEFAULT);
}
{
@@ -2091,59 +2860,95 @@ void sky() {
material_storage->material_set_shader(sky_globals.fog_material, sky_globals.fog_shader);
}
+
{
- {
- //quad buffers
-
- glGenBuffers(1, &sky_globals.quad);
- glBindBuffer(GL_ARRAY_BUFFER, sky_globals.quad);
- {
- const float qv[16] = {
- -1,
- -1,
- 0,
- 0,
- -1,
- 1,
- 0,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- -1,
- 1,
- 0,
- };
-
- glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW);
- }
+ glGenBuffers(1, &sky_globals.screen_triangle);
+ glBindBuffer(GL_ARRAY_BUFFER, sky_globals.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, &sky_globals.screen_triangle_array);
+ glBindVertexArray(sky_globals.screen_triangle_array);
+ glBindBuffer(GL_ARRAY_BUFFER, sky_globals.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
+ }
+
+ // Radical inverse vdc cache texture used for cubemap filtering.
+ {
+ glGenTextures(1, &sky_globals.radical_inverse_vdc_cache_tex);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, sky_globals.radical_inverse_vdc_cache_tex);
+
+ uint8_t radical_inverse[512];
- glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ for (uint32_t i = 0; i < 512; i++) {
+ uint32_t bits = i;
- glGenVertexArrays(1, &sky_globals.quad_array);
- glBindVertexArray(sky_globals.quad_array);
- glBindBuffer(GL_ARRAY_BUFFER, sky_globals.quad);
- glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, nullptr);
- glEnableVertexAttribArray(RS::ARRAY_VERTEX);
- glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8));
- glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
- glBindVertexArray(0);
- glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ bits = (bits << 16) | (bits >> 16);
+ bits = ((bits & 0x55555555) << 1) | ((bits & 0xAAAAAAAA) >> 1);
+ bits = ((bits & 0x33333333) << 2) | ((bits & 0xCCCCCCCC) >> 2);
+ bits = ((bits & 0x0F0F0F0F) << 4) | ((bits & 0xF0F0F0F0) >> 4);
+ bits = ((bits & 0x00FF00FF) << 8) | ((bits & 0xFF00FF00) >> 8);
+
+ float value = float(bits) * 2.3283064365386963e-10;
+ radical_inverse[i] = uint8_t(CLAMP(value * 255.0, 0, 255));
}
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 512, 1, 0, GL_RED, GL_UNSIGNED_BYTE, radical_inverse);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //need this for proper sampling
+
+ glBindTexture(GL_TEXTURE_2D, 0);
}
+#ifdef GLES_OVER_GL
+ glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS);
+#endif
}
RasterizerSceneGLES3::~RasterizerSceneGLES3() {
+ glDeleteBuffers(1, &scene_state.directional_light_buffer);
+ glDeleteBuffers(1, &scene_state.omni_light_buffer);
+ glDeleteBuffers(1, &scene_state.spot_light_buffer);
+ memdelete_arr(scene_state.directional_lights);
+ memdelete_arr(scene_state.omni_lights);
+ memdelete_arr(scene_state.spot_lights);
+ memdelete_arr(scene_state.omni_light_sort);
+ memdelete_arr(scene_state.spot_light_sort);
+
+ // Scene Shader
GLES3::MaterialStorage::get_singleton()->shaders.scene_shader.version_free(scene_globals.shader_default_version);
+ GLES3::MaterialStorage::get_singleton()->shaders.cubemap_filter_shader.version_free(scene_globals.cubemap_filter_shader_version);
storage->free(scene_globals.default_material);
storage->free(scene_globals.default_shader);
+
+ // Sky Shader
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_free(sky_globals.shader_default_version);
storage->free(sky_globals.default_material);
storage->free(sky_globals.default_shader);
storage->free(sky_globals.fog_material);
storage->free(sky_globals.fog_shader);
+ glDeleteBuffers(1, &sky_globals.screen_triangle);
+ glDeleteVertexArrays(1, &sky_globals.screen_triangle_array);
+ glDeleteTextures(1, &sky_globals.radical_inverse_vdc_cache_tex);
+ glDeleteBuffers(1, &sky_globals.directional_light_buffer);
+ memdelete_arr(sky_globals.directional_lights);
+ memdelete_arr(sky_globals.last_frame_directional_lights);
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index ac2f3c932a..d9a848c0f6 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -43,6 +43,7 @@
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
#include "shader_gles3.h"
+#include "shaders/cubemap_filter.glsl.gen.h"
#include "shaders/sky.glsl.gen.h"
enum RenderListType {
@@ -66,17 +67,26 @@ enum SceneUniformLocation {
SCENE_GLOBALS_UNIFORM_LOCATION,
SCENE_DATA_UNIFORM_LOCATION,
SCENE_MATERIAL_UNIFORM_LOCATION,
- SCENE_RADIANCE_UNIFORM_LOCATION,
+ SCENE_EMPTY, // Unused, put here to avoid conflicts with SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION.
SCENE_OMNILIGHT_UNIFORM_LOCATION,
SCENE_SPOTLIGHT_UNIFORM_LOCATION,
+ SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
};
enum SkyUniformLocation {
SKY_TONEMAP_UNIFORM_LOCATION,
SKY_GLOBALS_UNIFORM_LOCATION,
- SKY_SCENE_DATA_UNIFORM_LOCATION,
- SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
+ SKY_EMPTY, // Unused, put here to avoid conflicts with SCENE_DATA_UNIFORM_LOCATION.
SKY_MATERIAL_UNIFORM_LOCATION,
+ SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
+};
+
+enum {
+ SPEC_CONSTANT_DISABLE_LIGHTMAP = 0,
+ SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS = 1,
+ SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 2,
+ SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 3,
+ SPEC_CONSTANT_DISABLE_FOG = 4,
};
struct RenderDataGLES3 {
@@ -84,6 +94,7 @@ struct RenderDataGLES3 {
bool transparent_bg = false;
Transform3D cam_transform = Transform3D();
+ Transform3D inv_cam_transform = Transform3D();
CameraMatrix cam_projection = CameraMatrix();
bool cam_orthogonal = false;
@@ -97,14 +108,8 @@ struct RenderDataGLES3 {
const PagedArray<RendererSceneRender::GeometryInstance *> *instances = nullptr;
const PagedArray<RID> *lights = nullptr;
const PagedArray<RID> *reflection_probes = nullptr;
- //const PagedArray<RID> *voxel_gi_instances = nullptr;
- //const PagedArray<RID> *decals = nullptr;
- //const PagedArray<RID> *lightmaps = nullptr;
- //const PagedArray<RID> *fog_volumes = nullptr;
RID environment = RID();
RID camera_effects = RID();
- RID shadow_atlas = RID();
- RID reflection_atlas = RID();
RID reflection_probe = RID();
int reflection_probe_pass = 0;
@@ -113,6 +118,8 @@ struct RenderDataGLES3 {
float screen_mesh_lod_threshold = 0.0;
uint32_t directional_light_count = 0;
+ uint32_t spot_light_count = 0;
+ uint32_t omni_light_count = 0;
RendererScene::RenderInfo *render_info = nullptr;
};
@@ -126,90 +133,81 @@ private:
RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
uint64_t scene_pass = 0;
- struct SkyGlobals {
- RID shader_default_version;
- RID default_material;
- RID default_shader;
- RID fog_material;
- RID fog_shader;
- GLuint quad = 0;
- GLuint quad_array = 0;
- uint32_t max_directional_lights = 4;
- uint32_t roughness_layers = 8;
- uint32_t ggx_samples = 128;
- } sky_globals;
+ template <class T>
+ struct InstanceSort {
+ float depth;
+ T *instance = nullptr;
+ bool operator<(const InstanceSort &p_sort) const {
+ return depth < p_sort.depth;
+ }
+ };
struct SceneGlobals {
RID shader_default_version;
RID default_material;
RID default_shader;
+ RID cubemap_filter_shader_version;
} scene_globals;
- struct SceneState {
- struct UBO {
- float projection_matrix[16];
- float inv_projection_matrix[16];
- float inv_view_matrix[16];
- float view_matrix[16];
+ /* LIGHT INSTANCE */
- float viewport_size[2];
- float screen_pixel_size[2];
+ struct LightData {
+ float position[3];
+ float inv_radius;
- float ambient_light_color_energy[4];
+ float direction[3]; // Only used by SpotLight
+ float size;
- float ambient_color_sky_mix;
- uint32_t ambient_flags;
- uint32_t material_uv2_mode;
- float opaque_prepass_threshold;
- //bool use_ambient_light;
- //bool use_ambient_cubemap;
- //bool use_reflection_cubemap;
+ float color[3];
+ float attenuation;
- float radiance_inverse_xform[12];
+ float inv_spot_attenuation;
+ float cos_spot_angle;
+ float specular_amount;
+ uint32_t shadow_enabled;
+ };
+ static_assert(sizeof(LightData) % 16 == 0, "LightData size must be a multiple of 16 bytes");
- uint32_t directional_light_count;
- float z_far;
- float z_near;
- uint32_t pancake_shadows;
+ struct DirectionalLightData {
+ float direction[3];
+ float energy;
- uint32_t fog_enabled;
- float fog_density;
- float fog_height;
- float fog_height_density;
+ float color[3];
+ float size;
- float fog_light_color[3];
- float fog_sun_scatter;
+ uint32_t enabled; // For use by SkyShaders
+ float pad[2];
+ float specular;
+ };
+ static_assert(sizeof(DirectionalLightData) % 16 == 0, "DirectionalLightData size must be a multiple of 16 bytes");
- float fog_aerial_perspective;
- float time;
- uint32_t pad[2];
- };
- static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
+ struct LightInstance {
+ RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
- struct TonemapUBO {
- float exposure = 1.0;
- float white = 1.0;
- int32_t tonemapper = 0;
- int32_t pad = 0;
- };
- static_assert(sizeof(TonemapUBO) % 16 == 0, "Tonemap UBO size must be a multiple of 16 bytes");
+ AABB aabb;
+ RID self;
+ RID light;
+ Transform3D transform;
- UBO ubo;
- GLuint ubo_buffer = 0;
- GLuint tonemap_buffer = 0;
+ Vector3 light_vector;
+ Vector3 spot_vector;
+ float linear_att = 0.0;
- bool used_depth_prepass = false;
+ uint64_t shadow_pass = 0;
+ uint64_t last_scene_pass = 0;
+ uint64_t last_scene_shadow_pass = 0;
+ uint64_t last_pass = 0;
+ uint32_t cull_mask = 0;
+ uint32_t light_directional_index = 0;
- 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;
+ Rect2 directional_rect;
- bool texscreen_copied = false;
- bool used_screen_texture = false;
- bool used_normal_texture = false;
- bool used_depth_texture = false;
- } scene_state;
+ uint32_t gl_id = -1;
+
+ LightInstance() {}
+ };
+
+ mutable RID_Owner<LightInstance> light_instance_owner;
struct GeometryInstanceGLES3;
@@ -295,9 +293,11 @@ private:
float parent_fade_alpha = 1.0;
uint32_t omni_light_count = 0;
- uint32_t omni_lights[8];
+ LocalVector<RID> omni_lights;
uint32_t spot_light_count = 0;
- uint32_t spot_lights[8];
+ LocalVector<RID> spot_lights;
+ LocalVector<uint32_t> omni_light_gl_cache;
+ LocalVector<uint32_t> spot_light_gl_cache;
//used during setup
uint32_t base_flags = 0;
@@ -360,25 +360,96 @@ private:
void _geometry_instance_update(GeometryInstance *p_geometry_instance);
void _update_dirty_geometry_instances();
+ struct SceneState {
+ struct UBO {
+ float projection_matrix[16];
+ float inv_projection_matrix[16];
+ float inv_view_matrix[16];
+ float view_matrix[16];
+
+ float viewport_size[2];
+ float screen_pixel_size[2];
+
+ float ambient_light_color_energy[4];
+
+ float ambient_color_sky_mix;
+ uint32_t material_uv2_mode;
+ float pad2;
+ uint32_t use_ambient_light = 0;
+
+ uint32_t use_ambient_cubemap = 0;
+ uint32_t use_reflection_cubemap = 0;
+ float fog_aerial_perspective;
+ float time;
+
+ float radiance_inverse_xform[12];
+
+ uint32_t directional_light_count;
+ float z_far;
+ float z_near;
+ float pad1;
+
+ uint32_t fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
+ };
+ static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
+
+ struct TonemapUBO {
+ float exposure = 1.0;
+ float white = 1.0;
+ int32_t tonemapper = 0;
+ int32_t pad = 0;
+ };
+ static_assert(sizeof(TonemapUBO) % 16 == 0, "Tonemap UBO size must be a multiple of 16 bytes");
+
+ UBO ubo;
+ GLuint ubo_buffer = 0;
+ GLuint tonemap_buffer = 0;
+
+ 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 texscreen_copied = false;
+ bool used_screen_texture = false;
+ bool used_normal_texture = false;
+ bool used_depth_texture = false;
+
+ LightData *omni_lights = nullptr;
+ LightData *spot_lights = nullptr;
+
+ InstanceSort<LightInstance> *omni_light_sort;
+ InstanceSort<LightInstance> *spot_light_sort;
+ GLuint omni_light_buffer = 0;
+ GLuint spot_light_buffer = 0;
+ uint32_t omni_light_count = 0;
+ uint32_t spot_light_count = 0;
+
+ DirectionalLightData *directional_lights = nullptr;
+ GLuint directional_light_buffer = 0;
+ } scene_state;
+
struct RenderListParameters {
GeometryInstanceSurface **elements = nullptr;
int element_count = 0;
bool reverse_cull = false;
uint32_t spec_constant_base_flags = 0;
bool force_wireframe = false;
- Plane lod_plane;
- float lod_distance_multiplier = 0.0;
- float screen_mesh_lod_threshold = 0.0;
- RenderListParameters(GeometryInstanceSurface **p_elements, int p_element_count, bool p_reverse_cull, uint32_t p_spec_constant_base_flags, bool p_force_wireframe = false, const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0) {
+ RenderListParameters(GeometryInstanceSurface **p_elements, int p_element_count, bool p_reverse_cull, uint32_t p_spec_constant_base_flags, bool p_force_wireframe = false) {
elements = p_elements;
element_count = p_element_count;
reverse_cull = p_reverse_cull;
spec_constant_base_flags = p_spec_constant_base_flags;
force_wireframe = p_force_wireframe;
- lod_plane = p_lod_plane;
- lod_distance_multiplier = p_lod_distance_multiplier;
- screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
}
};
@@ -438,6 +509,7 @@ private:
RenderList render_list[RENDER_LIST_MAX];
+ void _setup_lights(const RenderDataGLES3 *p_render_data, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_omni_light_count, uint32_t &r_spot_light_count);
void _setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows);
void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false);
@@ -637,6 +709,33 @@ protected:
/* Sky */
+ struct SkyGlobals {
+ float fog_aerial_perspective = 0.0;
+ Color fog_light_color;
+ float fog_sun_scatter = 0.0;
+ bool fog_enabled = false;
+ float fog_density = 0.0;
+ float z_far = 0.0;
+ uint32_t directional_light_count = 0;
+
+ DirectionalLightData *directional_lights = nullptr;
+ DirectionalLightData *last_frame_directional_lights = nullptr;
+ uint32_t last_frame_directional_light_count = 0;
+ GLuint directional_light_buffer = 0;
+
+ RID shader_default_version;
+ RID default_material;
+ RID default_shader;
+ RID fog_material;
+ RID fog_shader;
+ GLuint screen_triangle = 0;
+ GLuint screen_triangle_array = 0;
+ GLuint radical_inverse_vdc_cache_tex = 0;
+ uint32_t max_directional_lights = 4;
+ uint32_t roughness_layers = 8;
+ uint32_t ggx_samples = 128;
+ } sky_globals;
+
struct Sky {
// Screen Buffers
GLuint half_res_pass = 0;
@@ -648,11 +747,13 @@ protected:
// Radiance Cubemap
GLuint radiance = 0;
GLuint radiance_framebuffer = 0;
+ GLuint raw_radiance = 0;
RID material;
- RID uniform_buffer;
+ GLuint uniform_buffer;
int radiance_size = 256;
+ int mipmap_count = 1;
RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC;
@@ -666,20 +767,18 @@ protected:
GLES3::SkyMaterialData *prev_material;
Vector3 prev_position = Vector3(0.0, 0.0, 0.0);
float prev_time = 0.0f;
-
- void free();
- bool set_radiance_size(int p_radiance_size);
- bool set_mode(RS::SkyMode p_mode);
- bool set_material(RID p_material);
- Ref<Image> bake_panorama(float p_energy, int p_roughness_layers, const Size2i &p_size);
};
Sky *dirty_sky_list = nullptr;
mutable RID_Owner<Sky, true> sky_owner;
+ void _setup_sky(Environment *p_env, RID p_render_buffers, const PagedArray<RID> &p_lights, const CameraMatrix &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(Environment *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform);
+ void _filter_sky_radiance(Sky *p_sky, int p_base_layer);
void _draw_sky(Environment *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform);
+ void _free_sky_data(Sky *p_sky);
public:
RasterizerStorageGLES3 *storage;
@@ -808,6 +907,15 @@ public:
void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
void light_instance_mark_visible(RID p_light_instance) override;
+ _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->light_type;
+ }
+ _FORCE_INLINE_ uint32_t light_instance_get_gl_id(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->gl_id;
+ }
+
RID fog_volume_instance_create(RID p_fog_volume) override;
void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override;
void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override;
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 3c28289bd0..8046a18f05 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -39,6 +39,19 @@
#include "servers/rendering/shader_language.h"
void RasterizerStorageGLES3::base_update_dependency(RID p_base, DependencyTracker *p_instance) {
+ if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_base)) {
+ GLES3::Mesh *mesh = GLES3::MeshStorage::get_singleton()->get_mesh(p_base);
+ p_instance->update_dependency(&mesh->dependency);
+ } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_base)) {
+ GLES3::MultiMesh *multimesh = GLES3::MeshStorage::get_singleton()->get_multimesh(p_base);
+ p_instance->update_dependency(&multimesh->dependency);
+ if (multimesh->mesh.is_valid()) {
+ base_update_dependency(multimesh->mesh, p_instance);
+ }
+ } else if (GLES3::LightStorage::get_singleton()->owns_light(p_base)) {
+ GLES3::Light *l = GLES3::LightStorage::get_singleton()->get_light(p_base);
+ p_instance->update_dependency(&l->dependency);
+ }
}
/* VOXEL GI API */
diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h
index 35fb202342..228bed6f9b 100644
--- a/drivers/gles3/shader_gles3.h
+++ b/drivers/gles3/shader_gles3.h
@@ -219,7 +219,10 @@ protected:
Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_COND_V(!version, -1);
ERR_FAIL_INDEX_V(p_variant, int(version->variants.size()), -1);
- return version->variants[p_variant].lookup_ptr(p_specialization)->uniform_location[p_which];
+ Version::Specialization *spec = version->variants[p_variant].lookup_ptr(p_specialization);
+ ERR_FAIL_COND_V(!spec, -1);
+ ERR_FAIL_INDEX_V(p_which, int(spec->uniform_location.size()), -1);
+ return spec->uniform_location[p_which];
}
virtual void _init() = 0;
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index ec32badc19..d8dd573f57 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/drivers/gles3/shaders/SCsub
@@ -2,11 +2,18 @@
Import("env")
-env.Depends("#drivers/gles3/shaders/copy.glsl.gen.h", "#core/math/basis.h")
-env.Depends("#drivers/gles3/shaders/copy.glsl.gen.h", "#core/math/transform_2d.h")
-
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)
+
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")
diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl
index 2081abfef6..81e66c956c 100644
--- a/drivers/gles3/shaders/cubemap_filter.glsl
+++ b/drivers/gles3/shaders/cubemap_filter.glsl
@@ -1,136 +1,102 @@
/* clang-format off */
-[vertex]
+#[modes]
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-precision highp float;
-precision highp int;
-#endif
+mode_default =
+mode_copy = #define MODE_DIRECT_WRITE
+
+#[specializations]
-layout(location = 0) in highp vec2 vertex;
+#[vertex]
+
+layout(location = 0) in highp vec2 vertex_attrib;
/* clang-format on */
-layout(location = 4) in highp vec2 uv;
out highp vec2 uv_interp;
void main() {
- uv_interp = uv;
- gl_Position = vec4(vertex, 0, 1);
+ uv_interp = vertex_attrib;
+ gl_Position = vec4(uv_interp, 0.0, 1.0);
}
/* clang-format off */
-[fragment]
+#[fragment]
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-#if defined(USE_HIGHP_PRECISION)
-precision highp float;
-precision highp int;
-#else
-precision mediump float;
-precision mediump int;
-#endif
-#endif
+#define M_PI 3.14159265359
-#ifdef USE_SOURCE_PANORAMA
-uniform sampler2D source_panorama; //texunit:0
-#else
uniform samplerCube source_cube; //texunit:0
-#endif
+
/* clang-format on */
uniform int face_id;
uniform float roughness;
-in highp vec2 uv_interp;
-
-uniform sampler2D radical_inverse_vdc_cache; // texunit:1
-
-#define M_PI 3.14159265359
-
-#ifdef LOW_QUALITY
-
-#define SAMPLE_COUNT 64
-
-#else
-
-#define SAMPLE_COUNT 512
+uniform float face_size;
+uniform int sample_count;
+//Todo, profile on low end hardware to see if fixed loop is faster
+#ifdef USE_FIXED_SAMPLES
+#define FIXED_SAMPLE_COUNT 32
#endif
-#ifdef USE_SOURCE_PANORAMA
+in highp vec2 uv_interp;
-vec4 texturePanorama(sampler2D pano, vec3 normal) {
- vec2 st = vec2(
- atan(normal.x, normal.z),
- acos(normal.y));
+uniform sampler2D radical_inverse_vdc_cache; // texunit:1
- if (st.x < 0.0)
- st.x += M_PI * 2.0;
+layout(location = 0) out vec4 frag_color;
- st /= vec2(M_PI * 2.0, M_PI);
+#define M_PI 3.14159265359
- return textureLod(pano, st, 0.0);
+// Don't include tonemap_inc.glsl because all we want is these functions, we don't want the uniforms
+vec3 linear_to_srgb(vec3 color) {
+ return max(vec3(1.055) * pow(color, vec3(0.416666667)) - vec3(0.055), vec3(0.0));
}
-#endif
+vec3 srgb_to_linear(vec3 color) {
+ return color * (color * (color * 0.305306011 + 0.682171111) + 0.012522878);
+}
vec3 texelCoordToVec(vec2 uv, int faceID) {
mat3 faceUvVectors[6];
// -x
- faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z
- faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face
+ faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
+ faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
// +x
- faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z
- faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face
+ faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
+ faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
// -y
- faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z
- faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face
+ faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
+ faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
// +y
- faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z
- faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face
+ faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
+ faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
// -z
- faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
- faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face
+ faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
+ faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
// +z
- faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face
+ faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
// out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
- vec3 result;
- for (int i = 0; i < 6; i++) {
- if (i == faceID) {
- result = (faceUvVectors[i][0] * uv.x) + (faceUvVectors[i][1] * uv.y) + faceUvVectors[i][2];
- break;
- }
- }
+ vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
return normalize(result);
}
-vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
- float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
-
+vec3 ImportanceSampleGGX(vec2 xi, float roughness4) {
// Compute distribution direction
- float Phi = 2.0 * M_PI * Xi.x;
- float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
+ float Phi = 2.0 * M_PI * xi.x;
+ float CosTheta = sqrt((1.0 - xi.y) / (1.0 + (roughness4 - 1.0) * xi.y));
float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
// Convert to spherical direction
@@ -139,12 +105,26 @@ vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
H.y = SinTheta * sin(Phi);
H.z = CosTheta;
- vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
- vec3 TangentX = normalize(cross(UpVector, N));
- vec3 TangentY = cross(N, TangentX);
+ return H;
+}
+
+float DistributionGGX(float NdotH, float roughness4) {
+ float NdotH2 = NdotH * NdotH;
+ float denom = (NdotH2 * (roughness4 - 1.0) + 1.0);
+ denom = M_PI * denom * denom;
+
+ return roughness4 / denom;
+}
+
+// https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float GGX(float NdotV, float a) {
+ float k = a / 2.0;
+ return NdotV / (NdotV * (1.0 - k) + k);
+}
- // Tangent to world space
- return TangentX * H.x + TangentY * H.y + N * H.z;
+// https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float G_Smith(float a, float nDotV, float nDotL) {
+ return GGX(nDotL, a * a) * GGX(nDotV, a * a);
}
float radical_inverse_VdC(int i) {
@@ -155,60 +135,54 @@ vec2 Hammersley(int i, int N) {
return vec2(float(i) / float(N), radical_inverse_VdC(i));
}
-uniform bool z_flip;
-
-layout(location = 0) out vec4 frag_color;
-
void main() {
vec3 color = vec3(0.0);
-
- vec2 uv = (uv_interp * 2.0) - 1.0;
+ vec2 uv = uv_interp;
vec3 N = texelCoordToVec(uv, face_id);
-#ifdef USE_DIRECT_WRITE
-
-#ifdef USE_SOURCE_PANORAMA
-
- frag_color = vec4(texturePanorama(source_panorama, N).rgb, 1.0);
-#else
-
- frag_color = vec4(textureCube(source_cube, N).rgb, 1.0);
-#endif //USE_SOURCE_PANORAMA
-
+#ifdef MODE_DIRECT_WRITE
+ frag_color = vec4(textureCubeLod(source_cube, N, 0.0).rgb, 1.0);
#else
vec4 sum = vec4(0.0);
+ float solid_angle_texel = 4.0 * M_PI / (6.0 * face_size * face_size);
+ float roughness2 = roughness * roughness;
+ float roughness4 = roughness2 * roughness2;
+ vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+ mat3 T;
+ T[0] = normalize(cross(UpVector, N));
+ T[1] = cross(N, T[0]);
+ T[2] = N;
- for (int sample_num = 0; sample_num < SAMPLE_COUNT; sample_num++) {
- vec2 xi = Hammersley(sample_num, SAMPLE_COUNT);
+ for (int sample_num = 0; sample_num < sample_count; sample_num++) {
+ vec2 xi = Hammersley(sample_num, sample_count);
- vec3 H = ImportanceSampleGGX(xi, roughness, N);
- vec3 V = N;
- vec3 L = (2.0 * dot(V, H) * H - V);
+ vec3 H = T * ImportanceSampleGGX(xi, roughness4);
+ float NdotH = dot(N, H);
+ vec3 L = (2.0 * NdotH * H - N);
float NdotL = clamp(dot(N, L), 0.0, 1.0);
if (NdotL > 0.0) {
+ float D = DistributionGGX(NdotH, roughness4);
+ float pdf = D * NdotH / (4.0 * NdotH) + 0.0001;
-#ifdef USE_SOURCE_PANORAMA
- vec3 val = texturePanorama(source_panorama, L).rgb;
-#else
- vec3 val = textureCubeLod(source_cube, L, 0.0).rgb;
-#endif
- //mix using Linear, to approximate high end back-end
- val = mix(pow((val + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), val * (1.0 / 12.92), vec3(lessThan(val, vec3(0.04045))));
+ float solid_angle_sample = 1.0 / (float(sample_count) * pdf + 0.0001);
- sum.rgb += val * NdotL;
+ float mipLevel = roughness == 0.0 ? 0.0 : 0.5 * log2(solid_angle_sample / solid_angle_texel);
+
+ vec3 val = textureCubeLod(source_cube, L, mipLevel).rgb;
+ // Mix using linear
+ val = srgb_to_linear(val);
+ sum.rgb += val * NdotL;
sum.a += NdotL;
}
}
sum /= sum.a;
- vec3 a = vec3(0.055);
- sum.rgb = mix((vec3(1.0) + a) * pow(sum.rgb, vec3(1.0 / 2.4)) - a, 12.92 * sum.rgb, vec3(lessThan(sum.rgb, vec3(0.0031308))));
-
+ sum.rgb = linear_to_srgb(sum.rgb);
frag_color = vec4(sum.rgb, 1.0);
#endif
}
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 12d70db7dd..198d1d9ec7 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -7,9 +7,12 @@ mode_depth = #define MODE_RENDER_DEPTH
#[specializations]
-USE_LIGHTMAP = false
-USE_LIGHT_DIRECTIONAL = false
-USE_LIGHT_POSITIONAL = false
+DISABLE_LIGHTMAP = false
+DISABLE_LIGHT_DIRECTIONAL = false
+DISABLE_LIGHT_OMNI = false
+DISABLE_LIGHT_SPOT = false
+DISABLE_FOG = false
+USE_RADIANCE_MAP = true
#[vertex]
@@ -109,12 +112,14 @@ layout(std140) uniform SceneData { // ubo:2
mediump vec4 ambient_light_color_energy;
mediump float ambient_color_sky_mix;
- uint ambient_flags;
bool material_uv2_mode;
- float opaque_prepass_threshold;
- //bool use_ambient_light;
- //bool use_ambient_cubemap;
- //bool use_reflection_cubemap;
+ float pad2;
+ bool use_ambient_light;
+ bool use_ambient_cubemap;
+ bool use_reflection_cubemap;
+
+ float fog_aerial_perspective;
+ float time;
mat3 radiance_inverse_xform;
@@ -130,13 +135,6 @@ layout(std140) uniform SceneData { // ubo:2
vec3 fog_light_color;
float fog_sun_scatter;
-
- float fog_aerial_perspective;
-
- float time;
- float reflection_multiplier; // one normally, zero when rendering reflections
-
- bool pancake_shadows;
}
scene_data;
@@ -169,7 +167,7 @@ out vec2 uv2_interp;
#endif
#endif
-#if defined(TANGENT_USED) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
out vec3 tangent_interp;
out vec3 binormal_interp;
#endif
@@ -191,9 +189,6 @@ layout(std140) uniform MaterialUniforms { // ubo:3
#GLOBALS
/* clang-format on */
-
-out highp vec4 position_interp;
-
invariant gl_Position;
void main() {
@@ -206,21 +201,16 @@ void main() {
#endif
highp mat3 model_normal_matrix = mat3(model_matrix);
-#if defined(TANGENT_USED) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
- vec3 tangent;
- float binormalf;
- tangent = normal_tangent_attrib.xyz;
- binormalf = normal_tangent_attrib.a;
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
+ float binormalf = tangent_attrib.a * 2.0 - 1.0;
+ vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
#if defined(COLOR_USED)
color_interp = color_attrib;
#endif
-#if defined(TANGENT_USED) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
- vec3 binormal = normalize(cross(normal, tangent) * binormalf);
-#endif
-
#if defined(UV_USED)
uv_interp = uv_attrib;
#endif
@@ -306,7 +296,7 @@ void main() {
normal_interp = normal;
#endif
-#if defined(TANGENT_USED) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
tangent_interp = tangent;
binormal_interp = binormal;
#endif
@@ -316,16 +306,6 @@ void main() {
#else
gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
#endif
-
-#ifdef MODE_RENDER_DEPTH
- if (scene_data.pancake_shadows) {
- if (gl_Position.z <= 0.00001) {
- gl_Position.z = 0.00001;
- }
- }
-#endif
-
- position_interp = gl_Position;
}
/* clang-format off */
@@ -357,10 +337,9 @@ void main() {
*/
-uniform highp mat4 world_transform;
+#define M_PI 3.14159265359
/* clang-format on */
-#define M_PI 3.14159265359
#define SHADER_IS_SRGB true
/* Varyings */
@@ -381,7 +360,7 @@ in vec2 uv2_interp;
#endif
#endif
-#if defined(TANGENT_USED) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
in vec3 tangent_interp;
in vec3 binormal_interp;
#endif
@@ -392,29 +371,11 @@ in vec3 normal_interp;
in highp vec3 vertex_interp;
-/* PBR CHANNELS */
-
#ifdef USE_RADIANCE_MAP
-layout(std140) uniform Radiance { // ubo:4
-
- mat4 radiance_inverse_xform;
- float radiance_ambient_contribution;
-};
-
#define RADIANCE_MAX_LOD 5.0
-uniform sampler2D radiance_map; // texunit:-2
-
-vec3 textureDualParaboloid(sampler2D p_tex, vec3 p_vec, float p_roughness) {
- vec3 norm = normalize(p_vec);
- norm.xy /= 1.0 + abs(norm.z);
- norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25);
- if (norm.z > 0.0) {
- norm.y = 0.5 - norm.y + 0.5;
- }
- return textureLod(p_tex, norm.xy, p_roughness * RADIANCE_MAX_LOD).xyz;
-}
+uniform samplerCube radiance_map; // texunit:-2
#endif
@@ -448,12 +409,14 @@ layout(std140) uniform SceneData { // ubo:2
mediump vec4 ambient_light_color_energy;
mediump float ambient_color_sky_mix;
- uint ambient_flags;
bool material_uv2_mode;
- float opaque_prepass_threshold;
- //bool use_ambient_light;
- //bool use_ambient_cubemap;
- //bool use_reflection_cubemap;
+ float pad2;
+ bool use_ambient_light;
+ bool use_ambient_cubemap;
+ bool use_reflection_cubemap;
+
+ float fog_aerial_perspective;
+ float time;
mat3 radiance_inverse_xform;
@@ -469,13 +432,6 @@ layout(std140) uniform SceneData { // ubo:2
vec3 fog_light_color;
float fog_sun_scatter;
-
- float fog_aerial_perspective;
-
- float time;
- float reflection_multiplier; // one normally, zero when rendering reflections
-
- bool pancake_shadows;
}
scene_data;
@@ -487,7 +443,7 @@ scene_data;
//directional light data
-#ifdef USE_LIGHT_DIRECTIONAL
+#ifndef DISABLE_LIGHT_DIRECTIONAL
struct DirectionalLightData {
mediump vec3 direction;
@@ -498,10 +454,14 @@ struct DirectionalLightData {
mediump float specular;
};
+layout(std140) uniform DirectionalLights { // ubo:7
+ DirectionalLightData directional_lights[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+};
+
#endif
// omni and spot
-#ifdef USE_LIGHT_POSITIONAL
+#if !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
struct LightData { //this structure needs to be as packed as possible
highp vec3 position;
highp float inv_radius;
@@ -517,36 +477,38 @@ struct LightData { //this structure needs to be as packed as possible
mediump float specular_amount;
bool shadow_enabled;
};
-
+#ifndef DISABLE_LIGHT_OMNI
layout(std140) uniform OmniLightData { // ubo:5
LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
};
+uniform uint omni_light_indices[MAX_FORWARD_LIGHTS];
+uniform int omni_light_count;
+#endif
+
+#ifndef DISABLE_LIGHT_SPOT
layout(std140) uniform SpotLightData { // ubo:6
LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
};
-
-uniform highp samplerCubeShadow positional_shadow; // texunit:-6
-
-uniform int omni_light_indices[MAX_FORWARD_LIGHTS];
-uniform int omni_light_count;
-
-uniform int spot_light_indices[MAX_FORWARD_LIGHTS];
+uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
uniform int spot_light_count;
+#endif
-uniform int reflection_indices[MAX_FORWARD_LIGHTS];
-uniform int reflection_count;
-
+#ifdef USE_ADDITIVE_LIGHTING
+uniform highp samplerCubeShadow positional_shadow; // texunit:-4
#endif
+#endif // !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
+
uniform highp sampler2D screen_texture; // texunit:-5
uniform highp sampler2D depth_buffer; // texunit:-6
-layout(location = 0) out vec4 frag_color;
+uniform highp mat4 world_transform;
+uniform mediump float opaque_prepass_threshold;
-in highp vec4 position_interp;
+layout(location = 0) out vec4 frag_color;
vec3 F0(float metallic, float specular, vec3 albedo) {
float dielectric = 0.16 * specular * specular;
@@ -555,7 +517,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
return mix(vec3(dielectric), albedo, vec3(metallic));
}
-#if defined(USE_LIGHT_DIRECTIONAL) || defined(USE_LIGHT_POSITIONAL)
+#if !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
float D_GGX(float cos_theta_m, float alpha) {
float a = cos_theta_m * alpha;
float k = alpha / (1.0 - cos_theta_m * cos_theta_m + a * a);
@@ -588,7 +550,7 @@ float SchlickFresnel(float u) {
return m2 * m2 * m; // pow(m,5)
}
-void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, vec3 albedo, inout float alpha,
+void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 f0, float roughness, float metallic, float specular_amount, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -603,11 +565,6 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
#endif
inout vec3 diffuse_light, inout vec3 specular_light) {
- vec4 orms_unpacked = unpackUnorm4x8(orms);
-
- float roughness = orms_unpacked.y;
- float metallic = orms_unpacked.z;
-
#if defined(USE_LIGHT_SHADER_CODE)
// light is written by the light shader
@@ -626,7 +583,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
float NdotL = min(A + dot(N, L), 1.0);
float cNdotL = max(NdotL, 0.0); // clamped NdotL
float NdotV = dot(N, V);
- float cNdotV = max(NdotV, 0.0);
+ float cNdotV = max(NdotV, 1e-4);
#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
vec3 H = normalize(V + L);
@@ -752,15 +709,10 @@ float get_omni_attenuation(float distance, float inv_range, float decay) {
return nd * pow(max(distance, 0.0001), -decay);
}
-void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha,
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
- vec4 transmittance_color,
- float transmittance_depth,
- float transmittance_boost,
-#endif
#ifdef LIGHT_RIM_USED
float rim, float rim_tint,
#endif
@@ -774,16 +726,15 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
vec3 light_rel_vec = omni_lights[idx].position - vertex;
float light_length = length(light_rel_vec);
float omni_attenuation = get_omni_attenuation(light_length, omni_lights[idx].inv_radius, omni_lights[idx].attenuation);
- vec3 light_attenuation = vec3(omni_attenuation);
vec3 color = omni_lights[idx].color;
float size_A = 0.0;
- if (omni_lights.data[idx].size > 0.0) {
+ if (omni_lights[idx].size > 0.0) {
float t = omni_lights[idx].size / max(0.001, light_length);
size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
}
- light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, omni_lights[idx].specular_amount, albedo, alpha,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -800,7 +751,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
specular_light);
}
-void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha,
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -823,17 +774,16 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights[idx].cone_angle);
float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights[idx].cone_angle));
spot_attenuation *= 1.0 - pow(spot_rim, spot_lights[idx].cone_attenuation);
- float light_attenuation = spot_attenuation;
vec3 color = spot_lights[idx].color;
float size_A = 0.0;
- if (spot_lights.data[idx].size > 0.0) {
- float t = spot_lights.data[idx].size / max(0.001, light_length);
+ if (spot_lights[idx].size > 0.0) {
+ float t = spot_lights[idx].size / max(0.001, light_length);
size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
}
- light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, spot_lights[idx].specular_amount, albedo, alpha,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -848,7 +798,56 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
#endif
diffuse_light, specular_light);
}
-#endif // defined(USE_LIGHT_DIRECTIONAL) || defined(USE_LIGHT_POSITIONAL)
+#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
+
+#ifndef MODE_RENDER_DEPTH
+vec4 fog_process(vec3 vertex) {
+ vec3 fog_color = scene_data.fog_light_color;
+
+#ifdef USE_RADIANCE_MAP
+/*
+ if (scene_data.fog_aerial_perspective > 0.0) {
+ vec3 sky_fog_color = vec3(0.0);
+ vec3 cube_view = scene_data.radiance_inverse_xform * vertex;
+ // mip_level always reads from the second mipmap and higher so the fog is always slightly blurred
+ float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near));
+
+ sky_fog_color = textureCubeLod(radiance_map, cube_view, mip_level * RADIANCE_MAX_LOD).rgb;
+
+ fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective);
+ }
+ */
+#endif
+
+#ifndef DISABLE_LIGHT_DIRECTIONAL
+ if (scene_data.fog_sun_scatter > 0.001) {
+ vec4 sun_scatter = vec4(0.0);
+ float sun_total = 0.0;
+ vec3 view = normalize(vertex);
+ for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
+ vec3 light_color = directional_lights[i].color * directional_lights[i].energy;
+ float light_amount = pow(max(dot(view, directional_lights[i].direction), 0.0), 8.0);
+ fog_color += light_color * light_amount * scene_data.fog_sun_scatter;
+ }
+ }
+#endif // !DISABLE_LIGHT_DIRECTIONAL
+
+ float fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density));
+
+ if (abs(scene_data.fog_height_density) >= 0.0001) {
+ float y = (scene_data.inv_view_matrix * vec4(vertex, 1.0)).y;
+
+ float y_dist = y - scene_data.fog_height;
+
+ float vfog_amount = 1.0 - exp(min(0.0, y_dist * scene_data.fog_height_density));
+
+ fog_amount = max(vfog_amount, fog_amount);
+ }
+
+ return vec4(fog_color, fog_amount);
+}
+
+#endif // !MODE_RENDER_DEPTH
void main() {
//lay out everything, whatever is unused is optimized away anyway
@@ -951,7 +950,7 @@ void main() {
#ifdef USE_OPAQUE_PREPASS
#if !defined(ALPHA_SCISSOR_USED)
- if (alpha < scene_data.opaque_prepass_threshold) {
+ if (alpha < opaque_prepass_threshold) {
discard;
}
@@ -982,9 +981,31 @@ void main() {
#endif
#ifndef MODE_RENDER_DEPTH
+
+#ifndef CUSTOM_FOG_USED
+#ifndef DISABLE_FOG
+ // fog must be processed as early as possible and then packed.
+ // to maximize VGPR usage
+
+ if (scene_data.fog_enabled) {
+ fog = fog_process(vertex);
+ }
+#endif // !DISABLE_FOG
+#endif //!CUSTOM_FOG_USED
+
+ uint fog_rg = packHalf2x16(fog.rg);
+ uint fog_ba = packHalf2x16(fog.ba);
+
+#endif //!MODE_RENDER_DEPTH
+
+#ifndef MODE_RENDER_DEPTH
+
+ // Convert colors to linear
+ albedo = srgb_to_linear(albedo);
+ emission = srgb_to_linear(emission);
+ // TODO Backlight and transmittance when used
+#ifndef MODE_UNSHADED
vec3 f0 = F0(metallic, specular, albedo);
- // Convert albedo to linear. Approximation from: http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
- albedo = albedo * (albedo * (albedo * 0.305306011 + 0.682171111) + 0.012522878);
vec3 specular_light = vec3(0.0, 0.0, 0.0);
vec3 diffuse_light = vec3(0.0, 0.0, 0.0);
vec3 ambient_light = vec3(0.0, 0.0, 0.0);
@@ -996,15 +1017,58 @@ void main() {
float ndotv = clamp(dot(normal, view), 0.0, 1.0);
vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0);
- // Calculate IBL
+#ifdef USE_RADIANCE_MAP
+ if (scene_data.use_reflection_cubemap) {
+#ifdef LIGHT_ANISOTROPY_USED
+ // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
+ vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent;
+ vec3 anisotropic_tangent = cross(anisotropic_direction, view);
+ vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction);
+ vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0)));
+ vec3 ref_vec = reflect(-view, bent_normal);
+#else
+ vec3 ref_vec = reflect(-view, normal);
+#endif
+ float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
+ ref_vec = scene_data.radiance_inverse_xform * ref_vec;
+ specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).rgb;
+ specular_light = srgb_to_linear(specular_light);
+ specular_light *= horizon * horizon;
+ specular_light *= scene_data.ambient_light_color_energy.a;
+ }
+#endif
+
// Calculate Reflection probes
- // Caclculate Lightmaps
+ // Calculate Lightmaps
- float specular_blob_intensity = 1.0;
+#if defined(CUSTOM_RADIANCE_USED)
+ specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a);
+#endif // CUSTOM_RADIANCE_USED
-#if defined(SPECULAR_TOON)
- specular_blob_intensity *= specular * 2.0;
+#ifndef USE_LIGHTMAP
+ //lightmap overrides everything
+ if (scene_data.use_ambient_light) {
+ ambient_light = scene_data.ambient_light_color_energy.rgb;
+#ifdef USE_RADIANCE_MAP
+ if (scene_data.use_ambient_cubemap) {
+ vec3 ambient_dir = scene_data.radiance_inverse_xform * normal;
+ vec3 cubemap_ambient = textureCubeLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).rgb;
+ cubemap_ambient = srgb_to_linear(cubemap_ambient);
+ ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix);
+ }
#endif
+ }
+#endif // USE_LIGHTMAP
+
+#if defined(CUSTOM_IRRADIANCE_USED)
+ ambient_light = mix(ambient_light, custom_irradiance.rgb, custom_irradiance.a);
+#endif // CUSTOM_IRRADIANCE_USED
+ ambient_light *= albedo.rgb;
+
+ ambient_light *= ao;
+
+ // convert ao to direct light ao
+ ao = mix(1.0, ao, ao_light_affect);
{
#if defined(DIFFUSE_TOON)
@@ -1029,36 +1093,34 @@ void main() {
#endif // BASE_PASS
- //this saves some VGPRs
- uint orms = packUnorm4x8(vec4(ao, roughness, metallic, specular));
-
-#ifdef USE_LIGHT_DIRECTIONAL
-
- float size_A = directional_lights[i].size;
-
- light_compute(normal, directional_lights[i].direction, normalize(view), size_A, directional_lights[i].color * directional_lights[i].energy, shadow, f0, orms, 1.0, albedo, alpha,
+#ifndef DISABLE_LIGHT_DIRECTIONAL
+ //diffuse_light = normal; //
+ for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
+ light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, 1.0, f0, roughness, metallic, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
- backlight,
+ backlight,
#endif
#ifdef LIGHT_RIM_USED
- rim, rim_tint,
+ rim, rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_roughness, normalize(normal_interp),
+ clearcoat, clearcoat_roughness, normalize(normal_interp),
#endif
#ifdef LIGHT_ANISOTROPY_USED
- binormal,
- tangent, anisotropy,
+ binormal,
+ tangent, anisotropy,
#endif
- diffuse_light,
- specular_light);
-
-#endif //#USE_LIGHT_DIRECTIONAL
+ diffuse_light,
+ specular_light);
+ }
+#endif //!DISABLE_LIGHT_DIRECTIONAL
-#ifdef USE_LIGHT_POSITIONAL
- float shadow = 0.0;
- for (int i = 0; i < omni_light_count; i++) {
- light_process_omni(omni_light_indices[i], vertex, view, normal, f0, orms, shadow, albedo, alpha,
+#ifndef DISABLE_LIGHT_OMNI
+ for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) {
+ if (i >= omni_light_count) {
+ break;
+ }
+ light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 0.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1070,13 +1132,18 @@ void main() {
clearcoat, clearcoat_roughness, normalize(normal_interp),
#endif
#ifdef LIGHT_ANISOTROPY_USED
- tangent, binormal, anisotropy,
+ binormal, tangent, anisotropy,
#endif
diffuse_light, specular_light);
}
+#endif // !DISABLE_LIGHT_OMNI
- for (int i = 0; i < spot_light_count; i++) {
- light_process_spot(spot_light_indices[i], vertex, view, normal, f0, orms, shadow, albedo, alpha,
+#ifndef DISABLE_LIGHT_SPOT
+ for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) {
+ if (i >= spot_light_count) {
+ break;
+ }
+ light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 0.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1094,8 +1161,9 @@ void main() {
diffuse_light, specular_light);
}
-#endif // USE_LIGHT_POSITIONAL
-#endif //!MODE_RENDER_DEPTH
+#endif // !DISABLE_LIGHT_SPOT
+#endif // !MODE_UNSHADED
+#endif // !MODE_RENDER_DEPTH
#if defined(USE_SHADOW_TO_OPACITY)
alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
@@ -1122,21 +1190,31 @@ void main() {
//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
#else // !MODE_RENDER_DEPTH
- specular_light *= scene_data.reflection_multiplier;
- ambient_light *= albedo; //ambient must be multiplied by albedo at the end
+#ifdef MODE_UNSHADED
+ frag_color = vec4(albedo, alpha);
+#else
+
+ diffuse_light *= albedo;
- // base color remapping
diffuse_light *= 1.0 - metallic;
ambient_light *= 1.0 - metallic;
-#ifdef MODE_UNSHADED
- frag_color = vec4(albedo, alpha);
-#else
- frag_color = vec4(ambient_light + diffuse_light + specular_light, alpha);
+ frag_color = vec4(diffuse_light + specular_light, alpha);
#ifdef BASE_PASS
- frag_color.rgb += emission;
+ frag_color.rgb += emission + ambient_light;
#endif
#endif //MODE_UNSHADED
+ fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
+
+#ifndef DISABLE_FOG
+ if (scene_data.fog_enabled) {
+#ifdef BASE_PASS
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+#else
+ frag_color.rgb *= (1.0 - fog.a);
+#endif // BASE_PASS
+ }
+#endif
// Tonemap before writing as we are writing to an sRGB framebuffer
frag_color.rgb *= exposure;
diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl
index 3a1bcd3b28..50ab38bc31 100644
--- a/drivers/gles3/shaders/sky.glsl
+++ b/drivers/gles3/shaders/sky.glsl
@@ -12,13 +12,13 @@ mode_cubemap_quarter_res = #define USE_CUBEMAP_PASS \n#define USE_QUARTER_RES_PA
#[vertex]
+layout(location = 0) in vec2 vertex_attrib;
+
out vec2 uv_interp;
/* clang-format on */
void main() {
- // One big triangle to cover the whole screen
- vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));
- uv_interp = base_arr[gl_VertexID];
+ uv_interp = vertex_attrib;
gl_Position = vec4(uv_interp, 1.0, 1.0);
}
@@ -46,18 +46,13 @@ layout(std140) uniform GlobalVariableData { //ubo:1
vec4 global_variables[MAX_GLOBAL_VARIABLES];
};
-layout(std140) uniform SceneData { //ubo:2
- float pad1;
- float pad2;
-};
-
struct DirectionalLightData {
vec4 direction_energy;
vec4 color_size;
bool enabled;
};
-layout(std140) uniform DirectionalLights { //ubo:3
+layout(std140) uniform DirectionalLights { //ubo:4
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
@@ -65,7 +60,7 @@ directional_lights;
/* clang-format off */
#ifdef MATERIAL_UNIFORMS_USED
-layout(std140) uniform MaterialUniforms{ //ubo:4
+layout(std140) uniform MaterialUniforms{ //ubo:3
#MATERIAL_UNIFORMS
@@ -98,6 +93,14 @@ uniform vec4 projection;
uniform vec3 position;
uniform float time;
+uniform float fog_aerial_perspective;
+uniform vec3 fog_light_color;
+uniform float fog_sun_scatter;
+uniform bool fog_enabled;
+uniform float fog_density;
+uniform float z_far;
+uniform uint directional_light_count;
+
layout(location = 0) out vec4 frag_color;
void main() {
@@ -106,12 +109,11 @@ void main() {
cube_normal.x = (uv_interp.x + projection.x) / projection.y;
cube_normal.y = (-uv_interp.y - projection.z) / projection.w;
cube_normal = mat3(orientation) * cube_normal;
- cube_normal.z = -cube_normal.z;
cube_normal = normalize(cube_normal);
vec2 uv = gl_FragCoord.xy; // uv_interp * 0.5 + 0.5;
- vec2 panorama_coords = vec2(atan(cube_normal.x, cube_normal.z), acos(cube_normal.y));
+ vec2 panorama_coords = vec2(atan(cube_normal.x, -cube_normal.z), acos(cube_normal.y));
if (panorama_coords.x < 0.0) {
panorama_coords.x += M_PI * 2.0;
@@ -126,13 +128,11 @@ void main() {
vec4 custom_fog = vec4(0.0);
#ifdef USE_CUBEMAP_PASS
- vec3 inverted_cube_normal = cube_normal;
- inverted_cube_normal.z *= -1.0;
#ifdef USES_HALF_RES_COLOR
- half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
+ half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal);
#endif
#ifdef USES_QUARTER_RES_COLOR
- quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
+ quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal);
#endif
#else
#ifdef USES_HALF_RES_COLOR
@@ -149,7 +149,8 @@ void main() {
}
- // Tonemap before writing as we are writing to an sRGB framebuffer
+ // Convert to Linear for tonemapping so color matches scene shader better
+ color = srgb_to_linear(color);
color *= exposure;
color = apply_tonemapping(color, white);
color = linear_to_srgb(color);
diff --git a/drivers/gles3/shaders/stdlib_inc.glsl b/drivers/gles3/shaders/stdlib_inc.glsl
index 6cce6c12bd..d5051760d7 100644
--- a/drivers/gles3/shaders/stdlib_inc.glsl
+++ b/drivers/gles3/shaders/stdlib_inc.glsl
@@ -42,11 +42,11 @@ vec2 unpackSnorm2x16(uint p) {
uint packUnorm4x8(vec4 v) {
uvec4 uv = uvec4(round(clamp(v, vec4(0.0), vec4(1.0)) * 255.0));
- return uv.x | uv.y << uint(8) | uv.z << uint(16) | uv.w << uint(24);
+ return uv.x | (uv.y << uint(8)) | (uv.z << uint(16)) | (uv.w << uint(24));
}
vec4 unpackUnorm4x8(uint p) {
- return vec4(float(p & uint(0xffff)), float((p >> uint(8)) & uint(0xffff)), float((p >> uint(16)) & uint(0xffff)), float(p >> uint(24))) * 0.00392156862; // 1.0 / 255.0
+ return vec4(float(p & uint(0xff)), float((p >> uint(8)) & uint(0xff)), float((p >> uint(16)) & uint(0xff)), float(p >> uint(24))) * 0.00392156862; // 1.0 / 255.0
}
uint packSnorm4x8(vec4 v) {
@@ -55,6 +55,6 @@ uint packSnorm4x8(vec4 v) {
}
vec4 unpackSnorm4x8(uint p) {
- vec4 v = vec4(float(p & uint(0xffff)), float((p >> uint(8)) & uint(0xffff)), float((p >> uint(16)) & uint(0xffff)), float(p >> uint(24)));
+ vec4 v = vec4(float(p & uint(0xff)), float((p >> uint(8)) & uint(0xff)), float((p >> uint(16)) & uint(0xff)), float(p >> uint(24)));
return clamp((v - vec4(127.0)) * vec4(0.00787401574), vec4(-1.0), vec4(1.0));
}
diff --git a/drivers/gles3/shaders/tonemap_inc.glsl b/drivers/gles3/shaders/tonemap_inc.glsl
index ea15c05359..f8f12760ec 100644
--- a/drivers/gles3/shaders/tonemap_inc.glsl
+++ b/drivers/gles3/shaders/tonemap_inc.glsl
@@ -92,11 +92,19 @@ vec3 tonemap_reinhard(vec3 color, float p_white) {
return (p_white * color + color) / (color * p_white + p_white);
}
+// This expects 0-1 range input.
vec3 linear_to_srgb(vec3 color) {
- //if going to srgb, clamp from 0 to 1.
- color = clamp(color, vec3(0.0), vec3(1.0));
- const vec3 a = vec3(0.055f);
- return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
+ //color = clamp(color, vec3(0.0), vec3(1.0));
+ //const vec3 a = vec3(0.055f);
+ //return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
+ // Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
+ return max(vec3(1.055) * pow(color, vec3(0.416666667)) - vec3(0.055), vec3(0.0));
+}
+
+// This expects 0-1 range input, outside that range it behaves poorly.
+vec3 srgb_to_linear(vec3 color) {
+ // Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
+ return color * (color * (color * 0.305306011 + 0.682171111) + 0.012522878);
}
#define TONEMAPPER_LINEAR 0
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 5ce02f6825..e93c503396 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1024,6 +1024,7 @@ MaterialData::~MaterialData() {
if (uniform_buffer) {
glDeleteBuffers(1, &uniform_buffer);
+ uniform_buffer = 0;
}
}
@@ -1677,9 +1678,6 @@ ShaderCompiler::DefaultIdentifierActions actions;
//shaders.copy.initialize();
//shaders.copy_version = shaders.copy.version_create(); //TODO
//shaders.copy.version_bind_shader(shaders.copy_version, CopyShaderGLES3::MODE_COPY_SECTION);
- //shaders.cubemap_filter.init();
- //bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx");
- //shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY, !ggx_hq);
}
MaterialStorage::~MaterialStorage() {
@@ -3133,6 +3131,7 @@ GLES3::ShaderData *GLES3::_create_sky_shader_func() {
// Sky material
void SkyMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ uniform_set_updated = true;
return update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
}
diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h
index d6f15e7056..6a11a10d76 100644
--- a/drivers/gles3/storage/material_storage.h
+++ b/drivers/gles3/storage/material_storage.h
@@ -45,6 +45,7 @@
#include "drivers/gles3/shaders/copy.glsl.gen.h"
#include "../shaders/canvas.glsl.gen.h"
+#include "../shaders/cubemap_filter.glsl.gen.h"
#include "../shaders/scene.glsl.gen.h"
#include "../shaders/sky.glsl.gen.h"
@@ -56,6 +57,7 @@ struct Shaders {
CanvasShaderGLES3 canvas_shader;
SkyShaderGLES3 sky_shader;
SceneShaderGLES3 scene_shader;
+ CubemapFilterShaderGLES3 cubemap_filter_shader;
ShaderCompiler compiler_canvas;
ShaderCompiler compiler_scene;
@@ -241,6 +243,7 @@ ShaderData *_create_sky_shader_func();
struct SkyMaterialData : public MaterialData {
SkyShaderData *shader_data = nullptr;
+ bool uniform_set_updated = false;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
@@ -458,8 +461,6 @@ private:
SelfList<Material>::List material_update_list;
- //static void _material_uniform_set_erased(void *p_material);
-
public:
static MaterialStorage *get_singleton();
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index e754d6150a..5739a63cac 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -570,24 +570,29 @@ void MeshStorage::mesh_clear(RID p_mesh) {
if (s.vertex_buffer != 0) {
glDeleteBuffers(1, &s.vertex_buffer);
+ s.vertex_buffer = 0;
}
if (s.version_count != 0) {
for (uint32_t j = 0; j < s.version_count; j++) {
glDeleteVertexArrays(1, &s.versions[j].vertex_array);
+ s.versions[j].vertex_array = 0;
}
}
if (s.attribute_buffer != 0) {
glDeleteBuffers(1, &s.attribute_buffer);
+ s.attribute_buffer = 0;
}
if (s.skin_buffer != 0) {
glDeleteBuffers(1, &s.skin_buffer);
+ s.skin_buffer = 0;
}
if (s.index_buffer != 0) {
glDeleteBuffers(1, &s.index_buffer);
+ s.index_buffer = 0;
}
memdelete(mesh->surfaces[i]);
}
@@ -804,17 +809,20 @@ void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
if (mi->surfaces[i].version_count != 0) {
for (uint32_t j = 0; j < mi->surfaces[i].version_count; j++) {
glDeleteVertexArrays(1, &mi->surfaces[i].versions[j].vertex_array);
+ mi->surfaces[i].versions[j].vertex_array = 0;
}
memfree(mi->surfaces[i].versions);
}
if (mi->surfaces[i].vertex_buffer != 0) {
glDeleteBuffers(1, &mi->surfaces[i].vertex_buffer);
+ mi->surfaces[i].vertex_buffer = 0;
}
}
mi->surfaces.clear();
if (mi->blend_weights_buffer != 0) {
glDeleteBuffers(1, &mi->blend_weights_buffer);
+ mi->blend_weights_buffer = 0;
}
mi->blend_weights.clear();
mi->weights_dirty = false;
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 4396ca4f93..f932fa8bad 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -554,7 +554,7 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
} break;
*/
default: {
- ERR_FAIL_V(Ref<Image>());
+ ERR_FAIL_V_MSG(Ref<Image>(), "Image Format: " + itos(p_format) + " is not supported by the OpenGL3 Renderer");
}
}
@@ -968,7 +968,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
Image::Format real_format;
Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), 0, real_format, format, internal_format, type, compressed, texture->resize_to_po2);
-
+ ERR_FAIL_COND(img.is_null());
if (texture->resize_to_po2) {
if (p_image->is_compressed()) {
ERR_PRINT("Texture '" + texture->path + "' is required to be a power of 2 because it uses either mipmaps or repeat, so it was decompressed. This will hurt performance and memory usage.");
@@ -1325,6 +1325,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
rt->color_internal_format = rt->flags[RENDER_TARGET_TRANSPARENT] ? GL_RGBA8 : GL_RGB10_A2;
rt->color_format = GL_RGBA;
+ rt->color_type = rt->flags[RENDER_TARGET_TRANSPARENT] ? GL_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
rt->image_format = Image::FORMAT_RGBA8;
glDisable(GL_SCISSOR_TEST);
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 8281b8c596..b092a009c1 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -249,7 +249,10 @@ struct Texture {
[[fallthrough]];
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
pmag = GL_NEAREST;
- if (config->use_nearest_mip_filter) {
+ if (mipmaps <= 1) {
+ pmin = GL_NEAREST;
+ max_lod = 0;
+ } else if (config->use_nearest_mip_filter) {
pmin = GL_NEAREST_MIPMAP_NEAREST;
} else {
pmin = GL_NEAREST_MIPMAP_LINEAR;
@@ -261,9 +264,11 @@ struct Texture {
[[fallthrough]];
case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
pmag = GL_LINEAR;
- if (config->use_nearest_mip_filter) {
+ if (mipmaps <= 1) {
+ pmin = GL_LINEAR;
+ max_lod = 0;
+ } else if (config->use_nearest_mip_filter) {
pmin = GL_LINEAR_MIPMAP_NEAREST;
-
} else {
pmin = GL_LINEAR_MIPMAP_LINEAR;
}