Eevee: Spherical Harmonic diffuse.
For now it's done each frame and it's rather slow (16ms) but result will be cached soon.
This commit is contained in:
@@ -105,6 +105,7 @@ data_to_c_simple(engines/clay/shaders/ssao_groundtruth.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lit_surface_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lit_surface_vert.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/probe_filter_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/probe_sh_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/probe_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/probe_geom.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/probe_vert.glsl SRC)
|
||||
|
||||
@@ -44,6 +44,7 @@ static struct {
|
||||
/* Temp : use world shader */
|
||||
struct GPUShader *probe_sh;
|
||||
struct GPUShader *probe_filter_sh;
|
||||
struct GPUShader *probe_spherical_harmonic_sh;
|
||||
|
||||
struct GPUTexture *ltc_mat;
|
||||
struct GPUTexture *brdf_lut;
|
||||
@@ -65,6 +66,7 @@ extern char datatoc_shadow_frag_glsl[];
|
||||
extern char datatoc_shadow_geom_glsl[];
|
||||
extern char datatoc_shadow_vert_glsl[];
|
||||
extern char datatoc_probe_filter_frag_glsl[];
|
||||
extern char datatoc_probe_sh_frag_glsl[];
|
||||
extern char datatoc_probe_frag_glsl[];
|
||||
extern char datatoc_probe_geom_glsl[];
|
||||
extern char datatoc_probe_vert_glsl[];
|
||||
@@ -238,19 +240,24 @@ static void EEVEE_engine_init(void *ved)
|
||||
}
|
||||
|
||||
if (!e_data.probe_filter_sh) {
|
||||
char *lib_str = NULL;
|
||||
char *shader_str = NULL;
|
||||
|
||||
DynStr *ds_vert = BLI_dynstr_new();
|
||||
BLI_dynstr_append(ds_vert, datatoc_bsdf_common_lib_glsl);
|
||||
BLI_dynstr_append(ds_vert, datatoc_bsdf_sampling_lib_glsl);
|
||||
lib_str = BLI_dynstr_get_cstring(ds_vert);
|
||||
BLI_dynstr_free(ds_vert);
|
||||
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_with_lib(datatoc_probe_vert_glsl, datatoc_probe_geom_glsl, datatoc_probe_filter_frag_glsl, lib_str,
|
||||
"#define HAMMERSLEY_SIZE 8192\n"
|
||||
"#define NOISE_SIZE 64\n");
|
||||
e_data.probe_filter_sh = DRW_shader_create(datatoc_probe_vert_glsl, datatoc_probe_geom_glsl, shader_str,
|
||||
"#define HAMMERSLEY_SIZE 8192\n"
|
||||
"#define NOISE_SIZE 64\n");
|
||||
|
||||
MEM_freeN(lib_str);
|
||||
MEM_freeN(shader_str);
|
||||
}
|
||||
|
||||
if (!e_data.probe_spherical_harmonic_sh) {
|
||||
e_data.probe_spherical_harmonic_sh = DRW_shader_create_fullscreen(datatoc_probe_sh_frag_glsl, NULL);
|
||||
}
|
||||
|
||||
if (!e_data.tonemap) {
|
||||
@@ -340,6 +347,17 @@ static void EEVEE_cache_init(void *vedata)
|
||||
DRW_shgroup_uniform_texture(grp, "probeHdr", txl->probe_rt, 3);
|
||||
}
|
||||
|
||||
{
|
||||
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", &stl->probes->shres, 1);
|
||||
DRW_shgroup_uniform_texture(grp, "probeHdr", txl->probe_rt, 0);
|
||||
|
||||
struct Batch *geom = DRW_cache_fullscreen_quad_get();
|
||||
DRW_shgroup_call_add(grp, geom, NULL);
|
||||
}
|
||||
|
||||
{
|
||||
psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
|
||||
stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass);
|
||||
@@ -357,6 +375,7 @@ static void EEVEE_cache_init(void *vedata)
|
||||
DRW_shgroup_uniform_block(stl->g_data->default_lit_grp, "shadow_block", stl->shadow_ubo, 1);
|
||||
DRW_shgroup_uniform_int(stl->g_data->default_lit_grp, "light_count", &stl->lamps->num_light, 1);
|
||||
DRW_shgroup_uniform_float(stl->g_data->default_lit_grp, "lodMax", &stl->probes->lodmax, 1);
|
||||
DRW_shgroup_uniform_vec3(stl->g_data->default_lit_grp, "shCoefs[0]", (float *)stl->probes->shcoefs, 9);
|
||||
DRW_shgroup_uniform_vec3(stl->g_data->default_lit_grp, "cameraPos", e_data.camera_pos, 1);
|
||||
DRW_shgroup_uniform_texture(stl->g_data->default_lit_grp, "ltcMat", e_data.ltc_mat, 0);
|
||||
DRW_shgroup_uniform_texture(stl->g_data->default_lit_grp, "brdfLut", e_data.brdf_lut, 1);
|
||||
@@ -455,6 +474,7 @@ static void EEVEE_engine_free(void)
|
||||
DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.probe_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.probe_filter_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.probe_spherical_harmonic_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.tonemap);
|
||||
DRW_TEXTURE_FREE_SAFE(e_data.ltc_mat);
|
||||
DRW_TEXTURE_FREE_SAFE(e_data.brdf_lut);
|
||||
|
||||
@@ -39,7 +39,7 @@ typedef struct EEVEE_PassList {
|
||||
/* Probes */
|
||||
struct DRWPass *probe_background;
|
||||
struct DRWPass *probe_prefilter;
|
||||
struct DRWPass *probe_sh;
|
||||
struct DRWPass *probe_sh_compute;
|
||||
|
||||
struct DRWPass *depth_pass;
|
||||
struct DRWPass *depth_pass_cull;
|
||||
@@ -69,6 +69,7 @@ typedef struct EEVEE_TextureList {
|
||||
struct GPUTexture *probe_rt; /* R16_G16_B16 */
|
||||
struct GPUTexture *probe_depth_rt;
|
||||
struct GPUTexture *probe_pool; /* R11_G11_B10 */
|
||||
struct GPUTexture *probe_sh; /* R16_G16_B16 */
|
||||
|
||||
struct GPUTexture *color; /* R16_G16_B16 */
|
||||
} EEVEE_TextureList;
|
||||
@@ -82,6 +83,7 @@ typedef struct EEVEE_StorageList {
|
||||
|
||||
/* Probes */
|
||||
struct EEVEE_ProbesInfo *probes;
|
||||
struct GPUUniformBuffer *probe_ubo;
|
||||
|
||||
struct g_data *g_data;
|
||||
} EEVEE_StorageList;
|
||||
@@ -144,6 +146,9 @@ typedef struct EEVEE_ProbesInfo {
|
||||
float roughness;
|
||||
float lodfactor;
|
||||
float lodmax;
|
||||
int shres;
|
||||
int shnbr;
|
||||
float shcoefs[9][3]; /* Temp */
|
||||
struct GPUTexture *backgroundtex;
|
||||
} EEVEE_ProbesInfo;
|
||||
|
||||
|
||||
@@ -98,6 +98,11 @@ void EEVEE_probes_init(EEVEE_Data *vedata)
|
||||
DRWFboTexture tex_filter = {&txl->probe_pool, DRW_BUF_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
|
||||
|
||||
DRW_framebuffer_init(&fbl->probe_filter_fb, PROBE_SIZE, PROBE_SIZE, &tex_filter, 1);
|
||||
|
||||
/* Spherical Harmonic Buffer */
|
||||
DRWFboTexture tex_sh = {&txl->probe_sh, DRW_BUF_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
|
||||
|
||||
DRW_framebuffer_init(&fbl->probe_sh_fb, 9, 1, &tex_sh, 1);
|
||||
}
|
||||
|
||||
void EEVEE_probes_cache_init(EEVEE_Data *UNUSED(vedata))
|
||||
@@ -203,7 +208,8 @@ void EEVEE_refresh_probe(EEVEE_Data *vedata)
|
||||
DRW_framebuffer_texture_attach(fbl->probe_filter_fb, txl->probe_pool, 0, 0);
|
||||
|
||||
/* 4 - Compute spherical harmonics */
|
||||
/* TODO */
|
||||
// DRW_framebuffer_bind(fbl->probe_sh_fb);
|
||||
// DRW_draw_pass(psl->probe_sh);
|
||||
pinfo->shres = 64;
|
||||
DRW_framebuffer_bind(fbl->probe_sh_fb);
|
||||
DRW_draw_pass(psl->probe_sh_compute);
|
||||
DRW_framebuffer_read_data(0, 0, 9, 1, 3, 0, (float *)pinfo->shcoefs);
|
||||
}
|
||||
|
||||
@@ -173,6 +173,41 @@ float buffer_depth(bool is_persp, float z, float zf, float zn)
|
||||
}
|
||||
}
|
||||
|
||||
#define spherical_harmonics spherical_harmonics_L2
|
||||
|
||||
/* http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ */
|
||||
vec3 spherical_harmonics_L1(vec3 N, vec3 shcoefs[9])
|
||||
{
|
||||
vec3 sh = vec3(0.0);
|
||||
|
||||
sh += 0.282095 * shcoefs[0];
|
||||
|
||||
sh += -0.488603 * N.z * shcoefs[1];
|
||||
sh += 0.488603 * N.y * shcoefs[2];
|
||||
sh += -0.488603 * N.x * shcoefs[3];
|
||||
|
||||
return sh;
|
||||
}
|
||||
|
||||
vec3 spherical_harmonics_L2(vec3 N, vec3 shcoefs[9])
|
||||
{
|
||||
vec3 sh = vec3(0.0);
|
||||
|
||||
sh += 0.282095 * shcoefs[0];
|
||||
|
||||
sh += -0.488603 * N.z * shcoefs[1];
|
||||
sh += 0.488603 * N.y * shcoefs[2];
|
||||
sh += -0.488603 * N.x * shcoefs[3];
|
||||
|
||||
sh += 1.092548 * N.x * N.z * shcoefs[4];
|
||||
sh += -1.092548 * N.z * N.y * shcoefs[5];
|
||||
sh += 0.315392 * (3.0 * N.y * N.y - 1.0) * shcoefs[6];
|
||||
sh += -1.092548 * N.x * N.y * shcoefs[7];
|
||||
sh += 0.546274 * (N.x * N.x - N.z * N.z) * shcoefs[8];
|
||||
|
||||
return sh;
|
||||
}
|
||||
|
||||
float rectangle_solid_angle(AreaData ad)
|
||||
{
|
||||
vec3 n0 = normalize(cross(ad.corner[0], ad.corner[1]));
|
||||
|
||||
@@ -6,6 +6,7 @@ uniform mat4 ProjectionMatrix;
|
||||
|
||||
uniform samplerCube probeFiltered;
|
||||
uniform float lodMax;
|
||||
uniform vec3 shCoefs[9];
|
||||
|
||||
#ifndef USE_LTC
|
||||
uniform sampler2D brdfLut;
|
||||
@@ -198,7 +199,7 @@ void main()
|
||||
sd.R = reflect(-sd.V, sd.N);
|
||||
|
||||
/* hardcoded test vars */
|
||||
vec3 albedo = vec3(0.0);
|
||||
vec3 albedo = mix(vec3(0.0, 0.0, 0.0), vec3(0.8, 0.8, 0.8), saturate(worldPosition.y/2));
|
||||
vec3 f0 = mix(vec3(0.83, 0.5, 0.1), vec3(0.03, 0.03, 0.03), saturate(worldPosition.y/2));
|
||||
vec3 specular = mix(f0, vec3(1.0), pow(max(0.0, 1.0 - dot(sd.N, sd.V)), 5.0));
|
||||
float roughness = saturate(worldPosition.x/lodMax);
|
||||
@@ -229,5 +230,7 @@ void main()
|
||||
vec3 Li = textureLod(probeFiltered, sd.spec_dominant_dir, roughness * lodMax).rgb;
|
||||
radiance += Li * brdf_lut.y + f0 * Li * brdf_lut.x;
|
||||
|
||||
radiance += spherical_harmonics(sd.N, shCoefs) * albedo;
|
||||
|
||||
fragColor = vec4(radiance, 1.0);
|
||||
}
|
||||
106
source/blender/draw/engines/eevee/shaders/probe_sh_frag.glsl
Normal file
106
source/blender/draw/engines/eevee/shaders/probe_sh_frag.glsl
Normal file
@@ -0,0 +1,106 @@
|
||||
|
||||
uniform samplerCube probeHdr;
|
||||
uniform int probeSize;
|
||||
|
||||
in vec3 worldPosition;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
#define M_4PI 12.5663706143591729
|
||||
|
||||
const mat3 CUBE_ROTATIONS[6] = mat3[](
|
||||
mat3(vec3( 0.0, 0.0, -1.0),
|
||||
vec3( 0.0, -1.0, 0.0),
|
||||
vec3(-1.0, 0.0, 0.0)),
|
||||
mat3(vec3( 0.0, 0.0, 1.0),
|
||||
vec3( 0.0, -1.0, 0.0),
|
||||
vec3( 1.0, 0.0, 0.0)),
|
||||
mat3(vec3( 1.0, 0.0, 0.0),
|
||||
vec3( 0.0, 0.0, 1.0),
|
||||
vec3( 0.0, -1.0, 0.0)),
|
||||
mat3(vec3( 1.0, 0.0, 0.0),
|
||||
vec3( 0.0, 0.0, -1.0),
|
||||
vec3( 0.0, 1.0, 0.0)),
|
||||
mat3(vec3( 1.0, 0.0, 0.0),
|
||||
vec3( 0.0, -1.0, 0.0),
|
||||
vec3( 0.0, 0.0, -1.0)),
|
||||
mat3(vec3(-1.0, 0.0, 0.0),
|
||||
vec3( 0.0, -1.0, 0.0),
|
||||
vec3( 0.0, 0.0, 1.0)));
|
||||
|
||||
vec3 get_cubemap_vector(vec2 co, int face)
|
||||
{
|
||||
return normalize(CUBE_ROTATIONS[face] * vec3(co * 2.0 - 1.0, 1.0));
|
||||
}
|
||||
|
||||
float area_element(float x, float y)
|
||||
{
|
||||
return atan(x * y, sqrt(x * x + y * y + 1));
|
||||
}
|
||||
|
||||
float texel_solid_angle(vec2 co, float halfpix)
|
||||
{
|
||||
vec2 v1 = (co - vec2(halfpix)) * 2.0 - 1.0;
|
||||
vec2 v2 = (co + vec2(halfpix)) * 2.0 - 1.0;
|
||||
|
||||
return area_element(v1.x, v1.y) - area_element(v1.x, v2.y) - area_element(v2.x, v1.y) + area_element(v2.x, v2.y);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float pixstep = 1.0 / probeSize;
|
||||
float halfpix = pixstep / 2.0;
|
||||
|
||||
float weight_accum = 0.0;
|
||||
vec3 sh = vec3(0.0);
|
||||
|
||||
int shnbr = int(floor(gl_FragCoord.x));
|
||||
|
||||
for (int face = 0; face < 6; ++face) {
|
||||
for (float x = halfpix; x < 1.0; x += pixstep) {
|
||||
for (float y = halfpix; y < 1.0; y += pixstep) {
|
||||
float shcoef;
|
||||
|
||||
vec2 facecoord = vec2(x,y);
|
||||
vec3 cubevec = get_cubemap_vector(facecoord, face);
|
||||
float weight = texel_solid_angle(facecoord, halfpix);
|
||||
|
||||
if (shnbr == 0) {
|
||||
shcoef = 0.282095;
|
||||
}
|
||||
else if (shnbr == 1) {
|
||||
shcoef = -0.488603 * cubevec.z * 2.0 / 3.0;
|
||||
}
|
||||
else if (shnbr == 2) {
|
||||
shcoef = 0.488603 * cubevec.y * 2.0 / 3.0;
|
||||
}
|
||||
else if (shnbr == 3) {
|
||||
shcoef = -0.488603 * cubevec.x * 2.0 / 3.0;
|
||||
}
|
||||
else if (shnbr == 4) {
|
||||
shcoef = 1.092548 * cubevec.x * cubevec.z * 1.0 / 4.0;
|
||||
}
|
||||
else if (shnbr == 5) {
|
||||
shcoef = -1.092548 * cubevec.z * cubevec.y * 1.0 / 4.0;
|
||||
}
|
||||
else if (shnbr == 6) {
|
||||
shcoef = 0.315392 * (3.0 * cubevec.y * cubevec.y - 1.0) * 1.0 / 4.0;
|
||||
}
|
||||
else if (shnbr == 7) {
|
||||
shcoef = 1.092548 * cubevec.x * cubevec.y * 1.0 / 4.0;
|
||||
}
|
||||
else { /* (shnbr == 8) */
|
||||
shcoef = 0.546274 * (cubevec.x * cubevec.x - cubevec.z * cubevec.z) * 1.0 / 4.0;
|
||||
}
|
||||
|
||||
vec4 sample = textureCube(probeHdr, cubevec);
|
||||
sh += sample.rgb * shcoef * weight;
|
||||
weight_accum += weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sh *= M_4PI / weight_accum;
|
||||
|
||||
gl_FragColor = vec4(sh, 1.0);
|
||||
}
|
||||
@@ -193,6 +193,7 @@ typedef struct DRWFboTexture {
|
||||
void DRW_framebuffer_init(struct GPUFrameBuffer **fb, int width, int height, DRWFboTexture textures[MAX_FBO_TEX], int texnbr);
|
||||
void DRW_framebuffer_bind(struct GPUFrameBuffer *fb);
|
||||
void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth);
|
||||
void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slot, float *data);
|
||||
void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip);
|
||||
void DRW_framebuffer_texture_detach(struct GPUTexture *tex);
|
||||
void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth);
|
||||
|
||||
@@ -1302,6 +1302,21 @@ void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col
|
||||
((stencil) ? GL_STENCIL_BUFFER_BIT : 0));
|
||||
}
|
||||
|
||||
void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slot, float *data)
|
||||
{
|
||||
GLenum type;
|
||||
switch (channels) {
|
||||
case 1: type = GL_RED; break;
|
||||
case 2: type = GL_RG; break;
|
||||
case 3: type = GL_RGB; break;
|
||||
case 4: type = GL_RGBA; break;
|
||||
default:
|
||||
BLI_assert(false && "wrong number of read channels");
|
||||
}
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0 + slot);
|
||||
glReadPixels(x, y, w, h, type, GL_FLOAT, data);
|
||||
}
|
||||
|
||||
void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip)
|
||||
{
|
||||
GPU_framebuffer_texture_attach(fb, tex, slot, mip);
|
||||
|
||||
Reference in New Issue
Block a user