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:
Laurynas Duburas
2024-08-09 16:26:17 +02:00
committed by Clément Foucault
parent 4505b854f7
commit e5805ba07d
6 changed files with 326 additions and 0 deletions

View File

@@ -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

View 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

View File

@@ -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);

View File

@@ -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_};

View File

@@ -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);
}
};
/**

View File

@@ -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;