Eevee: First Shadows implementation
authorClément Foucault <foucault.clem@gmail.com>
Mon, 10 Apr 2017 10:06:17 +0000 (12:06 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Mon, 10 Apr 2017 10:36:32 +0000 (12:36 +0200)
Using Texture Arrays to store shadow maps so less texture slots are used when shading. This means a large amount of shadows can be supported.

Support Projection Shadow Map for sun like in old BI/BGE.

Support Cube Shadow Map for Point/Spot/Area lights. the benefit of using it for spot light is that the spot angle does not change shadow resolution (at the cost of more memory used). The implementation of the cubemap sampling is targeted for 3.3 core. We rely on 2D texture arrays to store cubemaps faces and sample the right one manualy. Significant performance improvement can be done using Cubemap Arrays on supported hardware.

Shadows are only hardware filtered. Prefiltered shadows and settings comming next.

16 files changed:
source/blender/draw/CMakeLists.txt
source/blender/draw/engines/eevee/eevee.c
source/blender/draw/engines/eevee/eevee_lights.c
source/blender/draw/engines/eevee/eevee_private.h
source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
source/blender/draw/engines/eevee/shaders/shadow_frag.glsl [new file with mode: 0644]
source/blender/draw/engines/eevee/shaders/shadow_geom.glsl [new file with mode: 0644]
source/blender/draw/engines/eevee/shaders/shadow_vert.glsl [new file with mode: 0644]
source/blender/draw/intern/DRW_render.h
source/blender/draw/intern/draw_manager.c
source/blender/gpu/GPU_lamp.h
source/blender/gpu/GPU_viewport.h
source/blender/gpu/intern/gpu_framebuffer.c
source/blender/gpu/intern/gpu_lamp.c
source/blender/gpu/intern/gpu_texture.c

index e921a65bfe893eb18a75ff064c697c3c9fefb58a..67a1a6d5e88d135fc49a9dd8e501cde6e9958a02 100644 (file)
@@ -103,6 +103,9 @@ 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/shadow_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/shadow_geom.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC)
 data_to_c_simple(engines/eevee/shaders/tonemap_frag.glsl SRC)
 data_to_c_simple(engines/eevee/shaders/bsdf_direct_lib.glsl SRC)
 data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC)
index 7588ebede0c63f138b7072f6f59f63140f619a9f..2013df35deb0a07efea26fa76a1bac2189343035 100644 (file)
@@ -38,8 +38,10 @@ static struct {
        struct GPUShader *default_lit;
        struct GPUShader *depth_sh;
        struct GPUShader *tonemap;
+       struct GPUShader *shadow_sh;
        struct GPUTexture *ltc_mat;
        struct GPUTexture *ltc_mag;
+
        float camera_pos[3];
 } e_data = {NULL}; /* Engine data */
 
@@ -49,6 +51,9 @@ extern char datatoc_bsdf_direct_lib_glsl[];
 extern char datatoc_lit_surface_frag_glsl[];
 extern char datatoc_lit_surface_vert_glsl[];
 extern char datatoc_tonemap_frag_glsl[];
+extern char datatoc_shadow_frag_glsl[];
+extern char datatoc_shadow_geom_glsl[];
+extern char datatoc_shadow_vert_glsl[];
 
 /* *********** FUNCTIONS *********** */
 
@@ -79,11 +84,20 @@ static void EEVEE_engine_init(void *vedata)
                lib_str = BLI_dynstr_get_cstring(ds_vert);
                BLI_dynstr_free(ds_vert);
 
-               e_data.default_lit = DRW_shader_create_with_lib(datatoc_lit_surface_vert_glsl, NULL, datatoc_lit_surface_frag_glsl, lib_str, "#define MAX_LIGHT 128\n");
+               e_data.default_lit = DRW_shader_create_with_lib(datatoc_lit_surface_vert_glsl, NULL, datatoc_lit_surface_frag_glsl, lib_str,
+                                                               "#define MAX_LIGHT 128\n"
+                                                               "#define MAX_SHADOW_CUBE 42\n"
+                                                               "#define MAX_SHADOW_MAP 64\n"
+                                                               "#define MAX_SHADOW_CASCADE 8\n"
+                                                               "#define MAX_CASCADE_NUM 4\n");
 
                MEM_freeN(lib_str);
        }
 
+       if (!e_data.shadow_sh) {
+               e_data.shadow_sh = DRW_shader_create(datatoc_shadow_vert_glsl, datatoc_shadow_geom_glsl, datatoc_shadow_frag_glsl, NULL);
+       }
+
        if (!e_data.tonemap) {
                e_data.tonemap = DRW_shader_create_fullscreen(datatoc_tonemap_frag_glsl, NULL);
        }
@@ -96,8 +110,9 @@ static void EEVEE_engine_init(void *vedata)
                e_data.ltc_mag = DRW_texture_create_2D(64, 64, DRW_TEX_R_16, DRW_TEX_FILTER, ltc_mag_ggx);
        }
 
-       if (stl->lights_info == NULL)
+       if (stl->lamps == NULL) {
                EEVEE_lights_init(stl);
+       }
 
        // EEVEE_lights_update(stl);
        {
@@ -119,6 +134,14 @@ static void EEVEE_cache_init(void *vedata)
                stl->g_data = MEM_mallocN(sizeof(g_data), "g_data");
        }
 
