/* * ***** BEGIN GPL LICENSE BLOCK ***** * * 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. * * Copyright 2016, Blender Foundation. * Contributor(s): Blender Institute * * ***** END GPL LICENSE BLOCK ***** * */ /** \file eevee_lookdev.c * \ingroup draw_engine */ #include "DRW_render.h" #include "BKE_camera.h" #include "BKE_studiolight.h" #include "DNA_screen_types.h" #include "DNA_world_types.h" #include "DEG_depsgraph_query.h" #include "ED_screen.h" #include "UI_resources.h" #include "eevee_private.h" #include "eevee_lightcache.h" #include "draw_common.h" static void eevee_lookdev_lightcache_delete(EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; EEVEE_TextureList *txl = vedata->txl; MEM_SAFE_FREE(stl->lookdev_lightcache); MEM_SAFE_FREE(stl->lookdev_grid_data); MEM_SAFE_FREE(stl->lookdev_cube_data); DRW_TEXTURE_FREE_SAFE(txl->lookdev_grid_tx); DRW_TEXTURE_FREE_SAFE(txl->lookdev_cube_tx); } void EEVEE_lookdev_cache_init( EEVEE_Data *vedata, DRWShadingGroup **grp, DRWPass *pass, World *UNUSED(world), EEVEE_LightProbesInfo *pinfo) { EEVEE_StorageList *stl = vedata->stl; EEVEE_TextureList *txl = vedata->txl; const DRWContextState *draw_ctx = DRW_context_state_get(); View3D *v3d = draw_ctx->v3d; if (LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d)) { StudioLight *sl = BKE_studiolight_find(v3d->shading.lookdev_light, STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE); if (sl && (sl->flag & STUDIOLIGHT_TYPE_WORLD)) { GPUShader *shader = EEVEE_shaders_default_studiolight_sh_get(); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); GPUTexture *tex = NULL; /* If one of the component is missing we start from scratch. */ if ((stl->lookdev_grid_data == NULL) || (stl->lookdev_cube_data == NULL) || (txl->lookdev_grid_tx == NULL) || (txl->lookdev_cube_tx == NULL)) { eevee_lookdev_lightcache_delete(vedata); } if (stl->lookdev_lightcache == NULL) { const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); #if defined(IRRADIANCE_SH_L2) int grid_res = 4; #elif defined(IRRADIANCE_CUBEMAP) int grid_res = 8; #elif defined(IRRADIANCE_HL2) int grid_res = 4; #endif int cube_res = OCTAHEDRAL_SIZE_FROM_CUBESIZE(scene_eval->eevee.gi_cubemap_resolution); int vis_res = scene_eval->eevee.gi_visibility_resolution; stl->lookdev_lightcache = EEVEE_lightcache_create(1, 1, cube_res, vis_res, (int[3]){grid_res, grid_res, 1}); /* XXX: Fix memleak. TODO find out why. */ MEM_SAFE_FREE(stl->lookdev_cube_mips); /* We do this to use a special light cache for lookdev. * This lightcache needs to be per viewport. But we need to * have correct freeing when the viewport is closed. So we * need to reference all textures to the txl and the memblocks * to the stl. */ stl->lookdev_grid_data = stl->lookdev_lightcache->grid_data; stl->lookdev_cube_data = stl->lookdev_lightcache->cube_data; stl->lookdev_cube_mips = stl->lookdev_lightcache->cube_mips; txl->lookdev_grid_tx = stl->lookdev_lightcache->grid_tx.tex; txl->lookdev_cube_tx = stl->lookdev_lightcache->cube_tx.tex; } stl->g_data->light_cache = stl->lookdev_lightcache; static float background_color[4]; UI_GetThemeColor4fv(TH_BACK, background_color); /* XXX: Really quick conversion to avoid washed out background. * Needs to be addressed properly (color managed using ocio). */ srgb_to_linearrgb_v4(background_color, background_color); *grp = DRW_shgroup_create(shader, pass); axis_angle_to_mat3_single(stl->g_data->studiolight_matrix, 'Z', v3d->shading.studiolight_rot_z); DRW_shgroup_uniform_mat3(*grp, "StudioLightMatrix", stl->g_data->studiolight_matrix); DRW_shgroup_uniform_float(*grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); DRW_shgroup_uniform_vec3(*grp, "color", background_color, 1); DRW_shgroup_call_add(*grp, geom, NULL); if (!pinfo) { /* Do not fadeout when doing probe rendering, only when drawing the background */ DRW_shgroup_uniform_float(*grp, "studioLightBackground", &v3d->shading.studiolight_background, 1); BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE); tex = sl->equirect_irradiance_gputexture; } else { DRW_shgroup_uniform_float_copy(*grp, "studioLightBackground", 1.0f); BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE); tex = sl->equirect_radiance_gputexture; } DRW_shgroup_uniform_texture(*grp, "image", tex); /* Do we need to recalc the lightprobes? */ if (pinfo && ((pinfo->studiolight_index != sl->index) || (pinfo->studiolight_rot_z != v3d->shading.studiolight_rot_z))) { stl->lookdev_lightcache->flag |= LIGHTCACHE_UPDATE_WORLD; pinfo->studiolight_index = sl->index; pinfo->studiolight_rot_z = v3d->shading.studiolight_rot_z; } } } } void EEVEE_lookdev_draw_background(EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_EffectsInfo *effects = stl->effects; EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); const DRWContextState *draw_ctx = DRW_context_state_get(); if (psl->lookdev_pass && LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) { DRW_stats_group_start("Look Dev"); CameraParams params; BKE_camera_params_init(¶ms); View3D *v3d = draw_ctx->v3d; RegionView3D *rv3d = draw_ctx->rv3d; ARegion *ar = draw_ctx->ar; const float *viewport_size = DRW_viewport_size_get(); rcti rect; ED_region_visible_rect(draw_ctx->ar, &rect); const float viewport_size_target[2] = { viewport_size[0] / 4, viewport_size[1] / 4, }; const int viewport_inset[2] = { max_ii(viewport_size_target[0], 300), max_ii(viewport_size_target[0], 300) / 2, /* intentionally use 'x' here for 'y' value. */ }; /* minimum size for preview spheres viewport */ const float aspect[2] = { viewport_inset[0] / viewport_size_target[0], viewport_inset[1] / viewport_size_target[1], }; BKE_camera_params_from_view3d(¶ms, draw_ctx->depsgraph, v3d, rv3d); params.is_ortho = true; params.ortho_scale = 3.0f; params.zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; params.offsetx = 0.0f; params.offsety = 0.0f; params.shiftx = 0.0f; params.shifty = 0.0f; params.clipsta = 0.001f; params.clipend = 20.0f; BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, aspect[0], aspect[1]); BKE_camera_params_compute_matrix(¶ms); EEVEE_CommonUniformBuffer *common = &sldata->common_data; common->la_num_light = 0; common->prb_num_planar = 0; common->prb_num_render_cube = 1; common->prb_num_render_grid = 1; common->ao_dist = 0.0f; common->ao_factor = 0.0f; common->ao_settings = 0.0f; DRW_uniformbuffer_update(sldata->common_ubo, common); /* override matrices */ float winmat[4][4]; float winmat_inv[4][4]; copy_m4_m4(winmat, params.winmat); invert_m4_m4(winmat_inv, winmat); DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN); DRW_viewport_matrix_override_set(winmat_inv, DRW_MAT_WININV); float viewmat[4][4]; DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW); float persmat[4][4]; float persmat_inv[4][4]; mul_m4_m4m4(persmat, winmat, viewmat); invert_m4_m4(persmat_inv, persmat); DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS); DRW_viewport_matrix_override_set(persmat_inv, DRW_MAT_PERSINV); GPUFrameBuffer *fb = effects->final_fb; GPU_framebuffer_bind(fb); GPU_framebuffer_viewport_set(fb, rect.xmax - viewport_inset[0], rect.ymin, viewport_inset[0], viewport_inset[1]); DRW_draw_pass(psl->lookdev_pass); fb = dfbl->depth_only_fb; GPU_framebuffer_bind(fb); GPU_framebuffer_viewport_set(fb, rect.xmax - viewport_inset[0], rect.ymin, viewport_inset[0], viewport_inset[1]); DRW_draw_pass(psl->lookdev_pass); DRW_viewport_matrix_override_unset_all(); DRW_stats_group_end(); } }