Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_probes.c')
-rw-r--r--source/blender/draw/engines/eevee/eevee_probes.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_probes.c b/source/blender/draw/engines/eevee/eevee_probes.c
new file mode 100644
index 00000000000..9c9fc052b3f
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_probes.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_lights.c
+ * \ingroup DNA
+ */
+
+#include "DNA_world_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_image_types.h"
+
+#include "BLI_dynstr.h"
+
+#include "DRW_render.h"
+
+#include "eevee_engine.h"
+#include "eevee_private.h"
+#include "GPU_texture.h"
+#include "GPU_glew.h"
+
+typedef struct EEVEE_ProbeData {
+ short probe_id, shadow_id;
+} EEVEE_ProbeData;
+
+/* TODO Option */
+#define PROBE_CUBE_SIZE 512
+#define PROBE_SIZE 1024
+
+static struct {
+ struct GPUShader *probe_filter_sh;
+ struct GPUShader *probe_spherical_harmonic_sh;
+
+ struct GPUTexture *hammersley;
+
+ float camera_pos[3];
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_probe_filter_frag_glsl[];
+extern char datatoc_probe_sh_frag_glsl[];
+extern char datatoc_probe_geom_glsl[];
+extern char datatoc_probe_vert_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_bsdf_sampling_lib_glsl[];
+
+/* *********** FUNCTIONS *********** */
+
+/* Van der Corput sequence */
+ /* From http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html */
+static float radical_inverse(int i) {
+ unsigned int bits = (unsigned int)i;
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ return (float)bits * 2.3283064365386963e-10f;
+}
+
+static struct GPUTexture *create_hammersley_sample_texture(int samples)
+{
+ struct GPUTexture *tex;
+ float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * samples, "hammersley_tex");
+ int i;
+
+ for (i = 0; i < samples; i++) {
+ float phi = radical_inverse(i) * 2.0f * M_PI;
+ texels[i][0] = cos(phi);
+ texels[i][1] = sinf(phi);
+ }
+
+ tex = DRW_texture_create_1D(samples, DRW_TEX_RG_16, DRW_TEX_WRAP, (float *)texels);
+ MEM_freeN(texels);
+ return tex;
+}
+
+void EEVEE_probes_init(EEVEE_SceneLayerData *sldata)
+{
+ if (!e_data.probe_filter_sh) {
+ char *shader_str = NULL;
+
+ DynStr *ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_probe_filter_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.probe_filter_sh = DRW_shader_create(
+ datatoc_probe_vert_glsl, datatoc_probe_geom_glsl, shader_str,
+ "#define HAMMERSLEY_SIZE 1024\n"
+ "#define NOISE_SIZE 64\n");
+
+ MEM_freeN(shader_str);
+ }
+
+ if (!e_data.hammersley) {
+ e_data.hammersley = create_hammersley_sample_texture(1024);
+ }
+
+ if (!e_data.probe_spherical_harmonic_sh) {
+ e_data.probe_spherical_harmonic_sh = DRW_shader_create_fullscreen(datatoc_probe_sh_frag_glsl, NULL);
+ }
+
+ if (!sldata->probes) {
+ sldata->probes = MEM_callocN(sizeof(EEVEE_ProbesInfo), "EEVEE_ProbesInfo");
+ }
+
+ if (!sldata->probe_rt) {
+ sldata->probe_rt = DRW_texture_create_cube(PROBE_CUBE_SIZE, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ sldata->probe_depth_rt = DRW_texture_create_cube(PROBE_CUBE_SIZE, DRW_TEX_DEPTH_24, DRW_TEX_FILTER, NULL);
+ }
+
+ DRWFboTexture tex_probe[2] = {{&sldata->probe_depth_rt, DRW_TEX_DEPTH_24, DRW_TEX_FILTER},
+ {&sldata->probe_rt, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}};
+
+ DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, PROBE_CUBE_SIZE, PROBE_CUBE_SIZE, tex_probe, 2);
+
+ if (!sldata->probe_pool) {
+ /* TODO array */
+ sldata->probe_pool = DRW_texture_create_2D(PROBE_SIZE, PROBE_SIZE, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ }
+
+ DRWFboTexture tex_filter = {&sldata->probe_pool, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
+
+ DRW_framebuffer_init(&sldata->probe_filter_fb, &draw_engine_eevee_type, PROBE_SIZE, PROBE_SIZE, &tex_filter, 1);
+
+ /* Spherical Harmonic Buffer */
+ DRWFboTexture tex_sh = {&sldata->probe_sh, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
+
+ DRW_framebuffer_init(&sldata->probe_sh_fb, &draw_engine_eevee_type, 9, 1, &tex_sh, 1);
+}
+
+void EEVEE_probes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
+{
+ {
+ psl->probe_prefilter = DRW_pass_create("Probe Filtering", DRW_STATE_WRITE_COLOR);
+
+ struct Batch *geom = DRW_cache_fullscreen_quad_get();
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.probe_filter_sh, psl->probe_prefilter, geom);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "roughnessSquared", &sldata->probes->roughness, 1);
+ DRW_shgroup_uniform_float(grp, "lodFactor", &sldata->probes->lodfactor, 1);
+ DRW_shgroup_uniform_float(grp, "lodMax", &sldata->probes->lodmax, 1);
+ DRW_shgroup_uniform_float(grp, "texelSize", &sldata->probes->texel_size, 1);
+ DRW_shgroup_uniform_float(grp, "paddingSize", &sldata->probes->padding_size, 1);
+ DRW_shgroup_uniform_int(grp, "Layer", &sldata->probes->layer, 1);
+ DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
+ // DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
+ DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt);
+
+ DRW_shgroup_call_dynamic_add_empty(grp);
+ }
+
+ {
+ psl->probe_sh_compute = DRW_pass_create("Probe SH Compute", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_spherical_harmonic_sh, psl->probe_sh_compute);
+ DRW_shgroup_uniform_int(grp, "probeSize", &sldata->probes->shres, 1);
+ DRW_shgroup_uniform_float(grp, "lodBias", &sldata->probes->lodfactor, 1);
+ DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt);
+
+ struct Batch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+}
+
+void EEVEE_probes_cache_add(EEVEE_SceneLayerData *UNUSED(sldata), Object *UNUSED(ob))
+{
+ return;
+}
+
+void EEVEE_probes_cache_finish(EEVEE_SceneLayerData *UNUSED(sldata))
+{
+ return;
+}
+
+void EEVEE_probes_update(EEVEE_SceneLayerData *UNUSED(sldata))
+{
+ return;
+}
+
+void EEVEE_refresh_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
+{
+ EEVEE_ProbesInfo *pinfo = sldata->probes;
+
+ float projmat[4][4];
+
+ /* 1 - Render to cubemap target using geometry shader. */
+ /* We don't need to clear since we render the background. */
+ pinfo->layer = 0;
+ perspective_m4(projmat, -0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 100.0f);
+ for (int i = 0; i < 6; ++i) {
+ mul_m4_m4m4(pinfo->probemat[i], projmat, cubefacemat[i]);
+ }
+
+ DRW_framebuffer_bind(sldata->probe_fb);
+ DRW_draw_pass(psl->probe_background);
+
+ /* 2 - Let gpu create Mipmaps for Filtered Importance Sampling. */
+ /* Bind next framebuffer to be able to gen. mips for probe_rt. */
+ DRW_framebuffer_bind(sldata->probe_filter_fb);
+ DRW_texture_generate_mipmaps(sldata->probe_rt);
+
+ /* 3 - Render to probe array to the specified layer, do prefiltering. */
+ /* Detach to rebind the right mipmap. */
+ DRW_framebuffer_texture_detach(sldata->probe_pool);
+ float mipsize = PROBE_SIZE;
+ const int maxlevel = (int)floorf(log2f(PROBE_SIZE));
+ const int min_lod_level = 3;
+ for (int i = 0; i < maxlevel - min_lod_level; i++) {
+ float bias = (i == 0) ? 0.0f : 1.0f;
+ pinfo->texel_size = 1.0f / mipsize;
+ pinfo->padding_size = powf(2.0f, (float)(maxlevel - min_lod_level - 1 - i));
+ /* XXX : WHY THE HECK DO WE NEED THIS ??? */
+ /* padding is incorrect without this! float precision issue? */
+ if (pinfo->padding_size > 32) {
+ pinfo->padding_size += 5;
+ }
+ if (pinfo->padding_size > 16) {
+ pinfo->padding_size += 4;
+ }
+ else if (pinfo->padding_size > 8) {
+ pinfo->padding_size += 2;
+ }
+ else if (pinfo->padding_size > 4) {
+ pinfo->padding_size += 1;
+ }
+ pinfo->layer = 0;
+ pinfo->roughness = (float)i / ((float)maxlevel - 4.0f);
+ pinfo->roughness *= pinfo->roughness; /* Disney Roughness */
+ pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */
+ CLAMP(pinfo->roughness, 1e-8f, 0.99999f); /* Avoid artifacts */
+
+#if 1 /* Variable Sample count (fast) */
+ switch (i) {
+ case 0: pinfo->samples_ct = 1.0f; break;
+ case 1: pinfo->samples_ct = 16.0f; break;
+ case 2: pinfo->samples_ct = 32.0f; break;
+ case 3: pinfo->samples_ct = 64.0f; break;
+ default: pinfo->samples_ct = 128.0f; break;
+ }
+#else /* Constant Sample count (slow) */
+ pinfo->samples_ct = 1024.0f;
+#endif
+
+ pinfo->invsamples_ct = 1.0f / pinfo->samples_ct;
+ pinfo->lodfactor = bias + 0.5f * log((float)(PROBE_CUBE_SIZE * PROBE_CUBE_SIZE) * pinfo->invsamples_ct) / log(2);
+ pinfo->lodmax = floorf(log2f(PROBE_CUBE_SIZE)) - 2.0f;
+
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, i);
+ DRW_framebuffer_viewport_size(sldata->probe_filter_fb, mipsize, mipsize);
+ DRW_draw_pass(psl->probe_prefilter);
+ DRW_framebuffer_texture_detach(sldata->probe_pool);
+
+ mipsize /= 2;
+ CLAMP_MIN(mipsize, 1);
+ }
+ /* For shading, save max level of the octahedron map */
+ pinfo->lodmax = (float)(maxlevel - min_lod_level) - 1.0f;
+ /* reattach to have a valid framebuffer. */
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
+
+ /* 4 - Compute spherical harmonics */
+ /* Tweaking parameters to balance perf. vs precision */
+ pinfo->shres = 16; /* Less texture fetches & reduce branches */
+ pinfo->lodfactor = 4.0f; /* Improve cache reuse */
+ DRW_framebuffer_bind(sldata->probe_sh_fb);
+ DRW_draw_pass(psl->probe_sh_compute);
+ DRW_framebuffer_read_data(0, 0, 9, 1, 3, 0, (float *)pinfo->shcoefs);
+}
+
+void EEVEE_probes_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.probe_filter_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_spherical_harmonic_sh);
+ DRW_TEXTURE_FREE_SAFE(e_data.hammersley);
+}
+
+void EEVEE_scene_layer_probes_free(EEVEE_SceneLayerData *sldata)
+{
+ MEM_SAFE_FREE(sldata->probes);
+ DRW_UBO_FREE_SAFE(sldata->probe_ubo);
+ DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb);
+ DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb);
+ DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_sh_fb);
+ DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
+ DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt);
+ DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
+ DRW_TEXTURE_FREE_SAFE(sldata->probe_sh);
+}