Overlay-Next: Initial implementation #107045

Closed
Clément Foucault wants to merge 28 commits from fclem/blender:overlay-next into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
12 changed files with 619 additions and 17 deletions
Showing only changes of commit cdb9b6a041 - Show all commits

View File

@ -0,0 +1,147 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup overlay
*/
#pragma once
#include "DNA_object_types.h"
#include "draw_pass.hh"
#include "draw_shader_shared.h"
#include "overlay_private.hh"
#include "overlay_shape.hh"
namespace blender::draw::overlay {
class Empties {
private:
PassSimple empty_ps_ = {"Empties"};
PassSimple empty_in_front_ps_ = {"Empties_In_front"};
using EmptyInstanceBuf = StorageVectorBuffer<ExtraInstanceData>;
struct CallBuffers {
EmptyInstanceBuf plain_axes_buf = {"plain_axes_buf"};
EmptyInstanceBuf single_arrow_buf = {"single_arrow_buf"};
EmptyInstanceBuf cube_buf = {"cube_buf"};
EmptyInstanceBuf circle_buf = {"circle_buf"};
EmptyInstanceBuf sphere_buf = {"sphere_buf"};
EmptyInstanceBuf cone_buf = {"cone_buf"};
EmptyInstanceBuf arrows_buf = {"arrows_buf"};
EmptyInstanceBuf image_buf = {"image_buf"};
} call_buffers_[2];
public:
void begin_sync()
{
for (int i = 0; i < 2; i++) {
call_buffers_[i].plain_axes_buf.clear();
call_buffers_[i].single_arrow_buf.clear();
call_buffers_[i].cube_buf.clear();
call_buffers_[i].circle_buf.clear();
call_buffers_[i].sphere_buf.clear();
call_buffers_[i].cone_buf.clear();
call_buffers_[i].arrows_buf.clear();
call_buffers_[i].image_buf.clear();
}
}
void object_sync(const ObjectRef &ob_ref, const Resources &res, const State &state)
{
CallBuffers &call_bufs = call_buffers_[int((ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0)];
float4 color = res.object_wire_color(ob_ref, state);
ExtraInstanceData data(
float4x4(ob_ref.object->object_to_world), color, ob_ref.object->empty_drawsize);
switch (ob_ref.object->empty_drawtype) {
case OB_PLAINAXES:
call_bufs.plain_axes_buf.append(data);
break;
case OB_SINGLE_ARROW:
call_bufs.single_arrow_buf.append(data);
break;
case OB_CUBE:
call_bufs.cube_buf.append(data);
break;
case OB_CIRCLE:
call_bufs.circle_buf.append(data);
break;
case OB_EMPTY_SPHERE:
call_bufs.sphere_buf.append(data);
break;
case OB_EMPTY_CONE:
call_bufs.cone_buf.append(data);
break;
case OB_ARROWS:
call_bufs.arrows_buf.append(data);
break;
case OB_EMPTY_IMAGE:
/* This only show the frame. See OVERLAY_image_empty_cache_populate() for the image. */
call_bufs.image_buf.append(data);
break;
}
}
void end_sync(Resources &res, ShapeCache &shapes, const State &state)
{
auto init_pass = [&](PassSimple &pass, CallBuffers &call_bufs) {
pass.init();
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
state.clipping_state);
pass.shader_set(OVERLAY_shader_extra(false));
pass.bind_ubo("globalsBlock", &res.globals_buf);
call_bufs.plain_axes_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.plain_axes_buf);
pass.draw(shapes.plain_axes, call_bufs.plain_axes_buf.size());
call_bufs.single_arrow_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.single_arrow_buf);
pass.draw(shapes.single_arrow, call_bufs.single_arrow_buf.size());
call_bufs.cube_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.cube_buf);
pass.draw(shapes.cube, call_bufs.cube_buf.size());
call_bufs.circle_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.circle_buf);
pass.draw(shapes.circle, call_bufs.circle_buf.size());
call_bufs.sphere_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.sphere_buf);
pass.draw(shapes.empty_sphere, call_bufs.sphere_buf.size());
call_bufs.cone_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.cone_buf);
pass.draw(shapes.empty_cone, call_bufs.cone_buf.size());
call_bufs.arrows_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.arrows_buf);
pass.draw(shapes.arrows, call_bufs.arrows_buf.size());
call_bufs.image_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.image_buf);
pass.draw(shapes.quad_wire, call_bufs.image_buf.size());
};
init_pass(empty_ps_, call_buffers_[0]);
init_pass(empty_in_front_ps_, call_buffers_[1]);
}
void draw(Resources &res, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_fb);
manager.submit(empty_ps_, view);
}
void draw_in_front(Resources &res, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_in_front_fb);
manager.submit(empty_in_front_ps_, view);
}
};
} // namespace blender::draw::overlay