+       {
+               /* Shadow Pass */
+               psl->shadow_pass = DRW_pass_create("Shadow Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+               stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass);
+               DRW_shgroup_uniform_mat4(stl->g_data->shadow_shgrp, "ShadowMatrix", (float *)stl->lamps->shadowmat);
+               DRW_shgroup_uniform_int(stl->g_data->shadow_shgrp, "Layer", &stl->lamps->layer, 1);
+       }
+
        {
                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);
@@ -132,11 +155,13 @@ static void EEVEE_cache_init(void *vedata)
                psl->pass = DRW_pass_create("Default Light Pass", state);
 
                stl->g_data->default_lit_grp = DRW_shgroup_create(e_data.default_lit, psl->pass);
-               DRW_shgroup_uniform_block(stl->g_data->default_lit_grp, "light_block", stl->lights_ubo, 0);
-               DRW_shgroup_uniform_int(stl->g_data->default_lit_grp, "light_count", &stl->lights_info->light_count, 1);
+               DRW_shgroup_uniform_block(stl->g_data->default_lit_grp, "light_block", stl->light_ubo, 0);
+               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_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, "ltcMag", e_data.ltc_mag, 1);
+               /* NOTE : Adding Shadow Map textures uniform in EEVEE_cache_finish */
        }
 
        {
@@ -167,6 +192,7 @@ static void EEVEE_cache_populate(void *vedata, Object *ob)
                DRW_shgroup_call_add((do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp, geom, ob->obmat);
 
                DRW_shgroup_call_add(stl->g_data->default_lit_grp, geom, ob->obmat);
+               DRW_shgroup_call_add(stl->g_data->shadow_shgrp, geom, ob->obmat);
        }
        else if (ob->type == OB_LAMP) {
                EEVEE_lights_cache_add(stl, ob);
@@ -176,8 +202,14 @@ static void EEVEE_cache_populate(void *vedata, Object *ob)
 static void EEVEE_cache_finish(void *vedata)
 {
        EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+       EEVEE_TextureList *txl = ((EEVEE_Data *)vedata)->txl;
+       EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl;
 
-       EEVEE_lights_cache_finish(stl);
+       EEVEE_lights_cache_finish(stl, txl, fbl);
+
+       /* Shadows binding */
+       DRW_shgroup_uniform_texture(stl->g_data->default_lit_grp, "shadowMaps", txl->shadow_depth_map_pool, 2);
+       DRW_shgroup_uniform_texture(stl->g_data->default_lit_grp, "shadowCubes", txl->shadow_depth_cube_pool, 3);
 }
 
 static void EEVEE_draw_scene(void *vedata)
@@ -189,6 +221,9 @@ static void EEVEE_draw_scene(void *vedata)
        DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
        DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
 
+       /* Refresh shadows */
+       EEVEE_draw_shadows((EEVEE_Data *)vedata);
+
        /* Attach depth to the hdr buffer and bind it */        
        DRW_framebuffer_texture_detach(dtxl->depth);
        DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0);
@@ -197,7 +232,7 @@ static void EEVEE_draw_scene(void *vedata)
        /* Clear Depth */
        /* TODO do background */
        float clearcol[4] = {0.0f, 0.0f, 0.0f, 1.0f};
-       DRW_framebuffer_clear(true, true, true, clearcol, 1.0f);
+       DRW_framebuffer_clear(true, true, false, clearcol, 1.0f);
 
        DRW_draw_pass(psl->depth_pass);
        DRW_draw_pass(psl->depth_pass_cull);
@@ -215,6 +250,8 @@ static void EEVEE_engine_free(void)
 {
        if (e_data.default_lit)
                DRW_shader_free(e_data.default_lit);
+       if (e_data.shadow_sh)
+               DRW_shader_free(e_data.shadow_sh);
        if (e_data.tonemap)
                DRW_shader_free(e_data.tonemap);
        if (e_data.ltc_mat)
index 6a6947bdc3fd22ed59b0de018c881c4c9f92842c..9a06c665ae2fb3b1309f3559fe3565aa1cb6e329 100644 (file)
 
 #include "DRW_render.h"
 
+#include "eevee.h"
 #include "eevee_private.h"
 
-#define MAX_LIGHT 210 /* TODO : find size by dividing UBO max size by light data size */
+typedef struct EEVEE_LightData {
+       short light_id, shadow_id;
+} EEVEE_LightData;
 
-typedef struct EEVEE_Light {
-       float position[3], dist;
-       float color[3], spec;
-       float spotsize, spotblend, radius, shadowid;
-       float rightvec[3], sizex;
-       float upvec[3], sizey;
-       float forwardvec[3], lamptype;
-} EEVEE_Light;
+typedef struct EEVEE_ShadowCubeData {
+       short light_id, shadow_id;
+       float viewprojmat[6][4][4];
+} EEVEE_ShadowCubeData;
 
+typedef struct EEVEE_ShadowMapData {
+       short light_id, shadow_id;
+       float viewprojmat[4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
+} EEVEE_ShadowMapData;
+
+typedef struct EEVEE_ShadowCascadeData {
+       short light_id, shadow_id;
+       float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
+} EEVEE_ShadowCascadeData;
+
+/* *********** FUNCTIONS *********** */
 
 void EEVEE_lights_init(EEVEE_StorageList *stl)
 {
-       stl->lights_info = MEM_callocN(sizeof(EEVEE_LightsInfo), "EEVEE_LightsInfo");
-       stl->lights_data = MEM_mallocN(sizeof(EEVEE_Light) * MAX_LIGHT, "EEVEE_LightsUboStorage");
-       stl->lights_ref  = MEM_mallocN(sizeof(Object *) * MAX_LIGHT, "EEVEE lights_ref");
-       stl->lights_ubo  = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL);
+       const unsigned int shadow_ubo_size = sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
+                                            sizeof(EEVEE_ShadowMap) * MAX_SHADOW_MAP +
+                                            sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
+
+       if (!stl->lamps) {
+               stl->lamps  = MEM_callocN(sizeof(EEVEE_LampsInfo), "EEVEE_LampsInfo");
+               stl->light_ubo   = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL);
+               stl->shadow_ubo  = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
+       }
 }
 
 void EEVEE_lights_cache_init(EEVEE_StorageList *stl)
 {
-       BLI_listbase_clear(&stl->g_data->lamps);
-       stl->lights_info->light_count = 0;
-}
+       EEVEE_LampsInfo *linfo = stl->lamps;
 
-void EEVEE_lights_cache_add(EEVEE_StorageList *stl, Object *ob)
-{
-       BLI_addtail(&stl->g_data->lamps, BLI_genericNodeN(ob));
-       stl->lights_info->light_count += 1;
+       linfo->num_light = linfo->num_cube = linfo->num_map = linfo->num_cascade = 0;
+       memset(linfo->light_ref, 0, sizeof(linfo->light_ref));
+       memset(linfo->shadow_cube_ref, 0, sizeof(linfo->shadow_cube_ref));
+       memset(linfo->shadow_map_ref, 0, sizeof(linfo->shadow_map_ref));
+       memset(linfo->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref));
 }
 
-void EEVEE_lights_cache_finish(EEVEE_StorageList *stl)
+void EEVEE_lights_cache_add(EEVEE_StorageList *stl, Object *ob)
 {
-       int light_ct = stl->lights_info->light_count;
+       EEVEE_LampsInfo *linfo = stl->lamps;
 
-       if (light_ct > MAX_LIGHT) {
+       /* Step 1 find all lamps in the scene and setup them */
+       if (linfo->num_light > MAX_LIGHT) {
                printf("Too much lamps in the scene !!!\n");
-               stl->lights_info->light_count = MAX_LIGHT;
+               linfo->num_light = MAX_LIGHT;
        }
+       else {
+               Lamp *la = (Lamp *)ob->data;
+               EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type);
 
-       if (light_ct > 0) {
-               int i = 0;
-               for (LinkData *link = stl->g_data->lamps.first; link && i < MAX_LIGHT; link = link->next, i++) {
-                       Object *ob = (Object *)link->data;
-                       stl->lights_ref[i] = ob;
+               DRW_lamp_engine_data_free((void *)led);
+
+               if (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY)) {
+                       if (la->type == LA_SUN && linfo->num_map < MAX_SHADOW_MAP) {
+                               led->sto = MEM_mallocN(sizeof(EEVEE_ShadowMapData), "EEVEE_ShadowMapData");
+                               ((EEVEE_ShadowMapData *)led->sto)->shadow_id = linfo->num_map;
+                               linfo->shadow_map_ref[linfo->num_map] = ob;
+                               linfo->num_map++;
+                       }
+                       else if ((la->type == LA_SPOT || la->type == LA_LOCAL || la->type == LA_AREA)
+                                 && linfo->num_cube < MAX_SHADOW_CUBE) {
+                               led->sto = MEM_mallocN(sizeof(EEVEE_ShadowCubeData), "EEVEE_ShadowCubeData");
+                               ((EEVEE_ShadowCubeData *)led->sto)->shadow_id = linfo->num_cube;
+                               linfo->shadow_cube_ref[linfo->num_cube] = ob;
+                               linfo->num_cube++;
+                       }
                }
+
+               if (!led->sto) {
+                       led->sto = MEM_mallocN(sizeof(EEVEE_LightData), "EEVEE_LightData");
+                       ((EEVEE_LightData *)led->sto)->shadow_id = -1;
+               }
+
+               ((EEVEE_LightData *)led->sto)->light_id = linfo->num_light;
+               linfo->light_ref[linfo->num_light] = ob;
+               linfo->num_light++;
        }
-       BLI_freelistN(&stl->g_data->lamps);
+}
+
+void EEVEE_lights_cache_finish(EEVEE_StorageList *stl, EEVEE_TextureList *txl, EEVEE_FramebufferList *fbl)
+{
+       EEVEE_LampsInfo *linfo = stl->lamps;
 
-       /* We changed light data so we need to upload it */
+       /* Step 4 Update Lamp UBOs */
        EEVEE_lights_update(stl);
+
+       /* Step 5 Setup enough layers */
+       /* Free textures if number mismatch */
+       if (linfo->num_cube != linfo->cache_num_cube) {
+               if (txl->shadow_depth_cube_pool) {
+                       DRW_texture_free(txl->shadow_depth_cube_pool);
+                       txl->shadow_depth_cube_pool = NULL;
+               }
+               linfo->cache_num_cube = linfo->num_cube;
+       }
+       if (linfo->num_map != linfo->cache_num_map) {
+               if (txl->shadow_depth_map_pool) {
+                       DRW_texture_free(txl->shadow_depth_map_pool);
+                       txl->shadow_depth_map_pool = NULL;
+               }
+               linfo->cache_num_map = linfo->num_map;
+       }
+       if (linfo->num_cascade != linfo->cache_num_cascade) {
+               if (txl->shadow_depth_cascade_pool) {
+                       DRW_texture_free(txl->shadow_depth_cascade_pool);
+                       txl->shadow_depth_cascade_pool = NULL;
+               }
+               linfo->cache_num_cascade = linfo->num_cascade;
+       }
+
+       /* Initialize Textures Arrays first so DRW_framebuffer_init just bind them */
+       if (!txl->shadow_depth_cube_pool) {
+               txl->shadow_depth_cube_pool = DRW_texture_create_2D_array(512, 512, MAX2(1, linfo->num_cube * 6), DRW_TEX_DEPTH_24, DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
+               if (fbl->shadow_cube_fb)
+                       DRW_framebuffer_texture_attach(fbl->shadow_cube_fb, txl->shadow_depth_cube_pool, 0);
+       }
+       if (!txl->shadow_depth_map_pool) {
+               txl->shadow_depth_map_pool = DRW_texture_create_2D_array(512, 512, MAX2(1, linfo->num_map), DRW_TEX_DEPTH_24, DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
+               if (fbl->shadow_map_fb)
+                       DRW_framebuffer_texture_attach(fbl->shadow_map_fb, txl->shadow_depth_map_pool, 0);
+       }
+       if (!txl->shadow_depth_cascade_pool) {
+               txl->shadow_depth_cascade_pool = DRW_texture_create_2D_array(512, 512, MAX2(1, linfo->num_cascade), DRW_TEX_DEPTH_24, DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
+               if (fbl->shadow_cascade_fb)
+                       DRW_framebuffer_texture_attach(fbl->shadow_cascade_fb, txl->shadow_depth_map_pool, 0);
+       }
+
+       DRWFboTexture tex_cube = {&txl->shadow_depth_cube_pool, DRW_BUF_DEPTH_24, DRW_TEX_FILTER | DRW_TEX_COMPARE};
+       DRW_framebuffer_init(&fbl->shadow_cube_fb, 512, 512, &tex_cube, 1);
+
+       DRWFboTexture tex_map = {&txl->shadow_depth_map_pool, DRW_BUF_DEPTH_24, DRW_TEX_FILTER | DRW_TEX_COMPARE};
+       DRW_framebuffer_init(&fbl->shadow_map_fb, 512, 512, &tex_map, 1);
+
+       DRWFboTexture tex_cascade = {&txl->shadow_depth_cascade_pool, DRW_BUF_DEPTH_24, DRW_TEX_FILTER | DRW_TEX_COMPARE};
+       DRW_framebuffer_init(&fbl->shadow_cascade_fb, 512, 512, &tex_cascade, 1);
 }
 
-void EEVEE_lights_update(EEVEE_StorageList *stl)
+/* Update buffer with lamp data */
+static void eevee_light_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
 {
-       int light_ct = stl->lights_info->light_count;
-
        /* TODO only update if data changes */
-       /* Update buffer with lamp data */
-       for (int i = 0; i < light_ct; ++i) {
-               EEVEE_Light *evli = stl->lights_data + i;
-               Object *ob = stl->lights_ref[i];
-               Lamp *la = (Lamp *)ob->data;
-               float mat[4][4], scale[3], power;
+       EEVEE_LightData *evld = led->sto;
+       EEVEE_Light *evli = linfo->light_data + evld->light_id;
+       Lamp *la = (Lamp *)ob->data;
+       float mat[4][4], scale[3], power;
 
-               /* Position */
-               copy_v3_v3(evli->position, ob->obmat[3]);
+       /* Position */
+       copy_v3_v3(evli->position, ob->obmat[3]);
 
-               /* Color */
-               evli->color[0] = la->r * la->energy;
-               evli->color[1] = la->g * la->energy;
-               evli->color[2] = la->b * la->energy;
+       /* Color */
+       evli->color[0] = la->r * la->energy;
+       evli->color[1] = la->g * la->energy;
+       evli->color[2] = la->b * la->energy;
 
-               /* Influence Radius */
-               evli->dist = la->dist;
+       /* Influence Radius */
+       evli->dist = la->dist;
 
-               /* Vectors */
-               normalize_m4_m4_ex(mat, ob->obmat, scale);
-               copy_v3_v3(evli->forwardvec, mat[2]);
-               normalize_v3(evli->forwardvec);
-               negate_v3(evli->forwardvec);
+       /* Vectors */
+       normalize_m4_m4_ex(mat, ob->obmat, scale);
+       copy_v3_v3(evli->forwardvec, mat[2]);
+       normalize_v3(evli->forwardvec);
+       negate_v3(evli->forwardvec);
 
-               copy_v3_v3(evli->rightvec, mat[0]);
-               normalize_v3(evli->rightvec);
+       copy_v3_v3(evli->rightvec, mat[0]);
+       normalize_v3(evli->rightvec);
 
-               copy_v3_v3(evli->upvec, mat[1]);
-               normalize_v3(evli->upvec);
+       copy_v3_v3(evli->upvec, mat[1]);
+       normalize_v3(evli->upvec);
 
-               /* Spot size & blend */
-               if (la->type == LA_SPOT) {
-                       evli->sizex = scale[0] / scale[2];
-                       evli->sizey = scale[1] / scale[2];
-                       evli->spotsize = cosf(la->spotsize * 0.5f);
-                       evli->spotblend = (1.0f - evli->spotsize) * la->spotblend;
-               }
-               else if (la->type == LA_AREA) {
-                       evli->sizex = MAX2(0.0001f, la->area_size * scale[0] * 0.5f);
-                       if (la->area_shape == LA_AREA_RECT) {
-                               evli->sizey = MAX2(0.0001f, la->area_sizey * scale[1] * 0.5f);
-                       }
-                       else {
-                               evli->sizey = evli->sizex;
-                       }
+       /* Spot size & blend */
+       if (la->type == LA_SPOT) {
+               evli->sizex = scale[0] / scale[2];
+               evli->sizey = scale[1] / scale[2];
+               evli->spotsize = cosf(la->spotsize * 0.5f);
+               evli->spotblend = (1.0f - evli->spotsize) * la->spotblend;
+               evli->radius = MAX2(0.001f, la->area_size);
+       }
+       else if (la->type == LA_AREA) {
+               evli->sizex = MAX2(0.0001f, la->area_size * scale[0] * 0.5f);
+               if (la->area_shape == LA_AREA_RECT) {
+                       evli->sizey = MAX2(0.0001f, la->area_sizey * scale[1] * 0.5f);
                }
                else {
-                       evli->sizex = MAX2(0.001f, la->area_size);
+                       evli->sizey = evli->sizex;
                }
+       }
+       else {
+               evli->radius = MAX2(0.001f, la->area_size);
+       }
 
-               /* Make illumination power constant */
-               if (la->type == LA_AREA) {
-                       power = 1.0f / (evli->sizex * evli->sizey * 4.0f * M_PI) /* 1/(w*h*Pi) */
-                               * 80.0f; /* XXX : Empirical, Fit cycles power */
-               }
-               else if (la->type == LA_SPOT || la->type == LA_LOCAL) {
-                       power = 1.0f / (4.0f * evli->sizex * evli->sizex * M_PI * M_PI) /* 1/(4*r²*Pi²) */
-                               * M_PI * M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */
+       /* Make illumination power constant */
+       if (la->type == LA_AREA) {
+               power = 1.0f / (evli->sizex * evli->sizey * 4.0f * M_PI) /* 1/(w*h*Pi) */
+                       * 80.0f; /* XXX : Empirical, Fit cycles power */
+       }
+       else if (la->type == LA_SPOT || la->type == LA_LOCAL) {
+               power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) /* 1/(4*r²*Pi²) */
+                       * M_PI * M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */
 
-                       /* for point lights (a.k.a radius == 0.0) */
-                       // power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */
-               }
-               else {
-                       power = 1.0f;
+               /* for point lights (a.k.a radius == 0.0) */
+               // power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */
+       }
+       else {
+               power = 1.0f;
+       }
+       mul_v3_fl(evli->color, power);
+
+       /* Lamp Type */
+       evli->lamptype = (float)la->type;
+
+       /* No shadow by default */
+       evli->shadowid = -1.0f;
+}
+
+static float texcomat[4][4] = { /* From NDC to TexCo */
+       {0.5, 0.0, 0.0, 0.0},
+       {0.0, 0.5, 0.0, 0.0},
+       {0.0, 0.0, 0.5, 0.0},
+       {0.5, 0.5, 0.5, 1.0}
+};
+
+static float cubefacemat[6][4][4] = {
+       /* Pos X */
+       {{0.0, 0.0, -1.0, 0.0},
+        {0.0, -1.0, 0.0, 0.0},
+        {-1.0, 0.0, 0.0, 0.0},
+        {0.0, 0.0, 0.0, 1.0}},
+       /* Neg X */
+       {{0.0, 0.0, 1.0, 0.0},
+        {0.0, -1.0, 0.0, 0.0},
+        {1.0, 0.0, 0.0, 0.0},
+        {0.0, 0.0, 0.0, 1.0}},
+       /* Pos Y */
+       {{1.0, 0.0, 0.0, 0.0},
+        {0.0, 0.0, 1.0, 0.0},
+        {0.0, -1.0, 0.0, 0.0},
+        {0.0, 0.0, 0.0, 1.0}},
+       /* Neg Y */
+       {{1.0, 0.0, 0.0, 0.0},
+        {0.0, 0.0, -1.0, 0.0},
+        {0.0, 1.0, 0.0, 0.0},
+        {0.0, 0.0, 0.0, 1.0}},
+       /* Pos Z */
+       {{1.0, 0.0, 0.0, 0.0},
+        {0.0, -1.0, 0.0, 0.0},
+        {0.0, 0.0, -1.0, 0.0},
+        {0.0, 0.0, 0.0, 1.0}},
+       /* Neg Z */
+       {{-1.0, 0.0, 0.0, 0.0},
+        {0.0, -1.0, 0.0, 0.0},
+        {0.0, 0.0, 1.0, 0.0},
+        {0.0, 0.0, 0.0, 1.0}},
+};
+
+static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
+{
+       float projmat[4][4];
+
+       EEVEE_ShadowCubeData *evsmp = (EEVEE_ShadowCubeData *)led->sto;
+       EEVEE_Light *evli = linfo->light_data + evsmp->light_id;
+       EEVEE_ShadowCube *evsh = linfo->shadow_cube_data + evsmp->shadow_id;
+       Lamp *la = (Lamp *)ob->data;
+
+       perspective_m4(projmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend);
+
+       for (int i = 0; i < 6; ++i) {
+               float tmp[4][4];
+               unit_m4(tmp);
+               negate_v3_v3(tmp[3], ob->obmat[3]);
+               mul_m4_m4m4(tmp, cubefacemat[i], tmp);
+               mul_m4_m4m4(evsmp->viewprojmat[i], projmat, tmp);
+       }
+
+       evsh->bias = 0.05f * la->bias;
+       evsh->near = la->clipsta;
+       evsh->far = la->clipend;
+
+       evli->shadowid = (float)(evsmp->shadow_id);
+}
+
+static void eevee_shadow_map_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
+{
+       float viewmat[4][4], projmat[4][4];
+
+       EEVEE_ShadowMapData *evsmp = (EEVEE_ShadowMapData *)led->sto;
+       EEVEE_Light *evli = linfo->light_data + evsmp->light_id;
+       EEVEE_ShadowMap *evsh = linfo->shadow_map_data + evsmp->shadow_id;
+       Lamp *la = (Lamp *)ob->data;
+
+       invert_m4_m4(viewmat, ob->obmat);
+       normalize_v3(viewmat[0]);
+       normalize_v3(viewmat[1]);
+       normalize_v3(viewmat[2]);
+
+       float wsize = la->shadow_frustum_size;
+       orthographic_m4(projmat, -wsize, wsize, -wsize, wsize, la->clipsta, la->clipend);
+
+       mul_m4_m4m4(evsmp->viewprojmat, projmat, viewmat);
+       mul_m4_m4m4(evsh->shadowmat, texcomat, evsmp->viewprojmat);
+
+       evsh->bias = 0.005f * la->bias;
+
+       evli->shadowid = (float)(MAX_SHADOW_CUBE + evsmp->shadow_id);
+}
+
+void EEVEE_lights_update(EEVEE_StorageList *stl)
+{
+       EEVEE_LampsInfo *linfo = stl->lamps;
+       Object *ob;
+       int i;
+
+       for (i = 0; (ob = linfo->light_ref[i]) && (i < MAX_LIGHT); i++) {
+               EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type);
+               eevee_light_setup(ob, linfo, led);
+       }
+
+       for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
+               EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type);
+               eevee_shadow_cube_setup(ob, linfo, led);
+       }
+
+       for (i = 0; (ob = linfo->shadow_map_ref[i]) && (i < MAX_SHADOW_MAP); i++) {
+               EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type);
+               eevee_shadow_map_setup(ob, linfo, led);
+       }
+
+       // for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
+       //      EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type);
+       //      eevee_shadow_map_setup(ob, linfo, led);
+       // }
+
+       DRW_uniformbuffer_update(stl->light_ubo, &linfo->light_data);
+       DRW_uniformbuffer_update(stl->shadow_ubo, &linfo->shadow_cube_data); /* Update all data at once */
+}
+
+/* this refresh lamps shadow buffers */
+void EEVEE_draw_shadows(EEVEE_Data *vedata)
+{
+       EEVEE_StorageList *stl = vedata->stl;
+       EEVEE_FramebufferList *fbl = vedata->fbl;
+       EEVEE_LampsInfo *linfo = stl->lamps;
+       Object *ob;
+       int i;
+
+       /* Cube Shadow Maps */
+       /* For old hardware support, we render each face of the shadow map
+        * onto 6 layer of a big 2D texture array and sample manualy the right layer
+        * in the fragment shader. */
+       DRW_framebuffer_bind(fbl->shadow_cube_fb);
+       DRW_framebuffer_clear(false, true, false, NULL, 1.0);
+
+       /* Render each shadow to one layer of the array */
+       for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
+               EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type);
+               EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->sto;
+
+               for (int j = 0; j < 6; ++j) {
+                       linfo->layer = i * 6 + j;
+                       copy_m4_m4(linfo->shadowmat, evscd->viewprojmat[j]);
+                       DRW_draw_pass(vedata->psl->shadow_pass);
                }
-               mul_v3_fl(evli->color, power);
+       }
+
+       /* Standard Shadow Maps */
+       DRW_framebuffer_bind(fbl->shadow_map_fb);
+       DRW_framebuffer_clear(false, true, false, NULL, 1.0);
+
+       /* Render each shadow to one layer of the array */
+       for (i = 0; (ob = linfo->shadow_map_ref[i]) && (i < MAX_SHADOW_MAP); i++) {
+               EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type);
+               EEVEE_ShadowMapData *evsmd = (EEVEE_ShadowMapData *)led->sto;
 
-               /* Lamp Type */
-               evli->lamptype = (float)la->type;
+               linfo->layer = i;
+               copy_m4_m4(linfo->shadowmat, evsmd->viewprojmat);
+               DRW_draw_pass(vedata->psl->shadow_pass);
        }
 
