Overlay-Next: refactoring and fixes

Classes Speaker, Lattice, Metaball, Prepass refactored to contain one pass.
Stereo camera's connecting line fixed to always be dashed.
Metaball selection fixed in object and edit modes.

Pull Request: https://projects.blender.org/blender/blender/pulls/125684
This commit is contained in:
Laurynas Duburas
2024-08-02 12:55:33 +02:00
committed by Clément Foucault
parent 5ce29bedf6
commit 6f76ac236b
10 changed files with 123 additions and 195 deletions

View File

@@ -77,20 +77,20 @@ void Instance::begin_sync()
resources.begin_sync();
background.begin_sync(resources, state);
prepass.begin_sync(resources, state);
lattices.begin_sync(resources, state);
auto begin_sync_layer = [&](OverlayLayer &layer) {
layer.bounds.begin_sync();
layer.cameras.begin_sync();
layer.empties.begin_sync();
layer.lattices.begin_sync(resources, state);
layer.lights.begin_sync();
layer.metaballs.begin_sync();
layer.prepass.begin_sync(resources, state);
layer.speakers.begin_sync();
};
begin_sync_layer(regular);
begin_sync_layer(infront);
metaballs.begin_sync();
speakers.begin_sync();
grid.begin_sync(resources, state, view);
}
@@ -108,7 +108,7 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
case OB_CURVES:
case OB_FONT:
case OB_CURVES_LEGACY:
prepass.object_sync(manager, ob_ref, resources);
layer.prepass.object_sync(manager, ob_ref, resources);
break;
}
}
@@ -124,10 +124,10 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
case OB_SURF:
break;
case OB_LATTICE:
lattices.edit_object_sync(manager, ob_ref, resources);
layer.lattices.edit_object_sync(manager, ob_ref, resources);
break;
case OB_MBALL:
metaballs.edit_object_sync(ob_ref, resources);
layer.metaballs.edit_object_sync(ob_ref, resources);
break;
case OB_FONT:
break;
@@ -148,7 +148,7 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
break;
case OB_LATTICE:
if (!in_edit_mode) {
lattices.object_sync(manager, ob_ref, resources, state);
layer.lattices.object_sync(manager, ob_ref, resources, state);
}
break;
case OB_LAMP:
@@ -156,13 +156,13 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
break;
case OB_MBALL:
if (!in_edit_mode) {
metaballs.object_sync(ob_ref, resources, state);
layer.metaballs.object_sync(ob_ref, resources, state);
}
break;
case OB_GPENCIL_LEGACY:
break;
case OB_SPEAKER:
speakers.object_sync(ob_ref, resources, state);
layer.speakers.object_sync(ob_ref, resources, state);
break;
}
layer.bounds.object_sync(ob_ref, resources, state);
@@ -178,12 +178,11 @@ void Instance::end_sync()
layer.cameras.end_sync(resources, shapes, state);
layer.empties.end_sync(resources, shapes, state);
layer.lights.end_sync(resources, shapes, state);
layer.metaballs.end_sync(resources, shapes, state);
layer.speakers.end_sync(resources, shapes, state);
};
end_sync_layer(regular);
end_sync_layer(infront);
metaballs.end_sync(resources, shapes, state);
speakers.end_sync(resources, shapes, state);
}
void Instance::draw(Manager &manager)
@@ -243,24 +242,27 @@ void Instance::draw(Manager &manager)
float4 clear_color(0.0f);
GPU_framebuffer_clear_color(resources.overlay_color_only_fb, clear_color);
prepass.draw(resources, manager, view);
prepass.draw_in_front(resources, manager, view);
regular.prepass.draw(resources.overlay_line_fb, manager, view);
infront.prepass.draw(resources.overlay_line_in_front_fb, manager, view);
background.draw(resources, manager);
regular.bounds.draw(resources.overlay_line_fb, manager, view);
regular.cameras.draw(resources.overlay_line_fb, manager, view);
regular.empties.draw(resources.overlay_line_fb, manager, view);
regular.lights.draw(resources.overlay_line_fb, manager, view);
lattices.draw(resources, manager, view);
metaballs.draw(resources, manager, view);
speakers.draw(resources, manager, view);
auto draw_layer = [&](OverlayLayer &layer, Framebuffer &framebuffer) {
layer.bounds.draw(framebuffer, manager, view);
layer.cameras.draw(framebuffer, manager, view);
layer.empties.draw(framebuffer, manager, view);
layer.lights.draw(framebuffer, manager, view);
layer.speakers.draw(framebuffer, manager, view);
layer.lattices.draw(framebuffer, manager, view);
layer.metaballs.draw(framebuffer, manager, view);
};
draw_layer(regular, resources.overlay_line_fb);
grid.draw(resources, manager, view);
/* TODO(: Breaks selection on M1 Max. */
// lattices.draw_in_front(resources, manager, view);
metaballs.draw_in_front(resources, manager, view);
speakers.draw_in_front(resources, manager, view);
// infront.lattices.draw(resources.overlay_line_in_front_fb, manager, view);
// anti_aliasing.draw(resources, manager, view);

View File

@@ -43,19 +43,19 @@ class Instance {
/** Overlay types. */
Background background;
Prepass prepass;
struct OverlayLayer {
const SelectionType selection_type_;
Bounds bounds = {selection_type_};
Cameras cameras = {selection_type_};
Empties empties = {selection_type_};
Lattices lattices;
Lights lights = {selection_type_};
Metaballs metaballs = {selection_type_};
Prepass prepass;
Speakers speakers = {selection_type_};
} regular{selection_type_}, infront{selection_type_};
Metaballs metaballs = {selection_type_};
Lattices lattices;
Speakers speakers = {selection_type_};
Grid grid;
Instance(const SelectionType selection_type) : selection_type_(selection_type){};

View File

@@ -19,58 +19,51 @@ namespace blender::draw::overlay {
class Lattices {
private:
PassMain ps_ = {"Lattice"};
PassMain in_front_ps_ = {"Lattice_in_front"};
PassMain::Sub *lattice_ps_[2];
PassMain::Sub *edit_lattice_wire_ps_[2];
PassMain::Sub *edit_lattice_point_ps_[2];
PassMain::Sub *lattice_ps_;
PassMain::Sub *edit_lattice_wire_ps_;
PassMain::Sub *edit_lattice_point_ps_;
public:
void begin_sync(Resources &res, const State &state)
{
const DRWState pass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state;
auto init_pass = [&](PassMain &pass, int in_front) {
auto create_sub_pass = [&](const char *name, GPUShader *shader, bool add_weight_tex) {
PassMain::Sub &sub_pass = pass.sub(name);
sub_pass.state_set(pass_state);
sub_pass.shader_set(shader);
sub_pass.bind_ubo("globalsBlock", &res.globals_buf);
if (add_weight_tex) {
sub_pass.bind_texture("weightTex", &res.weight_ramp_tx);
}
return &sub_pass;
};
pass.init();
edit_lattice_wire_ps_[in_front] = create_sub_pass(
"edit_lattice_wire", res.shaders.lattice_wire.get(), true);
edit_lattice_point_ps_[in_front] = create_sub_pass(
"edit_lattice_points", res.shaders.lattice_points.get(), false);
lattice_ps_[in_front] = create_sub_pass(
"lattice", res.shaders.extra_wire_object.get(), false);
res.select_bind(pass);
auto create_sub_pass = [&](const char *name, GPUShader *shader, bool add_weight_tex) {
PassMain::Sub &sub_pass = ps_.sub(name);
sub_pass.state_set(pass_state);
sub_pass.shader_set(shader);
sub_pass.bind_ubo("globalsBlock", &res.globals_buf);
if (add_weight_tex) {
sub_pass.bind_texture("weightTex", &res.weight_ramp_tx);
}
return &sub_pass;
};
init_pass(ps_, 0);
init_pass(in_front_ps_, 1);
ps_.init();
edit_lattice_wire_ps_ = create_sub_pass(
"edit_lattice_wire", res.shaders.lattice_wire.get(), true);
edit_lattice_point_ps_ = create_sub_pass(
"edit_lattice_points", res.shaders.lattice_points.get(), false);
lattice_ps_ = create_sub_pass("lattice", res.shaders.extra_wire_object.get(), false);
res.select_bind(ps_);
}
void edit_object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res)
{
const int in_front = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? 1 : 0;
{
gpu::Batch *geom = DRW_cache_lattice_wire_get(ob_ref.object, true);
if (geom) {
ResourceHandle res_handle = manager.resource_handle(ob_ref);
edit_lattice_wire_ps_[in_front]->draw(geom, res_handle, res.select_id(ob_ref).get());
edit_lattice_wire_ps_->draw(geom, res_handle, res.select_id(ob_ref).get());
}
}
{
gpu::Batch *geom = DRW_cache_lattice_vert_overlay_get(ob_ref.object);
if (geom) {
ResourceHandle res_handle = manager.resource_handle(ob_ref);
edit_lattice_point_ps_[in_front]->draw(geom, res_handle, res.select_id(ob_ref).get());
edit_lattice_point_ps_->draw(geom, res_handle, res.select_id(ob_ref).get());
}
}
}
@@ -86,21 +79,14 @@ class Lattices {
}
draw_mat[3][3] = 0.0f /* No stipples. */;
ResourceHandle res_handle = manager.resource_handle(ob_ref, &draw_mat, nullptr, nullptr);
const int in_front = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? 1 : 0;
lattice_ps_[in_front]->draw(geom, res_handle, res.select_id(ob_ref).get());
lattice_ps_->draw(geom, res_handle, res.select_id(ob_ref).get());
}
}
void draw(Resources &res, Manager &manager, View &view)
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_fb);
GPU_framebuffer_bind(framebuffer);
manager.submit(ps_, view);
}
void draw_in_front(Resources &res, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_in_front_fb);
manager.submit(in_front_ps_, view);
}
};
} // namespace blender::draw::overlay

View File

@@ -21,11 +21,9 @@ class Metaballs {
private:
const SelectionType selection_type_;
PassSimple metaball_ps_ = {"MetaBalls"};
PassSimple metaball_in_front_ps_ = {"MetaBalls_In_front"};
PassSimple ps_ = {"MetaBalls"};
SphereOutlineInstanceBuf circle_buf_ = {selection_type_, "metaball_data_buf"};
SphereOutlineInstanceBuf circle_in_front_buf_ = {selection_type_, "metaball_data_buf"};
public:
Metaballs(const SelectionType selection_type) : selection_type_(selection_type){};
@@ -33,14 +31,10 @@ class Metaballs {
void begin_sync()
{
circle_buf_.clear();
circle_in_front_buf_.clear();
}
void edit_object_sync(const ObjectRef &ob_ref, Resources &res)
{
SphereOutlineInstanceBuf &circle_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ?
circle_in_front_buf_ :
circle_buf_;
MetaBall *mb = static_cast<MetaBall *>(ob_ref.object->data);
const float *color;
@@ -49,26 +43,25 @@ class Metaballs {
const float *col_stiffness = res.theme_settings.color_mball_stiffness;
const float *col_stiffness_select = res.theme_settings.color_mball_stiffness_select;
int elem_num = 0;
LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
const bool is_selected = (ml->flag & SELECT) != 0;
const bool is_scale_radius = (ml->flag & MB_SCALE_RAD) != 0;
float stiffness_radius = ml->rad * atanf(ml->s) / float(M_PI_2);
const float stiffness_radius = ml->rad * atanf(ml->s) * 2.0f / math::numbers::pi;
const select::ID radius_id = res.select_id(ob_ref, MBALLSEL_RADIUS);
const select::ID radius_id = res.select_id(ob_ref, MBALLSEL_RADIUS | elem_num);
color = (is_selected && is_scale_radius) ? col_radius_select : col_radius;
circle_buf.append({ob_ref.object, &ml->x, ml->rad, color}, radius_id);
circle_buf_.append({ob_ref.object, &ml->x, ml->rad, color}, radius_id);
const select::ID stiff_id = res.select_id(ob_ref, MBALLSEL_STIFF);
const select::ID stiff_id = res.select_id(ob_ref, MBALLSEL_STIFF | elem_num);
color = (is_selected && !is_scale_radius) ? col_stiffness_select : col_stiffness;
circle_buf.append({ob_ref.object, &ml->x, stiffness_radius, color}, stiff_id);
circle_buf_.append({ob_ref.object, &ml->x, stiffness_radius, color}, stiff_id);
elem_num += 1 << 16;
}
}
void object_sync(const ObjectRef &ob_ref, Resources &res, const State &state)
{
SphereOutlineInstanceBuf &circle_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ?
circle_in_front_buf_ :
circle_buf_;
MetaBall *mb = static_cast<MetaBall *>(ob_ref.object->data);
const float4 &color = res.object_wire_color(ob_ref, state);
@@ -76,38 +69,28 @@ class Metaballs {
LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
/* Draw radius only. */
circle_buf.append({ob_ref.object, &ml->x, ml->rad, color}, select_id);
circle_buf_.append({ob_ref.object, &ml->x, ml->rad, color}, select_id);
}
}
void end_sync(Resources &res, ShapeCache &shapes, const State &state)
{
auto init_pass = [&](PassSimple &pass, SphereOutlineInstanceBuf &call_buf) {
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.get());
pass.bind_ubo("globalsBlock", &res.globals_buf);
res.select_bind(pass);
ps_.init();
ps_.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. */
ps_.shader_set(res.shaders.armature_sphere_outline.get());
ps_.bind_ubo("globalsBlock", &res.globals_buf);
res.select_bind(ps_);
call_buf.end_sync(pass, shapes.metaball_wire_circle.get());
};
init_pass(metaball_ps_, circle_buf_);
init_pass(metaball_in_front_ps_, circle_in_front_buf_);
circle_buf_.end_sync(ps_, shapes.metaball_wire_circle.get());
}
void draw(Resources &res, Manager &manager, View &view)
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_fb);
manager.submit(metaball_ps_, view);
}
void draw_in_front(Resources &res, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_in_front_fb);
manager.submit(metaball_in_front_ps_, view);
GPU_framebuffer_bind(framebuffer);
manager.submit(ps_, view);
}
};

View File

@@ -17,48 +17,33 @@ namespace blender::draw::overlay {
class Prepass {
private:
PassMain prepass_ps_ = {"prepass"};
PassMain prepass_in_front_ps_ = {"prepass_in_front"};
PassMain ps_ = {"prepass"};
public:
void begin_sync(Resources &res, const State &state)
{
auto init_pass = [&](PassMain &pass) {
pass.init();
pass.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state);
pass.shader_set(res.shaders.depth_mesh.get());
res.select_bind(pass);
};
init_pass(prepass_ps_);
init_pass(prepass_in_front_ps_);
ps_.init();
ps_.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state);
ps_.shader_set(res.shaders.depth_mesh.get());
res.select_bind(ps_);
}
void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res)
{
PassMain &pass = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? prepass_in_front_ps_ :
prepass_ps_;
/* TODO(fclem) This function should contain what `basic_cache_populate` contained. */
gpu::Batch *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).get());
ps_.draw(geom, res_handle, res.select_id(ob_ref).get());
}
}
void draw(Resources &res, Manager &manager, View &view)
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
{
/* Should be fine to use the line buffer since the prepass only writes to the depth buffer. */
GPU_framebuffer_bind(res.overlay_line_fb);
manager.submit(prepass_ps_, view);
}
void draw_in_front(Resources &res, Manager &manager, View &view)
{
/* Should be fine to use the line buffer since the prepass only writes to the depth buffer. */
GPU_framebuffer_bind(res.overlay_line_in_front_fb);
manager.submit(prepass_in_front_ps_, view);
GPU_framebuffer_bind(framebuffer);
manager.submit(ps_, view);
}
};

View File

@@ -339,9 +339,7 @@ struct LineInstanceBuf : private select::SelectBuf {
this->select_bind(pass);
data_buf.push_update();
pass.bind_ssbo("data_buf", &data_buf);
if (color_id) {
pass.push_constant("colorid", color_id);
}
pass.push_constant("colorid", color_id);
pass.draw_procedural(GPU_PRIM_LINES, 1, data_buf.size());
}
};

View File

@@ -86,8 +86,8 @@ ShaderModule::ShaderModule(const SelectionType selection_type, const bool clippi
info.typedef_source("overlay_shader_shared.h");
info.storage_buf(0, Qualifier::READ, "PointData", "data_buf[]");
info.push_constant(gpu::shader::Type::INT, "colorid");
info.define("pos", "data_buf[gl_InstanceID * 2 + gl_VertexID].pos_.xyz");
info.define("color", "data_buf[gl_InstanceID * 2 + gl_VertexID].color_");
info.define("pos", "data_buf[gl_VertexID].pos_.xyz");
info.define("color", "data_buf[gl_VertexID].color_");
info.additional_infos_.clear();
info.additional_info(
"draw_view", "draw_modelmat_new", "draw_resource_handle_new", "draw_globals");

View File

@@ -514,41 +514,30 @@ ShapeCache::ShapeCache()
/* speaker */
{
constexpr int segments = 16;
constexpr float bottom_r = 0.5f;
constexpr float bottom_z = -0.125f;
constexpr float step_z = 0.25f;
const Vector<float2> diamond = ring_vertices(bottom_r, 4);
Vector<float2> ring = ring_vertices(bottom_r, segments);
Vector<Vertex> verts;
for (int j = 0; j < 3; j++) {
float z = 0.25f * j - 0.125f;
float r = (j == 0 ? 0.5f : 0.25f);
verts.append({{r, 0.0f, z}});
for (int i = 1; i < segments; i++) {
float x = cosf(2.0f * math::numbers::pi * i / segments) * r;
float y = sinf(2.0f * math::numbers::pi * i / segments) * r;
Vertex v{{x, y, z}};
verts.append(v);
verts.append(v);
}
Vertex v{{r, 0.0f, z}};
verts.append(v);
append_line_loop(verts, ring, bottom_z, VCLASS_NONE);
for (float2 &point : ring) {
point *= 0.5f;
}
for (const int j : IndexRange(1, 2)) {
const float z = step_z * j + bottom_z;
append_line_loop(verts, ring, z, VCLASS_NONE);
}
for (int j = 0; j < 4; j++) {
float x = (((j + 1) % 2) * (j - 1)) * 0.5f;
float y = ((j % 2) * (j - 2)) * 0.5f;
for (int i = 0; i < 3; i++) {
if (i == 1) {
x *= 0.5f;
y *= 0.5f;
}
float z = 0.25f * i - 0.125f;
Vertex v{{x, y, z}};
verts.append(v);
if (i == 1) {
verts.append(v);
}
}
for (const float2 &point : diamond) {
Vertex vertex{float3{point, bottom_z}};
verts.append(vertex);
vertex.pos = float3{point * 0.5f, bottom_z + step_z};
verts.append(vertex);
verts.append(vertex);
vertex.pos.z += step_z;
verts.append(vertex);
}
speaker = BatchPtr(
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));

View File

@@ -20,11 +20,9 @@ class Speakers {
private:
const SelectionType selection_type_;
PassSimple speaker_ps_ = {"Speakers"};
PassSimple speaker_in_front_ps_ = {"Speakers_In_front"};
PassSimple ps_ = {"Speakers"};
SpeakerInstanceBuf speaker_buf_ = {selection_type_, "speaker_data_buf"};
SpeakerInstanceBuf speaker_in_front_buf_ = {selection_type_, "speaker_data_buf"};
public:
Speakers(const SelectionType selection_type) : selection_type_(selection_type){};
@@ -32,47 +30,32 @@ class Speakers {
void begin_sync()
{
speaker_buf_.clear();
speaker_in_front_buf_.clear();
}
void object_sync(const ObjectRef &ob_ref, Resources &res, const State &state)
{
SpeakerInstanceBuf &speaker_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ?
speaker_in_front_buf_ :
speaker_buf_;
float4 color = res.object_wire_color(ob_ref, state);
const float4 color = res.object_wire_color(ob_ref, state);
const select::ID select_id = res.select_id(ob_ref);
speaker_buf.append({ob_ref.object->object_to_world(), color, 1.0f}, select_id);
speaker_buf_.append({ob_ref.object->object_to_world(), color, 1.0f}, select_id);
}
void end_sync(Resources &res, ShapeCache &shapes, const State &state)
{
auto init_pass = [&](PassSimple &pass, SpeakerInstanceBuf &call_buf) {
pass.init();
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
state.clipping_state);
pass.shader_set(res.shaders.extra_shape.get());
pass.bind_ubo("globalsBlock", &res.globals_buf);
res.select_bind(pass);
ps_.init();
ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
state.clipping_state);
ps_.shader_set(res.shaders.extra_shape.get());
ps_.bind_ubo("globalsBlock", &res.globals_buf);
res.select_bind(ps_);
call_buf.end_sync(pass, shapes.speaker.get());
};
init_pass(speaker_ps_, speaker_buf_);
init_pass(speaker_in_front_ps_, speaker_in_front_buf_);
speaker_buf_.end_sync(ps_, shapes.speaker.get());
}
void draw(Resources &res, Manager &manager, View &view)
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_fb);
manager.submit(speaker_ps_, view);
}
void draw_in_front(Resources &res, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_in_front_fb);
manager.submit(speaker_in_front_ps_, view);
GPU_framebuffer_bind(framebuffer);
manager.submit(ps_, view);
}
};

View File

@@ -4,6 +4,7 @@
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(select_lib.glsl)
/* project to screen space */
vec2 proj(vec4 pos)
@@ -13,6 +14,7 @@ vec2 proj(vec4 pos)
void main()
{
select_id_set(in_select_buf[gl_InstanceID]);
vec4 bone_color, state_color;
mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);