View File

@ -42,8 +42,8 @@ class Grid {
/* Default, nothing is drawn. */
grid_flag_ = zneg_flag_ = zpos_flag_ = OVERLAY_GridBits(0);
View3D *v3d = state.v3d;
RegionView3D *rv3d = state.rv3d;
const View3D *v3d = state.v3d;
const RegionView3D *rv3d = state.rv3d;
const bool show_axis_x = (state.v3d_gridflag & V3D_SHOW_X) != 0;
const bool show_axis_y = (state.v3d_gridflag & V3D_SHOW_Y) != 0;

View File

@ -4,9 +4,10 @@
* \ingroup overlay
*/
#include "overlay_instance.hh"
#include "draw_debug.hh"
#include "overlay_instance.hh"
namespace blender::draw::overlay {
void Instance::init()
@ -18,12 +19,16 @@ void Instance::init()
/* TODO(fclem): Remove DRW global usage. */
const DRWContextState *ctx = DRW_context_state_get();
/* Was needed by `object_wire_theme_id()` when doing the port. Not sure if needed nowadays. */
BKE_view_layer_synced_ensure(ctx->scene, ctx->view_layer);
state.depsgraph = ctx->depsgraph;
state.view_layer = ctx->view_layer;
state.scene = ctx->scene;
state.v3d = ctx->v3d;
state.rv3d = ctx->rv3d;
state.active_base = BKE_view_layer_active_base_get(ctx->view_layer);
state.object_mode = ctx->object_mode;
state.pixelsize = U.pixelsize;
state.ctx_mode = CTX_data_mode_enum_ex(ctx->object_edit, ctx->obact, ctx->object_mode);
@ -66,6 +71,7 @@ void Instance::begin_sync()
View view("OverlayView", view_legacy);
background.begin_sync(resources, state);
empties.begin_sync();
metaballs.begin_sync();
grid.begin_sync(resources, state, view);
}
@ -98,6 +104,9 @@ void Instance::object_sync(ObjectRef &ob_ref)
if (!state.hide_overlays) {
switch (ob_ref.object->type) {
case OB_EMPTY:
empties.object_sync(ob_ref, resources, state);
break;
case OB_ARMATURE:
break;
case OB_MBALL:
@ -114,6 +123,7 @@ void Instance::object_sync(ObjectRef &ob_ref)
void Instance::end_sync()
{
metaballs.end_sync(resources, state);
empties.end_sync(resources, shapes, state);
}
void Instance::draw(Manager &manager)
@ -158,10 +168,12 @@ void Instance::draw(Manager &manager)
background.draw(resources, manager);
empties.draw(resources, manager, view);
metaballs.draw(resources, manager, view);
grid.draw(resources, manager, view);
empties.draw_in_front(resources, manager, view);
metaballs.draw_in_front(resources, manager, view);
// anti_aliasing.draw(resources, manager, view);

View File

@ -9,8 +9,10 @@
#include "draw_manager.hh"
#include "overlay_background.hh"
#include "overlay_empty.hh"
#include "overlay_grid.hh"
#include "overlay_metaball.hh"
#include "overlay_shape.hh"
namespace blender::draw::overlay {
@ -49,6 +51,7 @@ class SceneResources {
class Instance {
public:
ShaderCache shaders;
ShapeCache shapes;
/* WORKAROUND: Legacy. Move to grid pass. */
GPUUniformBuf *grid_ubo = nullptr;
@ -60,6 +63,7 @@ class Instance {
/** Overlay types. */
Background background;
Metaballs metaballs;
Empties empties;
Grid grid;
~Instance()

View File

@ -86,10 +86,7 @@ class Metaballs {
data_buf_;
MetaBall *mb = static_cast<MetaBall *>(ob_ref.object->data);
float *color;
/* TODO(fclem): Remove DRW global usage. */
UNUSED_VARS(res);
DRW_object_wire_theme_get(ob_ref.object, state.view_layer, &color);
const float4 &color = res.object_wire_color(ob_ref, state);
LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
/* Draw radius only. */

View File

@ -7,9 +7,15 @@
#pragma once
#include "BKE_global.h"
#include "DRW_gpu_wrapper.hh"
#include "DRW_render.h"
#include "UI_resources.h"
#include "draw_handle.hh"
#include "overlay_shader_shared.h"
#ifdef __cplusplus
@ -33,13 +39,15 @@ class Instance;
struct State {
Depsgraph *depsgraph;
ViewLayer *view_layer;
Scene *scene;
View3D *v3d;
RegionView3D *rv3d;
const ViewLayer *view_layer;
const Scene *scene;
const View3D *v3d;
const RegionView3D *rv3d;
const Base *active_base;
View3DOverlay overlay;
float pixelsize;
enum eContextObjectMode ctx_mode;
enum eObjectMode object_mode;
bool clear_in_front;
bool use_in_front;
bool is_wireframe_mode;
@ -79,6 +87,80 @@ struct Resources {
TextureRef depth_in_front_tx;
TextureRef color_overlay_tx;
TextureRef color_render_tx;
[[nodiscard]] ThemeColorID object_wire_theme_id(const ObjectRef &ob_ref,
const State &state) const
{
const bool is_edit = (state.object_mode & OB_MODE_EDIT) &&
(ob_ref.object->mode & OB_MODE_EDIT);
const bool active = (state.active_base != nullptr) &&
((ob_ref.dupli_parent != nullptr) ?
(state.active_base->object == ob_ref.dupli_parent) :
(state.active_base->object == ob_ref.object));
const bool is_selected = ((ob_ref.object->base_flag & BASE_SELECTED) != 0);
/* Object in edit mode. */
if (is_edit) {
return TH_WIRE_EDIT;
}
/* Transformed object during operators. */
if (((G.moving & G_TRANSFORM_OBJ) != 0) && is_selected) {
return TH_TRANSFORM;
}
/* Sets the 'theme_id' or fallback to wire */
if ((ob_ref.object->base_flag & BASE_SELECTED) != 0) {
return (active) ? TH_ACTIVE : TH_SELECT;
}
switch (ob_ref.object->type) {
case OB_LAMP:
return TH_LIGHT;
case OB_SPEAKER:
return TH_SPEAKER;
case OB_CAMERA:
return TH_CAMERA;
case OB_LIGHTPROBE:
/* TODO: add light-probe color. Use empty color for now. */
case OB_EMPTY:
return TH_EMPTY;
default:
return (is_edit) ? TH_WIRE_EDIT : TH_WIRE;
}
}
[[nodiscard]] const float4 &object_wire_color(const ObjectRef &ob_ref,
ThemeColorID theme_id) const
{
if (UNLIKELY(ob_ref.object->base_flag & BASE_FROM_SET)) {
return theme_settings.color_wire;
}
switch (theme_id) {
case TH_WIRE_EDIT:
return theme_settings.color_wire_edit;
case TH_ACTIVE:
return theme_settings.color_active;
case TH_SELECT:
return theme_settings.color_select;
case TH_TRANSFORM:
return theme_settings.color_transform;
case TH_SPEAKER:
return theme_settings.color_speaker;
case TH_CAMERA:
return theme_settings.color_camera;
case TH_EMPTY:
return theme_settings.color_empty;
case TH_LIGHT:
return theme_settings.color_light;
default:
return theme_settings.color_wire;
}
}
[[nodiscard]] const float4 &object_wire_color(const ObjectRef &ob_ref, const State &state) const
{
ThemeColorID theme_id = object_wire_theme_id(ob_ref, state);
return object_wire_color(ob_ref, theme_id);
}
};
} // namespace blender::draw::overlay

View File

@ -490,6 +490,18 @@ GPUShader *OVERLAY_shader_extra(bool is_select)
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
GPUShader **sh = (is_select) ? &sh_data->extra_select : &sh_data->extra;
if (!*sh) {
using namespace blender::gpu::shader;
ShaderCreateInfo &info = const_cast<ShaderCreateInfo &>(
*reinterpret_cast<const ShaderCreateInfo *>(GPU_shader_create_info_get("overlay_extra")));
if (U.experimental.enable_overlay_next) {
info.storage_buf(0, Qualifier::READ, "ExtraInstanceData", "data_buf[]");
info.define("color", "data_buf[gl_InstanceID].color_");
info.define("inst_obmat", "data_buf[gl_InstanceID].object_to_world_");
info.vertex_inputs_.pop_last();
info.vertex_inputs_.pop_last();
}
*sh = GPU_shader_create_from_info_name(
(draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ?
(is_select ? "overlay_extra_select_clipped" : "overlay_extra_clipped") :

View File

@ -15,6 +15,7 @@ typedef enum OVERLAY_GridBits OVERLAY_GridBits;
# endif
typedef struct OVERLAY_GridData OVERLAY_GridData;
typedef struct ThemeColorData ThemeColorData;
typedef struct ExtraInstanceData ExtraInstanceData;
#endif
/* TODO(fclem): Should eventually become OVERLAY_BackgroundType.
@ -191,6 +192,22 @@ struct ThemeColorData {
};
BLI_STATIC_ASSERT_ALIGN(ThemeColorData, 16)
/* TODO Move to overlay engine. */
struct ExtraInstanceData {
float4 color_;
float4x4 object_to_world_;
#if !defined(GPU_SHADER) && defined(__cplusplus)
ExtraInstanceData(const float4x4 &object_to_world, float4 &color, float draw_size)
{
this->color_ = color;
this->object_to_world_ = object_to_world;
this->object_to_world_[3][3] = draw_size;
};
#endif
};
BLI_STATIC_ASSERT_ALIGN(ExtraInstanceData, 16)
#ifndef GPU_SHADER
# ifdef __cplusplus
}

View File

@ -0,0 +1,330 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup overlay
*/
#pragma once
#include "BLI_vector.hh"
#include "GPU_batch.h"
namespace blender::draw::overlay {
/**
* Contains all overlay generic geometry batches.
*/
class ShapeCache {
private:
/* Needs to be first for other lambdas to access. */
GPUVertFormat format = []() {
GPUVertFormat format = {0};
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, "vclass", GPU_COMP_I32, 1, GPU_FETCH_INT);
return format;
}();
/* Matches Vertex Format. */
struct Vertex {
float3 pos;
int vclass;
};
struct AutoFreeGPUBatch {
GPUBatch *batch;
AutoFreeGPUBatch(GPUBatch *_batch) : batch(_batch){};
~AutoFreeGPUBatch()
{
GPU_BATCH_DISCARD_SAFE(batch);
}
operator GPUBatch *()
{
return batch;
}
};
/* Caller gets ownership of the #GPUVertBuf. */
GPUVertBuf *vbo_from_vector(Vector<Vertex> &vector)
{
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, vector.size());
Vertex *vbo_data = (Vertex *)GPU_vertbuf_get_data(vbo);
/* Copy data to VBO using a wrapper span. Could use memcpy if that's too slow. */
MutableSpan<Vertex> span(vbo_data, vector.size());
span.copy_from(vector);
return vbo;
}
enum VertexClass {
VCLASS_LIGHT_AREA_SHAPE = 1 << 0,
VCLASS_LIGHT_SPOT_SHAPE = 1 << 1,
VCLASS_LIGHT_SPOT_BLEND = 1 << 2,
VCLASS_LIGHT_SPOT_CONE = 1 << 3,
VCLASS_LIGHT_DIST = 1 << 4,
VCLASS_CAMERA_FRAME = 1 << 5,
VCLASS_CAMERA_DIST = 1 << 6,
VCLASS_CAMERA_VOLUME = 1 << 7,
VCLASS_SCREENSPACE = 1 << 8,
VCLASS_SCREENALIGNED = 1 << 9,
VCLASS_EMPTY_SCALED = 1 << 10,
VCLASS_EMPTY_AXES = 1 << 11,
VCLASS_EMPTY_AXES_NAME = 1 << 12,
VCLASS_EMPTY_AXES_SHADOW = 1 << 13,
VCLASS_EMPTY_SIZE = 1 << 14,
};
static constexpr float bone_box_verts[8][3] = {
{1.0f, 0.0f, 1.0f},
{1.0f, 0.0f, -1.0f},
{-1.0f, 0.0f, -1.0f},
{-1.0f, 0.0f, 1.0f},
{1.0f, 1.0f, 1.0f},
{1.0f, 1.0f, -1.0f},
{-1.0f, 1.0f, -1.0f},
{-1.0f, 1.0f, 1.0f},
};
static constexpr std::array<uint, 24> bone_box_wire = {
0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7,
};
/* A single ring of vertices. */
static Vector<float2> ring_vertices(const float radius, const int segments)
{
Vector<float2> verts;
for (int i : IndexRange(segments)) {
float angle = (2 * M_PI * i) / segments;
verts.append(radius * float2(math::cos(angle), math::sin(angle)));
}
return verts;
}
/* Returns lines segment geometry forming 3 circles, one on each axis. */
static Vector<Vertex> sphere_axes_circles(const float radius,
const VertexClass vclass,
const int segments)
{
Vector<float2> ring = ring_vertices(radius, segments);
Vector<Vertex> verts;
for (int axis : IndexRange(3)) {
for (int i : IndexRange(segments)) {
for (int j : IndexRange(2)) {
float2 cv = ring[(i + j) % segments];
if (axis == 0) {
verts.append({{cv[0], cv[1], 0.0f}, vclass});
}
else if (axis == 1) {
verts.append({{cv[0], 0.0f, cv[1]}, vclass});
}
else {
verts.append({{0.0f, cv[0], cv[1]}, vclass});
}
}
}
}
return verts;
}
public:
AutoFreeGPUBatch quad_wire = [this]() {
Vector<Vertex> verts;
verts.append({{-1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
verts.append({{-1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
verts.append({{-1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
verts.append({{+1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
verts.append({{+1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
verts.append({{+1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
verts.append({{+1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
verts.append({{-1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
return GPU_batch_create_ex(
GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO);
}();
AutoFreeGPUBatch plain_axes = [this]() {
Vector<Vertex> verts;
verts.append({{0.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
verts.append({{0.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
verts.append({{-1.0f, 0.0f, 0.0f}, VCLASS_EMPTY_SCALED});
verts.append({{+1.0f, 0.0f, 0.0f}, VCLASS_EMPTY_SCALED});
verts.append({{0.0f, 0.0f, -1.0f}, VCLASS_EMPTY_SCALED});
verts.append({{0.0f, 0.0f, +1.0f}, VCLASS_EMPTY_SCALED});
return GPU_batch_create_ex(
GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO);
}();
AutoFreeGPUBatch single_arrow = [this]() {
Vector<Vertex> verts;
float p[3][3] = {{0}};
p[0][2] = 1.0f;
p[1][0] = 0.035f;
p[1][1] = 0.035f;
p[2][0] = -0.035f;
p[2][1] = 0.035f;
p[1][2] = p[2][2] = 0.75f;
for (int sides : IndexRange(4)) {
if (sides % 2 == 1) {
p[1][0] = -p[1][0];
p[2][1] = -p[2][1];
}
else {
p[1][1] = -p[1][1];
p[2][0] = -p[2][0];
}
for (int i = 0, a = 1; i < 2; i++, a++) {
verts.append({{p[i][0], p[i][1], p[i][2]}, VCLASS_EMPTY_SCALED});
verts.append({{p[a][0], p[a][1], p[a][2]}, VCLASS_EMPTY_SCALED});
}
}
verts.append({{0.0f, 0.0f, 0.0}, VCLASS_EMPTY_SCALED});
verts.append({{0.0f, 0.0f, 0.75f}, VCLASS_EMPTY_SCALED});
return GPU_batch_create_ex(
GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO);
}();
AutoFreeGPUBatch cube = [this]() {
Vector<Vertex> verts;
for (auto index : bone_box_wire) {
float x = bone_box_verts[index][0];
float y = bone_box_verts[index][1] * 2.0 - 1.0f;
float z = bone_box_verts[index][2];
verts.append({{x, y, z}, VCLASS_EMPTY_SCALED});
}
return GPU_batch_create_ex(
GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO);
}();
AutoFreeGPUBatch circle = [this]() {
constexpr int resolution = 64;
Vector<float2> ring = ring_vertices(1.0f, resolution);
Vector<Vertex> verts;
for (int a : IndexRange(resolution + 1)) {
float2 cv = ring[a % resolution];
verts.append({{cv.x, 0.0f, cv.y}, VCLASS_EMPTY_SCALED});
}
return GPU_batch_create_ex(
GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO);
}();
AutoFreeGPUBatch empty_sphere = [this]() {
Vector<Vertex> verts = sphere_axes_circles(1.0f, VCLASS_EMPTY_SCALED, 32);
return GPU_batch_create_ex(
GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO);
}();
AutoFreeGPUBatch empty_cone = [this]() {
/* A single ring of vertices. */
constexpr int resolution = 8;
Vector<float2> ring = ring_vertices(1.0f, resolution);
Vector<Vertex> verts;
for (int i : IndexRange(resolution)) {
float2 cv = ring[i % resolution];
/* Cone sides. */
verts.append({{cv[0], 0.0f, cv[1]}, VCLASS_EMPTY_SCALED});
verts.append({{0.0f, 2.0f, 0.0f}, VCLASS_EMPTY_SCALED});
/* Base ring. */
for (int j : IndexRange(2)) {
float2 cv = ring[(i + j) % resolution];
verts.append({{cv[0], 0.0f, cv[1]}, VCLASS_EMPTY_SCALED});
}
}
return GPU_batch_create_ex(
GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO);
}();
AutoFreeGPUBatch arrows = [this]() {
float2 x_axis_name_scale = {0.0215f, 0.025f};
Vector<float2> x_axis_name = {
float2(0.9f, 1.0f) * x_axis_name_scale,
float2(-1.0f, -1.0f) * x_axis_name_scale,
float2(-0.9f, 1.0f) * x_axis_name_scale,
float2(1.0f, -1.0f) * x_axis_name_scale,
};
float2 y_axis_name_scale = {0.0175f, 0.025f};
Vector<float2> y_axis_name = {
float2(-1.0f, 1.0f) * y_axis_name_scale,
float2(0.0f, -0.1f) * y_axis_name_scale,
float2(1.0f, 1.0f) * y_axis_name_scale,
float2(0.0f, -0.1f) * y_axis_name_scale,
float2(0.0f, -0.1f) * y_axis_name_scale,
float2(0.0f, -1.0f) * y_axis_name_scale,
};
float2 z_axis_name_scale = {0.02f, 0.025f};
Vector<float2> z_axis_name = {
float2(-0.95f, 1.00f) * z_axis_name_scale,
float2(0.95f, 1.00f) * z_axis_name_scale,
float2(0.95f, 1.00f) * z_axis_name_scale,
float2(0.95f, 0.90f) * z_axis_name_scale,
float2(0.95f, 0.90f) * z_axis_name_scale,
float2(-1.00f, -0.90f) * z_axis_name_scale,
float2(-1.00f, -0.90f) * z_axis_name_scale,
float2(-1.00f, -1.00f) * z_axis_name_scale,
float2(-1.00f, -1.00f) * z_axis_name_scale,
float2(1.00f, -1.00f) * z_axis_name_scale,
};
float2 axis_marker_scale = {0.007f, 0.007f};
Vector<float2> axis_marker = {
#if 0 /* square */
float2(-1.0f, 1.0f) * axis_marker_scale,
float2(1.0f, 1.0f) * axis_marker_scale,
float2(1.0f, 1.0f) * axis_marker_scale,
float2(1.0f, -1.0f) * axis_marker_scale,
float2(1.0f, -1.0f) * axis_marker_scale,
float2(-1.0f, -1.0f) * axis_marker_scale,
float2(-1.0f, -1.0f) * axis_marker_scale,
float2(-1.0f, 1.0f) * axis_marker_scale,
#else /* diamond */
float2(-1.0f, 0.0f) * axis_marker_scale,
float2(0.0f, 1.0f) * axis_marker_scale,
float2(0.0f, 1.0f) * axis_marker_scale,
float2(1.0f, 0.0f) * axis_marker_scale,
float2(1.0f, 0.0f) * axis_marker_scale,
float2(0.0f, -1.0f) * axis_marker_scale,
float2(0.0f, -1.0f) * axis_marker_scale,
float2(-1.0f, 0.0f) * axis_marker_scale,
#endif
};
Vector<Vertex> verts;
for (int axis : IndexRange(3)) {
/* Vertex layout is XY screen position and axis in Z.
* Fractional part of Z is a positive offset at axis unit position. */
int flag = VCLASS_EMPTY_AXES | VCLASS_SCREENALIGNED;
/* Center to axis line. */
verts.append({{0.0f, 0.0f, 0.0f}, 0});
verts.append({{0.0f, 0.0f, float(axis)}, flag});
/* Axis end marker. */
constexpr int marker_fill_layer = 6;
for (int j = 1; j < marker_fill_layer + 1; j++) {
for (float2 axis_marker_vert : axis_marker) {
verts.append({{axis_marker_vert * ((4.0f * j) / marker_fill_layer), float(axis)}, flag});
}
}
/* Axis name. */
Vector<float2> *axis_names[3] = {&x_axis_name, &y_axis_name, &z_axis_name};
for (float2 axis_name_vert : *(axis_names[axis])) {
int flag = VCLASS_EMPTY_AXES | VCLASS_EMPTY_AXES_NAME | VCLASS_SCREENALIGNED;
verts.append({{axis_name_vert * 4.0f, axis + 0.25f}, flag});
}
}
return GPU_batch_create_ex(
GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO);
}();
};
} // namespace blender::draw::overlay

View File

@ -13,6 +13,7 @@ GPU_SHADER_INTERFACE_INFO(overlay_extra_iface, "")
GPU_SHADER_CREATE_INFO(overlay_extra)
.do_static_compilation(true)
.typedef_source("overlay_shader_shared.h")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "vclass")
/* Instance attributes. */

View File

@ -1270,11 +1270,11 @@ bool ED_view3d_distance_set_from_location(struct RegionView3D *rv3d,
*/
float ED_scene_grid_scale(const struct Scene *scene, const char **r_grid_unit);
float ED_view3d_grid_scale(const struct Scene *scene,
struct View3D *v3d,
const struct View3D *v3d,
const char **r_grid_unit);
void ED_view3d_grid_steps(const struct Scene *scene,
struct View3D *v3d,
struct RegionView3D *rv3d,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
float r_grid_steps[8]);
/**
* Simulates the grid scale that is actually viewed.

View File

@ -850,15 +850,15 @@ float ED_scene_grid_scale(const Scene *scene, const char **r_grid_unit)
return 1.0f;
}
float ED_view3d_grid_scale(const Scene *scene, View3D *v3d, const char **r_grid_unit)
float ED_view3d_grid_scale(const Scene *scene, const View3D *v3d, const char **r_grid_unit)
{
return v3d->grid * ED_scene_grid_scale(scene, r_grid_unit);
}
#define STEPS_LEN 8
void ED_view3d_grid_steps(const Scene *scene,
View3D *v3d,
RegionView3D *rv3d,
const View3D *v3d,
const RegionView3D *rv3d,
float r_grid_steps[STEPS_LEN])
{
const void *usys;