summaryrefslogtreecommitdiff
path: root/drivers/gles2
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gles2')
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.cpp42
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.h3
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp57
-rw-r--r--drivers/gles2/rasterizer_gles2.h1
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp104
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.h33
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp31
-rw-r--r--drivers/gles2/shaders/SCsub1
-rw-r--r--drivers/gles2/shaders/canvas.glsl11
-rw-r--r--drivers/gles2/shaders/lens_distorted.glsl62
-rw-r--r--drivers/gles2/shaders/scene.glsl246
11 files changed, 525 insertions, 66 deletions
diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp
index 263f210fa2..18b5dd3483 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.cpp
+++ b/drivers/gles2/rasterizer_canvas_gles2.cpp
@@ -1049,6 +1049,43 @@ void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &p_rect, cons
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
+void RasterizerCanvasGLES2::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {
+ Vector2 half_size;
+ if (storage->frame.current_rt) {
+ half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height);
+ } else {
+ half_size = OS::get_singleton()->get_window_size();
+ }
+ half_size *= 0.5;
+ Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y);
+ Vector2 scale(p_rect.size.x / half_size.x, p_rect.size.y / half_size.y);
+
+ float aspect_ratio = p_rect.size.x / p_rect.size.y;
+
+ // setup our lens shader
+ state.lens_shader.bind();
+ state.lens_shader.set_uniform(LensDistortedShaderGLES2::OFFSET, offset);
+ state.lens_shader.set_uniform(LensDistortedShaderGLES2::SCALE, scale);
+ state.lens_shader.set_uniform(LensDistortedShaderGLES2::K1, p_k1);
+ state.lens_shader.set_uniform(LensDistortedShaderGLES2::K2, p_k2);
+ state.lens_shader.set_uniform(LensDistortedShaderGLES2::EYE_CENTER, p_eye_center);
+ state.lens_shader.set_uniform(LensDistortedShaderGLES2::UPSCALE, p_oversample);
+ state.lens_shader.set_uniform(LensDistortedShaderGLES2::ASPECT_RATIO, aspect_ratio);
+
+ // bind our quad buffer
+ _bind_quad_buffer();
+
+ // and draw
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // and cleanup
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ for (int i = 0; i < VS::ARRAY_MAX; i++) {
+ glDisableVertexAttribArray(i);
+ }
+}
+
void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_image) {
}
@@ -1148,7 +1185,6 @@ void RasterizerCanvasGLES2::initialize() {
_EIDX(1, 1), _EIDX(1, 2), _EIDX(2, 2),
_EIDX(2, 2), _EIDX(2, 1), _EIDX(1, 1)
};
- ;
#undef _EIDX
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elems), elems, GL_STATIC_DRAW);
@@ -1161,6 +1197,10 @@ void RasterizerCanvasGLES2::initialize() {
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
state.canvas_shader.bind();
+
+ state.lens_shader.init();
+
+ state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false));
}
void RasterizerCanvasGLES2::finalize() {
diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h
index cda3ec79e7..cf1c239b6e 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.h
+++ b/drivers/gles2/rasterizer_canvas_gles2.h
@@ -34,6 +34,7 @@
#include "servers/visual/rasterizer.h"
#include "shaders/canvas.glsl.gen.h"
+#include "shaders/lens_distorted.glsl.gen.h"
// #include "shaders/canvas_shadow.glsl.gen.h"
@@ -70,6 +71,7 @@ public:
bool canvas_texscreen_used;
CanvasShaderGLES2 canvas_shader;
// CanvasShadowShaderGLES3 canvas_shadow_shader;
+ LensDistortedShaderGLES2 lens_shader;
bool using_texture_rect;
bool using_ninepatch;
@@ -117,6 +119,7 @@ public:
void _bind_quad_buffer();
void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src);
+ void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
void initialize();
void finalize();
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index 1dd594cc20..848ac8b78f 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -64,6 +64,17 @@
#define GLAPIENTRY
#endif
+#if !defined(GLES_OVER_GL) && !defined(IPHONE_ENABLED)
+// Used for debugging on mobile, but not iOS as EGL is not available
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2platform.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif
+
+#ifndef IPHONE_ENABLED
static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) {
if (type == _EXT_DEBUG_TYPE_OTHER_ARB)
@@ -110,6 +121,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL
ERR_PRINTS(output);
}
+#endif // IPHONE_ENABLED
typedef void (*DEBUGPROCARB)(GLenum source,
GLenum type,
@@ -179,7 +191,7 @@ Error RasterizerGLES2::is_viable() {
return ERR_UNAVAILABLE;
}
}
-#endif
+#endif // GLES_OVER_GL
#endif // GLAD_ENABLED
@@ -191,7 +203,7 @@ void RasterizerGLES2::initialize() {
print_verbose("Using GLES2 video driver");
#ifdef GLAD_ENABLED
- if (true || OS::get_singleton()->is_stdout_verbose()) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
if (GLAD_GL_ARB_debug_output) {
glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
glDebugMessageCallbackARB(_gl_debug_print, NULL);
@@ -204,7 +216,7 @@ void RasterizerGLES2::initialize() {
// For debugging
#ifdef GLES_OVER_GL
- if (GLAD_GL_ARB_debug_output) {
+ if (OS::get_singleton()->is_stdout_verbose() && GLAD_GL_ARB_debug_output) {
glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_ERROR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
@@ -217,7 +229,24 @@ void RasterizerGLES2::initialize() {
GL_DEBUG_SEVERITY_HIGH_ARB, 5, "hello");
*/
}
-#endif
+#else
+#ifndef IPHONE_ENABLED
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ DebugMessageCallbackARB callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallback");
+ if (!callback) {
+ callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallbackKHR");
+ }
+
+ if (callback) {
+
+ print_line("godot: ENABLING GL DEBUG");
+ glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+ callback(_gl_debug_print, NULL);
+ glEnable(_EXT_DEBUG_OUTPUT);
+ }
+ }
+#endif // !IPHONE_ENABLED
+#endif // GLES_OVER_GL
const GLubyte *renderer = glGetString(GL_RENDERER);
print_line("OpenGL ES 2.0 Renderer: " + String((const char *)renderer));
@@ -380,6 +409,26 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re
canvas->canvas_end();
}
+void RasterizerGLES2::output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {
+ ERR_FAIL_COND(storage->frame.current_rt);
+
+ RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ glDisable(GL_BLEND);
+
+ // render to our framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
+
+ // output our texture
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, rt->color);
+
+ canvas->draw_lens_distortion_rect(p_screen_rect, p_k1, p_k2, p_eye_center, p_oversample);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
void RasterizerGLES2::end_frame(bool p_swap_buffers) {
if (OS::get_singleton()->is_layered_allowed()) {
diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h
index 45a9db73f2..97f8ee7c1c 100644
--- a/drivers/gles2/rasterizer_gles2.h
+++ b/drivers/gles2/rasterizer_gles2.h
@@ -59,6 +59,7 @@ public:
virtual void restore_render_target();
virtual void clear_render_target(const Color &p_color);
virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0);
+ virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
virtual void end_frame(bool p_swap_buffers);
virtual void finalize();
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 22cc45a0f6..fbcbebc88c 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -42,6 +42,8 @@
#define glClearDepth glClearDepthf
#endif
+#define _DEPTH_COMPONENT24_OES 0x81A6
+
static const GLenum _cube_side_enum[6] = {
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
@@ -461,7 +463,8 @@ RID RasterizerSceneGLES2::reflection_probe_instance_create(RID p_probe) {
glGenFramebuffers(1, &rpi->fbo_blur);
glGenRenderbuffers(1, &rpi->depth);
- glGenTextures(1, &rpi->cubemap);
+ rpi->cubemap = 0;
+ //glGenTextures(1, &rpi->cubemap);
return rpi->self;
}
@@ -502,14 +505,37 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance
int size = rpi->probe_ptr->resolution;
rpi->current_resolution = size;
- int lod = 0;
-
- GLenum internal_format = GL_RGBA;
- GLenum format = GL_RGBA;
+ GLenum internal_format = GL_RGB;
+ GLenum format = GL_RGB;
GLenum type = GL_UNSIGNED_BYTE;
glActiveTexture(GL_TEXTURE0);
+ if (rpi->cubemap != 0) {
+ glDeleteTextures(1, &rpi->cubemap);
+ }
+ glGenTextures(1, &rpi->cubemap);
glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap);
+#if 1
+ //Mobile hardware (PowerVR specially) prefers this approach, the other one kills the game
+ for (int i = 0; i < 6; i++) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, NULL);
+ }
+
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+
+ glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth); //resize depth buffer
+ glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, size, size);
+
+ for (int i = 0; i < 6; i++) {
+ glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth);
+ }
+
+#else
+ int lod = 0;
+
+ //the approach below is fatal for powervr
// Set the initial (empty) mipmaps, all need to be set for this to work in GLES2, even if later wont be used.
while (size >= 1) {
@@ -521,7 +547,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance
glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, 0);
glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth);
- glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
+ glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, size, size);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth);
#ifdef DEBUG_ENABLED
@@ -535,7 +561,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance
size >>= 1;
}
-
+#endif
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -716,20 +742,38 @@ void RasterizerSceneGLES2::environment_set_adjustment(RID p_env, bool p_enable,
}
void RasterizerSceneGLES2::environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) {
+
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
+
+ env->fog_enabled = p_enable;
+ env->fog_color = p_color;
+ env->fog_sun_color = p_sun_color;
+ env->fog_sun_amount = p_sun_amount;
}
void RasterizerSceneGLES2::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve) {
+
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
+
+ env->fog_depth_enabled = p_enable;
+ env->fog_depth_begin = p_depth_begin;
+ env->fog_depth_curve = p_depth_curve;
+ env->fog_transmit_enabled = p_transmit;
+ env->fog_transmit_curve = p_transmit_curve;
}
void RasterizerSceneGLES2::environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {
+
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
-}
+ env->fog_height_enabled = p_enable;
+ env->fog_height_min = p_min_height;
+ env->fog_height_max = p_max_height;
+ env->fog_height_curve = p_height_curve;
+}
bool RasterizerSceneGLES2::is_environment(RID p_env) {
return environment_owner.owns(p_env);
}
@@ -2005,6 +2049,15 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
glDisable(GL_BLEND);
}
+ float fog_max_distance = 0;
+ bool using_fog = false;
+ if (p_env && !p_shadow && p_env->fog_enabled && (p_env->fog_depth_enabled || p_env->fog_height_enabled)) {
+ state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, p_env->fog_depth_enabled);
+ state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, p_env->fog_height_enabled);
+ fog_max_distance = p_projection.get_z_far();
+ using_fog = true;
+ }
+
RasterizerStorageGLES2::Texture *prev_lightmap = NULL;
float lightmap_energy = 1.0;
bool prev_use_lightmap_capture = false;
@@ -2116,7 +2169,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
}
//condition to enable vertex lighting on this object
- bool vertex_lit = light && (material->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading) && !unshaded;
+ bool vertex_lit = (material->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading) && ((!unshaded && light) || using_fog); //fog forces vertex lighting because it still applies even if unshaded or no fog
if (vertex_lit != prev_vertex_lit) {
state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, vertex_lit);
@@ -2242,10 +2295,34 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
rebind_light = true;
rebind_reflection = true;
rebind_lightmap = true;
+
+ if (using_fog) {
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::FOG_COLOR_BASE, p_env->fog_color);
+ Color sun_color_amount = p_env->fog_sun_color;
+ sun_color_amount.a = p_env->fog_sun_amount;
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::FOG_SUN_COLOR_AMOUNT, sun_color_amount);
+ state.scene_shader.set_uniform(SceneShaderGLES2::FOG_TRANSMIT_ENABLED, p_env->fog_transmit_enabled);
+ state.scene_shader.set_uniform(SceneShaderGLES2::FOG_TRANSMIT_CURVE, p_env->fog_transmit_curve);
+
+ if (p_env->fog_depth_enabled) {
+ state.scene_shader.set_uniform(SceneShaderGLES2::FOG_DEPTH_BEGIN, p_env->fog_depth_begin);
+ state.scene_shader.set_uniform(SceneShaderGLES2::FOG_DEPTH_CURVE, p_env->fog_depth_curve);
+ state.scene_shader.set_uniform(SceneShaderGLES2::FOG_MAX_DISTANCE, fog_max_distance);
+ }
+
+ if (p_env->fog_height_enabled) {
+ state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MIN, p_env->fog_height_min);
+ state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MAX, p_env->fog_height_max);
+ state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MAX, p_env->fog_height_max);
+ state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_CURVE, p_env->fog_height_curve);
+ }
+ }
}
- state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, view_transform_inverse);
- state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform);
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform);
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, view_transform_inverse);
state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection);
state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, projection_inverse);
@@ -2302,6 +2379,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, false);
}
void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy) {
@@ -2540,7 +2619,6 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
_render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, true, false);
- glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
//#define GLES2_SHADOW_ATLAS_DEBUG_VIEW
@@ -2984,7 +3062,7 @@ void RasterizerSceneGLES2::initialize() {
glBindTexture(GL_TEXTURE_CUBE_MAP, cube.cubemap);
for (int i = 0; i < 6; i++) {
- glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
+ glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h
index 14b9116952..33ac99366d 100644
--- a/drivers/gles2/rasterizer_scene_gles2.h
+++ b/drivers/gles2/rasterizer_scene_gles2.h
@@ -353,6 +353,21 @@ public:
int canvas_max_layer;
+ bool fog_enabled;
+ Color fog_color;
+ Color fog_sun_color;
+ float fog_sun_amount;
+
+ bool fog_depth_enabled;
+ float fog_depth_begin;
+ float fog_depth_curve;
+ bool fog_transmit_enabled;
+ float fog_transmit_curve;
+ bool fog_height_enabled;
+ float fog_height_min;
+ float fog_height_max;
+ float fog_height_curve;
+
Environment() {
bg_mode = VS::ENV_BG_CLEAR_COLOR;
sky_custom_fov = 0.0;
@@ -361,6 +376,24 @@ public:
ambient_energy = 1.0;
ambient_sky_contribution = 0.0;
canvas_max_layer = 0;
+
+ fog_enabled = false;
+ fog_color = Color(0.5, 0.5, 0.5);
+ fog_sun_color = Color(0.8, 0.8, 0.0);
+ fog_sun_amount = 0;
+
+ fog_depth_enabled = true;
+
+ fog_depth_begin = 10;
+ fog_depth_curve = 1;
+
+ fog_transmit_enabled = true;
+ fog_transmit_curve = 1;
+
+ fog_height_enabled = false;
+ fog_height_min = 0;
+ fog_height_max = 100;
+ fog_height_curve = 1;
}
};
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index 6314a69a90..d5865064cf 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -901,26 +901,27 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
// attachements for it, so we can fill them by issuing draw calls.
GLuint tmp_fb;
- glGenFramebuffers(1, &tmp_fb);
- glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb);
-
int size = p_radiance_size;
int lod = 0;
- shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, texture->target == GL_TEXTURE_2D);
-
- shaders.cubemap_filter.bind();
-
int mipmaps = 6;
int mm_level = mipmaps;
- GLenum internal_format = GL_RGBA;
- GLenum format = GL_RGBA;
- GLenum type = GL_UNSIGNED_BYTE; // This is suboptimal... TODO other format for FBO?
+ GLenum internal_format = GL_RGB;
+ GLenum format = GL_RGB;
+ GLenum type = GL_UNSIGNED_BYTE;
// Set the initial (empty) mipmaps
+#if 1
+ //Mobile hardware (PowerVR specially) prefers this approach, the other one kills the game
+ for (int i = 0; i < 6; i++) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, NULL);
+ }
+
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+#else
while (size >= 1) {
for (int i = 0; i < 6; i++) {
@@ -931,7 +932,14 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
size >>= 1;
}
+#endif
+ //framebuffer
+ glGenFramebuffers(1, &tmp_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb);
+
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, texture->target == GL_TEXTURE_2D);
+ shaders.cubemap_filter.bind();
lod = 0;
mm_level = mipmaps;
@@ -3154,6 +3162,9 @@ void RasterizerStorageGLES2::light_set_reverse_cull_face_mode(RID p_light, bool
ERR_FAIL_COND(!light);
light->reverse_cull = p_enabled;
+
+ light->version++;
+ light->instance_change_notify();
}
void RasterizerStorageGLES2::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) {
diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub
index acb93fff8f..d959d3f740 100644
--- a/drivers/gles2/shaders/SCsub
+++ b/drivers/gles2/shaders/SCsub
@@ -20,3 +20,4 @@ if 'GLES2_GLSL' in env['BUILDERS']:
# env.GLES2_GLSL('exposure.glsl');
# env.GLES2_GLSL('tonemap.glsl');
# env.GLES2_GLSL('particles.glsl');
+ env.GLES2_GLSL('lens_distorted.glsl');
diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl
index ba69ca9b6e..b990384949 100644
--- a/drivers/gles2/shaders/canvas.glsl
+++ b/drivers/gles2/shaders/canvas.glsl
@@ -89,9 +89,18 @@ VERTEX_SHADER_CODE
/* clang-format on */
}
+#if !defined(SKIP_TRANSFORM_USED)
+ outvec = extra_matrix * outvec;
+ outvec = modelview_matrix * outvec;
+#endif
+
color_interp = color;
- gl_Position = projection_matrix * modelview_matrix * outvec;
+#ifdef USE_PIXEL_SNAP
+ outvec.xy = floor(outvec + 0.5).xy;
+#endif
+
+ gl_Position = projection_matrix * outvec;
}
/* clang-format off */
diff --git a/drivers/gles2/shaders/lens_distorted.glsl b/drivers/gles2/shaders/lens_distorted.glsl
new file mode 100644
index 0000000000..d541db9bf9
--- /dev/null
+++ b/drivers/gles2/shaders/lens_distorted.glsl
@@ -0,0 +1,62 @@
+/* clang-format off */
+[vertex]
+
+attribute highp vec2 vertex; // attrib:0
+/* clang-format on */
+
+uniform vec2 offset;
+uniform vec2 scale;
+
+varying vec2 uv_interp;
+
+void main() {
+
+ uv_interp = vertex.xy * 2.0 - 1.0;
+
+ vec2 v = vertex.xy * scale + offset;
+ gl_Position = vec4(v, 0.0, 1.0);
+}
+
+/* clang-format off */
+[fragment]
+
+uniform sampler2D source; //texunit:0
+/* clang-format on */
+
+uniform vec2 eye_center;
+uniform float k1;
+uniform float k2;
+uniform float upscale;
+uniform float aspect_ratio;
+
+varying vec2 uv_interp;
+
+void main() {
+ vec2 coords = uv_interp;
+ vec2 offset = coords - eye_center;
+
+ // take aspect ratio into account
+ offset.y /= aspect_ratio;
+
+ // distort
+ vec2 offset_sq = offset * offset;
+ float radius_sq = offset_sq.x + offset_sq.y;
+ float radius_s4 = radius_sq * radius_sq;
+ float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4);
+ offset *= distortion_scale;
+
+ // reapply aspect ratio
+ offset.y *= aspect_ratio;
+
+ // add our eye center back in
+ coords = offset + eye_center;
+ coords /= upscale;
+
+ // and check our color
+ if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) {
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+ } else {
+ coords = (coords + vec2(1.0)) / vec2(2.0);
+ gl_FragColor = texture2D(source, coords);
+ }
+}
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index 958de94485..fae010b003 100644
--- a/drivers/gles2/shaders/scene.glsl
+++ b/drivers/gles2/shaders/scene.glsl
@@ -286,6 +286,33 @@ varying mediump vec3 refprobe2_ambient_normal;
#endif //vertex lighting for refprobes
+#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED)
+
+varying vec4 fog_interp;
+
+uniform mediump vec4 fog_color_base;
+#ifdef LIGHT_MODE_DIRECTIONAL
+uniform mediump vec4 fog_sun_color_amount;
+#endif
+
+uniform bool fog_transmit_enabled;
+uniform mediump float fog_transmit_curve;
+
+#ifdef FOG_DEPTH_ENABLED
+uniform highp float fog_depth_begin;
+uniform mediump float fog_depth_curve;
+uniform mediump float fog_max_distance;
+#endif
+
+#ifdef FOG_HEIGHT_ENABLED
+uniform highp float fog_height_min;
+uniform highp float fog_height_max;
+uniform mediump float fog_height_curve;
+#endif
+
+
+#endif //fog
+
void main() {
highp vec4 vertex = vertex_attrib;
@@ -379,7 +406,7 @@ void main() {
#endif
- mat4 modelview = camera_matrix * world_matrix;
+ mat4 modelview = camera_inverse_matrix * world_matrix;
float roughness = 1.0;
#define world_transform world_matrix
@@ -406,11 +433,11 @@ VERTEX_SHADER_CODE
#endif
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
- vertex = camera_matrix * vertex;
- normal = normalize((camera_matrix * vec4(normal, 0.0)).xyz);
+ vertex = camera_inverse_matrix * vertex;
+ normal = normalize((camera_inverse_matrix * vec4(normal, 0.0)).xyz);
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
- tangent = normalize((camera_matrix * vec4(tangent, 0.0)).xyz);
- binormal = normalize((camera_matrix * vec4(binormal, 0.0)).xyz);
+ tangent = normalize((camera_inverse_matrix * vec4(tangent, 0.0)).xyz);
+ binormal = normalize((camera_inverse_matrix * vec4(binormal, 0.0)).xyz);
#endif
#endif
@@ -583,6 +610,37 @@ VERTEX_SHADER_CODE
#endif //USE_REFLECTION_PROBE2
+#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED)
+
+ float fog_amount = 0.0;
+
+#ifdef LIGHT_MODE_DIRECTIONAL
+
+ vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(normalize(vertex_interp), light_direction), 0.0), 8.0));
+#else
+ vec3 fog_color = fog_color_base.rgb;
+#endif
+
+#ifdef FOG_DEPTH_ENABLED
+
+ {
+
+ float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex));
+
+ fog_amount = pow(fog_z, fog_depth_curve);
+ }
+#endif
+
+#ifdef FOG_HEIGHT_ENABLED
+ {
+ float y = (camera_matrix * vec4(vertex_interp, 1.0)).y;
+ fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve));
+ }
+#endif
+ fog_interp = vec4(fog_color,fog_amount);
+
+#endif //fog
+
#endif //use vertex lighting
gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
}
@@ -816,6 +874,8 @@ uniform float ambient_energy;
varying highp vec3 diffuse_interp;
varying highp vec3 specular_interp;
+uniform vec3 light_direction; //may be used by fog, so leave here
+
#else
//done in fragment
// general for all lights
@@ -898,10 +958,11 @@ varying vec2 uv2_interp;
varying vec3 view_interp;
-vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) {
- float dielectric = (0.034 * 2.0) * specular;
- // energy conservation
- return mix(vec3(dielectric), albedo, metallic); // TODO: reference?
+vec3 F0(float metallic, float specular, vec3 albedo) {
+ float dielectric = 0.16 * specular * specular;
+ // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials;
+ // see https://google.github.io/filament/Filament.md.html
+ return mix(vec3(dielectric), albedo, vec3(metallic));
}
/* clang-format off */
@@ -934,6 +995,7 @@ varying highp float dp_clip;
// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014).
// Eqns 71-72 and 85-86 (see also Eqns 43 and 80).
+/*
float G_GGX_2cos(float cos_theta_m, float alpha) {
// Schlick's approximation
// C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994)
@@ -946,6 +1008,15 @@ float G_GGX_2cos(float cos_theta_m, float alpha) {
// float sin2 = (1.0 - cos2);
// return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2));
}
+*/
+
+// This approximates G_GGX_2cos(cos_theta_l, alpha) * G_GGX_2cos(cos_theta_v, alpha)
+// See Filament docs, Specular G section.
+float V_GGX(float cos_theta_l, float cos_theta_v, float alpha) {
+ float v = cos_theta_l * (cos_theta_v * (1.0 - alpha) + alpha);
+ float l = cos_theta_v * (cos_theta_l * (1.0 - alpha) + alpha);
+ return 0.5 / (v + l);
+}
float D_GGX(float cos_theta_m, float alpha) {
float alpha2 = alpha * alpha;
@@ -953,6 +1024,7 @@ float D_GGX(float cos_theta_m, float alpha) {
return alpha2 / (M_PI * d * d);
}
+/*
float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
float cos2 = cos_theta_m * cos_theta_m;
float sin2 = (1.0 - cos2);
@@ -960,14 +1032,30 @@ float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, fl
float s_y = alpha_y * sin_phi;
return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001);
}
+*/
-float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
- float cos2 = cos_theta_m * cos_theta_m;
+// This approximates G_GGX_anisotropic_2cos(cos_theta_l, ...) * G_GGX_anisotropic_2cos(cos_theta_v, ...)
+// See Filament docs, Anisotropic specular BRDF section.
+float V_GGX_anisotropic(float alpha_x, float alpha_y, float TdotV, float TdotL, float BdotV, float BdotL, float NdotV, float NdotL) {
+ float Lambda_V = NdotL * length(vec3(alpha_x * TdotV, alpha_y * BdotV, NdotV));
+ float Lambda_L = NdotV * length(vec3(alpha_x * TdotL, alpha_y * BdotL, NdotL));
+ return 0.5 / (Lambda_V + Lambda_L);
+}
+
+float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi, float NdotH) {
+ float alpha2 = alpha_x * alpha_y;
+ highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * NdotH);
+ highp float v2 = dot(v, v);
+ float w2 = alpha2 / v2;
+ float D = alpha2 * w2 * w2 * (1.0 / M_PI);
+ return D;
+
+ /* float cos2 = cos_theta_m * cos_theta_m;
float sin2 = (1.0 - cos2);
float r_x = cos_phi / alpha_x;
float r_y = sin_phi / alpha_y;
float d = cos2 + sin2 * (r_x * r_x + r_y * r_y);
- return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001);
+ return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); */
}
float SchlickFresnel(float u) {
@@ -996,6 +1084,7 @@ void light_compute(
float specular_blob_intensity,
float roughness,
float metallic,
+ float specular,
float rim,
float rim_tint,
float clearcoat,
@@ -1112,9 +1201,11 @@ LIGHT_SHADER_CODE
if (roughness > 0.0) {
- // D
-
- float specular_brdf_NL;
+#if defined(SPECULAR_SCHLICK_GGX)
+ vec3 specular_brdf_NL = vec3(0.0);
+#else
+ float specular_brdf_NL = 0.0;
+#endif
#if defined(SPECULAR_BLINN)
@@ -1147,7 +1238,6 @@ LIGHT_SHADER_CODE
#elif defined(SPECULAR_DISABLED)
// none..
- specular_brdf_NL = 0.0;
#elif defined(SPECULAR_SCHLICK_GGX)
// shlick+ggx as default
@@ -1157,28 +1247,28 @@ LIGHT_SHADER_CODE
float cLdotH = max(dot(L, H), 0.0);
#if defined(LIGHT_USE_ANISOTROPY)
-
+ float alpha = roughness * roughness;
float aspect = sqrt(1.0 - anisotropy * 0.9);
- float rx = roughness / aspect;
- float ry = roughness * aspect;
- float ax = rx * rx;
- float ay = ry * ry;
+ float ax = alpha / aspect;
+ float ay = alpha * aspect;
float XdotH = dot(T, H);
float YdotH = dot(B, H);
- float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH);
- float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH);
+ float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH, cNdotH);
+ //float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH);
+ float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL))
#else
float alpha = roughness * roughness;
float D = D_GGX(cNdotH, alpha);
- float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha);
+ //float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha);
+ float G = V_GGX(cNdotL, cNdotV, alpha);
#endif
// F
- //float F0 = 1.0;
- //float cLdotH5 = SchlickFresnel(cLdotH);
- //float F = mix(cLdotH5, 1.0, F0);
+ vec3 f0 = F0(metallic, specular, diffuse_color);
+ float cLdotH5 = SchlickFresnel(cLdotH);
+ vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0);
- specular_brdf_NL = cNdotL * D /* F */ * G;
+ specular_brdf_NL = cNdotL * D * F * G;
#endif
@@ -1197,11 +1287,12 @@ LIGHT_SHADER_CODE
#endif
float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss));
float Fr = mix(.04, 1.0, cLdotH5);
- float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25);
+ //float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25);
+ float Gr = V_GGX(cNdotL, cNdotV, 0.25);
- float specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL;
+ float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL;
- specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation;
+ specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation;
}
#endif
}
@@ -1265,6 +1356,36 @@ float sample_shadow(
#endif
+#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED)
+
+#if defined(USE_VERTEX_LIGHTING)
+
+varying vec4 fog_interp;
+
+#else
+uniform mediump vec4 fog_color_base;
+#ifdef LIGHT_MODE_DIRECTIONAL
+uniform mediump vec4 fog_sun_color_amount;
+#endif
+
+uniform bool fog_transmit_enabled;
+uniform mediump float fog_transmit_curve;
+
+#ifdef FOG_DEPTH_ENABLED
+uniform highp float fog_depth_begin;
+uniform mediump float fog_depth_curve;
+uniform mediump float fog_max_distance;
+#endif
+
+#ifdef FOG_HEIGHT_ENABLED
+uniform highp float fog_height_min;
+uniform highp float fog_height_max;
+uniform mediump float fog_height_curve;
+#endif
+
+#endif //vertex lit
+#endif //fog
+
void main() {
#ifdef RENDER_DEPTH_DUAL_PARABOLOID
@@ -1290,6 +1411,11 @@ void main() {
float alpha = 1.0;
float side = 1.0;
+ float specular_blob_intensity = 1.0;
+#if defined(SPECULAR_TOON)
+ specular_blob_intensity *= specular * 2.0;
+#endif
+
#if defined(ENABLE_AO)
float ao = 1.0;
float ao_light_affect = 0.0;
@@ -1504,7 +1630,7 @@ FRAGMENT_SHADER_CODE
highp vec4 splane = shadow_coord;
float shadow_len = length(splane.xyz);
- splane = normalize(splane.xyz);
+ splane.xyz = normalize(splane.xyz);
vec4 clamp_rect = light_clamp;
@@ -1808,7 +1934,7 @@ FRAGMENT_SHADER_CODE
#ifdef USE_VERTEX_LIGHTING
//vertex lighting
- specular_light += specular_interp * specular * light_att;
+ specular_light += specular_interp * specular_blob_intensity * light_att;
diffuse_light += diffuse_interp * albedo * light_att;
#else
@@ -1823,9 +1949,10 @@ FRAGMENT_SHADER_CODE
light_att,
albedo,
transmission,
- specular * light_specular,
+ specular_blob_intensity * light_specular,
roughness,
metallic,
+ specular,
rim,
rim_tint,
clearcoat,
@@ -1872,10 +1999,10 @@ FRAGMENT_SHADER_CODE
vec4 r = roughness * c0 + c1;
float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
- vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;
+ vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
- vec3 specular_color = metallic_to_specular_color(metallic, specular, albedo);
- specular_light *= AB.x * specular_color + AB.y;
+ vec3 f0 = F0(metallic, specular, albedo);
+ specular_light *= env.x * f0 + env.y;
#endif
}
@@ -1889,5 +2016,50 @@ FRAGMENT_SHADER_CODE
#endif //unshaded
+//apply fog
+#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED)
+
+#if defined(USE_VERTEX_LIGHTING)
+
+ gl_FragColor.rgb = mix(gl_FragColor.rgb,fog_interp.rgb,fog_interp.a);
+#else //pixel based fog
+ float fog_amount = 0.0;
+
+#ifdef LIGHT_MODE_DIRECTIONAL
+
+ vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(eye_position, light_direction), 0.0), 8.0));
+#else
+ vec3 fog_color = fog_color_base.rgb;
+#endif
+
+#ifdef FOG_DEPTH_ENABLED
+
+ {
+
+ float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex));
+
+ fog_amount = pow(fog_z, fog_depth_curve);
+
+ if (fog_transmit_enabled) {
+ vec3 total_light = gl_FragColor.rgb;
+ float transmit = pow(fog_z, fog_transmit_curve);
+ fog_color = mix(max(total_light, fog_color), fog_color, transmit);
+ }
+ }
+#endif
+
+#ifdef FOG_HEIGHT_ENABLED
+ {
+ float y = (camera_matrix * vec4(vertex, 1.0)).y;
+ fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve));
+ }
+#endif
+
+ gl_FragColor.rgb = mix(gl_FragColor.rgb,fog_color,fog_amount);
+
+#endif //use vertex lit
+
+#endif // defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED)
+
#endif // not RENDER_DEPTH
}