summaryrefslogtreecommitdiff
path: root/drivers/gles3/rasterizer_scene_gles3.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gles3/rasterizer_scene_gles3.cpp')
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp1055
1 files changed, 930 insertions, 125 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