Overlay-Next: Force Field
Overlay-Next version of force field. Rel #102179 #109059 was used as a reference. Pull Request: https://projects.blender.org/blender/blender/pulls/126060
This commit is contained in:
committed by
Clément Foucault
parent
4505b854f7
commit
e5805ba07d
@@ -294,6 +294,7 @@ set(SRC
|
||||
engines/overlay/overlay_next_bounds.hh
|
||||
engines/overlay/overlay_next_empty.hh
|
||||
engines/overlay/overlay_next_camera.hh
|
||||
engines/overlay/overlay_next_force_field.hh
|
||||
engines/overlay/overlay_next_grid.hh
|
||||
engines/overlay/overlay_next_instance.hh
|
||||
engines/overlay/overlay_next_lattice.hh
|
||||
|
||||
169
source/blender/draw/engines/overlay/overlay_next_force_field.hh
Normal file
169
source/blender/draw/engines/overlay/overlay_next_force_field.hh
Normal file
@@ -0,0 +1,169 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_anim_path.h"
|
||||
|
||||
#include "BLI_math_rotation.h"
|
||||
|
||||
#include "DNA_object_force_types.h"
|
||||
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
class ForceFields {
|
||||
using ForceFieldsInstanceBuf = ShapeInstanceBuf<ExtraInstanceData>;
|
||||
|
||||
private:
|
||||
PassSimple ps_ = {"ForceFields"};
|
||||
|
||||
struct CallBuffers {
|
||||
const SelectionType selection_type_;
|
||||
|
||||
ForceFieldsInstanceBuf field_force_buf = {selection_type_, "field_force_buf"};
|
||||
ForceFieldsInstanceBuf field_wind_buf = {selection_type_, "field_wind_buf"};
|
||||
ForceFieldsInstanceBuf field_vortex_buf = {selection_type_, "field_vortex_buf"};
|
||||
ForceFieldsInstanceBuf field_curve_buf = {selection_type_, "field_curve_buf"};
|
||||
ForceFieldsInstanceBuf field_sphere_limit_buf = {selection_type_, "field_sphere_limit_buf"};
|
||||
ForceFieldsInstanceBuf field_tube_limit_buf = {selection_type_, "field_tube_limit_buf"};
|
||||
ForceFieldsInstanceBuf field_cone_limit_buf = {selection_type_, "field_cone_limit_buf"};
|
||||
} call_buffers_;
|
||||
|
||||
public:
|
||||
ForceFields(const SelectionType selection_type) : call_buffers_{selection_type} {}
|
||||
|
||||
void begin_sync()
|
||||
{
|
||||
call_buffers_.field_force_buf.clear();
|
||||
call_buffers_.field_wind_buf.clear();
|
||||
call_buffers_.field_vortex_buf.clear();
|
||||
call_buffers_.field_curve_buf.clear();
|
||||
call_buffers_.field_sphere_limit_buf.clear();
|
||||
call_buffers_.field_tube_limit_buf.clear();
|
||||
call_buffers_.field_cone_limit_buf.clear();
|
||||
}
|
||||
|
||||
void object_sync(const ObjectRef &ob_ref, Resources &res, const State &state)
|
||||
{
|
||||
const select::ID select_id = res.select_id(ob_ref);
|
||||
const Object *ob = ob_ref.object;
|
||||
PartDeflect *pd = ob->pd;
|
||||
Curve *cu = (ob->type == OB_CURVES_LEGACY) ? static_cast<Curve *>(ob->data) : nullptr;
|
||||
|
||||
ExtraInstanceData data(
|
||||
ob->object_to_world(), res.object_background_blend_color(ob_ref, state), 1.0f);
|
||||
float4x4 &matrix = data.object_to_world_;
|
||||
float &size_x = matrix[0][3];
|
||||
float &size_y = matrix[1][3];
|
||||
float &size_z = matrix[2][3];
|
||||
|
||||
size_x = size_y = size_z = ob->empty_drawsize;
|
||||
|
||||
switch (pd->forcefield) {
|
||||
case PFIELD_FORCE:
|
||||
call_buffers_.field_force_buf.append(data, select_id);
|
||||
break;
|
||||
case PFIELD_WIND:
|
||||
size_z = pd->f_strength;
|
||||
call_buffers_.field_wind_buf.append(data, select_id);
|
||||
break;
|
||||
case PFIELD_VORTEX:
|
||||
size_y = (pd->f_strength < 0.0f) ? -size_y : size_y;
|
||||
call_buffers_.field_vortex_buf.append(data, select_id);
|
||||
break;
|
||||
case PFIELD_GUIDE:
|
||||
if (cu && (cu->flag & CU_PATH) && ob->runtime->curve_cache->anim_path_accum_length) {
|
||||
size_x = size_y = size_z = pd->f_strength;
|
||||
float4 pos;
|
||||
BKE_where_on_path(ob, 0.0f, pos, nullptr, nullptr, nullptr, nullptr);
|
||||
matrix.location() = ob->object_to_world().location();
|
||||
matrix = math::translate(matrix, pos.xyz());
|
||||
call_buffers_.field_curve_buf.append(data, select_id);
|
||||
|
||||
BKE_where_on_path(ob, 1.0f, pos, nullptr, nullptr, nullptr, nullptr);
|
||||
matrix.location() = ob->object_to_world().location();
|
||||
matrix = math::translate(matrix, pos.xyz());
|
||||
call_buffers_.field_sphere_limit_buf.append(data, select_id);
|
||||
/* Restore */
|
||||
matrix.location() = ob->object_to_world().location();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (pd->falloff == PFIELD_FALL_TUBE) {
|
||||
if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
|
||||
size_z = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
|
||||
size_x = (pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f;
|
||||
size_y = size_x;
|
||||
call_buffers_.field_tube_limit_buf.append(data, select_id);
|
||||
}
|
||||
if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
|
||||
size_z = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
|
||||
size_x = (pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f;
|
||||
size_y = size_x;
|
||||
call_buffers_.field_tube_limit_buf.append(data, select_id);
|
||||
}
|
||||
}
|
||||
else if (pd->falloff == PFIELD_FALL_CONE) {
|
||||
if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
|
||||
float radius = DEG2RADF((pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f);
|
||||
float distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
|
||||
size_x = distance * sinf(radius);
|
||||
size_z = distance * cosf(radius);
|
||||
size_y = size_x;
|
||||
call_buffers_.field_cone_limit_buf.append(data, select_id);
|
||||
}
|
||||
if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
|
||||
float radius = DEG2RADF((pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f);
|
||||
float distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
|
||||
size_x = distance * sinf(radius);
|
||||
size_z = distance * cosf(radius);
|
||||
size_y = size_x;
|
||||
call_buffers_.field_cone_limit_buf.append(data, select_id);
|
||||
}
|
||||
}
|
||||
else if (pd->falloff == PFIELD_FALL_SPHERE) {
|
||||
if (pd->flag & PFIELD_USEMAX) {
|
||||
size_x = size_y = size_z = pd->maxdist;
|
||||
call_buffers_.field_sphere_limit_buf.append(data, select_id);
|
||||
}
|
||||
if (pd->flag & PFIELD_USEMIN) {
|
||||
size_x = size_y = size_z = pd->mindist;
|
||||
call_buffers_.field_sphere_limit_buf.append(data, select_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void end_sync(Resources &res, ShapeCache &shapes, const State &state)
|
||||
{
|
||||
ps_.init();
|
||||
res.select_bind(ps_);
|
||||
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);
|
||||
|
||||
call_buffers_.field_force_buf.end_sync(ps_, shapes.field_force.get());
|
||||
call_buffers_.field_wind_buf.end_sync(ps_, shapes.field_wind.get());
|
||||
call_buffers_.field_vortex_buf.end_sync(ps_, shapes.field_vortex.get());
|
||||
call_buffers_.field_curve_buf.end_sync(ps_, shapes.field_curve.get());
|
||||
call_buffers_.field_sphere_limit_buf.end_sync(ps_, shapes.field_sphere_limit.get());
|
||||
call_buffers_.field_tube_limit_buf.end_sync(ps_, shapes.field_tube_limit.get());
|
||||
call_buffers_.field_cone_limit_buf.end_sync(ps_, shapes.field_cone_limit.get());
|
||||
}
|
||||
|
||||
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
|
||||
{
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
manager.submit(ps_, view);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::draw::overlay
|
||||
@@ -82,6 +82,7 @@ void Instance::begin_sync()
|
||||
layer.bounds.begin_sync();
|
||||
layer.cameras.begin_sync();
|
||||
layer.empties.begin_sync();
|
||||
layer.force_fields.begin_sync();
|
||||
layer.lattices.begin_sync(resources, state);
|
||||
layer.lights.begin_sync();
|
||||
layer.light_probes.begin_sync(resources, state);
|
||||
@@ -172,6 +173,9 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
|
||||
layer.speakers.object_sync(ob_ref, resources, state);
|
||||
break;
|
||||
}
|
||||
if (ob_ref.object->pd && ob_ref.object->pd->forcefield) {
|
||||
layer.force_fields.object_sync(ob_ref, resources, state);
|
||||
}
|
||||
layer.bounds.object_sync(ob_ref, resources, state);
|
||||
layer.relations.object_sync(ob_ref, resources, state);
|
||||
}
|
||||
@@ -185,6 +189,7 @@ void Instance::end_sync()
|
||||
layer.bounds.end_sync(resources, shapes, state);
|
||||
layer.cameras.end_sync(resources, shapes, state);
|
||||
layer.empties.end_sync(resources, shapes, state);
|
||||
layer.force_fields.end_sync(resources, shapes, state);
|
||||
layer.lights.end_sync(resources, shapes, state);
|
||||
layer.light_probes.end_sync(resources, shapes, state);
|
||||
layer.metaballs.end_sync(resources, shapes, state);
|
||||
@@ -279,6 +284,7 @@ void Instance::draw(Manager &manager)
|
||||
layer.bounds.draw(framebuffer, manager, view);
|
||||
layer.cameras.draw(framebuffer, manager, view);
|
||||
layer.empties.draw(framebuffer, manager, view);
|
||||
layer.force_fields.draw(framebuffer, manager, view);
|
||||
layer.lights.draw(framebuffer, manager, view);
|
||||
layer.light_probes.draw(framebuffer, manager, view);
|
||||
layer.speakers.draw(framebuffer, manager, view);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "overlay_next_bounds.hh"
|
||||
#include "overlay_next_camera.hh"
|
||||
#include "overlay_next_empty.hh"
|
||||
#include "overlay_next_force_field.hh"
|
||||
#include "overlay_next_grid.hh"
|
||||
#include "overlay_next_lattice.hh"
|
||||
#include "overlay_next_light.hh"
|
||||
@@ -52,6 +53,7 @@ class Instance {
|
||||
Bounds bounds = {selection_type_};
|
||||
Cameras cameras = {selection_type_};
|
||||
Empties empties = {selection_type_};
|
||||
ForceFields force_fields = {selection_type_};
|
||||
Lattices lattices;
|
||||
Lights lights = {selection_type_};
|
||||
LightProbes light_probes = {selection_type_};
|
||||
|
||||
@@ -110,6 +110,14 @@ class ShapeCache {
|
||||
BatchPtr light_area_square_lines;
|
||||
BatchPtr light_spot_volume;
|
||||
|
||||
BatchPtr field_force;
|
||||
BatchPtr field_wind;
|
||||
BatchPtr field_vortex;
|
||||
BatchPtr field_curve;
|
||||
BatchPtr field_sphere_limit;
|
||||
BatchPtr field_tube_limit;
|
||||
BatchPtr field_cone_limit;
|
||||
|
||||
BatchPtr lightprobe_cube;
|
||||
BatchPtr lightprobe_planar;
|
||||
BatchPtr lightprobe_grid;
|
||||
@@ -281,6 +289,19 @@ struct Resources : public select::SelectMap {
|
||||
ThemeColorID theme_id = object_wire_theme_id(ob_ref, state);
|
||||
return object_wire_color(ob_ref, theme_id);
|
||||
}
|
||||
|
||||
float4 background_blend_color(ThemeColorID theme_id) const
|
||||
{
|
||||
float4 color;
|
||||
UI_GetThemeColorBlendShade4fv(theme_id, TH_BACK, 0.5, 0, color);
|
||||
return color;
|
||||
}
|
||||
|
||||
float4 object_background_blend_color(const ObjectRef &ob_ref, const State &state) const
|
||||
{
|
||||
ThemeColorID theme_id = object_wire_theme_id(ob_ref, state);
|
||||
return background_blend_color(theme_id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -778,6 +778,133 @@ ShapeCache::ShapeCache()
|
||||
light_area_square_lines = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* field_force */
|
||||
{
|
||||
constexpr int circle_resol = 32;
|
||||
constexpr int flag = VCLASS_EMPTY_SIZE | VCLASS_SCREENALIGNED;
|
||||
constexpr std::array<float, 2> scales{2.0f, 0.75};
|
||||
Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
||||
|
||||
Vector<Vertex> verts;
|
||||
|
||||
append_line_loop(verts, ring, 0.0f, flag);
|
||||
for (const float scale : scales) {
|
||||
for (float2 &point : ring) {
|
||||
point *= scale;
|
||||
}
|
||||
append_line_loop(verts, ring, 0.0f, flag);
|
||||
}
|
||||
|
||||
field_force = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* field_wind */
|
||||
{
|
||||
constexpr int circle_resol = 32;
|
||||
const Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
||||
|
||||
Vector<Vertex> verts;
|
||||
|
||||
for (const int i : IndexRange(4)) {
|
||||
const float z = 0.05f * float(i);
|
||||
append_line_loop(verts, ring, z, VCLASS_EMPTY_SIZE);
|
||||
}
|
||||
|
||||
field_wind = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* field_vortex */
|
||||
{
|
||||
constexpr int spiral_resol = 32;
|
||||
const Vector<float2> ring = ring_vertices(1.0f, spiral_resol);
|
||||
|
||||
Vector<Vertex> verts;
|
||||
|
||||
for (const int i : IndexRange(ring.size() * 2 + 1)) {
|
||||
/* r: [-1, .., 0, .., 1] */
|
||||
const float r = (i - spiral_resol) / float(spiral_resol);
|
||||
/* index: [9, spiral_resol - 1, spiral_resol - 2, .., 2, 1, 0, 1, 2, .., spiral_resol - 1, 0]
|
||||
*/
|
||||
const float2 point = ring[abs(spiral_resol - i) % spiral_resol] * r;
|
||||
verts.append({float3(point.y, point.x, 0.0f), VCLASS_EMPTY_SIZE});
|
||||
}
|
||||
field_vortex = BatchPtr(GPU_batch_create_ex(
|
||||
GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* field_curve */
|
||||
{
|
||||
constexpr int circle_resol = 32;
|
||||
const Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
||||
|
||||
Vector<Vertex> verts;
|
||||
|
||||
append_line_loop(verts, ring, 0.0f, VCLASS_EMPTY_SIZE | VCLASS_SCREENALIGNED);
|
||||
|
||||
field_curve = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* field_sphere_limit */
|
||||
{
|
||||
constexpr int circle_resol = 32 * 2;
|
||||
const Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
||||
|
||||
Vector<Vertex> verts;
|
||||
|
||||
append_line_loop(verts, ring, 0.0f, VCLASS_EMPTY_SIZE | VCLASS_SCREENALIGNED, true);
|
||||
|
||||
field_sphere_limit = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* field_tube_limit */
|
||||
{
|
||||
constexpr int circle_resol = 32;
|
||||
constexpr int side_stipple = 32;
|
||||
const Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
||||
const Vector<float2> diamond = ring_vertices(1.0f, 4);
|
||||
|
||||
Vector<Vertex> verts;
|
||||
|
||||
/* Caps */
|
||||
for (const int i : IndexRange(2)) {
|
||||
const float z = i * 2.0f - 1.0f;
|
||||
append_line_loop(verts, ring, z, VCLASS_EMPTY_SIZE, true);
|
||||
}
|
||||
/* Side Edges */
|
||||
for (const float2 &point : diamond) {
|
||||
for (const int i : IndexRange(side_stipple)) {
|
||||
const float z = (i / float(side_stipple)) * 2.0f - 1.0f;
|
||||
verts.append({float3(point.y, point.x, z), VCLASS_EMPTY_SIZE});
|
||||
}
|
||||
}
|
||||
|
||||
field_tube_limit = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* field_cone_limit */
|
||||
{
|
||||
constexpr int circle_resol = 32;
|
||||
constexpr int side_stipple = 32;
|
||||
const Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
||||
const Vector<float2> diamond = ring_vertices(1.0f, 4);
|
||||
|
||||
Vector<Vertex> verts;
|
||||
|
||||
/* Caps */
|
||||
for (const int i : IndexRange(2)) {
|
||||
const float z = i * 2.0f - 1.0f;
|
||||
append_line_loop(verts, ring, z, VCLASS_EMPTY_SIZE, true);
|
||||
}
|
||||
/* Side Edges */
|
||||
for (const float2 &point : diamond) {
|
||||
for (const int i : IndexRange(side_stipple)) {
|
||||
const float z = (i / float(side_stipple)) * 2.0f - 1.0f;
|
||||
verts.append({float3(point.y * z, point.x * z, z), VCLASS_EMPTY_SIZE});
|
||||
}
|
||||
}
|
||||
|
||||
field_cone_limit = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* lightprobe_cube */
|
||||
{
|
||||
constexpr float r = 14.0f;
|
||||
|
||||
Reference in New Issue
Block a user