-       /* Upload buffer to GPU */
-       DRW_uniformbuffer_update(stl->lights_ubo, stl->lights_data);
+       // DRW_framebuffer_bind(e_data.shadow_cascade_fb);
 }
index 401b39fbd3e95a769b890fc224565dafefa8c18b..7ed80ac68c2af64c513564c17495b032403dbd89 100644 (file)
 
 struct Object;
 
+/* Minimum UBO is 16384 bytes */
+#define MAX_LIGHT 128 /* TODO : find size by dividing UBO max size by light data size */
+#define MAX_SHADOW_CUBE 42 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
+#define MAX_SHADOW_MAP 64
+#define MAX_SHADOW_CASCADE 8
+#define MAX_CASCADE_NUM 4
+
 /* keep it under MAX_PASSES */
 typedef struct EEVEE_PassList {
+       struct DRWPass *shadow_pass;
        struct DRWPass *depth_pass;
        struct DRWPass *depth_pass_cull;
        struct DRWPass *pass;
@@ -36,26 +44,78 @@ typedef struct EEVEE_PassList {
 /* keep it under MAX_BUFFERS */
 typedef struct EEVEE_FramebufferList {
        struct GPUFrameBuffer *main; /* HDR */
+       struct GPUFrameBuffer *shadow_cube_fb;
+       struct GPUFrameBuffer *shadow_map_fb;
+       struct GPUFrameBuffer *shadow_cascade_fb;
 } EEVEE_FramebufferList;
 
 /* keep it under MAX_TEXTURES */
 typedef struct EEVEE_TextureList {
        struct GPUTexture *color; /* R11_G11_B10 */
+       struct GPUTexture *shadow_depth_cube_pool;
+       struct GPUTexture *shadow_depth_map_pool;
+       struct GPUTexture *shadow_depth_cascade_pool;
 } EEVEE_TextureList;
 
 /* keep it under MAX_STORAGE */
 typedef struct EEVEE_StorageList {
-       /* Lights */
-       struct EEVEE_LightsInfo *lights_info;       /* Number of lights, ... */
-       struct EEVEE_Light *lights_data;            /* Array, Packed lights data info, duplication of what is in the Uniform Buffer in Vram */
-       struct Object **lights_ref;                 /* List of all lights in the buffer. */
-       struct GPUUniformBuffer *lights_ubo;
+       /* Lamps */
+       /* XXX this should be per-scenelayer and not per_viewport */
+       struct EEVEE_LampsInfo *lamps;
+       struct GPUUniformBuffer *light_ubo;
+       struct GPUUniformBuffer *shadow_ubo;
+
        struct g_data *g_data;
 } EEVEE_StorageList;
 
-typedef struct EEVEE_LightsInfo {
-       int light_count;
-} EEVEE_LightsInfo;
+/* ************ LIGHT UBO ************* */
+typedef struct EEVEE_Light {
+       float position[3], dist;
+       float color[3], spec;
+       float spotsize, spotblend, radius, shadowid;
+       float rightvec[3], sizex;
+       float upvec[3], sizey;
+       float forwardvec[3], lamptype;
+} EEVEE_Light;
+
+typedef struct EEVEE_ShadowCube {
+       float near, far, bias, pad;
+} EEVEE_ShadowCube;
+
+typedef struct EEVEE_ShadowMap {
+       float shadowmat[4][4]; /* World->Lamp->NDC->Tex : used for sampling the shadow map. */
+       float near, far, bias, pad;
+} EEVEE_ShadowMap;
+
+typedef struct EEVEE_ShadowCascade {
+       float shadowmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC->Tex : used for sampling the shadow map. */
+       float bias, count, pad[2];
+       float near[MAX_CASCADE_NUM];
+       float far[MAX_CASCADE_NUM];
+} EEVEE_ShadowCascade;
+
+/* ************ LIGHT DATA ************* */
+typedef struct EEVEE_LampsInfo {
+       /* For rendering shadows */
+       float shadowmat[4][4];
+       int layer;
+
+       int num_light, cache_num_light;
+       int num_cube, cache_num_cube;
+       int num_map, cache_num_map;
+       int num_cascade, cache_num_cascade;
+       /* List of lights in the scene. */
+       struct Object *light_ref[MAX_LIGHT];
+       struct Object *shadow_cube_ref[MAX_SHADOW_CUBE];
+       struct Object *shadow_map_ref[MAX_SHADOW_MAP];
+       struct Object *shadow_cascade_ref[MAX_SHADOW_CASCADE];
+       /* UBO Storage : data used by UBO */
+       struct EEVEE_Light         light_data[MAX_LIGHT];
+       struct EEVEE_ShadowCube    shadow_cube_data[MAX_SHADOW_CUBE];
+       struct EEVEE_ShadowMap     shadow_map_data[MAX_SHADOW_MAP];
+       struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE];
+} EEVEE_LampsInfo;
+/* *********************************** */
 
 typedef struct EEVEE_Data {
        void *engine_type;
@@ -65,8 +125,15 @@ typedef struct EEVEE_Data {
        EEVEE_StorageList *stl;
 } EEVEE_Data;
 
+/* Keep it sync with MAX_LAMP_DATA */
+typedef struct EEVEE_LampEngineData {
+       void *sto;
+       void *pad;
+} EEVEE_LampEngineData;
+
 typedef struct g_data{
        struct DRWShadingGroup *default_lit_grp;
+       struct DRWShadingGroup *shadow_shgrp;
        struct DRWShadingGroup *depth_shgrp;
        struct DRWShadingGroup *depth_shgrp_select;
        struct DRWShadingGroup *depth_shgrp_active;
@@ -81,5 +148,6 @@ typedef struct g_data{
 void EEVEE_lights_init(EEVEE_StorageList *stl);
 void EEVEE_lights_cache_init(EEVEE_StorageList *stl);
 void EEVEE_lights_cache_add(EEVEE_StorageList *stl, struct Object *ob);
-void EEVEE_lights_cache_finish(EEVEE_StorageList *stl);
+void EEVEE_lights_cache_finish(EEVEE_StorageList *stl, EEVEE_TextureList *txl, EEVEE_FramebufferList *fbl);
 void EEVEE_lights_update(EEVEE_StorageList *stl);
+void EEVEE_draw_shadows(EEVEE_Data *vedata);
\ No newline at end of file
index 5067155acedee1a0f3f1ee3040f17a7c9bb11b07..ef684e3b9708ed39174349883aa3ee47134fb033 100644 (file)
@@ -7,12 +7,12 @@
 /* ------- Structures -------- */
 
 struct LightData {
-       vec4 position_influence;     /* w : InfluenceRadius */
-       vec4 color_spec;          /* w : Spec Intensity */
-       vec4 spotdata_shadow;  /* x : spot size, y : spot blend */
-       vec4 rightvec_sizex;         /* xyz: Normalized up vector, w: Lamp Type */
-       vec4 upvec_sizey;      /* xyz: Normalized right vector, w: Lamp Type */
-       vec4 forwardvec_type;     /* xyz: Normalized forward vector, w: Lamp Type */
+       vec4 position_influence;      /* w : InfluenceRadius */
+       vec4 color_spec;              /* w : Spec Intensity */
+       vec4 spotdata_radius_shadow;  /* x : spot size, y : spot blend, z : radius, w: shadow id */
+       vec4 rightvec_sizex;          /* xyz: Normalized up vector, w: area size X or spot scale X */
+       vec4 upvec_sizey;             /* xyz: Normalized right vector, w: area size Y or spot scale Y */
+       vec4 forwardvec_type;         /* xyz: Normalized forward vector, w: Lamp Type */
 };
 
 /* convenience aliases */
@@ -21,14 +21,48 @@ struct LightData {
 #define l_position     position_influence.xyz
 #define l_influence    position_influence.w
 #define l_sizex        rightvec_sizex.w
-#define l_radius       rightvec_sizex.w
 #define l_sizey        upvec_sizey.w
 #define l_right        rightvec_sizex.xyz
 #define l_up           upvec_sizey.xyz
 #define l_forward      forwardvec_type.xyz
 #define l_type         forwardvec_type.w
-#define l_spot_size    spotdata_shadow.x
-#define l_spot_blend   spotdata_shadow.y
+#define l_spot_size    spotdata_radius_shadow.x
+#define l_spot_blend   spotdata_radius_shadow.y
+#define l_radius       spotdata_radius_shadow.z
+#define l_shadowid     spotdata_radius_shadow.w
+
+
+struct ShadowCubeData {
+       vec4 near_far_bias;
+};
+
+/* convenience aliases */
+#define sh_cube_near   near_far_bias.x
+#define sh_cube_far    near_far_bias.y
+#define sh_cube_bias   near_far_bias.z
+
+
+struct ShadowMapData {
+       mat4 shadowmat;
+       vec4 near_far_bias;
+};
+
+/* convenience aliases */
+#define sh_map_near   near_far_bias.x
+#define sh_map_far    near_far_bias.y
+#define sh_map_bias   near_far_bias.z
+
+struct ShadowCascadeData {
+       mat4 shadowmat[MAX_CASCADE_NUM];
+       vec4 bias_count;
+       float near[MAX_CASCADE_NUM];
+       float far[MAX_CASCADE_NUM];
+};
+
+/* convenience aliases */
+#define sh_cascade_bias   bias_count.x
+#define sh_cascade_count  bias_count.y
+
 
 struct AreaData {
        vec3 corner[4];
@@ -64,6 +98,26 @@ float hypot(float x, float y) { return sqrt(x*x + y*y); }
 
 float inverse_distance(vec3 V) { return max( 1 / length(V), 1e-8); }
 
+float linear_depth(float z, float zf, float zn)
+{
+       if (gl_ProjectionMatrix[3][3] == 0.0) {
+               return (zn  * zf) / (z * (zn - zf) + zf);
+       }
+       else {
+               return (z * 2.0 - 1.0) * zf;
+       }
+}
+
+float buffer_depth(float z, float zf, float zn)
+{
+       if (gl_ProjectionMatrix[3][3] == 0.0) {
+               return (zf * (zn - z)) / (z * (zn - zf));
+       }
+       else {
+               return (z / (zf * 2.0)) + 0.5;
+       }
+}
+
 float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal)
 {
        return dot(planenormal, planeorigin - lineorigin) / dot(planenormal, linedirection);
index ced22074be32f86b138b7aeb10fe8a8236ed09e4..6c62e7c2e473b6aa9eabfb0922fc6c848b4f562a 100644 (file)
@@ -3,10 +3,18 @@ uniform int light_count;
 uniform vec3 cameraPos;
 uniform vec3 eye;
 uniform mat4 ProjectionMatrix;
-
+uniform sampler2DArrayShadow shadowCubes;
+uniform sampler2DArrayShadow shadowMaps;
+// uniform sampler2DArrayShadow shadowCascades;
 
 layout(std140) uniform light_block {
-       LightData   lights_data[MAX_LIGHT];
+       LightData lights_data[MAX_LIGHT];
+};
+
+layout(std140) uniform shadow_block {
+       ShadowCubeData    shadows_cube_data[MAX_SHADOW_CUBE];
+       ShadowMapData     shadows_map_data[MAX_SHADOW_MAP];
+       ShadowCascadeData shadows_cascade_data[MAX_SHADOW_CASCADE];
 };
 
 in vec3 worldPosition;
@@ -69,6 +77,80 @@ float light_visibility(LightData ld, ShadingData sd)
                vis *= step(0.0, -dot(sd.L, ld.l_forward));
        }
 
+       /* shadowing */
+       if (ld.l_shadowid >= (MAX_SHADOW_MAP + MAX_SHADOW_CUBE)) {
+               /* Shadow Cascade */
+       }
+       else if (ld.l_shadowid >= MAX_SHADOW_CUBE) {
+               /* Shadow Map */
+               float shid = ld.l_shadowid - MAX_SHADOW_CUBE;
+               ShadowMapData smd = shadows_map_data[int(shid)];
+               vec4 shpos = smd.shadowmat * vec4(sd.W, 1.0);
+               shpos.z -= smd.sh_map_bias * shpos.w;
+               shpos.xyz /= shpos.w;
+
+               if (shpos.w > 0.0 && min(shpos.x, shpos.y) > 0.0 && max(shpos.x, shpos.y) < 1.0) {
+                       vis *= texture(shadowMaps, vec4(shpos.xy, shid, shpos.z));
+               }
+       }
+       else {
+               /* Shadow Cube */
+               float shid = ld.l_shadowid;
+               ShadowCubeData scd = shadows_cube_data[int(shid)];
+
+               float face;
+               vec2 uvs;
+               vec3 Linv = sd.L;
+               vec3 Labs = abs(Linv);
+               vec3 maj_axis;
+
+               if (max(Labs.y, Labs.z) < Labs.x) {
+                       if (Linv.x > 0.0) {
+                               face = 1.0;
+                               uvs = vec2(1.0, -1.0) * Linv.zy / -Linv.x;
+                               maj_axis = vec3(1.0, 0.0, 0.0);
+                       }
+                       else {
+                               face = 0.0;
+                               uvs = -Linv.zy / Linv.x;
+                               maj_axis = vec3(-1.0, 0.0, 0.0);
+                       }
+               }
+               else if (max(Labs.x, Labs.z) < Labs.y) {
+                       if (Linv.y > 0.0) {
+                               face = 2.0;
+                               uvs = vec2(-1.0, 1.0) * Linv.xz / Linv.y;
+                               maj_axis = vec3(0.0, 1.0, 0.0);
+                       }
+                       else {
+                               face = 3.0;
+                               uvs = -Linv.xz / -Linv.y;
+                               maj_axis = vec3(0.0, -1.0, 0.0);
+                       }
+               }
+               else {
+                       if (Linv.z > 0.0) {
+                               face = 5.0;
+                               uvs = Linv.xy / Linv.z;
+                               maj_axis = vec3(0.0, 0.0, 1.0);
+                       }
+                       else {
+                               face = 4.0;
+                               uvs = vec2(-1.0, 1.0) * Linv.xy / -Linv.z;
+                               maj_axis = vec3(0.0, 0.0, -1.0);
+                       }
+               }
+
+               uvs = uvs * 0.5 + 0.5;
+
+               /* Depth in lightspace to compare against shadow map */
+               float w = dot(maj_axis, sd.l_vector);
+               w -= scd.sh_map_bias * w;
+               float shdepth = buffer_depth(w, scd.sh_cube_far, scd.sh_cube_near);
+
+               vis *= texture(shadowCubes, vec4(uvs, shid * 6.0 + face, shdepth));
+       }
+
        return vis;
 }
 
@@ -108,8 +190,8 @@ void main()
        sd.R = reflect(-sd.V, sd.N);
 
        /* hardcoded test vars */
-       vec3 albedo = vec3(0.0);
-       vec3 specular = mix(vec3(1.0), vec3(1.0), pow(max(0.0, 1.0 - dot(sd.N, sd.V)), 5.0));
+       vec3 albedo = vec3(0.8);
+       vec3 specular = mix(vec3(0.03), vec3(1.0), pow(max(0.0, 1.0 - dot(sd.N, sd.V)), 5.0));
        float roughness = 0.1;
 
        sd.spec_dominant_dir = get_specular_dominant_dir(sd.N, sd.R, roughness);
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_frag.glsl
new file mode 100644 (file)
index 0000000..2933520
--- /dev/null
@@ -0,0 +1,3 @@
+
+void main() {
+}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_geom.glsl b/source/blender/draw/engines/eevee/shaders/shadow_geom.glsl
new file mode 100644 (file)
index 0000000..1032fe4
--- /dev/null
@@ -0,0 +1,21 @@
+
+layout(triangles) in;
+layout(triangle_strip, max_vertices=3) out;
+
+uniform mat4 ShadowMatrix;
+uniform int Layer;
+
+in vec4 vPos[];
+
+void main() {
+       gl_Layer = Layer;
+       gl_Position = ShadowMatrix * vPos[0];
+       EmitVertex();
+       gl_Layer = Layer;
+       gl_Position = ShadowMatrix * vPos[1];
+       EmitVertex();
+       gl_Layer = Layer;
+       gl_Position = ShadowMatrix * vPos[2];
+       EmitVertex();
+       EndPrimitive();
+}
\ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
new file mode 100644 (file)
index 0000000..1adf2cc
--- /dev/null
@@ -0,0 +1,11 @@
+
+uniform mat4 ShadowMatrix;
+uniform mat4 ModelMatrix;
+
+in vec3 pos;
+
+out vec4 vPos;
+
+void main() {
+       vPos = ModelMatrix * vec4(pos, 1.0);
+}
\ No newline at end of file
index 1e99b95f27c73bb8f0acc0be7466fdfd6dbe0b61..7475e562833dccf479a393da517c891298fb7899 100644 (file)
@@ -61,6 +61,8 @@ struct Object;
 struct Batch;
 struct DefaultFramebufferList;
 struct DefaultTextureList;
+struct LampEngineData;
+struct RenderEngineType;
 
 typedef struct DRWUniform DRWUniform;
 typedef struct DRWInterface DRWInterface;
@@ -252,6 +254,8 @@ struct DefaultTextureList     *DRW_viewport_texture_list_get(void);
 
 /* Objects */
 void **DRW_object_engine_data_get(Object *ob, DrawEngineType *det);
+struct LampEngineData *DRW_lamp_engine_data_get(Object *ob, struct RenderEngineType *engine_type);
+void DRW_lamp_engine_data_free(struct LampEngineData *led);
 
 /* Settings */
 bool DRW_is_object_renderable(struct Object *ob);
index 3f150a06cb7c8f1811228ddd6e72af72cbc2fca3..20a91fc9d430dde83b74529ccd231e688d0dbe28 100644 (file)
@@ -50,6 +50,7 @@
 #include "GPU_draw.h"
 #include "GPU_extensions.h"
 #include "GPU_framebuffer.h"
+#include "GPU_lamp.h"
 #include "GPU_shader.h"
 #include "GPU_texture.h"
 #include "GPU_uniformbuffer.h"
@@ -1197,6 +1198,7 @@ void DRW_state_reset(void) {}
 
 #endif  /* WITH_CLAY_ENGINE */
 
+
 /* ****************************************** Settings ******************************************/
 
 bool DRW_is_object_renderable(Object *ob)
@@ -1234,7 +1236,6 @@ static GPUTextureFormat convert_tex_format(int fbo_format, int *channels, bool *
        }
 }
 
-
 void DRW_framebuffer_init(struct GPUFrameBuffer **fb, int width, int height, DRWFboTexture textures[MAX_FBO_TEX],
                           int texnbr)
 {
@@ -1431,6 +1432,21 @@ void DRW_object_engine_data_free(Object *ob)
        BLI_freelistN(&ob->drawdata);
 }
 
+LampEngineData *DRW_lamp_engine_data_get(Object *ob, RenderEngineType *engine_type)
+{
+       BLI_assert(ob->type == OB_LAMP);
+
+       Scene *scene = CTX_data_scene(DST.context);
+
+       /* TODO Dupliobjects */
+       return GPU_lamp_engine_data_get(scene, ob, NULL, engine_type);
+}
+
+void DRW_lamp_engine_data_free(LampEngineData *led)
+{
+       return GPU_lamp_engine_data_free(led);
+}
+
 /* **************************************** RENDERING ************************************** */
 
 #define TIMER_FALLOFF 0.1f
index 32793830479407752de7b58fe6315eeb460e608f..e08fbede80ae39b28bd491712060891d75f7a1a0 100644 (file)
@@ -42,15 +42,17 @@ struct RenderEngineType;
 
 typedef struct GPULamp GPULamp;
 
+#define MAX_LAMP_DATA 2
+
 typedef struct LampEngineData {
-       struct GPUFrameBuffer *framebuffers[4];
-       struct GPUTexture *textures[4];
-       void *storage[4];
+       void *storage[MAX_LAMP_DATA];
 } LampEngineData;
 
-GPULamp *GPU_lamp_from_engine(struct Scene *scene, struct Object *ob, Object *par, struct RenderEngineType *re);
+LampEngineData *GPU_lamp_engine_data_get(struct Scene *scene, struct Object *ob, struct Object *par, struct RenderEngineType *re);
+
 GPULamp *GPU_lamp_from_blender(struct Scene *scene, struct Object *ob, struct Object *par);
 void GPU_lamp_free(struct Object *ob);
+void GPU_lamp_engine_data_free(LampEngineData *led);
 
 bool GPU_lamp_override_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma);
 bool GPU_lamp_has_shadow_buffer(GPULamp *lamp);
index 2411fe755af9c71586d679b8ff88979126813566..8bc7bdb6df2e3492cdf1ec8c16e2008deee372e0 100644 (file)
@@ -44,7 +44,7 @@ typedef struct GPUViewport GPUViewport;
 #define MAX_BUFFERS 8
 #define MAX_TEXTURES 16
 #define MAX_PASSES 16
-#define MAX_STORAGE 5 /* extend if needed */
+#define MAX_STORAGE 9 /* extend if needed */
 
 /* All FramebufferLists are just the same pointers with different names */
 typedef struct FramebufferList {
index 425fcecae0c740cb658a918a22f414197c77eb43..fb02efb8e9997ac664ea2bd493b62160fe62e04e 100644 (file)
@@ -143,8 +143,7 @@ bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slo
        else
                attachment = GL_COLOR_ATTACHMENT0 + slot;
 
-       glFramebufferTexture2D(GL_FRAMEBUFFER, attachment,
-               GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0);
+       glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), 0);
 
        if (GPU_texture_depth(tex))
                fb->depthtex = tex;
index ee0bcb83a6a06c3dbe3574100e46c25fd9bcbdaa..75198122ab584ccd6394568310559d44c91aa980 100644 (file)
@@ -214,7 +214,7 @@ static GPUTexture *gpu_lamp_create_vsm_shadow_map(int size)
        return GPU_texture_create_2D_custom(size, size, 2, GPU_RG32F, NULL, NULL);
 }
 
-GPULamp *GPU_lamp_from_engine(Scene *scene, Object *ob, Object *par, struct RenderEngineType *re)
+LampEngineData *GPU_lamp_engine_data_get(Scene *scene, Object *ob, Object *par, struct RenderEngineType *re)
 {
        GPULamp *lamp;
        LinkData *link;
@@ -223,7 +223,7 @@ GPULamp *GPU_lamp_from_engine(Scene *scene, Object *ob, Object *par, struct Rend
                lamp = (GPULamp *)link->data;
 
                if ((lamp->par == par) && (lamp->scene == scene) && (lamp->re == re))
-                       return link->data;
+                       return &lamp->data;
        }
 
        lamp = MEM_callocN(sizeof(GPULamp), "GPULamp");
@@ -238,7 +238,7 @@ GPULamp *GPU_lamp_from_engine(Scene *scene, Object *ob, Object *par, struct Rend
        lamp->la = ob->data;
        lamp->re = re;
 
-       return lamp;
+       return &lamp->data;
 }
 
 GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
@@ -364,6 +364,16 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
        return lamp;
 }
 
+void GPU_lamp_engine_data_free(LampEngineData *led)
+{
+       for (int i = 0; i < MAX_LAMP_DATA; ++i) {
+               if (led->storage[i]) {
+                       MEM_freeN(led->storage[i]);
+                       led->storage[i] = NULL;
+               }
+       }
+}
+
 void GPU_lamp_free(Object *ob)
 {
        GPULamp *lamp;
@@ -384,6 +394,7 @@ void GPU_lamp_free(Object *ob)
                }
 
                gpu_lamp_shadow_free(lamp);
+               GPU_lamp_engine_data_free(&lamp->data);
 
                MEM_freeN(lamp);
        }
index f4c3e16c0b56f4f2523f8af5064b9362dcbf7b51..4b3570e3831b57226c4ce218d654f3a684bdcd3b 100644 (file)
@@ -169,9 +169,11 @@ static bool GPU_texture_try_alloc(
                case GL_PROXY_TEXTURE_1D:
                        glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, data_format, NULL);
                        break;
+               case GL_PROXY_TEXTURE_1D_ARRAY:
                case GL_PROXY_TEXTURE_2D:
                        glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, data_format, NULL);
                        break;
+               case GL_PROXY_TEXTURE_2D_ARRAY:
                case GL_PROXY_TEXTURE_3D:
                        glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, NULL);
                        break;
@@ -279,14 +281,20 @@ static GPUTexture *GPU_texture_create_nD(
        glBindTexture(tex->target, tex->bindcode);
 
        /* Check if texture fit in VRAM */
-       if (d > 0) {
-               proxy = GL_PROXY_TEXTURE_3D;
+       if (n == 1) {
+               if (h == 0)
+                       proxy = GL_PROXY_TEXTURE_1D;
+               else
+                       proxy = GL_PROXY_TEXTURE_1D_ARRAY;
        }
-       else if (h > 0) {
-               proxy = GL_PROXY_TEXTURE_2D;
+       else if (n == 2) {
+               if (d == 0)
+                       proxy = GL_PROXY_TEXTURE_2D;
+               else
+                       proxy = GL_PROXY_TEXTURE_2D_ARRAY;
        }
-       else {
-               proxy = GL_PROXY_TEXTURE_1D;
+       else if (n == 3) {
+               proxy = GL_PROXY_TEXTURE_3D;
        }
 
        valid = GPU_texture_try_alloc(tex, proxy, internalformat, format, data_format, components, can_rescale, fpixels,