Overlay-Next: Initial implementation #107045
|
@ -597,6 +597,8 @@ set(GLSL_SRC
|
|||
engines/select/shaders/select_id_frag.glsl
|
||||
engines/select/shaders/select_lib.glsl
|
||||
|
||||
engines/select/select_shader_shared.hh
|
||||
|
||||
engines/basic/shaders/basic_conservative_depth_geom.glsl
|
||||
engines/basic/shaders/basic_depth_vert.glsl
|
||||
engines/basic/shaders/basic_depth_vert_conservative_no_geom.glsl
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
#include "overlay_prepass.hh"
|
||||
#include "overlay_shape.hh"
|
||||
|
||||
#include "../select/select_empty.hh"
|
||||
#include "../select/select_object.hh"
|
||||
#include "../select/select_instance.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
|
@ -25,7 +24,7 @@ template<
|
|||
* selectable component and using a special shaders for drawing.
|
||||
* Making the select engine templated makes it easier to phase out any overhead of the
|
||||
* selection for the regular non-selection case.*/
|
||||
typename SelectEngineT = select::EngineEmpty>
|
||||
typename SelectEngineT = select::Instance>
|
||||
class Instance {
|
||||
public:
|
||||
/* WORKAROUND: Legacy. Move to grid pass. */
|
||||
|
|
|
@ -88,6 +88,8 @@ template<typename SelectEngineT> class Metaballs {
|
|||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
|
||||
state.clipping_state);
|
||||
/* NOTE: Use armature sphere outline shader to have perspective correct outline instead of
|
||||
* just a circle facing the camera. */
|
||||
pass.shader_set(res.shaders.armature_sphere_outline);
|
||||
pass.bind_ubo("globalsBlock", &res.globals_buf);
|
||||
res.select_bind(pass);
|
||||
|
|
|
@ -46,7 +46,7 @@ template<typename SelectEngineT> class Prepass {
|
|||
GPUBatch *geom = DRW_cache_object_surface_get(ob_ref.object);
|
||||
if (geom) {
|
||||
ResourceHandle res_handle = manager.resource_handle(ob_ref);
|
||||
pass.draw(geom, res_handle, res.select_id(ob_ref).value);
|
||||
pass.draw(geom, res_handle, res.select_id(ob_ref).get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1236,15 +1236,16 @@ void OVERLAY_shader_free(void)
|
|||
namespace blender::draw::overlay {
|
||||
|
||||
template<>
|
||||
ShaderModule<select::EngineEmpty> *ShaderModule<select::EngineEmpty>::g_shader_module = nullptr;
|
||||
ShaderModule<select::Instance> *ShaderModule<select::Instance>::g_shader_module = nullptr;
|
||||
|
||||
template<>
|
||||
ShaderModule<select::EngineObject> *ShaderModule<select::EngineObject>::g_shader_module = nullptr;
|
||||
ShaderModule<select::InstanceDummy> *ShaderModule<select::InstanceDummy>::g_shader_module =
|
||||
nullptr;
|
||||
|
||||
void shader_module_free()
|
||||
{
|
||||
ShaderModule<select::EngineEmpty>::module_free();
|
||||
ShaderModule<select::EngineObject>::module_free();
|
||||
ShaderModule<select::Instance>::module_free();
|
||||
ShaderModule<select::InstanceDummy>::module_free();
|
||||
}
|
||||
|
||||
} // namespace blender::draw::overlay
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
#include "../select/select_empty.hh"
|
||||
#include "../select/select_object.hh"
|
||||
#include "../select/select_instance.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define SELECT_DATA 4
|
||||
#define SELECT_ID_IN 5
|
||||
#define SELECT_ID_OUT 6
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Dummy implementation of the select engine types to avoid any overhead.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "draw_manager.hh"
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
namespace blender::draw::select {
|
||||
|
||||
struct EngineEmpty {
|
||||
/* Add type safety to selection ID. Only the select engine should provide them. */
|
||||
struct ID {};
|
||||
|
||||
struct SelectShader {
|
||||
static void patch(gpu::shader::ShaderCreateInfo &){};
|
||||
};
|
||||
|
||||
struct SelectBuf {
|
||||
void select_clear(){};
|
||||
void select_append(ID){};
|
||||
void select_bind(PassSimple &){};
|
||||
};
|
||||
|
||||
struct SelectMap {
|
||||
[[nodiscard]] const ID select_id(const ObjectRef &, uint = 0)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void begin_sync(){};
|
||||
|
||||
void select_bind(PassSimple &){};
|
||||
|
||||
void select_bind(PassMain &){};
|
||||
|
||||
void end_sync(){};
|
||||
|
||||
void read_result(){};
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace blender::draw::select
|
|
@ -4,8 +4,6 @@
|
|||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* This is an implementation of the Select engine specialized for selecting object.
|
||||
* Should plug seamlessly inside the overlay engine logic.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
@ -18,19 +16,72 @@
|
|||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
#include "select_defines.h"
|
||||
#include "select_shader_shared.hh"
|
||||
|
||||
namespace blender::draw::select {
|
||||
|
||||
struct EngineObject {
|
||||
/**
|
||||
* Dummy implementation of the select engine types to avoid any overhead.
|
||||
* Bypass any selection logic.
|
||||
*/
|
||||
struct InstanceDummy {
|
||||
/* Add type safety to selection ID. Only the select engine should provide them. */
|
||||
struct ID {
|
||||
class ID {
|
||||
public:
|
||||
constexpr uint32_t get() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct SelectShader {
|
||||
static void patch(gpu::shader::ShaderCreateInfo &){};
|
||||
};
|
||||
|
||||
struct SelectBuf {
|
||||
void select_clear(){};
|
||||
void select_append(ID){};
|
||||
void select_bind(PassSimple &){};
|
||||
};
|
||||
|
||||
struct SelectMap {
|
||||
[[nodiscard]] const ID select_id(const ObjectRef &, uint = 0)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void begin_sync(){};
|
||||
|
||||
void select_bind(PassSimple &){};
|
||||
|
||||
void select_bind(PassMain &){};
|
||||
|
||||
void end_sync(){};
|
||||
|
||||
void read_result(){};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* This is an implementation of the Select engine specialized for selecting object.
|
||||
* Should plug seamlessly inside the overlay engine logic.
|
||||
*/
|
||||
struct Instance {
|
||||
/* Add type safety to selection ID. Only the select engine should provide them. */
|
||||
class ID {
|
||||
public:
|
||||
uint32_t value;
|
||||
|
||||
uint32_t get() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
struct SelectShader {
|
||||
static void patch(gpu::shader::ShaderCreateInfo &info)
|
||||
{
|
||||
info.define("SELECT_UNORDERED");
|
||||
info.define("SELECT_ENABLE");
|
||||
/* Replace additional info. */
|
||||
for (StringRefNull &str : info.additional_infos_) {
|
||||
if (str == "draw_modelmat_new") {
|
||||
|
@ -43,7 +94,7 @@ struct EngineObject {
|
|||
|
||||
/**
|
||||
* Add a dedicated selection id buffer to a pass.
|
||||
* Use this when not using a #PassMain which can pass the select ID via CustomID.
|
||||
* To be used when not using a #PassMain which can pass the select ID via CustomID.
|
||||
*/
|
||||
struct SelectBuf {
|
||||
StorageVectorBuffer<uint32_t> select_buf = {"select_buf"};
|
||||
|
@ -55,7 +106,7 @@ struct EngineObject {
|
|||
|
||||
void select_append(ID select_id)
|
||||
{
|
||||
select_buf.append(select_id.value);
|
||||
select_buf.append(select_id.get());
|
||||
}
|
||||
|
||||
void select_bind(PassSimple &pass)
|
||||
|
@ -80,6 +131,8 @@ struct EngineObject {
|
|||
StorageArrayBuffer<uint> select_output_buf = {"select_output_buf"};
|
||||
/** Dummy buffer. Might be better to remove, but simplify the shader create info patching. */
|
||||
StorageArrayBuffer<uint, 4, true> dummy_select_buf = {"dummy_select_buf"};
|
||||
/** Uniform buffer to bind to all passes to pass information about the selection state. */
|
||||
UniformBuffer<SelectInfoData> info_buf;
|
||||
|
||||
/* TODO(fclem): The sub_object_id id should eventually become some enum or take a sub-object
|
||||
* reference directly. This would isolate the selection logic to this class. */
|
||||
|
@ -93,6 +146,12 @@ struct EngineObject {
|
|||
return {id};
|
||||
}
|
||||
|
||||
/* Load an invalid index that will not write to the output (not selectable). */
|
||||
[[nodiscard]] const ID select_invalid_id()
|
||||
{
|
||||
return {uint32_t(-1)};
|
||||
}
|
||||
|
||||
void begin_sync()
|
||||
{
|
||||
select_id_map.clear();
|
||||
|
@ -101,14 +160,18 @@ struct EngineObject {
|
|||
#endif
|
||||
}
|
||||
|
||||
/** IMPORTANT: Changes the draw state. Need to be called after the pass own state. */
|
||||
void select_bind(PassSimple &pass)
|
||||
{
|
||||
pass.bind_ubo(SELECT_DATA, &info_buf);
|
||||
pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf);
|
||||
}
|
||||
|
||||
/** IMPORTANT: Changes the draw state. Need to be called after the pass own state. */
|
||||
void select_bind(PassMain &pass)
|
||||
{
|
||||
pass.use_custom_ids = true;
|
||||
pass.bind_ubo(SELECT_DATA, &info_buf);
|
||||
/* IMPORTANT: This binds a dummy buffer `in_select_buf` but it is not supposed to be used. */
|
||||
pass.bind_ssbo(SELECT_ID_IN, &dummy_select_buf);
|
||||
pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf);
|
||||
|
@ -116,6 +179,11 @@ struct EngineObject {
|
|||
|
||||
void end_sync()
|
||||
{
|
||||
info_buf.mode = SelectType::SELECT_ALL;
|
||||
/* TODO: Should be select rect center. */
|
||||
info_buf.cursor = int2(512, 512);
|
||||
info_buf.push_update();
|
||||
|
||||
select_output_buf.resize(ceil_to_multiple_u(select_id_map.size(), 4));
|
||||
select_output_buf.push_update();
|
||||
select_output_buf.clear_to_zero();
|
|
@ -0,0 +1,28 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef GPU_SHADER
|
||||
# pragma once
|
||||
|
||||
# include "GPU_shader_shared_utils.h"
|
||||
|
||||
namespace blender::draw::select {
|
||||
|
||||
#endif
|
||||
|
||||
/* Matches eV3DSelectMode */
|
||||
enum SelectType : uint32_t {
|
||||
SELECT_ALL = 0u,
|
||||
SELECT_PICK_ALL = 1u,
|
||||
SELECT_PICK_NEAREST = 2u,
|
||||
};
|
||||
|
||||
struct SelectInfoData {
|
||||
int2 cursor;
|
||||
SelectType mode;
|
||||
uint _pad0;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(SelectInfoData, 16)
|
||||
|
||||
#ifndef GPU_SHADER
|
||||
} // namespace blender::draw::select
|
||||
#endif
|
|
@ -44,7 +44,11 @@ GPU_SHADER_CREATE_INFO(select_id_uniform_clipped)
|
|||
|
||||
/* Used to patch overlay shaders. */
|
||||
GPU_SHADER_CREATE_INFO(select_id_patch)
|
||||
.typedef_source("select_shader_shared.hh")
|
||||
.vertex_out(select_id_iface)
|
||||
/* Need to make sure the depth & stencil comparison runs before the fragment shader. */
|
||||
.early_fragment_test(true)
|
||||
.uniform_buf(SELECT_DATA, "SelectInfoData", "select_info_buf")
|
||||
/* Select IDs for instanced draw-calls not using #PassMain. */
|
||||
.storage_buf(SELECT_ID_IN, Qualifier::READ, "int", "in_select_buf[]")
|
||||
/* Stores the result of the whole selection drawing. Content depends on selection mode. */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
#if !(defined(SELECT_UNORDERED) || defined(SELECT_DEPTH_PICKING))
|
||||
#ifndef SELECT_ENABLE
|
||||
/* Avoid requesting the select_id when not in selection mode. */
|
||||
# define select_id_set(select_id)
|
||||
# define select_id_output(select_id)
|
||||
|
@ -16,19 +16,34 @@ void select_id_set(int id)
|
|||
|
||||
void select_id_output(int id)
|
||||
{
|
||||
# if defined(SELECT_UNORDERED)
|
||||
/* Used by rectangle selection.
|
||||
* Set the bit of the select id in the bitmap. */
|
||||
atomicOr(out_select_buf[id / 32u], 1u << (uint(id) % 32u));
|
||||
if (id == -1) {
|
||||
/* Invalid index */
|
||||
return;
|
||||
}
|
||||
|
||||
# elif defined(SELECT_DEPTH_PICKING)
|
||||
/* Used by mouse-clicking selection.
|
||||
* Stores the nearest depth for this select id. */
|
||||
atomicMin(out_select_buf[id], floatBitsToUint(gl_FragCoord.z));
|
||||
if (select_info_buf.mode == SELECT_ALL) {
|
||||
/* Set the bit of the select id in the bitmap. */
|
||||
atomicOr(out_select_buf[id / 32u], 1u << (uint(id) % 32u));
|
||||
}
|
||||
else if (select_info_buf.mode == SELECT_PICK_ALL) {
|
||||
/* Stores the nearest depth for this select id. */
|
||||
atomicMin(out_select_buf[id], floatBitsToUint(gl_FragCoord.z));
|
||||
}
|
||||
else if (select_info_buf.mode == SELECT_PICK_NEAREST) {
|
||||
/* Stores the nearest depth with the distance to the cursor. */
|
||||
|
||||
# else
|
||||
# error
|
||||
# endif
|
||||
/* Distance function to the cursor. Currently a simple pixel ring distance. */
|
||||
ivec2 coord = abs(ivec2(gl_FragCoord.xy) - select_info_buf.cursor);
|
||||
uint dist = uint(max(coord.x, coord.y));
|
||||
|
||||
uint depth = uint(gl_FragCoord.z * float(0x00FFFFFFu));
|
||||
|
||||
/* Reject hits outside of valid range. */
|
||||
if (dist < 0xFFu) {
|
||||
/* Packed values to ensure the atomicMin is performed on the whole result. */
|
||||
atomicMin(out_select_buf[id], (depth << 8u) | dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue