Fix T67832: Camera Background Images View Transform

This patch will apply the view transform when a movie clip is used as
camera background image. It does this by rendering the image in the
color buffer when it needs the view transform. For other images it uses
the overlay buffer.

Reviewed By: Clément Foucault

Differential Revision: https://developer.blender.org/D7067
This commit is contained in:
Jeroen Bakker 2020-11-03 14:39:50 +01:00
parent 7a7f294940
commit 3ffa0452af
Notes: blender-bot 2023-10-12 12:49:04 +02:00
Referenced by issue #85750, Camera background movieclips are not visible if "Viewport Shading" is set to "Rendered"
Referenced by issue #85750, Camera background movieclips are not visible if "Viewport Shading" is set to "Rendered"
Referenced by issue #67832, Background images ignore View transform
7 changed files with 55 additions and 6 deletions

View File

@ -509,6 +509,11 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_FramebufferList *fbl = data->fbl;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
/* Needs to be done first as it modifies the scene color and depth buffer. */
if (!pd->is_image_editor) {
OVERLAY_image_scene_background_draw(vedata);
}
if (DRW_state_is_fbo()) {
const float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_bind(dfbl->overlay_only_fb);

View File

@ -57,6 +57,8 @@ void OVERLAY_image_cache_init(OVERLAY_Data *vedata)
state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_BLEND_ALPHA_PREMUL;
DRW_PASS_CREATE(psl->image_background_ps, state);
state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL;
DRW_PASS_CREATE(psl->image_background_scene_ps, state);
state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
DRW_PASS_CREATE(psl->image_empties_ps, state | pd->clipping_state);
@ -68,6 +70,7 @@ void OVERLAY_image_cache_init(OVERLAY_Data *vedata)
state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL;
DRW_PASS_CREATE(psl->image_empties_front_ps, state);
DRW_PASS_CREATE(psl->image_foreground_ps, state);
DRW_PASS_CREATE(psl->image_foreground_scene_ps, state);
}
static void overlay_image_calc_aspect(Image *ima, const int size[2], float r_image_aspect[2])
@ -136,7 +139,8 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
const DRWContextState *draw_ctx,
OVERLAY_PrivateData *pd,
float *r_aspect,
bool *r_use_alpha_premult)
bool *r_use_alpha_premult,
bool *r_use_view_transform)
{
void *lock;
Image *image = bgpic->ima;
@ -148,6 +152,7 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
int width, height;
int ctime = (int)DEG_get_ctime(draw_ctx->depsgraph);
*r_use_alpha_premult = false;
*r_use_view_transform = false;
switch (bgpic->source) {
case CAM_BGIMG_SOURCE_IMAGE:
@ -155,6 +160,7 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
return NULL;
}
*r_use_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL);
*r_use_view_transform = (image->flag & IMA_VIEW_AS_RENDER) != 0;
BKE_image_user_frame_calc(image, iuser, ctime);
if (image->source == IMA_SRC_SEQUENCE && !(iuser->flag & IMA_USER_FRAME_IN_RANGE)) {
@ -183,7 +189,6 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
aspect_x = bgpic->ima->aspx;
aspect_y = bgpic->ima->aspy;
break;
case CAM_BGIMG_SOURCE_MOVIE:
@ -208,6 +213,7 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
aspect_x = clip->aspx;
aspect_y = clip->aspy;
*r_use_view_transform = true;
BKE_movieclip_get_size(clip, &bgpic->cuser, &width, &height);
@ -328,21 +334,27 @@ void OVERLAY_image_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
float aspect = 1.0;
bool use_alpha_premult;
bool use_view_transform = false;
float mat[4][4];
/* retrieve the image we want to show, continue to next when no image could be found */
GPUTexture *tex = image_camera_background_texture_get(
bgpic, draw_ctx, pd, &aspect, &use_alpha_premult);
bgpic, draw_ctx, pd, &aspect, &use_alpha_premult, &use_view_transform);
if (tex) {
image_camera_background_matrix_get(cam, bgpic, draw_ctx, aspect, mat);
mul_m4_m4m4(mat, modelmat, mat);
const bool is_foreground = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != 0;
/* Alpha is clamped just below 1.0 to fix background images to intefere with foreground
* images. Without this a background image with 1.0 will be rendered on top of a transparent
* foreground image due to the differnet blending modes they use. */
const float color_premult_alpha[4] = {1.0f, 1.0f, 1.0f, MIN2(bgpic->alpha, 0.999999)};
const float color_premult_alpha[4] = {1.0f, 1.0f, 1.0f, bgpic->alpha};
DRWPass *pass = is_foreground ? psl->image_foreground_ps : psl->image_background_ps;
DRWPass *pass = is_foreground ? (use_view_transform ? psl->image_foreground_scene_ps :
psl->image_foreground_ps) :
(use_view_transform ? psl->image_background_scene_ps :
psl->image_background_ps);
GPUShader *sh = OVERLAY_shader_image();
DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
@ -449,6 +461,22 @@ void OVERLAY_image_cache_finish(OVERLAY_Data *vedata)
DRW_pass_sort_shgroup_z(psl->image_empties_back_ps);
}
/* This function draws images that needs the view transform applied.
* It draws these images directly into the scene color buffer. */
void OVERLAY_image_scene_background_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
if (DRW_state_is_fbo() && (!DRW_pass_is_empty(psl->image_background_scene_ps) ||
!DRW_pass_is_empty(psl->image_foreground_scene_ps))) {
const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
GPU_framebuffer_bind(dfbl->default_fb);
DRW_draw_pass(psl->image_background_scene_ps);
DRW_draw_pass(psl->image_foreground_scene_ps);
}
}
void OVERLAY_image_background_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;

View File

@ -103,11 +103,13 @@ typedef struct OVERLAY_PassList {
DRWPass *fade_ps[2];
DRWPass *grid_ps;
DRWPass *image_background_ps;
DRWPass *image_background_scene_ps;
DRWPass *image_empties_ps;
DRWPass *image_empties_back_ps;
DRWPass *image_empties_blend_ps;
DRWPass *image_empties_front_ps;
DRWPass *image_foreground_ps;
DRWPass *image_foreground_scene_ps;
DRWPass *metaball_ps[2];
DRWPass *motion_paths_ps;
DRWPass *outlines_prepass_ps;
@ -592,6 +594,7 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_image_cache_finish(OVERLAY_Data *vedata);
void OVERLAY_image_draw(OVERLAY_Data *vedata);
void OVERLAY_image_background_draw(OVERLAY_Data *vedata);
void OVERLAY_image_scene_background_draw(OVERLAY_Data *vedata);
void OVERLAY_image_in_front_draw(OVERLAY_Data *vedata);
void OVERLAY_metaball_cache_init(OVERLAY_Data *vedata);

View File

@ -347,6 +347,8 @@ typedef enum {
/** Use dual source blending. WARNING: Only one color buffer allowed. */
DRW_STATE_BLEND_CUSTOM = (9 << 11),
DRW_STATE_LOGIC_INVERT = (10 << 11),
DRW_STATE_BLEND_ALPHA_UNDER_PREMUL = (11 << 11),
DRW_STATE_IN_FRONT_SELECT = (1 << 27),
DRW_STATE_SHADOW_OFFSET = (1 << 28),

View File

@ -203,6 +203,9 @@ void drw_state_set(DRWState state)
case DRW_STATE_LOGIC_INVERT:
blend = GPU_BLEND_INVERT;
break;
case DRW_STATE_BLEND_ALPHA_UNDER_PREMUL:
blend = GPU_BLEND_ALPHA_UNDER_PREMUL;
break;
default:
blend = GPU_BLEND_NONE;
break;

View File

@ -71,6 +71,7 @@ typedef enum eGPUBlend {
/** Custom blend parameters using dual source blending : SRC0 + SRC1 * DST
* NOTE: Can only be used with _ONE_ Draw Buffer and shader needs to be specialized. */
GPU_BLEND_CUSTOM,
GPU_BLEND_ALPHA_UNDER_PREMUL,
} eGPUBlend;
typedef enum eGPUDepthTest {

View File

@ -421,6 +421,13 @@ void GLStateManager::set_blend(const eGPUBlend value)
dst_alpha = GL_SRC_ALPHA;
break;
}
case GPU_BLEND_ALPHA_UNDER_PREMUL: {
src_rgb = GL_ONE_MINUS_DST_ALPHA;
dst_rgb = GL_ONE;
src_alpha = GL_ONE_MINUS_DST_ALPHA;
dst_alpha = GL_ONE;
break;
}
case GPU_BLEND_CUSTOM: {
src_rgb = GL_ONE;
dst_rgb = GL_SRC1_COLOR;