Fix: GPv3 depth buffer

Resolves #113422.

The depth buffer was rendered to, but not correctly merged
with the scene depth buffer. This lead to, e.g. the object appearing
behind the grid.

This fixes the issue by rendering a "merge" pass.

Pull Request: https://projects.blender.org/blender/blender/pulls/113779
This commit is contained in:
Falk David 2023-10-19 13:22:38 +02:00 committed by Falk David
parent 26816931c4
commit 6281d9a039
7 changed files with 94 additions and 3 deletions

View File

@ -695,6 +695,7 @@ set(GLSL_SRC
engines/gpencil/shaders/gpencil_mask_invert_frag.glsl
engines/gpencil/shaders/gpencil_depth_merge_frag.glsl
engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
engines/gpencil/shaders/grease_pencil_depth_merge_vert.glsl
engines/gpencil/shaders/gpencil_vfx_frag.glsl
engines/gpencil/gpencil_defines.h

View File

@ -140,7 +140,7 @@ class Instance {
{
switch (object_ref.object->type) {
case OB_GREASE_PENCIL:
objects.sync_grease_pencil(manager, object_ref, main_fb_, main_ps_);
objects.sync_grease_pencil(manager, object_ref, main_fb_, depth_tx_, main_ps_);
break;
case OB_LAMP:
lights.sync(object_ref);

View File

@ -8,6 +8,8 @@
#pragma once
#include "BLI_math_quaternion_types.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_image.h"
#include "DRW_gpu_wrapper.hh"
@ -52,8 +54,11 @@ class ObjectModule {
bool use_stroke_fill_ = true;
bool use_vfx_ = true;
bool is_render_ = true;
bool is_persp_ = true;
/** Forward vector used to sort gpencil objects. */
float3 camera_forward_;
float3 camera_pos_;
/** Scene current frame. */
float current_frame_ = 0;
@ -90,12 +95,14 @@ class ObjectModule {
void begin_sync(Depsgraph *depsgraph, const View &main_view)
{
camera_forward_ = float3(main_view.viewinv()[2]);
camera_forward_ = main_view.forward();
camera_pos_ = main_view.location();
current_frame_ = DEG_get_ctime(depsgraph);
is_object_fb_needed_ = false;
is_layer_fb_needed_ = false;
is_persp_ = main_view.is_persp();
/* TODO(fclem): Shrink buffer. */
// objects_buf_.shrink();
}
@ -103,6 +110,7 @@ class ObjectModule {
void sync_grease_pencil(Manager &manager,
ObjectRef &object_ref,
Framebuffer &main_fb,
TextureFromPool &depth_tx,
PassSortable &main_ps)
{
using namespace blender::bke::greasepencil;
@ -188,6 +196,14 @@ class ObjectModule {
object_subpass.draw(geom, handle);
}
float4x4 plane_mat = get_object_plane_mat(object);
ResourceHandle handle_plane_mat = manager.resource_handle(plane_mat);
object_subpass.framebuffer_set(&DRW_viewport_framebuffer_list_get()->depth_only_fb);
object_subpass.state_set(DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_DEPTH);
object_subpass.shader_set(shaders_.static_shader_get(DEPTH_MERGE));
object_subpass.bind_texture("depthBuf", (object_has_vfx) ? nullptr : &depth_tx);
object_subpass.draw(DRW_cache_quad_get(), handle_plane_mat);
/* TODO: Do object VFX. */
#if 0
if (object_has_vfx) {
@ -249,6 +265,55 @@ class ObjectModule {
{
return objects_buf_.size() > 0;
}
float4x4 get_object_plane_mat(Object *object)
{
using namespace math;
/* Find the normal most likely to represent the gpObject. */
/* TODO: This does not work quite well if you use
* strokes not aligned with the object axes. Maybe we could try to
* compute the minimum axis of all strokes. But this would be more
* computationally heavy and should go into the GPData evaluation. */
const BoundBox *bbox = BKE_object_boundbox_get(object);
float4x4 object_to_world = float4x4(object->object_to_world);
/* Convert bbox to matrix */
float3 size;
float3 center;
BKE_boundbox_calc_size_aabb(bbox, size);
BKE_boundbox_calc_center_aabb(bbox, center);
/* Avoid division by 0.0 later. */
size += 1e-8f;
/* BBox space to World. */
float4x4 bbox_mat = object_to_world *
from_loc_rot_scale<float4x4>(center, Quaternion::identity(), size);
float3 plane_normal;
if (is_persp_) {
/* BBox center to camera vector. */
plane_normal = camera_pos_ - bbox_mat.location();
}
else {
plane_normal = camera_forward_;
}
/* World to BBox space. */
float4x4 bbox_mat_inv = invert(bbox_mat);
/* mat_inv_t is a "normal" matrix which will transform
* BBox normal space to world space. */
float4x4 bbox_mat_inv_t = transpose(bbox_mat_inv);
/* Normalize the vector in BBox space. */
plane_normal = normalize(transform_direction(bbox_mat_inv, plane_normal));
plane_normal = normalize(transform_direction(bbox_mat_inv_t, plane_normal));
/* Define a matrix that will be used to render a triangle to merge the depth of the rendered
* gpencil object with the rest of the scene. */
float4x4 plane_mat = from_up_axis<float4x4>(plane_normal);
float radius = length(transform_direction(object_to_world, size));
plane_mat = scale(plane_mat, float3(radius));
plane_mat.location() = transform_point(object_to_world, center);
return plane_mat;
}
};
} // namespace blender::draw::greasepencil

View File

@ -74,7 +74,7 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
case LAYER_BLEND:
return "gpencil_layer_blend";
case DEPTH_MERGE:
return "gpencil_depth_merge";
return "grease_pencil_depth_merge";
case MASK_INVERT:
return "gpencil_mask_invert";
case FX_COMPOSITE:

View File

@ -0,0 +1,9 @@
/* SPDX-FileCopyrightText: 2020-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma BLENDER_REQUIRE(draw_model_lib.glsl)
void main()
{
gl_Position = drw_point_object_to_homogenous(pos);
}

View File

@ -126,6 +126,16 @@ GPU_SHADER_CREATE_INFO(gpencil_depth_merge)
.depth_write(DepthWrite::ANY)
.additional_info("draw_view");
GPU_SHADER_CREATE_INFO(grease_pencil_depth_merge)
.do_static_compilation(true)
.define("strokeOrder3d", "false")
.sampler(0, ImageType::DEPTH_2D, "depthBuf")
.vertex_in(0, Type::VEC3, "pos")
.vertex_source("grease_pencil_depth_merge_vert.glsl")
.fragment_source("gpencil_depth_merge_frag.glsl")
.depth_write(DepthWrite::ANY)
.additional_info("draw_modelmat_new", "draw_view");
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -126,6 +126,12 @@ class View {
return data_[view_id].viewinv.location();
}
const float3 &forward(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
return data_[view_id].viewinv.z_axis();
}
const float4x4 &viewmat(int view_id = 0) const
{
BLI_assert(view_id < view_len_);