Merge pull request #33668 from clayjohn/Fix_environment_mapping_issues
Fix issues with environment mapping
This commit is contained in:
commit
3be6e76f22
7 changed files with 285 additions and 63 deletions
|
@ -1547,7 +1547,11 @@ FRAGMENT_SHADER_CODE
|
|||
#endif // !USE_SHADOW_TO_OPACITY
|
||||
|
||||
#ifdef BASE_PASS
|
||||
//none
|
||||
|
||||
// IBL precalculations
|
||||
float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
|
||||
vec3 f0 = F0(metallic, specular, albedo);
|
||||
vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0);
|
||||
|
||||
#ifdef AMBIENT_LIGHT_DISABLED
|
||||
ambient_light = vec3(0.0, 0.0, 0.0);
|
||||
|
@ -1561,12 +1565,15 @@ FRAGMENT_SHADER_CODE
|
|||
ref_vec.z *= -1.0;
|
||||
|
||||
specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy;
|
||||
#ifndef USE_LIGHTMAP
|
||||
{
|
||||
vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz);
|
||||
vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).xyz * bg_energy;
|
||||
vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, 4.0).xyz * bg_energy;
|
||||
env_ambient *= 1.0 - F;
|
||||
|
||||
ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
|
@ -1574,7 +1581,6 @@ FRAGMENT_SHADER_CODE
|
|||
specular_light = bg_color.rgb * bg_energy;
|
||||
|
||||
#endif
|
||||
|
||||
#endif // AMBIENT_LIGHT_DISABLED
|
||||
ambient_light *= ambient_energy;
|
||||
|
||||
|
@ -1646,12 +1652,9 @@ FRAGMENT_SHADER_CODE
|
|||
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
|
||||
const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
|
||||
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 env = vec2(-1.04, 1.04) * a004 + r.zw;
|
||||
|
||||
vec3 f0 = F0(metallic, specular, albedo);
|
||||
specular_light *= env.x * f0 + env.y;
|
||||
specular_light *= env.x * F + env.y;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -2011,7 +2011,7 @@ void RasterizerSceneGLES3::_set_cull(bool p_front, bool p_disabled, bool p_rever
|
|||
}
|
||||
}
|
||||
|
||||
void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, GLuint p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows) {
|
||||
void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RasterizerStorageGLES3::Sky *p_sky, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows) {
|
||||
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.scene_ubo); //bind globals ubo
|
||||
|
||||
|
@ -2019,14 +2019,15 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
|
|||
if (!p_shadow && !p_directional_add) {
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, 2, state.env_radiance_ubo); //bind environment radiance info
|
||||
|
||||
if (p_base_env) {
|
||||
if (p_sky != NULL) {
|
||||
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2);
|
||||
if (storage->config.use_texture_array_environment) {
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, p_base_env);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, p_sky->radiance);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, p_base_env);
|
||||
glBindTexture(GL_TEXTURE_2D, p_sky->radiance);
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6);
|
||||
glBindTexture(GL_TEXTURE_2D, p_sky->irradiance);
|
||||
state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, true);
|
||||
state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP_ARRAY, storage->config.use_texture_array_environment);
|
||||
use_radiance_map = true;
|
||||
|
@ -4231,7 +4232,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
|
|||
_fill_render_list(p_cull_result, p_cull_count, true, false);
|
||||
render_list.sort_by_key(false);
|
||||
state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, true);
|
||||
_render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, 0, false, false, true, false, false);
|
||||
_render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, NULL, false, false, true, false, false);
|
||||
state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, false);
|
||||
|
||||
glColorMask(1, 1, 1, 1);
|
||||
|
@ -4355,7 +4356,6 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
|
|||
|
||||
RasterizerStorageGLES3::Sky *sky = NULL;
|
||||
Ref<CameraFeed> feed;
|
||||
GLuint env_radiance_tex = 0;
|
||||
|
||||
if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
|
||||
clear_color = Color(0, 0, 0, 0);
|
||||
|
@ -4409,9 +4409,6 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
|
|||
|
||||
sky = storage->sky_owner.getornull(env->sky);
|
||||
|
||||
if (sky) {
|
||||
env_radiance_tex = sky->radiance;
|
||||
}
|
||||
break;
|
||||
case VS::ENV_BG_CANVAS:
|
||||
//copy canvas to 3d buffer and convert it to linear
|
||||
|
@ -4505,7 +4502,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
|
|||
}
|
||||
|
||||
if (probe && probe->probe_ptr->interior) {
|
||||
env_radiance_tex = 0; //for rendering probe interiors, radiance must not be used.
|
||||
sky = NULL; //for rendering probe interiors, radiance must not be used.
|
||||
}
|
||||
|
||||
state.texscreen_copied = false;
|
||||
|
@ -4524,7 +4521,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
|
|||
|
||||
if (state.directional_light_count == 0) {
|
||||
directional_light = NULL;
|
||||
_render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, false, false, false, shadow_atlas != NULL);
|
||||
_render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, sky, false, false, false, false, shadow_atlas != NULL);
|
||||
} else {
|
||||
for (int i = 0; i < state.directional_light_count; i++) {
|
||||
directional_light = directional_lights[i];
|
||||
|
@ -4532,7 +4529,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
|
|||
glEnable(GL_BLEND);
|
||||
}
|
||||
_setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != NULL && shadow_atlas->size > 0);
|
||||
_render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, false, false, i > 0, shadow_atlas != NULL);
|
||||
_render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, sky, false, false, false, i > 0, shadow_atlas != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4610,12 +4607,12 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
|
|||
|
||||
if (state.directional_light_count == 0) {
|
||||
directional_light = NULL;
|
||||
_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, env_radiance_tex, false, true, false, false, shadow_atlas != NULL);
|
||||
_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, sky, false, true, false, false, shadow_atlas != NULL);
|
||||
} else {
|
||||
for (int i = 0; i < state.directional_light_count; i++) {
|
||||
directional_light = directional_lights[i];
|
||||
_setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != NULL && shadow_atlas->size > 0);
|
||||
_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, env_radiance_tex, false, true, false, i > 0, shadow_atlas != NULL);
|
||||
_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, sky, false, true, false, i > 0, shadow_atlas != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4898,7 +4895,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_
|
|||
if (light->reverse_cull) {
|
||||
flip_facing = !flip_facing;
|
||||
}
|
||||
_render_list(render_list.elements, render_list.element_count, light_transform, light_projection, 0, flip_facing, false, true, false, false);
|
||||
_render_list(render_list.elements, render_list.element_count, light_transform, light_projection, NULL, flip_facing, false, true, false, false);
|
||||
|
||||
state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, false);
|
||||
state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH_DUAL_PARABOLOID, false);
|
||||
|
|
|
@ -837,7 +837,7 @@ public:
|
|||
_FORCE_INLINE_ void _render_geometry(RenderList::Element *e);
|
||||
_FORCE_INLINE_ void _setup_light(RenderList::Element *e, const Transform &p_view_transform);
|
||||
|
||||
void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, GLuint p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows);
|
||||
void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RasterizerStorageGLES3::Sky *p_sky, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows);
|
||||
|
||||
_FORCE_INLINE_ void _add_geometry(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass);
|
||||
|
||||
|
|
|
@ -1757,6 +1757,7 @@ RID RasterizerStorageGLES3::sky_create() {
|
|||
|
||||
Sky *sky = memnew(Sky);
|
||||
sky->radiance = 0;
|
||||
sky->irradiance = 0;
|
||||
return sky_owner.make_rid(sky);
|
||||
}
|
||||
|
||||
|
@ -1768,7 +1769,9 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
|
|||
if (sky->panorama.is_valid()) {
|
||||
sky->panorama = RID();
|
||||
glDeleteTextures(1, &sky->radiance);
|
||||
glDeleteTextures(1, &sky->irradiance);
|
||||
sky->radiance = 0;
|
||||
sky->irradiance = 0;
|
||||
}
|
||||
|
||||
sky->panorama = p_panorama;
|
||||
|
@ -1791,10 +1794,14 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
|
|||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(texture->target, texture->tex_id);
|
||||
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_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //need this for proper sampling
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 10);
|
||||
// Need Mipmaps regardless of whether they are set in import by user
|
||||
glGenerateMipmap(texture->target);
|
||||
glTexParameterf(texture->target, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameterf(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameterf(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
|
||||
if (config.srgb_decode_supported && texture->srgb && !texture->using_srgb) {
|
||||
|
||||
|
@ -1808,6 +1815,66 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
|
|||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
//Irradiance map
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glGenTextures(1, &sky->irradiance);
|
||||
glBindTexture(GL_TEXTURE_2D, sky->irradiance);
|
||||
|
||||
GLuint tmp_fb;
|
||||
|
||||
glGenFramebuffers(1, &tmp_fb);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb);
|
||||
|
||||
int size = 64;
|
||||
|
||||
bool use_float = config.framebuffer_half_float_supported;
|
||||
|
||||
GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2;
|
||||
GLenum format = GL_RGBA;
|
||||
GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV;
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size * 2, 0, format, type, NULL);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexParameterf(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sky->irradiance, 0);
|
||||
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, true);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::COMPUTE_IRRADIANCE, true);
|
||||
shaders.cubemap_filter.bind();
|
||||
|
||||
// Very large Panoramas require way too much effort to compute irradiance so use a mipmap
|
||||
// level that corresponds to a panorama of 1024x512
|
||||
shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_MIP_LEVEL, MAX(Math::log(float(texture->width)) / Math::log(2.0f) - 10.0f, 0.0f));
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
glViewport(0, i * size, size, size);
|
||||
glBindVertexArray(resources.quadie_array);
|
||||
|
||||
shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP, i > 0);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, false);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::COMPUTE_IRRADIANCE, false);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
|
||||
glDeleteFramebuffers(1, &tmp_fb);
|
||||
}
|
||||
|
||||
// Now compute radiance
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glGenTextures(1, &sky->radiance);
|
||||
|
||||
|
@ -1833,8 +1900,8 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
|
|||
|
||||
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, internal_format, size, size * 2, array_level, 0, format, type, NULL);
|
||||
|
||||
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
GLuint tmp_fb2;
|
||||
GLuint tmp_tex;
|
||||
|
@ -1846,8 +1913,8 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
|
|||
glBindTexture(GL_TEXTURE_2D, tmp_tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size * 2, 0, format, type, NULL);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_tex, 0);
|
||||
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
#ifdef DEBUG_ENABLED
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
|
||||
|
@ -1858,25 +1925,25 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
|
|||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb2);
|
||||
|
||||
if (j == 0) {
|
||||
if (j < 3) {
|
||||
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, true);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE, true);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID_ARRAY, false);
|
||||
shaders.cubemap_filter.bind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(texture->target, texture->tex_id);
|
||||
shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_RESOLUTION, float(texture->width / 4));
|
||||
} else {
|
||||
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID_ARRAY, true);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE, false);
|
||||
shaders.cubemap_filter.bind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, sky->radiance);
|
||||
shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_ARRAY_INDEX, j - 1); //read from previous to ensure better blur
|
||||
shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_RESOLUTION, float(size / 2));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
|
@ -1902,7 +1969,6 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
|
|||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, false);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID_ARRAY, false);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE, false);
|
||||
|
||||
//restore ranges
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
@ -1947,23 +2013,64 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
|
|||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmaps - 1);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
GLuint tmp_fb2;
|
||||
GLuint tmp_tex;
|
||||
{
|
||||
// Need a temporary framebuffer for rendering so we can read from previous iterations
|
||||
glGenFramebuffers(1, &tmp_fb2);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb2);
|
||||
glGenTextures(1, &tmp_tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tmp_tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size * 2, 0, format, type, NULL);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_tex, 0);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
#ifdef DEBUG_ENABLED
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
|
||||
#endif
|
||||
}
|
||||
|
||||
lod = 0;
|
||||
mm_level = mipmaps;
|
||||
|
||||
size = p_radiance_size;
|
||||
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, true);
|
||||
shaders.cubemap_filter.bind();
|
||||
|
||||
while (mm_level) {
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sky->radiance, lod);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE);
|
||||
#endif
|
||||
glBindTexture(GL_TEXTURE_2D, tmp_tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size * 2, 0, format, type, NULL);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb2);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_tex, 0);
|
||||
if (lod < 3) {
|
||||
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, true);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID, false);
|
||||
shaders.cubemap_filter.bind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(texture->target, texture->tex_id);
|
||||
shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_RESOLUTION, float(texture->width / 4));
|
||||
} else {
|
||||
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false);
|
||||
shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID, true);
|
||||
shaders.cubemap_filter.bind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, sky->radiance);
|
||||
shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_MIP_LEVEL, lod - 1); //read from previous to ensure better blur
|
||||
shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_RESOLUTION, float(size));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
glViewport(0, i * size, size, size);
|
||||
|
@ -1976,6 +2083,14 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
|
|||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tmp_fb);
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, sky->radiance, 0, lod);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, tmp_fb2);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glBlitFramebuffer(0, 0, size, size * 2, 0, 0, size, size * 2, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
||||
if (size > 1)
|
||||
size >>= 1;
|
||||
lod++;
|
||||
|
@ -1995,6 +2110,8 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
|
|||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
|
||||
glDeleteFramebuffers(1, &tmp_fb);
|
||||
glDeleteFramebuffers(1, &tmp_fb2);
|
||||
glDeleteTextures(1, &tmp_tex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -388,6 +388,7 @@ public:
|
|||
|
||||
RID panorama;
|
||||
GLuint radiance;
|
||||
GLuint irradiance;
|
||||
int radiance_size;
|
||||
};
|
||||
|
||||
|
|
|
@ -30,12 +30,22 @@ uniform sampler2DArray source_dual_paraboloid_array; //texunit:0
|
|||
uniform int source_array_index;
|
||||
#endif
|
||||
|
||||
#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
|
||||
#ifdef USE_SOURCE_DUAL_PARABOLOID
|
||||
uniform sampler2D source_dual_paraboloid; //texunit:0
|
||||
#endif
|
||||
|
||||
#if defined(USE_SOURCE_DUAL_PARABOLOID) || defined(COMPUTE_IRRADIANCE)
|
||||
uniform int source_mip_level;
|
||||
#endif
|
||||
|
||||
#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA) && !defined(USE_SOURCE_DUAL_PARABOLOID)
|
||||
uniform samplerCube source_cube; //texunit:0
|
||||
#endif
|
||||
|
||||
uniform int face_id;
|
||||
uniform float roughness;
|
||||
uniform float source_resolution;
|
||||
|
||||
in highp vec2 uv_interp;
|
||||
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
|
@ -133,6 +143,19 @@ vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
|
|||
return TangentX * H.x + TangentY * H.y + N * H.z;
|
||||
}
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness) {
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
|
||||
float nom = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = M_PI * denom * denom;
|
||||
|
||||
return nom / denom;
|
||||
}
|
||||
|
||||
// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
|
||||
float GGX(float NdotV, float a) {
|
||||
float k = a / 2.0;
|
||||
|
@ -160,10 +183,12 @@ vec2 Hammersley(uint i, uint N) {
|
|||
#ifdef LOW_QUALITY
|
||||
|
||||
#define SAMPLE_COUNT 64u
|
||||
#define SAMPLE_DELTA 0.05
|
||||
|
||||
#else
|
||||
|
||||
#define SAMPLE_COUNT 1024u
|
||||
#define SAMPLE_COUNT 512u
|
||||
#define SAMPLE_DELTA 0.01
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -171,7 +196,7 @@ uniform bool z_flip;
|
|||
|
||||
#ifdef USE_SOURCE_PANORAMA
|
||||
|
||||
vec4 texturePanorama(vec3 normal, sampler2D pano) {
|
||||
vec4 texturePanorama(vec3 normal, sampler2D pano, float mipLevel) {
|
||||
|
||||
vec2 st = vec2(
|
||||
atan(normal.x, normal.z),
|
||||
|
@ -182,7 +207,7 @@ vec4 texturePanorama(vec3 normal, sampler2D pano) {
|
|||
|
||||
st /= vec2(M_PI * 2.0, M_PI);
|
||||
|
||||
return textureLod(pano, st, 0.0);
|
||||
return textureLod(pano, st, mipLevel);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -202,6 +227,20 @@ vec4 textureDualParaboloidArray(vec3 normal) {
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef USE_SOURCE_DUAL_PARABOLOID
|
||||
vec4 textureDualParaboloid(vec3 normal) {
|
||||
|
||||
vec3 norm = normalize(normal);
|
||||
norm.xy /= 1.0 + abs(norm.z);
|
||||
norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25);
|
||||
if (norm.z < 0.0) {
|
||||
norm.y = 0.5 - norm.y + 0.5;
|
||||
}
|
||||
return textureLod(source_dual_paraboloid, norm.xy, float(source_mip_level));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
|
||||
#ifdef USE_DUAL_PARABOLOID
|
||||
|
@ -225,7 +264,7 @@ void main() {
|
|||
|
||||
#ifdef USE_SOURCE_PANORAMA
|
||||
|
||||
frag_color = vec4(texturePanorama(N, source_panorama).rgb, 1.0);
|
||||
frag_color = vec4(texturePanorama(N, source_panorama, 0.0).rgb, 1.0);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
|
||||
|
@ -233,12 +272,51 @@ void main() {
|
|||
frag_color = vec4(textureDualParaboloidArray(N).rgb, 1.0);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
|
||||
#ifdef USE_SOURCE_DUAL_PARABOLOID
|
||||
|
||||
frag_color = vec4(textureDualParaboloid(N).rgb, 1.0);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA) && !defined(USE_SOURCE_DUAL_PARABOLOID)
|
||||
|
||||
N.y = -N.y;
|
||||
frag_color = vec4(texture(N, source_cube).rgb, 1.0);
|
||||
#endif
|
||||
|
||||
#else // USE_DIRECT_WRITE
|
||||
|
||||
#ifdef COMPUTE_IRRADIANCE
|
||||
|
||||
vec3 irradiance = vec3(0.0);
|
||||
|
||||
// tangent space calculation from origin point
|
||||
vec3 UpVector = vec3(0.0, 1.0, 0.0);
|
||||
vec3 TangentX = cross(UpVector, N);
|
||||
vec3 TangentY = cross(N, TangentX);
|
||||
|
||||
float num_samples = 0.0f;
|
||||
|
||||
for (float phi = 0.0; phi < 2.0 * M_PI; phi += SAMPLE_DELTA) {
|
||||
for (float theta = 0.0; theta < 0.5 * M_PI; theta += SAMPLE_DELTA) {
|
||||
// Calculate sample positions
|
||||
vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
|
||||
// Find world vector of sample position
|
||||
vec3 H = tangentSample.x * TangentX + tangentSample.y * TangentY + tangentSample.z * N;
|
||||
|
||||
vec2 st = vec2(atan(H.x, H.z), acos(H.y));
|
||||
if (st.x < 0.0) {
|
||||
st.x += M_PI * 2.0;
|
||||
}
|
||||
st /= vec2(M_PI * 2.0, M_PI);
|
||||
|
||||
irradiance += texture(source_panorama, st, source_mip_level).rgb * cos(theta) * sin(theta);
|
||||
num_samples++;
|
||||
}
|
||||
}
|
||||
irradiance = M_PI * irradiance * (1.0 / float(num_samples));
|
||||
|
||||
frag_color = vec4(irradiance, 1.0);
|
||||
|
||||
#else
|
||||
|
||||
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
@ -246,15 +324,26 @@ void main() {
|
|||
for (uint sampleNum = 0u; sampleNum < SAMPLE_COUNT; sampleNum++) {
|
||||
vec2 xi = Hammersley(sampleNum, SAMPLE_COUNT);
|
||||
|
||||
vec3 H = ImportanceSampleGGX(xi, roughness, N);
|
||||
vec3 H = normalize(ImportanceSampleGGX(xi, roughness, N));
|
||||
vec3 V = N;
|
||||
vec3 L = (2.0 * dot(V, H) * H - V);
|
||||
vec3 L = normalize(2.0 * dot(V, H) * H - V);
|
||||
|
||||
float ndotl = clamp(dot(N, L), 0.0, 1.0);
|
||||
float ndotl = max(dot(N, L), 0.0);
|
||||
|
||||
if (ndotl > 0.0) {
|
||||
|
||||
float D = DistributionGGX(N, H, roughness);
|
||||
float ndoth = max(dot(N, H), 0.0);
|
||||
float hdotv = max(dot(H, V), 0.0);
|
||||
float pdf = D * ndoth / (4.0 * hdotv) + 0.0001;
|
||||
|
||||
float saTexel = 4.0 * M_PI / (6.0 * source_resolution * source_resolution);
|
||||
float saSample = 1.0 / (float(SAMPLE_COUNT) * pdf + 0.0001);
|
||||
|
||||
float mipLevel = roughness == 0.0 ? 0.0 : 0.5 * log2(saSample / saTexel);
|
||||
|
||||
#ifdef USE_SOURCE_PANORAMA
|
||||
sum.rgb += texturePanorama(L, source_panorama).rgb * ndotl;
|
||||
sum.rgb += texturePanorama(L, source_panorama, mipLevel).rgb * ndotl;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
|
||||
|
@ -262,7 +351,12 @@ void main() {
|
|||
sum.rgb += textureDualParaboloidArray(L).rgb * ndotl;
|
||||
#endif
|
||||
|
||||
#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
|
||||
#ifdef USE_SOURCE_DUAL_PARABOLOID
|
||||
|
||||
sum.rgb += textureDualParaboloid(L).rgb * ndotl;
|
||||
#endif
|
||||
|
||||
#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA) && !defined(USE_SOURCE_DUAL_PARABOLOID)
|
||||
L.y = -L.y;
|
||||
sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl;
|
||||
#endif
|
||||
|
@ -273,5 +367,6 @@ void main() {
|
|||
|
||||
frag_color = vec4(sum.rgb, 1.0);
|
||||
|
||||
#endif
|
||||
#endif // COMPUTE_IRRADIANCE
|
||||
#endif // USE_DIRECT_WRITE
|
||||
}
|
||||
|
|
|
@ -627,6 +627,8 @@ layout(std140) uniform Radiance { // ubo:2
|
|||
|
||||
#define RADIANCE_MAX_LOD 5.0
|
||||
|
||||
uniform sampler2D irradiance_map; // texunit:-6
|
||||
|
||||
#ifdef USE_RADIANCE_MAP_ARRAY
|
||||
|
||||
uniform sampler2DArray radiance_map; // texunit:-2
|
||||
|
@ -1766,6 +1768,11 @@ FRAGMENT_SHADER_CODE
|
|||
|
||||
vec3 eye_vec = view;
|
||||
|
||||
// IBL precalculations
|
||||
float ndotv = clamp(dot(normal, eye_vec), 0.0, 1.0);
|
||||
vec3 f0 = F0(metallic, specular, albedo);
|
||||
vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0);
|
||||
|
||||
#ifdef USE_RADIANCE_MAP
|
||||
|
||||
#ifdef AMBIENT_LIGHT_DISABLED
|
||||
|
@ -1775,22 +1782,27 @@ FRAGMENT_SHADER_CODE
|
|||
|
||||
{ //read radiance from dual paraboloid
|
||||
|
||||
vec3 ref_vec = reflect(-eye_vec, normal); //2.0 * ndotv * normal - view; // reflect(v, n);
|
||||
vec3 ref_vec = reflect(-eye_vec, normal);
|
||||
ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz);
|
||||
vec3 radiance = textureDualParaboloid(radiance_map, ref_vec, roughness) * bg_energy;
|
||||
env_reflection_light = radiance;
|
||||
}
|
||||
//no longer a cubemap
|
||||
//vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y);
|
||||
}
|
||||
#ifndef USE_LIGHTMAP
|
||||
{
|
||||
|
||||
vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz);
|
||||
vec3 env_ambient = textureDualParaboloid(radiance_map, ambient_dir, 1.0) * bg_energy;
|
||||
vec3 norm = normal;
|
||||
norm = normalize((radiance_inverse_xform * vec4(norm, 0.0)).xyz);
|
||||
norm.xy /= 1.0 + abs(norm.z);
|
||||
norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25);
|
||||
if (norm.z > 0.0) {
|
||||
norm.y = 0.5 - norm.y + 0.5;
|
||||
}
|
||||
|
||||
vec3 env_ambient = texture(irradiance_map, norm.xy).rgb * bg_energy;
|
||||
env_ambient *= 1.0 - F;
|
||||
|
||||
ambient_light = mix(ambient_light_color.rgb, env_ambient, radiance_ambient_contribution);
|
||||
//ambient_light=vec3(0.0,0.0,0.0);
|
||||
}
|
||||
#endif
|
||||
#endif //AMBIENT_LIGHT_DISABLED
|
||||
|
@ -1892,12 +1904,9 @@ FRAGMENT_SHADER_CODE
|
|||
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
|
||||
const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
|
||||
vec4 r = roughness * c0 + c1;
|
||||
float ndotv = clamp(dot(normal, eye_vec), 0.0, 1.0);
|
||||
float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
|
||||
vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
|
||||
|
||||
vec3 f0 = F0(metallic, specular, albedo);
|
||||
specular_light *= env.x * f0 + env.y;
|
||||
specular_light *= env.x * F + env.y;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue