Overlay-Next: Object Bounds
Overlay-Next version of bounds and collisions. Rel #102179 Pull Request: https://projects.blender.org/blender/blender/pulls/124654
This commit is contained in:
committed by
Clément Foucault
parent
1ea09e514b
commit
e356737451
@@ -290,6 +290,7 @@ set(SRC
|
||||
engines/image/image_usage.hh
|
||||
engines/overlay/overlay_engine.h
|
||||
engines/overlay/overlay_next_background.hh
|
||||
engines/overlay/overlay_next_bounds.hh
|
||||
engines/overlay/overlay_next_empty.hh
|
||||
engines/overlay/overlay_next_grid.hh
|
||||
engines/overlay/overlay_next_instance.hh
|
||||
|
||||
171
source/blender/draw/engines/overlay/overlay_next_bounds.hh
Normal file
171
source/blender/draw/engines/overlay/overlay_next_bounds.hh
Normal file
@@ -0,0 +1,171 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_mball.hh"
|
||||
|
||||
#include "BLI_bounds_types.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_rigidbody_types.h"
|
||||
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
class Bounds {
|
||||
using BoundsInstanceBuf = ShapeInstanceBuf<ExtraInstanceData>;
|
||||
|
||||
private:
|
||||
PassSimple ps_ = {"Bounds"};
|
||||
|
||||
struct CallBuffers {
|
||||
const SelectionType selection_type_;
|
||||
|
||||
BoundsInstanceBuf box = {selection_type_, "bound_box"};
|
||||
BoundsInstanceBuf sphere = {selection_type_, "bound_sphere"};
|
||||
BoundsInstanceBuf cylinder = {selection_type_, "bound_cylinder"};
|
||||
BoundsInstanceBuf cone = {selection_type_, "bound_cone"};
|
||||
BoundsInstanceBuf capsule_body = {selection_type_, "bound_capsule_body"};
|
||||
BoundsInstanceBuf capsule_cap = {selection_type_, "bound_capsule_cap"};
|
||||
} call_buffers_;
|
||||
|
||||
public:
|
||||
Bounds(const SelectionType selection_type) : call_buffers_{selection_type} {}
|
||||
|
||||
void begin_sync()
|
||||
{
|
||||
call_buffers_.box.clear();
|
||||
call_buffers_.sphere.clear();
|
||||
call_buffers_.cylinder.clear();
|
||||
call_buffers_.cone.clear();
|
||||
call_buffers_.capsule_body.clear();
|
||||
call_buffers_.capsule_cap.clear();
|
||||
}
|
||||
|
||||
void object_sync(const ObjectRef &ob_ref, Resources &res, const State &state)
|
||||
{
|
||||
const Object *ob = ob_ref.object;
|
||||
const bool from_dupli = (ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) != 0;
|
||||
const bool has_bounds = !ELEM(
|
||||
ob->type, OB_LAMP, OB_CAMERA, OB_EMPTY, OB_SPEAKER, OB_LIGHTPROBE);
|
||||
const bool draw_bounds = has_bounds && ((ob->dt == OB_BOUNDBOX) ||
|
||||
((ob->dtx & OB_DRAWBOUNDOX) && !from_dupli));
|
||||
const float4 color = res.object_wire_color(ob_ref, state);
|
||||
|
||||
auto add_bounds = [&](const bool around_origin, const char bound_type) {
|
||||
if (ob->type == OB_MBALL && !BKE_mball_is_basis(ob)) {
|
||||
return;
|
||||
}
|
||||
const float4x4 object_mat{ob->object_to_world().ptr()};
|
||||
const blender::Bounds<float3> bounds = BKE_object_boundbox_get(ob).value_or(
|
||||
blender::Bounds(float3(-1.0f), float3(1.0f)));
|
||||
const float3 size = (bounds.max - bounds.min) * 0.5f;
|
||||
const float3 center = around_origin ? float3(0) : math::midpoint(bounds.min, bounds.max);
|
||||
const select::ID select_id = res.select_id(ob_ref);
|
||||
|
||||
switch (bound_type) {
|
||||
case OB_BOUND_BOX: {
|
||||
float4x4 scale = math::from_scale<float4x4>(size);
|
||||
scale.location() = center;
|
||||
ExtraInstanceData data(object_mat * scale, color, 1.0f);
|
||||
call_buffers_.box.append(data, select_id);
|
||||
break;
|
||||
}
|
||||
case OB_BOUND_SPHERE: {
|
||||
float4x4 scale = math::from_scale<float4x4>(float3{math::reduce_max(size)});
|
||||
scale.location() = center;
|
||||
ExtraInstanceData data(object_mat * scale, color, 1.0f);
|
||||
call_buffers_.sphere.append(data, select_id);
|
||||
break;
|
||||
}
|
||||
case OB_BOUND_CYLINDER: {
|
||||
float4x4 scale = math::from_scale<float4x4>(
|
||||
float3{float2{math::max(size.x, size.y)}, size.z});
|
||||
scale.location() = center;
|
||||
ExtraInstanceData data(object_mat * scale, color, 1.0f);
|
||||
call_buffers_.cylinder.append(data, select_id);
|
||||
break;
|
||||
}
|
||||
case OB_BOUND_CONE: {
|
||||
float4x4 mat = math::from_scale<float4x4>(
|
||||
float3{float2{math::max(size.x, size.y)}, size.z});
|
||||
mat.location() = center;
|
||||
/* Cone batch has base at 0 and is pointing towards +Y. */
|
||||
std::swap(mat[1], mat[2]);
|
||||
mat.location().z -= size.z;
|
||||
ExtraInstanceData data(object_mat * mat, color, 1.0f);
|
||||
call_buffers_.cone.append(data, select_id);
|
||||
break;
|
||||
}
|
||||
case OB_BOUND_CAPSULE: {
|
||||
float4x4 mat = math::from_scale<float4x4>(float3{math::max(size.x, size.y)});
|
||||
mat.location() = center;
|
||||
mat.location().z = center.z + std::max(0.0f, size.z - size.x);
|
||||
ExtraInstanceData data(object_mat * mat, color, 1.0f);
|
||||
call_buffers_.capsule_cap.append(data, select_id);
|
||||
mat.z_axis() *= -1;
|
||||
mat.location().z = center.z - std::max(0.0f, size.z - size.x);
|
||||
data.object_to_world_ = object_mat * mat;
|
||||
call_buffers_.capsule_cap.append(data, select_id);
|
||||
mat.z_axis().z = std::max(0.0f, size.z * 2.0f - size.x * 2.0f);
|
||||
data.object_to_world_ = object_mat * mat;
|
||||
call_buffers_.capsule_body.append(data, select_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (draw_bounds) {
|
||||
add_bounds(false, ob->boundtype);
|
||||
}
|
||||
if (!from_dupli && ob->rigidbody_object != nullptr) {
|
||||
switch (ob->rigidbody_object->shape) {
|
||||
case RB_SHAPE_BOX:
|
||||
add_bounds(true, OB_BOUND_BOX);
|
||||
break;
|
||||
case RB_SHAPE_SPHERE:
|
||||
add_bounds(true, OB_BOUND_SPHERE);
|
||||
break;
|
||||
case RB_SHAPE_CONE:
|
||||
add_bounds(true, OB_BOUND_CONE);
|
||||
break;
|
||||
case RB_SHAPE_CYLINDER:
|
||||
add_bounds(true, OB_BOUND_CYLINDER);
|
||||
break;
|
||||
case RB_SHAPE_CAPSULE:
|
||||
add_bounds(true, OB_BOUND_CAPSULE);
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void end_sync(Resources &res, ShapeCache &shapes, const State &state)
|
||||
{
|
||||
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_buffers_.box.end_sync(ps_, shapes.cube.get());
|
||||
call_buffers_.sphere.end_sync(ps_, shapes.empty_sphere.get());
|
||||
call_buffers_.cylinder.end_sync(ps_, shapes.cylinder.get());
|
||||
call_buffers_.cone.end_sync(ps_, shapes.empty_cone.get());
|
||||
call_buffers_.capsule_body.end_sync(ps_, shapes.capsule_body.get());
|
||||
call_buffers_.capsule_cap.end_sync(ps_, shapes.capsule_cap.get());
|
||||
}
|
||||
|
||||
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
|
||||
{
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
manager.submit(ps_, view);
|
||||
}
|
||||
};
|
||||
} // namespace blender::draw::overlay
|
||||
@@ -81,7 +81,10 @@ void Instance::begin_sync()
|
||||
empties.begin_sync();
|
||||
lattices.begin_sync(resources, state);
|
||||
|
||||
auto begin_sync_layer = [&](OverlayLayer &layer) { layer.lights.begin_sync(); };
|
||||
auto begin_sync_layer = [&](OverlayLayer &layer) {
|
||||
layer.bounds.begin_sync();
|
||||
layer.lights.begin_sync();
|
||||
};
|
||||
begin_sync_layer(regular);
|
||||
begin_sync_layer(infront);
|
||||
|
||||
@@ -158,6 +161,7 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
|
||||
speakers.object_sync(ob_ref, resources, state);
|
||||
break;
|
||||
}
|
||||
regular.bounds.object_sync(ob_ref, resources, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +170,7 @@ void Instance::end_sync()
|
||||
resources.end_sync();
|
||||
|
||||
auto end_sync_layer = [&](OverlayLayer &layer) {
|
||||
layer.bounds.end_sync(resources, shapes, state);
|
||||
layer.lights.end_sync(resources, shapes, state);
|
||||
};
|
||||
end_sync_layer(regular);
|
||||
@@ -237,7 +242,7 @@ void Instance::draw(Manager &manager)
|
||||
prepass.draw_in_front(resources, manager, view);
|
||||
|
||||
background.draw(resources, manager);
|
||||
|
||||
regular.bounds.draw(resources.overlay_line_fb, manager, view);
|
||||
regular.lights.draw(resources.overlay_line_fb, manager, view);
|
||||
empties.draw(resources, manager, view);
|
||||
lattices.draw(resources, manager, view);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
#include "overlay_next_background.hh"
|
||||
#include "overlay_next_bounds.hh"
|
||||
#include "overlay_next_empty.hh"
|
||||
#include "overlay_next_grid.hh"
|
||||
#include "overlay_next_lattice.hh"
|
||||
@@ -45,7 +46,7 @@ class Instance {
|
||||
|
||||
struct OverlayLayer {
|
||||
const SelectionType selection_type_;
|
||||
|
||||
Bounds bounds = {selection_type_};
|
||||
Lights lights = {selection_type_};
|
||||
} regular{selection_type_}, infront{selection_type_};
|
||||
|
||||
|
||||
@@ -79,6 +79,9 @@ class ShapeCache {
|
||||
BatchPtr circle;
|
||||
BatchPtr empty_sphere;
|
||||
BatchPtr empty_cone;
|
||||
BatchPtr cylinder;
|
||||
BatchPtr capsule_body;
|
||||
BatchPtr capsule_cap;
|
||||
BatchPtr arrows;
|
||||
BatchPtr metaball_wire_circle;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ struct Vertex {
|
||||
};
|
||||
|
||||
/* Caller gets ownership of the #gpu::VertBuf. */
|
||||
static gpu::VertBuf *vbo_from_vector(Vector<Vertex> &vector)
|
||||
static gpu::VertBuf *vbo_from_vector(const Vector<Vertex> &vector)
|
||||
{
|
||||
static GPUVertFormat format = {0};
|
||||
if (format.attr_len == 0) {
|
||||
@@ -32,6 +32,8 @@ static gpu::VertBuf *vbo_from_vector(Vector<Vertex> &vector)
|
||||
}
|
||||
|
||||
enum VertexClass {
|
||||
VCLASS_NONE = 0,
|
||||
|
||||
VCLASS_LIGHT_AREA_SHAPE = 1 << 0,
|
||||
VCLASS_LIGHT_SPOT_SHAPE = 1 << 1,
|
||||
VCLASS_LIGHT_SPOT_BLEND = 1 << 2,
|
||||
@@ -76,9 +78,9 @@ static void append_line_loop(
|
||||
Vector<Vertex> &dest, Span<float2> verts, float z, int flag, bool dashed = false)
|
||||
{
|
||||
const int step = dashed ? 2 : 1;
|
||||
for (int i : IndexRange(verts.size() / step)) {
|
||||
for (int j : IndexRange(2)) {
|
||||
float2 cv = verts[(i * step + j) % (verts.size())];
|
||||
for (const int i : IndexRange(verts.size() / step)) {
|
||||
for (const int j : IndexRange(2)) {
|
||||
const float2 &cv = verts[(i * step + j) % (verts.size())];
|
||||
dest.append({{cv[0], cv[1], z}, flag});
|
||||
}
|
||||
}
|
||||
@@ -267,6 +269,54 @@ ShapeCache::ShapeCache()
|
||||
empty_cone = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* cylinder */
|
||||
{
|
||||
constexpr int n_segments = 12;
|
||||
const Vector<float2> ring = ring_vertices(1.0f, n_segments);
|
||||
Vector<Vertex> verts;
|
||||
/* top ring */
|
||||
append_line_loop(verts, ring, 1.0f, VCLASS_EMPTY_SCALED);
|
||||
/* bottom ring */
|
||||
append_line_loop(verts, ring, -1.0f, VCLASS_EMPTY_SCALED);
|
||||
/* cylinder sides */
|
||||
for (const float2 &point : ring) {
|
||||
verts.append({{point.x, point.y, 1.0f}, VCLASS_EMPTY_SCALED});
|
||||
verts.append({{point.x, point.y, -1.0f}, VCLASS_EMPTY_SCALED});
|
||||
}
|
||||
cylinder = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* capsule body */
|
||||
{
|
||||
const Vector<float2> diamond = ring_vertices(1.0f, 4);
|
||||
Vector<Vertex> verts;
|
||||
for (const float2 &point : diamond) {
|
||||
verts.append({{point.x, point.y, 1.0f}, VCLASS_NONE});
|
||||
verts.append({{point.x, point.y, 0.0f}, VCLASS_NONE});
|
||||
}
|
||||
capsule_body = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* capsule cap */
|
||||
{
|
||||
constexpr int n_segments = 24;
|
||||
const Vector<float2> ring = ring_vertices(1.0f, n_segments);
|
||||
Vector<Vertex> verts;
|
||||
/* Base circle */
|
||||
append_line_loop(verts, ring, 0.0f, VCLASS_NONE);
|
||||
for (const int i : IndexRange(n_segments / 2)) {
|
||||
const float2 &point = ring[i];
|
||||
const float2 &next_point = ring[i + 1];
|
||||
/* Y half circle */
|
||||
verts.append({{point.x, 0.0f, point.y}, VCLASS_NONE});
|
||||
verts.append({{next_point.x, 0.0f, next_point.y}, VCLASS_NONE});
|
||||
/* X half circle */
|
||||
verts.append({{0.0f, point.x, point.y}, VCLASS_NONE});
|
||||
verts.append({{0.0f, next_point.x, next_point.y}, VCLASS_NONE});
|
||||
}
|
||||
capsule_cap = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* arrows */
|
||||
{
|
||||
float2 x_axis_name_scale = {0.0215f, 0.025f};
|
||||
|
||||
Reference in New Issue
Block a user