Skip to content

Commit 509d8db

Browse files
committed
Add reflection probe support to compatibility renderer using 2 probe approach.
1 parent 9d6bdbc commit 509d8db

17 files changed

+1160
-220
lines changed
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/**************************************************************************/
2+
/* cubemap_filter.cpp */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#ifdef GLES3_ENABLED
32+
33+
#include "cubemap_filter.h"
34+
35+
#include "../storage/texture_storage.h"
36+
#include "core/config/project_settings.h"
37+
38+
using namespace GLES3;
39+
40+
CubemapFilter *CubemapFilter::singleton = nullptr;
41+
42+
CubemapFilter::CubemapFilter() {
43+
singleton = this;
44+
ggx_samples = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples");
45+
46+
{
47+
String defines;
48+
defines += "\n#define MAX_SAMPLE_COUNT " + itos(ggx_samples) + "\n";
49+
cubemap_filter.shader.initialize(defines);
50+
cubemap_filter.shader_version = cubemap_filter.shader.version_create();
51+
}
52+
53+
{ // Screen Triangle.
54+
glGenBuffers(1, &screen_triangle);
55+
glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
56+
57+
const float qv[6] = {
58+
-1.0f,
59+
-1.0f,
60+
3.0f,
61+
-1.0f,
62+
-1.0f,
63+
3.0f,
64+
};
65+
66+
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW);
67+
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
68+
69+
glGenVertexArrays(1, &screen_triangle_array);
70+
glBindVertexArray(screen_triangle_array);
71+
glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
72+
glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
73+
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
74+
glBindVertexArray(0);
75+
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
76+
}
77+
}
78+
79+
CubemapFilter::~CubemapFilter() {
80+
glDeleteBuffers(1, &screen_triangle);
81+
glDeleteVertexArrays(1, &screen_triangle_array);
82+
83+
cubemap_filter.shader.version_free(cubemap_filter.shader_version);
84+
singleton = nullptr;
85+
}
86+
87+
// Helper functions for IBL filtering
88+
89+
Vector3 importance_sample_GGX(Vector2 xi, float roughness4) {
90+
// Compute distribution direction
91+
float phi = 2.0 * Math_PI * xi.x;
92+
float cos_theta = sqrt((1.0 - xi.y) / (1.0 + (roughness4 - 1.0) * xi.y));
93+
float sin_theta = sqrt(1.0 - cos_theta * cos_theta);
94+
95+
// Convert to spherical direction
96+
Vector3 half_vector;
97+
half_vector.x = sin_theta * cos(phi);
98+
half_vector.y = sin_theta * sin(phi);
99+
half_vector.z = cos_theta;
100+
101+
return half_vector;
102+
}
103+
104+
float distribution_GGX(float NdotH, float roughness4) {
105+
float NdotH2 = NdotH * NdotH;
106+
float denom = (NdotH2 * (roughness4 - 1.0) + 1.0);
107+
denom = Math_PI * denom * denom;
108+
109+
return roughness4 / denom;
110+
}
111+
112+
float radical_inverse_vdC(uint32_t bits) {
113+
bits = (bits << 16) | (bits >> 16);
114+
bits = ((bits & 0x55555555) << 1) | ((bits & 0xAAAAAAAA) >> 1);
115+
bits = ((bits & 0x33333333) << 2) | ((bits & 0xCCCCCCCC) >> 2);
116+
bits = ((bits & 0x0F0F0F0F) << 4) | ((bits & 0xF0F0F0F0) >> 4);
117+
bits = ((bits & 0x00FF00FF) << 8) | ((bits & 0xFF00FF00) >> 8);
118+
119+
return float(bits) * 2.3283064365386963e-10;
120+
}
121+
122+
Vector2 hammersley(uint32_t i, uint32_t N) {
123+
return Vector2(float(i) / float(N), radical_inverse_vdC(i));
124+
}
125+
126+
void CubemapFilter::filter_radiance(GLuint p_source_cubemap, GLuint p_dest_cubemap, GLuint p_dest_framebuffer, int p_source_size, int p_mipmap_count, int p_layer) {
127+
glActiveTexture(GL_TEXTURE0);
128+
glBindTexture(GL_TEXTURE_CUBE_MAP, p_source_cubemap);
129+
glBindFramebuffer(GL_FRAMEBUFFER, p_dest_framebuffer);
130+
131+
CubemapFilterShaderGLES3::ShaderVariant mode = CubemapFilterShaderGLES3::MODE_DEFAULT;
132+
133+
if (p_layer == 0) {
134+
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
135+
// Copy over base layer without filtering.
136+
mode = CubemapFilterShaderGLES3::MODE_COPY;
137+
}
138+
139+
int size = p_source_size >> p_layer;
140+
glViewport(0, 0, size, size);
141+
glBindVertexArray(screen_triangle_array);
142+
143+
bool success = cubemap_filter.shader.version_bind_shader(cubemap_filter.shader_version, mode);
144+
if (!success) {
145+
return;
146+
}
147+
148+
if (p_layer > 0) {
149+
const uint32_t sample_counts[4] = { 1, ggx_samples / 4, ggx_samples / 2, ggx_samples };
150+
uint32_t sample_count = sample_counts[MIN(3, p_layer)];
151+
152+
float roughness = float(p_layer) / (p_mipmap_count);
153+
float roughness4 = roughness * roughness;
154+
roughness4 *= roughness4;
155+
156+
float solid_angle_texel = 4.0 * Math_PI / float(6 * size * size);
157+
158+
LocalVector<float> sample_directions;
159+
sample_directions.resize(4 * sample_count);
160+
161+
uint32_t index = 0;
162+
float weight = 0.0;
163+
for (uint32_t i = 0; i < sample_count; i++) {
164+
Vector2 xi = hammersley(i, sample_count);
165+
Vector3 dir = importance_sample_GGX(xi, roughness4);
166+
Vector3 light_vec = (2.0 * dir.z * dir - Vector3(0.0, 0.0, 1.0));
167+
168+
if (light_vec.z < 0.0) {
169+
continue;
170+
}
171+
172+
sample_directions[index * 4] = light_vec.x;
173+
sample_directions[index * 4 + 1] = light_vec.y;
174+
sample_directions[index * 4 + 2] = light_vec.z;
175+
176+
float D = distribution_GGX(dir.z, roughness4);
177+
float pdf = D * dir.z / (4.0 * dir.z) + 0.0001;
178+
179+
float solid_angle_sample = 1.0 / (float(sample_count) * pdf + 0.0001);
180+
181+
float mip_level = MAX(0.5 * log2(solid_angle_sample / solid_angle_texel) + float(MAX(1, p_layer - 3)), 1.0);
182+
183+
sample_directions[index * 4 + 3] = mip_level;
184+
weight += light_vec.z;
185+
index++;
186+
}
187+
188+
glUniform4fv(cubemap_filter.shader.version_get_uniform(CubemapFilterShaderGLES3::SAMPLE_DIRECTIONS_MIP, cubemap_filter.shader_version, mode), sample_count, sample_directions.ptr());
189+
cubemap_filter.shader.version_set_uniform(CubemapFilterShaderGLES3::WEIGHT, weight, cubemap_filter.shader_version, mode);
190+
cubemap_filter.shader.version_set_uniform(CubemapFilterShaderGLES3::SAMPLE_COUNT, index, cubemap_filter.shader_version, mode);
191+
}
192+
193+
for (int i = 0; i < 6; i++) {
194+
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, p_dest_cubemap, p_layer);
195+
#ifdef DEBUG_ENABLED
196+
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
197+
if (status != GL_FRAMEBUFFER_COMPLETE) {
198+
WARN_PRINT("Could not bind sky radiance face: " + itos(i) + ", status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
199+
}
200+
#endif
201+
cubemap_filter.shader.version_set_uniform(CubemapFilterShaderGLES3::FACE_ID, i, cubemap_filter.shader_version, mode);
202+
203+
glDrawArrays(GL_TRIANGLES, 0, 3);
204+
}
205+
glBindVertexArray(0);
206+
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
207+
}
208+
209+
#endif // GLES3_ENABLED
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**************************************************************************/
2+
/* cubemap_filter.h */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#ifndef CUBEMAP_FILTER_GLES3_H
32+
#define CUBEMAP_FILTER_GLES3_H
33+
34+
#ifdef GLES3_ENABLED
35+
36+
#include "drivers/gles3/shaders/effects/cubemap_filter.glsl.gen.h"
37+
38+
namespace GLES3 {
39+
40+
class CubemapFilter {
41+
private:
42+
struct CMF {
43+
CubemapFilterShaderGLES3 shader;
44+
RID shader_version;
45+
} cubemap_filter;
46+
47+
static CubemapFilter *singleton;
48+
49+
// Use for full-screen effects. Slightly more efficient than screen_quad as this eliminates pixel overdraw along the diagonal.
50+
GLuint screen_triangle = 0;
51+
GLuint screen_triangle_array = 0;
52+
53+
uint32_t ggx_samples = 128;
54+
55+
public:
56+
static CubemapFilter *get_singleton() {
57+
return singleton;
58+
}
59+
60+
CubemapFilter();
61+
~CubemapFilter();
62+
63+
void filter_radiance(GLuint p_source_cubemap, GLuint p_dest_cubemap, GLuint p_dest_framebuffer, int p_source_size, int p_mipmap_count, int p_layer);
64+
};
65+
66+
} //namespace GLES3
67+
68+
#endif // GLES3_ENABLED
69+
70+
#endif // CUBEMAP_FILTER_GLES3_H

drivers/gles3/rasterizer_gles3.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ void RasterizerGLES3::finalize() {
208208
memdelete(fog);
209209
memdelete(post_effects);
210210
memdelete(glow);
211+
memdelete(cubemap_filter);
211212
memdelete(copy_effects);
212213
memdelete(light_storage);
213214
memdelete(particles_storage);
@@ -354,6 +355,7 @@ RasterizerGLES3::RasterizerGLES3() {
354355
particles_storage = memnew(GLES3::ParticlesStorage);
355356
light_storage = memnew(GLES3::LightStorage);
356357
copy_effects = memnew(GLES3::CopyEffects);
358+
cubemap_filter = memnew(GLES3::CubemapFilter);
357359
glow = memnew(GLES3::Glow);
358360
post_effects = memnew(GLES3::PostEffects);
359361
gi = memnew(GLES3::GI);

drivers/gles3/rasterizer_gles3.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#ifdef GLES3_ENABLED
3535

3636
#include "effects/copy_effects.h"
37+
#include "effects/cubemap_filter.h"
3738
#include "effects/glow.h"
3839
#include "effects/post_effects.h"
3940
#include "environment/fog.h"
@@ -70,6 +71,7 @@ class RasterizerGLES3 : public RendererCompositor {
7071
GLES3::GI *gi = nullptr;
7172
GLES3::Fog *fog = nullptr;
7273
GLES3::CopyEffects *copy_effects = nullptr;
74+
GLES3::CubemapFilter *cubemap_filter = nullptr;
7375
GLES3::Glow *glow = nullptr;
7476
GLES3::PostEffects *post_effects = nullptr;
7577
RasterizerCanvasGLES3 *canvas = nullptr;

0 commit comments

Comments
 (0)