Fix: EEVEE: Object holdout not working
This implement the holdout flag by switching to the holdout case in the shader. This has a few benefits: - Doesn't recompile the shaders. - Makes the object infos mandatory (already the case in practice) - Handle transparent materials properly, keeping the transparency working. Fix #123284 Pull Request: https://projects.blender.org/blender/blender/pulls/123315
This commit is contained in:
committed by
Clément Foucault
parent
df98aa61bb
commit
b5a9a67dcf
@@ -421,9 +421,6 @@ Material &MaterialModule::material_sync(Object *ob,
|
||||
|
||||
::Material *MaterialModule::material_from_slot(Object *ob, int slot)
|
||||
{
|
||||
if (ob->base_flag & BASE_HOLDOUT) {
|
||||
return BKE_material_default_holdout();
|
||||
}
|
||||
::Material *ma = BKE_object_material_get(ob, slot + 1);
|
||||
if (ma == nullptr) {
|
||||
if (ob->type == OB_VOLUME) {
|
||||
|
||||
@@ -404,12 +404,6 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
|
||||
GPUCodegenOutput &codegen = *codegen_;
|
||||
ShaderCreateInfo &info = *reinterpret_cast<ShaderCreateInfo *>(codegen.create_info);
|
||||
|
||||
/* WORKAROUND: Replace by new ob info. */
|
||||
int64_t ob_info_index = info.additional_infos_.first_index_of_try("draw_object_infos");
|
||||
if (ob_info_index != -1) {
|
||||
info.additional_infos_[ob_info_index] = "draw_object_infos_new";
|
||||
}
|
||||
|
||||
/* WORKAROUND: Add new ob attr buffer. */
|
||||
if (GPU_material_uniform_attributes(gpumat) != nullptr) {
|
||||
info.additional_info("draw_object_attribute_new");
|
||||
@@ -586,9 +580,6 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
|
||||
info.vertex_inputs_.clear();
|
||||
/* Volume materials require these for loading the grid attributes from smoke sims. */
|
||||
info.additional_info("draw_volume_infos");
|
||||
if (ob_info_index == -1) {
|
||||
info.additional_info("draw_object_infos_new");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MAT_GEOM_POINT_CLOUD:
|
||||
|
||||
@@ -22,7 +22,7 @@ int g_attr_id = 0;
|
||||
/* Point clouds and curves are not compatible with volume grids.
|
||||
* They will fallback to their own attributes loading. */
|
||||
#if defined(MAT_VOLUME) && !defined(MAT_GEOM_CURVES) && !defined(MAT_GEOM_POINT_CLOUD)
|
||||
# if defined(OBINFO_LIB) && !defined(MAT_GEOM_WORLD)
|
||||
# if defined(VOLUME_INFO_LIB) && !defined(MAT_GEOM_WORLD)
|
||||
# define GRID_ATTRIBUTES
|
||||
# endif
|
||||
|
||||
|
||||
@@ -731,7 +731,7 @@ float film_scaling_factor_get()
|
||||
/* Point clouds and curves are not compatible with volume grids.
|
||||
* They will fallback to their own attributes loading. */
|
||||
#if defined(MAT_VOLUME) && !defined(MAT_GEOM_CURVES) && !defined(MAT_GEOM_POINT_CLOUD)
|
||||
# if defined(OBINFO_LIB) && !defined(MAT_GEOM_WORLD)
|
||||
# if defined(VOLUME_INFO_LIB) && !defined(MAT_GEOM_WORLD)
|
||||
/* We could just check for GRID_ATTRIBUTES but this avoids for header dependency. */
|
||||
# define GRID_ATTRIBUTES_LOAD_POST
|
||||
# endif
|
||||
@@ -740,7 +740,7 @@ float film_scaling_factor_get()
|
||||
float attr_load_temperature_post(float attr)
|
||||
{
|
||||
#ifdef GRID_ATTRIBUTES_LOAD_POST
|
||||
/* Bring the into standard range without having to modify the grid values */
|
||||
/* Bring the value into standard range without having to modify the grid values */
|
||||
attr = (attr > 0.01) ? (attr * drw_volume.temperature_mul + drw_volume.temperature_bias) : 0.0;
|
||||
#endif
|
||||
return attr;
|
||||
|
||||
@@ -50,9 +50,20 @@ void main()
|
||||
float thickness = nodetree_thickness() * thickness_mode;
|
||||
|
||||
/** Transparency weight is already applied through dithering, remove it from other closures. */
|
||||
float transparency = 1.0 - average(g_transmittance);
|
||||
float transparency_rcp = safe_rcp(transparency);
|
||||
g_emission *= transparency_rcp;
|
||||
float alpha = 1.0 - average(g_transmittance);
|
||||
float alpha_rcp = safe_rcp(alpha);
|
||||
|
||||
/* Object holdout. */
|
||||
eObjectInfoFlag ob_flag = eObjectInfoFlag(floatBitsToUint(drw_infos[resource_id].infos.w));
|
||||
if (flag_test(ob_flag, OBJECT_HOLDOUT)) {
|
||||
/* alpha is set from rejected pixels / dithering. */
|
||||
g_holdout = 1.0;
|
||||
|
||||
/* Set alpha to 0.0 so that lighting is not computed. */
|
||||
alpha_rcp = 0.0;
|
||||
}
|
||||
|
||||
g_emission *= alpha_rcp;
|
||||
|
||||
ivec2 out_texel = ivec2(gl_FragCoord.xy);
|
||||
|
||||
@@ -72,12 +83,12 @@ void main()
|
||||
/* ----- GBuffer output ----- */
|
||||
|
||||
GBufferData gbuf_data;
|
||||
gbuf_data.closure[0] = g_closure_get_resolved(0, transparency_rcp);
|
||||
gbuf_data.closure[0] = g_closure_get_resolved(0, alpha_rcp);
|
||||
#if CLOSURE_BIN_COUNT > 1
|
||||
gbuf_data.closure[1] = g_closure_get_resolved(1, transparency_rcp);
|
||||
gbuf_data.closure[1] = g_closure_get_resolved(1, alpha_rcp);
|
||||
#endif
|
||||
#if CLOSURE_BIN_COUNT > 2
|
||||
gbuf_data.closure[2] = g_closure_get_resolved(2, transparency_rcp);
|
||||
gbuf_data.closure[2] = g_closure_get_resolved(2, alpha_rcp);
|
||||
#endif
|
||||
gbuf_data.surface_N = g_data.N;
|
||||
gbuf_data.thickness = thickness;
|
||||
|
||||
@@ -49,6 +49,13 @@ void main()
|
||||
|
||||
nodetree_surface(closure_rand);
|
||||
|
||||
eObjectInfoFlag ob_flag = eObjectInfoFlag(floatBitsToUint(drw_infos[resource_id].infos.w));
|
||||
if (flag_test(ob_flag, OBJECT_HOLDOUT)) {
|
||||
g_holdout = 1.0;
|
||||
}
|
||||
|
||||
g_holdout = saturate(g_holdout);
|
||||
|
||||
vec3 radiance, transmittance;
|
||||
forward_lighting_eval(g_thickness, radiance, transmittance);
|
||||
|
||||
@@ -64,6 +71,6 @@ void main()
|
||||
|
||||
radiance *= 1.0 - saturate(g_holdout);
|
||||
|
||||
out_radiance = vec4(radiance, 0.0);
|
||||
out_radiance = vec4(radiance, g_holdout);
|
||||
out_transmittance = vec4(transmittance, saturate(average(transmittance)));
|
||||
}
|
||||
|
||||
@@ -53,9 +53,20 @@ void main()
|
||||
g_holdout = saturate(g_holdout);
|
||||
|
||||
/** Transparency weight is already applied through dithering, remove it from other closures. */
|
||||
float transparency = 1.0 - average(g_transmittance);
|
||||
float transparency_rcp = safe_rcp(transparency);
|
||||
g_emission *= transparency_rcp;
|
||||
float alpha = 1.0 - average(g_transmittance);
|
||||
float alpha_rcp = safe_rcp(alpha);
|
||||
|
||||
/* Object holdout. */
|
||||
eObjectInfoFlag ob_flag = eObjectInfoFlag(floatBitsToUint(drw_infos[resource_id].infos.w));
|
||||
if (flag_test(ob_flag, OBJECT_HOLDOUT)) {
|
||||
/* alpha is set from rejected pixels / dithering. */
|
||||
g_holdout = 1.0;
|
||||
|
||||
/* Set alpha to 0.0 so that lighting is not computed. */
|
||||
alpha_rcp = 0.0;
|
||||
}
|
||||
|
||||
g_emission *= alpha_rcp;
|
||||
|
||||
ivec2 out_texel = ivec2(gl_FragCoord.xy);
|
||||
|
||||
@@ -75,12 +86,12 @@ void main()
|
||||
/* ----- GBuffer output ----- */
|
||||
|
||||
GBufferData gbuf_data;
|
||||
gbuf_data.closure[0] = g_closure_get_resolved(0, transparency_rcp);
|
||||
gbuf_data.closure[0] = g_closure_get_resolved(0, alpha_rcp);
|
||||
#if CLOSURE_BIN_COUNT > 1
|
||||
gbuf_data.closure[1] = g_closure_get_resolved(1, transparency_rcp);
|
||||
gbuf_data.closure[1] = g_closure_get_resolved(1, alpha_rcp);
|
||||
#endif
|
||||
#if CLOSURE_BIN_COUNT > 2
|
||||
gbuf_data.closure[2] = g_closure_get_resolved(2, transparency_rcp);
|
||||
gbuf_data.closure[2] = g_closure_get_resolved(2, alpha_rcp);
|
||||
#endif
|
||||
gbuf_data.surface_N = g_data.N;
|
||||
gbuf_data.thickness = g_thickness;
|
||||
|
||||
@@ -54,7 +54,10 @@ GPU_SHADER_CREATE_INFO(eevee_geom_mesh)
|
||||
.vertex_in(1, Type::VEC3, "nor")
|
||||
.vertex_source("eevee_geom_mesh_vert.glsl")
|
||||
.vertex_out(eevee_surf_iface)
|
||||
.additional_info("draw_modelmat_new", "draw_resource_id_varying", "draw_view");
|
||||
.additional_info("draw_modelmat_new",
|
||||
"draw_object_infos_new",
|
||||
"draw_resource_id_varying",
|
||||
"draw_view");
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(eevee_surf_point_cloud_iface, "point_cloud_interp")
|
||||
.smooth(Type::FLOAT, "radius")
|
||||
@@ -71,6 +74,7 @@ GPU_SHADER_CREATE_INFO(eevee_geom_point_cloud)
|
||||
.vertex_out(eevee_surf_point_cloud_flat_iface)
|
||||
.additional_info("draw_pointcloud_new",
|
||||
"draw_modelmat_new",
|
||||
"draw_object_infos_new",
|
||||
"draw_resource_id_varying",
|
||||
"draw_view");
|
||||
|
||||
@@ -91,7 +95,10 @@ GPU_SHADER_CREATE_INFO(eevee_geom_gpencil)
|
||||
.define("MAT_GEOM_GPENCIL")
|
||||
.vertex_source("eevee_geom_gpencil_vert.glsl")
|
||||
.vertex_out(eevee_surf_iface)
|
||||
.additional_info("draw_gpencil_new", "draw_resource_id_varying", "draw_resource_id_new");
|
||||
.additional_info("draw_gpencil_new",
|
||||
"draw_object_infos_new",
|
||||
"draw_resource_id_varying",
|
||||
"draw_resource_id_new");
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(eevee_surf_curve_iface, "curve_interp")
|
||||
.smooth(Type::VEC2, "barycentric_coords")
|
||||
@@ -111,6 +118,7 @@ GPU_SHADER_CREATE_INFO(eevee_geom_curves)
|
||||
.vertex_out(eevee_surf_curve_iface)
|
||||
.vertex_out(eevee_surf_curve_flat_iface)
|
||||
.additional_info("draw_modelmat_new",
|
||||
"draw_object_infos_new",
|
||||
"draw_resource_id_varying",
|
||||
"draw_view",
|
||||
"draw_hair_new",
|
||||
@@ -122,7 +130,10 @@ GPU_SHADER_CREATE_INFO(eevee_geom_world)
|
||||
.builtins(BuiltinBits::VERTEX_ID)
|
||||
.vertex_source("eevee_geom_world_vert.glsl")
|
||||
.vertex_out(eevee_surf_iface)
|
||||
.additional_info("draw_modelmat_new", "draw_resource_id_varying", "draw_view");
|
||||
.additional_info("draw_modelmat_new",
|
||||
"draw_object_infos_new", /* Unused, but allow debug compilation. */
|
||||
"draw_resource_id_varying",
|
||||
"draw_view");
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
@@ -73,6 +73,8 @@ inline void ObjectInfos::sync(const blender::draw::ObjectRef ref, bool is_active
|
||||
{
|
||||
object_attrs_len = 0;
|
||||
object_attrs_offset = 0;
|
||||
bool is_holdout = (ref.object->base_flag & BASE_HOLDOUT) ||
|
||||
(ref.object->visibility_flag & OB_HOLDOUT);
|
||||
|
||||
ob_color = ref.object->color;
|
||||
index = ref.object->index;
|
||||
@@ -85,6 +87,7 @@ inline void ObjectInfos::sync(const blender::draw::ObjectRef ref, bool is_active
|
||||
flag, ref.object->base_flag & BASE_FROM_SET, eObjectInfoFlag::OBJECT_FROM_SET);
|
||||
SET_FLAG_FROM_TEST(
|
||||
flag, ref.object->transflag & OB_NEG_SCALE, eObjectInfoFlag::OBJECT_NEGATIVE_SCALE);
|
||||
SET_FLAG_FROM_TEST(flag, is_holdout, eObjectInfoFlag::OBJECT_HOLDOUT);
|
||||
|
||||
if (ref.dupli_object == nullptr) {
|
||||
/* TODO(fclem): this is rather costly to do at draw time. Maybe we can
|
||||
|
||||
@@ -153,8 +153,9 @@ enum eObjectInfoFlag : uint32_t {
|
||||
OBJECT_FROM_SET = (1u << 2u),
|
||||
OBJECT_ACTIVE = (1u << 3u),
|
||||
OBJECT_NEGATIVE_SCALE = (1u << 4u),
|
||||
OBJECT_HOLDOUT = (1u << 5u),
|
||||
/* Avoid skipped info to change culling. */
|
||||
OBJECT_NO_INFO = ~OBJECT_NEGATIVE_SCALE
|
||||
OBJECT_NO_INFO = ~OBJECT_HOLDOUT
|
||||
};
|
||||
|
||||
struct ObjectInfos {
|
||||
|
||||
@@ -18,6 +18,7 @@ GPU_SHADER_CREATE_INFO(draw_object_infos)
|
||||
|
||||
GPU_SHADER_CREATE_INFO(draw_volume_infos)
|
||||
.typedef_source("draw_shader_shared.hh")
|
||||
.define("VOLUME_INFO_LIB")
|
||||
.uniform_buf(DRW_OBJ_DATA_INFO_UBO_SLOT, "VolumeInfos", "drw_volume", Frequency::BATCH);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(draw_curves_infos)
|
||||
|
||||
@@ -282,10 +282,6 @@ class GPUCodegen {
|
||||
create_info = new GPUCodegenCreateInfo("codegen");
|
||||
output.create_info = reinterpret_cast<GPUShaderCreateInfo *>(
|
||||
static_cast<ShaderCreateInfo *>(create_info));
|
||||
|
||||
if (GPU_material_flag_get(mat_, GPU_MATFLAG_OBJECT_INFO)) {
|
||||
create_info->additional_info("draw_object_infos");
|
||||
}
|
||||
}
|
||||
|
||||
~GPUCodegen()
|
||||
|
||||
Reference in New Issue
Block a user