WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 354 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
26 changed files with 800 additions and 96 deletions
Showing only changes of commit 22a1c00eb3 - Show all commits

View File

@ -196,6 +196,7 @@ class OBJECT_MT_modifier_add_deform(ModifierAddMenu, Menu):
if ob_type == 'VOLUME':
self.operator_modifier_add(layout, 'VOLUME_DISPLACE')
if ob_type == 'GREASEPENCIL':
self.operator_modifier_add(layout, 'GREASE_PENCIL_HOOK')
self.operator_modifier_add(layout, 'GREASE_PENCIL_LATTICE')
self.operator_modifier_add(layout, 'GREASE_PENCIL_NOISE')
self.operator_modifier_add(layout, 'GREASE_PENCIL_OFFSET')

View File

@ -114,6 +114,7 @@ class DenoiseFilter {
DenoiseBaseOperation::DenoiseBaseOperation()
{
flags_.is_fullframe_operation = true;
flags_.can_be_constant = true;
output_rendered_ = false;
}
@ -203,27 +204,23 @@ void DenoiseOperation::generate_denoise(MemoryBuffer *output,
MemoryBuffer *input_albedo,
const NodeDenoise *settings)
{
BLI_assert(input_color->get_buffer());
if (!input_color->get_buffer()) {
if (input_color->is_a_single_elem()) {
output->fill(output->get_rect(), input_color->get_elem(0, 0));
return;
}
BLI_assert(COM_is_denoise_supported());
/* OpenImageDenoise needs full buffers. */
MemoryBuffer *buf_color = input_color->is_a_single_elem() ? input_color->inflate() : input_color;
MemoryBuffer *buf_normal = input_normal && input_normal->is_a_single_elem() ?
input_normal->inflate() :
input_normal;
MemoryBuffer *buf_albedo = input_albedo && input_albedo->is_a_single_elem() ?
input_albedo->inflate() :
input_albedo;
DenoiseFilter filter;
filter.init_and_lock_denoiser(this, output);
filter.set_image("color", buf_color);
filter.set_image("normal", buf_normal);
filter.set_image("albedo", buf_albedo);
filter.set_image("color", input_color);
if (!input_albedo->is_a_single_elem()) {
filter.set_image("albedo", input_albedo);
if (!input_normal->is_a_single_elem()) {
filter.set_image("normal", input_normal);
}
}
BLI_assert(settings);
if (settings) {
@ -237,17 +234,6 @@ void DenoiseOperation::generate_denoise(MemoryBuffer *output,
/* Copy the alpha channel, OpenImageDenoise currently only supports RGB. */
output->copy_from(input_color, input_color->get_rect(), 3, COM_DATA_TYPE_VALUE_CHANNELS, 3);
/* Delete inflated buffers. */
if (input_color->is_a_single_elem()) {
delete buf_color;
}
if (input_normal && input_normal->is_a_single_elem()) {
delete buf_normal;
}
if (input_albedo && input_albedo->is_a_single_elem()) {
delete buf_albedo;
}
}
void DenoiseOperation::update_memory_buffer(MemoryBuffer *output,
@ -286,21 +272,18 @@ MemoryBuffer *DenoisePrefilterOperation::create_memory_buffer(rcti *rect2)
void DenoisePrefilterOperation::generate_denoise(MemoryBuffer *output, MemoryBuffer *input)
{
BLI_assert(COM_is_denoise_supported());
if (input->is_a_single_elem()) {
copy_v4_v4(output->get_elem(0, 0), input->get_elem(0, 0));
return;
}
/* Denoising needs full buffers. */
MemoryBuffer *input_buf = input->is_a_single_elem() ? input->inflate() : input;
BLI_assert(COM_is_denoise_supported());
DenoiseFilter filter;
filter.init_and_lock_denoiser(this, output);
filter.set_image(image_name_, input_buf);
filter.set_image(image_name_, input);
filter.execute();
filter.deinit_and_unlock_denoiser();
/* Delete inflated buffers. */
if (input->is_a_single_elem()) {
delete input_buf;
}
}
void DenoisePrefilterOperation::update_memory_buffer(MemoryBuffer *output,

View File

@ -17,7 +17,6 @@
#include "AS_asset_catalog_path.hh"
#include "AS_asset_catalog_tree.hh"
struct AssetFilterSettings;
struct AssetLibraryReference;
struct bContext;
@ -28,6 +27,13 @@ class AssetRepresentation;
namespace blender::ed::asset {
struct AssetFilterSettings {
/** Tags to match against. These are newly allocated, and compared against the
* #AssetMetaData.tags. */
ListBase tags; /* AssetTag */
uint64_t id_types; /* rna_enum_id_type_filter_items */
};
/**
* Compare \a asset against the settings of \a filter.
*

View File

@ -769,7 +769,7 @@ void clear_operator_asset_trees()
static asset::AssetItemTree build_catalog_tree(const bContext &C, const Object &active_object)
{
AssetFilterSettings type_filter{};
asset::AssetFilterSettings type_filter{};
type_filter.id_types = FILTER_ID_NT;
const GeometryNodeAssetTraitFlag flag = asset_flag_for_context(active_object);
auto meta_data_filter = [&](const AssetMetaData &meta_data) {

View File

@ -23,7 +23,6 @@
/* Struct Declarations */
struct ARegion;
struct AssetFilterSettings;
struct AutoComplete;
struct EnumPropertyItem;
struct FileSelectParams;
@ -68,6 +67,9 @@ struct wmOperator;
struct wmOperatorType;
struct wmRegionListenerParams;
struct wmWindow;
namespace blender::ed::asset {
struct AssetFilterSettings;
}
struct uiBlock;
struct uiBut;
@ -2690,7 +2692,7 @@ void uiTemplateAssetView(uiLayout *layout,
const char *assets_propname,
PointerRNA *active_dataptr,
const char *active_propname,
const AssetFilterSettings *filter_settings,
const blender::ed::asset::AssetFilterSettings *filter_settings,
int display_flags,
const char *activate_opname,
PointerRNA *r_activate_op_properties,

View File

@ -35,7 +35,7 @@ using namespace blender::ed;
struct AssetViewListData {
AssetLibraryReference asset_library_ref;
AssetFilterSettings filter_settings;
asset::AssetFilterSettings filter_settings;
bScreen *screen;
bool show_names;
};
@ -118,7 +118,7 @@ static void asset_view_filter_items(uiList *ui_list,
const char *propname)
{
AssetViewListData *list_data = (AssetViewListData *)ui_list->dyn_data->customdata;
AssetFilterSettings &filter_settings = list_data->filter_settings;
asset::AssetFilterSettings &filter_settings = list_data->filter_settings;
uiListNameFilter name_filter(*ui_list);
@ -219,7 +219,7 @@ void uiTemplateAssetView(uiLayout *layout,
const char *assets_propname,
PointerRNA *active_dataptr,
const char *active_propname,
const AssetFilterSettings *filter_settings,
const asset::AssetFilterSettings *filter_settings,
const int display_flags,
const char *activate_opname,
PointerRNA *r_activate_op_properties,

View File

@ -50,7 +50,7 @@ static bool all_loading_finished()
static asset::AssetItemTree build_catalog_tree(const bContext &C)
{
AssetFilterSettings type_filter{};
asset::AssetFilterSettings type_filter{};
type_filter.id_types = FILTER_ID_NT;
auto meta_data_filter = [&](const AssetMetaData &meta_data) {
const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&meta_data, "type");

View File

@ -15,6 +15,7 @@
#include "WM_api.hh"
#include "WM_types.hh"
#include "ED_object.hh"
#include "ED_screen.hh"
#include "DNA_array_utils.hh"
@ -199,6 +200,12 @@ static bool bake_simulation_poll(bContext *C)
CTX_wm_operator_poll_msg_set(C, "File must be saved before baking");
return false;
}
Object *ob = ED_object_active_context(C);
const bool use_frame_cache = ob->flag & OB_FLAG_USE_SIMULATION_CACHE;
if (!use_frame_cache) {
CTX_wm_operator_poll_msg_set(C, "Cache has to be enabled");
return false;
}
return true;
}

View File

@ -91,10 +91,11 @@ using blender::Vector;
static CLG_LogRef LOG = {"ed.sculpt_paint"};
static float sculpt_calc_radius(ViewContext *vc,
const Brush *brush,
const Scene *scene,
const float3 location)
namespace blender::ed::sculpt_paint {
float sculpt_calc_radius(ViewContext *vc,
const Brush *brush,
const Scene *scene,
const float3 location)
{
if (!BKE_brush_use_locked_size(scene, brush)) {
return paint_calc_object_space_radius(vc, location, BKE_brush_size_get(scene, brush));
@ -103,6 +104,7 @@ static float sculpt_calc_radius(ViewContext *vc,
return BKE_brush_unprojected_radius_get(scene, brush);
}
}
} // namespace blender::ed::sculpt_paint
bool ED_sculpt_report_if_shape_key_is_locked(const Object *ob, ReportList *reports)
{

View File

@ -19,6 +19,7 @@
#include "DNA_brush_types.h"
#include "DNA_mesh_types.h"
#include "BKE_brush.hh"
#include "BKE_context.hh"
#include "BKE_layer.hh"
#include "BKE_paint.hh"
@ -42,6 +43,9 @@
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_prototypes.h"
#include "UI_interface.hh"
#include "CLG_log.h"
@ -467,10 +471,18 @@ void SCULPT_OT_set_detail_size(wmOperatorType *ot)
#define DETAIL_SIZE_DELTA_SPEED 0.08f
#define DETAIL_SIZE_DELTA_ACCURATE_SPEED 0.004f
enum eDyntopoDetailingMode {
DETAILING_MODE_RESOLUTION = 0,
DETAILING_MODE_BRUSH_PERCENT = 1,
DETAILING_MODE_DETAIL_SIZE = 2
};
struct DyntopoDetailSizeEditCustomData {
void *draw_handle;
Object *active_object;
eDyntopoDetailingMode mode;
float init_mval[2];
float accurate_mval[2];
@ -479,11 +491,19 @@ struct DyntopoDetailSizeEditCustomData {
bool accurate_mode;
bool sample_mode;
float init_detail_size;
float accurate_detail_size;
float detail_size;
/* The values stored here vary based on the detailing mode. */
float init_value;
float accurate_value;
float current_value;
float radius;
float brush_radius;
float pixel_radius;
float min_value;
float max_value;
float preview_tri[3][3];
float gizmo_mat[4][4];
};
@ -495,9 +515,20 @@ static void dyntopo_detail_size_parallel_lines_draw(uint pos3d,
bool flip,
const float angle)
{
float object_space_constant_detail = 1.0f /
(cd->detail_size *
mat4_to_scale(cd->active_object->object_to_world().ptr()));
float object_space_constant_detail;
if (cd->mode == DETAILING_MODE_RESOLUTION) {
object_space_constant_detail = 1.0f /
(cd->current_value *
mat4_to_scale(cd->active_object->object_to_world().ptr()));
}
else if (cd->mode == DETAILING_MODE_BRUSH_PERCENT) {
object_space_constant_detail = cd->brush_radius * cd->current_value / 100.0f;
}
else {
object_space_constant_detail = (cd->brush_radius / cd->pixel_radius) *
(cd->current_value * U.pixelsize) /
detail_size::RELATIVE_SCALE_FACTOR;
}
/* The constant detail represents the maximum edge length allowed before subdividing it. If the
* triangle grid preview is created with this value it will represent an ideal mesh density where
@ -593,6 +624,26 @@ static void dyntopo_detail_size_edit_cancel(bContext *C, wmOperator *op)
ss->draw_faded_cursor = false;
MEM_freeN(op->customdata);
ED_workspace_status_text(C, nullptr);
ScrArea *area = CTX_wm_area(C);
ED_area_status_text(area, nullptr);
}
static void dyntopo_detail_size_bounds(DyntopoDetailSizeEditCustomData *cd)
{
/* TODO: Get range from RNA for these values? */
if (cd->mode == DETAILING_MODE_RESOLUTION) {
cd->min_value = 1.0f;
cd->max_value = 500.0f;
}
else if (cd->mode == DETAILING_MODE_BRUSH_PERCENT) {
cd->min_value = 0.5f;
cd->max_value = 100.0f;
}
else {
cd->min_value = 0.5f;
cd->max_value = 40.0f;
}
}
static void dyntopo_detail_size_sample_from_surface(Object *ob,
@ -616,7 +667,19 @@ static void dyntopo_detail_size_sample_from_surface(Object *ob,
/* Use 0.7 as the average of min and max dyntopo edge length. */
const float detail_size = 0.7f / (avg_edge_len *
mat4_to_scale(cd->active_object->object_to_world().ptr()));
cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f);
float sampled_value;
if (cd->mode == DETAILING_MODE_RESOLUTION) {
sampled_value = detail_size;
}
else if (cd->mode == DETAILING_MODE_BRUSH_PERCENT) {
sampled_value = detail_size::constant_to_brush_detail(
detail_size, cd->brush_radius, cd->active_object);
}
else {
sampled_value = detail_size::constant_to_relative_detail(
detail_size, cd->brush_radius, cd->pixel_radius, cd->active_object);
}
cd->current_value = clamp_f(sampled_value, cd->min_value, cd->max_value);
}
}
@ -626,27 +689,58 @@ static void dyntopo_detail_size_update_from_mouse_delta(DyntopoDetailSizeEditCus
const float mval[2] = {float(event->mval[0]), float(event->mval[1])};
float detail_size_delta;
float invert = cd->mode == DETAILING_MODE_RESOLUTION ? 1.0f : -1.0f;
if (cd->accurate_mode) {
detail_size_delta = mval[0] - cd->accurate_mval[0];
cd->detail_size = cd->accurate_detail_size +
detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED;
cd->current_value = cd->accurate_value +
detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED * invert;
}
else {
detail_size_delta = mval[0] - cd->init_mval[0];
cd->detail_size = cd->init_detail_size + detail_size_delta * DETAIL_SIZE_DELTA_SPEED;
cd->current_value = cd->init_value + detail_size_delta * DETAIL_SIZE_DELTA_SPEED * invert;
}
if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
cd->accurate_mode = true;
copy_v2_v2(cd->accurate_mval, mval);
cd->accurate_detail_size = cd->detail_size;
cd->accurate_value = cd->current_value;
}
if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
cd->accurate_mode = false;
cd->accurate_detail_size = 0.0f;
cd->accurate_value = 0.0f;
}
cd->detail_size = clamp_f(cd->detail_size, 1.0f, 500.0f);
cd->current_value = clamp_f(cd->current_value, cd->min_value, cd->max_value);
}
static void dyntopo_detail_size_update_header(bContext *C,
const DyntopoDetailSizeEditCustomData *cd)
{
Scene *scene = CTX_data_scene(C);
Sculpt *sd = scene->toolsettings->sculpt;
PointerRNA sculpt_ptr = RNA_pointer_create(&scene->id, &RNA_Sculpt, sd);
char msg[UI_MAX_DRAW_STR];
const char *format_string;
const char *property_name;
if (cd->mode == DETAILING_MODE_RESOLUTION) {
property_name = "constant_detail_resolution";
format_string = "%s: %0.4f";
}
else if (cd->mode == DETAILING_MODE_BRUSH_PERCENT) {
property_name = "detail_percent";
format_string = "%s: %3.1f%%";
}
else {
property_name = "detail_size";
format_string = "%s: %0.4f";
}
const PropertyRNA *prop = RNA_struct_find_property(&sculpt_ptr, property_name);
const char *ui_name = RNA_property_ui_name(prop);
SNPRINTF(msg, format_string, ui_name, cd->current_value);
ScrArea *area = CTX_wm_area(C);
ED_area_status_text(area, msg);
}
static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
@ -673,11 +767,23 @@ static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmE
(event->type == EVT_PADENTER && event->val == KM_PRESS))
{
ED_region_draw_cb_exit(region->type, cd->draw_handle);
sd->constant_detail = cd->detail_size;
if (cd->mode == DETAILING_MODE_RESOLUTION) {
sd->constant_detail = cd->current_value;
}
else if (cd->mode == DETAILING_MODE_BRUSH_PERCENT) {
sd->detail_percent = cd->current_value;
}
else {
sd->detail_size = cd->current_value;
}
ss->draw_faded_cursor = false;
MEM_freeN(op->customdata);
ED_region_tag_redraw(region);
ED_workspace_status_text(C, nullptr);
ScrArea *area = CTX_wm_area(C);
ED_area_status_text(area, nullptr);
return OPERATOR_FINISHED;
}
@ -699,23 +805,29 @@ static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmE
}
/* Regular mode, changes the detail size by moving the cursor. */
dyntopo_detail_size_update_from_mouse_delta(cd, event);
dyntopo_detail_size_update_header(C, cd);
return OPERATOR_RUNNING_MODAL;
}
static float dyntopo_detail_size_initial_value(const Sculpt *sd, const eDyntopoDetailingMode mode)
{
if (mode == DETAILING_MODE_RESOLUTION) {
return sd->constant_detail;
}
else if (mode == DETAILING_MODE_BRUSH_PERCENT) {
return sd->detail_percent;
}
else {
return sd->detail_size;
}
}
static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
const ToolSettings *tool_settings = CTX_data_tool_settings(C);
Sculpt *sd = tool_settings->sculpt;
/* Fallback to radial control for modes other than SCULPT_DYNTOPO_DETAIL_CONSTANT [same as in
* SCULPT_OT_set_detail_size]. */
if (!(sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL))) {
sculpt_detail_size_set_radial_control(C);
return OPERATOR_FINISHED;
}
/* Special method for SCULPT_DYNTOPO_DETAIL_CONSTANT. */
ARegion *region = CTX_wm_region(C);
Object *active_object = CTX_data_active_object(C);
Brush *brush = BKE_paint_brush(&sd->paint);
@ -728,16 +840,36 @@ static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wm
cd->active_object = active_object;
cd->init_mval[0] = event->mval[0];
cd->init_mval[1] = event->mval[1];
cd->detail_size = sd->constant_detail;
cd->init_detail_size = sd->constant_detail;
if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) {
cd->mode = DETAILING_MODE_RESOLUTION;
}
else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
cd->mode = DETAILING_MODE_BRUSH_PERCENT;
}
else {
cd->mode = DETAILING_MODE_DETAIL_SIZE;
}
const float initial_detail_size = dyntopo_detail_size_initial_value(sd, cd->mode);
cd->current_value = initial_detail_size;
cd->init_value = initial_detail_size;
copy_v4_v4(cd->outline_col, brush->add_col);
op->customdata = cd;
SculptSession *ss = active_object->sculpt;
dyntopo_detail_size_bounds(cd);
cd->radius = ss->cursor_radius;
/* Generates the matrix to position the gizmo in the surface of the mesh using the same location
* and orientation as the brush cursor. */
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc = ED_view3d_viewcontext_init(C, depsgraph);
const Scene *scene = CTX_data_scene(C);
cd->brush_radius = blender::ed::sculpt_paint::sculpt_calc_radius(
&vc, brush, scene, ss->cursor_location);
cd->pixel_radius = BKE_brush_size_get(scene, brush);
/* Generates the matrix to position the gizmo in the surface of the mesh using the same
* location and orientation as the brush cursor. */
float cursor_trans[4][4], cursor_rot[4][4];
const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
float quat[4];
@ -775,7 +907,9 @@ static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wm
const char *status_str = IFACE_(
"Move the mouse to change the dyntopo detail size. LMB: confirm size, ESC/RMB: cancel, "
"SHIFT: precision mode, CTRL: sample detail size");
ED_workspace_status_text(C, status_str);
dyntopo_detail_size_update_header(C, cd);
return OPERATOR_RUNNING_MODAL;
}
@ -798,4 +932,26 @@ void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot)
} // namespace blender::ed::sculpt_paint::dyntopo
namespace blender::ed::sculpt_paint::dyntopo::detail_size {
float constant_to_brush_detail(const float constant_detail,
const float brush_radius,
const Object *ob)
{
const float object_scale = mat4_to_scale(ob->object_to_world().ptr());
return 100.0f / (constant_detail * brush_radius * object_scale);
}
float constant_to_relative_detail(const float constant_detail,
const float brush_radius,
const float pixel_radius,
const Object *ob)
{
const float object_scale = mat4_to_scale(ob->object_to_world().ptr());
return (pixel_radius / brush_radius) * (RELATIVE_SCALE_FACTOR / U.pixelsize) *
(1.0f / (constant_detail * object_scale));
}
} // namespace blender::ed::sculpt_paint::dyntopo::detail_size
/** \} */

View File

@ -1229,6 +1229,28 @@ void triangulate(BMesh *bm);
WarnFlag check_attribute_warning(Scene *scene, Object *ob);
namespace detail_size {
constexpr float RELATIVE_SCALE_FACTOR = 0.4f;
/**
* Converts from Sculpt#constant_detail to equivalent Sculpt#detail_percent value.
*
* Corresponds to a change from Constant & Manual Detailing to Brush Detailing.
*/
float constant_to_brush_detail(const float constant_detail,
const float brush_radius,
const Object *ob);
/**
* Converts from Sculpt#constant_detail to equivalent Sculpt#detail_size value.
*
* Corresponds to a change from Constant & Manual Detailing to Relative Detailing.
*/
float constant_to_relative_detail(const float constant_detail,
const float brush_radius,
const float pixel_radius,
const Object *ob);
}
}
/** \} */
@ -1901,6 +1923,13 @@ int SCULPT_vertex_island_get(const SculptSession *ss, PBVHVertRef vertex);
/** \} */
namespace blender::ed::sculpt_paint {
float sculpt_calc_radius(ViewContext *vc,
const Brush *brush,
const Scene *scene,
const float3 location);
}
inline void *SCULPT_vertex_attr_get(const PBVHVertRef vertex, const SculptAttribute *attr)
{
if (attr->data) {

View File

@ -41,7 +41,7 @@ static bool all_loading_finished()
static asset::AssetItemTree build_catalog_tree(const bContext &C, const bNodeTree &node_tree)
{
AssetFilterSettings type_filter{};
asset::AssetFilterSettings type_filter{};
type_filter.id_types = FILTER_ID_NT;
auto meta_data_filter = [&](const AssetMetaData &meta_data) {
const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&meta_data, "type");

View File

@ -233,7 +233,7 @@ static void gather_search_link_ops_for_asset_library(const bContext &C,
const bool skip_local,
Vector<SocketLinkOperation> &search_link_ops)
{
AssetFilterSettings filter_settings{};
asset::AssetFilterSettings filter_settings{};
filter_settings.id_types = FILTER_ID_NT;
asset::list::storage_fetch(&library_ref, &C);

View File

@ -279,7 +279,7 @@ eSnapMode SnapData::snap_edge_points_impl(SnapObjectContext *sctx,
if (lambda < (range) || (1.0f - range) < lambda) {
int v_id = lambda < 0.5f ? 0 : 1;
if (this->snap_point(v_pair[v_id], v_id)) {
if (this->snap_point(v_pair[v_id], vindex[v_id])) {
elem = SCE_SNAP_TO_EDGE_ENDPOINT;
this->copy_vert_no(vindex[v_id], this->nearest_point.no);
}

View File

@ -32,15 +32,6 @@ typedef struct AssetTag {
char name[64]; /* MAX_NAME */
} AssetTag;
#
#
typedef struct AssetFilterSettings {
/** Tags to match against. These are newly allocated, and compared against the
* #AssetMetaData.tags. */
ListBase tags; /* AssetTag */
uint64_t id_types; /* rna_enum_id_type_filter_items */
} AssetFilterSettings;
/**
* \brief The meta-data of an asset.
* By creating and giving this for a data-block (#ID.asset_data), the data-block becomes an asset.

View File

@ -942,7 +942,7 @@
.seed = 1, \
.mat_rpl = 0, \
}
#define _DNA_DEFAULT_GreasePencilWeightProximityModifierData \
{ \
.target_vgname = "", \
@ -950,5 +950,16 @@
.dist_start = 0.0f, \
.dist_end = 20.0f, \
}
#define _DNA_DEFAULT_GreasePencilHookModifierData \
{ \
.object = NULL, \
.subtarget = "", \
.flag = 0, \
.falloff_type = MOD_GREASE_PENCIL_HOOK_Falloff_Smooth, \
.parentinv = _DNA_DEFAULT_UNIT_M4, \
.cent = {0.0f, 0.0f, 0.0f}, \
.falloff = 0.0f, \
.force = 0.5f, \
}
/* clang-format off */

View File

@ -111,6 +111,7 @@ typedef enum ModifierType {
eModifierType_GreasePencilWeightAngle = 74,
eModifierType_GreasePencilArray = 75,
eModifierType_GreasePencilWeightProximity = 76,
eModifierType_GreasePencilHook = 77,
NUM_MODIFIER_TYPES,
} ModifierType;
@ -2947,3 +2948,42 @@ typedef enum GreasePencilWeightProximityFlag {
MOD_GREASE_PENCIL_WEIGHT_PROXIMITY_INVERT_OUTPUT = (1 << 0),
MOD_GREASE_PENCIL_WEIGHT_PROXIMITY_MULTIPLY_DATA = (1 << 1),
} GreasePencilWeightProximityFlag;
typedef struct GreasePencilHookModifierData {
ModifierData modifier;
GreasePencilModifierInfluenceData influence;
struct Object *object;
/** Optional name of bone target, MAX_ID_NAME-2. */
char subtarget[64];
char _pad[4];
/** #GreasePencilHookFlag. */
int flag;
/** #GreasePencilHookFalloff. */
char falloff_type;
char _pad1[3];
/** Matrix making current transform unmodified. */
float parentinv[4][4];
/** Visualization of hook. */
float cent[3];
/** If not zero, falloff is distance where influence zero. */
float falloff;
float force;
} GreasePencilHookModifierData;
typedef enum GreasePencilHookFlag {
MOD_GRAESE_PENCIL_HOOK_UNIFORM_SPACE = (1 << 0),
} GreasePencilHookFlag;
typedef enum GreasePencilHookFalloff {
MOD_GREASE_PENCIL_HOOK_Falloff_None = 0,
MOD_GREASE_PENCIL_HOOK_Falloff_Curve = 1,
MOD_GREASE_PENCIL_HOOK_Falloff_Sharp = 2,
MOD_GREASE_PENCIL_HOOK_Falloff_Smooth = 3,
MOD_GREASE_PENCIL_HOOK_Falloff_Root = 4,
MOD_GREASE_PENCIL_HOOK_Falloff_Linear = 5,
MOD_GREASE_PENCIL_HOOK_Falloff_Const = 6,
MOD_GREASE_PENCIL_HOOK_Falloff_Sphere = 7,
MOD_GREASE_PENCIL_HOOK_Falloff_InvSquare = 8,
} GreasePencilHookFalloff;

View File

@ -342,6 +342,7 @@ SDNA_DEFAULT_DECL_STRUCT(GreasePencilMultiModifierData);
SDNA_DEFAULT_DECL_STRUCT(GreasePencilWeightAngleModifierData);
SDNA_DEFAULT_DECL_STRUCT(GreasePencilArrayModifierData);
SDNA_DEFAULT_DECL_STRUCT(GreasePencilWeightProximityModifierData);
SDNA_DEFAULT_DECL_STRUCT(GreasePencilHookModifierData);
#undef SDNA_DEFAULT_DECL_STRUCT
@ -561,6 +562,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL(GreasePencilNoiseModifierData),
SDNA_DEFAULT_DECL(GreasePencilLengthModifierData),
SDNA_DEFAULT_DECL(GreasePencilWeightAngleModifierData),
SDNA_DEFAULT_DECL(GreasePencilHookModifierData),
/* Grease Pencil 3.0 defaults. */
SDNA_DEFAULT_DECL(GreasePencilSmoothModifierData),

View File

@ -328,6 +328,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_VOLUME_DATA,
"Volume Displace",
"Deform volume based on noise or other vector fields"}, /* TODO: Use correct icon. */
{eModifierType_GreasePencilHook,
"GREASE_PENCIL_HOOK",
ICON_HOOK,
"Hook",
"Deform stroke points using objects"},
{eModifierType_GreasePencilNoise,
"GREASE_PENCIL_NOISE",
ICON_MOD_NOISE,
@ -987,6 +992,7 @@ RNA_MOD_OBJECT_SET(GreasePencilMirror, object, OB_EMPTY);
RNA_MOD_OBJECT_SET(GreasePencilTint, object, OB_EMPTY);
RNA_MOD_OBJECT_SET(GreasePencilLattice, object, OB_LATTICE);
RNA_MOD_OBJECT_SET(GreasePencilWeightProximity, object, OB_EMPTY);
RNA_MOD_OBJECT_SET(GreasePencilHook, object, OB_EMPTY);
static void rna_HookModifier_object_set(PointerRNA *ptr,
PointerRNA value,
@ -1905,6 +1911,7 @@ RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilLength);
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilWeightAngle);
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilArray);
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilWeightProximity);
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilHook);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOffset);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOpacity);
@ -1917,6 +1924,7 @@ RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilLattice);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilLength);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilWeightAngle);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilWeightProximity);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilHook);
static void rna_GreasePencilOpacityModifier_opacity_factor_range(
PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax)
@ -9068,6 +9076,103 @@ static void rna_def_modifier_grease_pencil_multiply(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
static void rna_def_modifier_grease_pencil_hook(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem hook_falloff_items[] = {
{MOD_GREASE_PENCIL_HOOK_Falloff_None, "NONE", 0, "No Falloff", ""},
{MOD_GREASE_PENCIL_HOOK_Falloff_Curve, "CURVE", 0, "Curve", ""},
{MOD_GREASE_PENCIL_HOOK_Falloff_Smooth, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
{MOD_GREASE_PENCIL_HOOK_Falloff_Sphere, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
{MOD_GREASE_PENCIL_HOOK_Falloff_Root, "ROOT", ICON_ROOTCURVE, "Root", ""},
{MOD_GREASE_PENCIL_HOOK_Falloff_InvSquare,
"INVERSE_SQUARE",
ICON_ROOTCURVE,
"Inverse Square",
""},
{MOD_GREASE_PENCIL_HOOK_Falloff_Sharp, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
{MOD_GREASE_PENCIL_HOOK_Falloff_Linear, "LINEAR", ICON_LINCURVE, "Linear", ""},
{MOD_GREASE_PENCIL_HOOK_Falloff_Const, "CONSTANT", ICON_NOCURVE, "Constant", ""},
{0, nullptr, 0, nullptr, nullptr},
};
srna = RNA_def_struct(brna, "GreasePencilHookModifier", "Modifier");
RNA_def_struct_ui_text(
srna, "Hook Modifier", "Hook modifier to modify the location of stroke points");
RNA_def_struct_sdna(srna, "GreasePencilHookModifierData");
RNA_def_struct_ui_icon(srna, ICON_HOOK);
rna_def_modifier_grease_pencil_layer_filter(srna);
rna_def_modifier_grease_pencil_material_filter(
srna, "rna_GreasePencilHookModifier_material_filter_set");
rna_def_modifier_grease_pencil_vertex_group(
srna, "rna_GreasePencilHookModifier_vertex_group_name_set");
rna_def_modifier_grease_pencil_custom_curve(srna);
rna_def_modifier_panel_open_prop(srna, "open_influence_panel", 0);
rna_def_modifier_panel_open_prop(srna, "open_falloff_panel", 1);
RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(
prop, "Object", "Parent Object for hook, also recalculates and clears offset");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_pointer_funcs(
prop, nullptr, "rna_GreasePencilHookModifier_object_set", nullptr, nullptr);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, nullptr, "subtarget");
RNA_def_property_ui_text(
prop,
"Sub-Target",
"Name of Parent Bone for hook (if applicable), also recalculates and clears offset");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, nullptr, "force");
RNA_def_property_range(prop, 0, 1);
RNA_def_property_ui_text(prop, "Strength", "Relative force of the hook");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "falloff_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, hook_falloff_items); /* share the enum */
RNA_def_property_ui_text(prop, "Falloff Type", "");
RNA_def_property_translation_context(prop,
BLT_I18NCONTEXT_ID_CURVE_LEGACY); /* Abusing id_curve :/ */
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "falloff_radius", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, nullptr, "falloff");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 100, 2);
RNA_def_property_ui_text(
prop, "Radius", "If not zero, the distance from the hook where influence ends");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, nullptr, "cent");
RNA_def_property_ui_text(prop, "Hook Center", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, nullptr, "parentinv");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
RNA_def_property_ui_text(
prop, "Matrix", "Reverse the transformation between this object and its target");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_falloff_uniform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_HOOK_UNIFORM_SPACE);
RNA_def_property_ui_text(prop, "Uniform Falloff", "Compensate for non-uniform object scale");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_define_lib_overridable(false);
}
static void rna_def_modifier_grease_pencil_weight_proximity(BlenderRNA *brna)
{
StructRNA *srna;
@ -9324,6 +9429,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_grease_pencil_weight_angle(brna);
rna_def_modifier_grease_pencil_array(brna);
rna_def_modifier_grease_pencil_weight_proximity(brna);
rna_def_modifier_grease_pencil_hook(brna);
}
#endif

View File

@ -37,6 +37,7 @@ const EnumPropertyItem rna_enum_icon_items[] = {
# include "DNA_asset_types.h"
# include "ED_asset_filter.hh"
# include "ED_geometry.hh"
# include "ED_node.hh"
# include "ED_object.hh"
@ -720,7 +721,7 @@ static void rna_uiTemplateAssetView(uiLayout *layout,
const char *drag_opname,
PointerRNA *r_drag_op_properties)
{
AssetFilterSettings filter_settings{};
blender::ed::asset::AssetFilterSettings filter_settings{};
filter_settings.id_types = filter_id_types ? filter_id_types : FILTER_ID_ALL;
uiTemplateAssetView(layout,

View File

@ -47,6 +47,7 @@ set(SRC
intern/MOD_grease_pencil_array.cc
intern/MOD_grease_pencil_color.cc
intern/MOD_grease_pencil_dash.cc
intern/MOD_grease_pencil_hook.cc
intern/MOD_grease_pencil_lattice.cc
intern/MOD_grease_pencil_length.cc
intern/MOD_grease_pencil_mirror.cc

View File

@ -89,6 +89,7 @@ extern ModifierTypeInfo modifierType_GreasePencilLength;
extern ModifierTypeInfo modifierType_GreasePencilWeightAngle;
extern ModifierTypeInfo modifierType_GreasePencilArray;
extern ModifierTypeInfo modifierType_GreasePencilWeightProximity;
extern ModifierTypeInfo modifierType_GreasePencilHook;
/* MOD_util.cc */

View File

@ -0,0 +1,361 @@
/* SPDX-FileCopyrightText: 2005 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup modifiers
*/
#include "BLI_index_mask.hh"
#include "BLI_math_rotation.hh"
#include "BLI_string.h" /* For #STRNCPY. */
#include "BLT_translation.hh"
#include "BLO_read_write.hh"
#include "DNA_defaults.h"
#include "DNA_modifier_types.h"
#include "DNA_screen_types.h"
#include "RNA_access.hh"
#include "BKE_action.h"
#include "BKE_colortools.hh"
#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_lib_query.hh"
#include "BKE_modifier.hh"
#include "BKE_object_types.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "MOD_grease_pencil_util.hh"
#include "MOD_modifiertypes.hh"
#include "MOD_ui_common.hh"
#include "RNA_prototypes.h"
namespace blender {
static void init_data(ModifierData *md)
{
auto *gpmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(GreasePencilHookModifierData), modifier);
modifier::greasepencil::init_influence_data(&gpmd->influence, true);
}
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
{
const auto *gmd = reinterpret_cast<const GreasePencilHookModifierData *>(md);
auto *tgmd = reinterpret_cast<GreasePencilHookModifierData *>(target);
BKE_modifier_copydata_generic(md, target, flag);
modifier::greasepencil::copy_influence_data(&gmd->influence, &tgmd->influence, flag);
}
static void free_data(ModifierData *md)
{
auto *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
modifier::greasepencil::free_influence_data(&mmd->influence);
}
static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
{
auto *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
return (mmd->object == nullptr);
}
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
auto *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
if (mmd->object != nullptr) {
DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
}
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
}
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
{
auto *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
modifier::greasepencil::foreach_influence_ID_link(&mmd->influence, ob, walk, user_data);
}
static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
{
const auto *mmd = reinterpret_cast<const GreasePencilHookModifierData *>(md);
BLO_write_struct(writer, GreasePencilHookModifierData, mmd);
modifier::greasepencil::write_influence_data(writer, &mmd->influence);
}
static void blend_read(BlendDataReader *reader, ModifierData *md)
{
auto *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
modifier::greasepencil::read_influence_data(reader, &mmd->influence);
}
/* Calculate the factor of falloff. */
static float hook_falloff(const float falloff,
const int falloff_type,
const float falloff_sq,
const float fac_orig,
const CurveMapping *curfalloff,
const float len_sq)
{
BLI_assert(falloff_sq);
if (len_sq > falloff_sq) {
return 0.0f;
}
if (len_sq <= 0.0f) {
return fac_orig;
}
if (falloff_type == MOD_GREASE_PENCIL_HOOK_Falloff_Const) {
return fac_orig;
}
else if (falloff_type == MOD_GREASE_PENCIL_HOOK_Falloff_InvSquare) {
/* Avoid sqrt below. */
return (1.0f - (len_sq / falloff_sq)) * fac_orig;
}
float fac = 1.0f - (math::sqrt(len_sq) / falloff);
switch (falloff_type) {
case MOD_GREASE_PENCIL_HOOK_Falloff_Curve:
return BKE_curvemapping_evaluateF(curfalloff, 0, fac) * fac_orig;
case MOD_GREASE_PENCIL_HOOK_Falloff_Sharp:
return fac * fac * fac_orig;
case MOD_GREASE_PENCIL_HOOK_Falloff_Smooth:
return (3.0f * fac * fac - 2.0f * fac * fac * fac) * fac_orig;
case MOD_GREASE_PENCIL_HOOK_Falloff_Root:
return math::sqrt(fac) * fac_orig;
break;
case MOD_GREASE_PENCIL_HOOK_Falloff_Sphere:
return math::sqrt(2 * fac - fac * fac) * fac_orig;
case MOD_GREASE_PENCIL_HOOK_Falloff_Linear:
ATTR_FALLTHROUGH; /* Pass. */
default:
return fac * fac_orig;
}
}
static void deform_drawing(const ModifierData &md,
const Object &ob,
bke::greasepencil::Drawing &drawing)
{
const auto &mmd = reinterpret_cast<const GreasePencilHookModifierData &>(md);
bke::CurvesGeometry &curves = drawing.strokes_for_write();
if (curves.points_num() == 0) {
return;
}
IndexMaskMemory memory;
const IndexMask strokes = modifier::greasepencil::get_filtered_stroke_mask(
&ob, curves, mmd.influence, memory);
if (strokes.is_empty()) {
return;
}
const VArray<float> input_weights = modifier::greasepencil::get_influence_vertex_weights(
curves, mmd.influence);
const int falloff_type = mmd.falloff_type;
const float falloff = (mmd.falloff_type == eHook_Falloff_None) ? 0.0f : mmd.falloff;
const float falloff_sq = square_f(falloff);
const float fac_orig = mmd.force;
const bool use_falloff = falloff_sq != 0.0f;
const bool use_uniform = (mmd.flag & MOD_GRAESE_PENCIL_HOOK_UNIFORM_SPACE) != 0;
const float3x3 mat_uniform = use_uniform ? float3x3(float4x4(mmd.parentinv)) :
float3x3::identity();
const float3 cent = use_uniform ? math::transform_point(mat_uniform, float3(mmd.cent)) :
float3(mmd.cent);
float4x4 dmat;
/* Get world-space matrix of target, corrected for the space the verts are in. */
if (mmd.subtarget[0]) {
bPoseChannel *pchan = BKE_pose_channel_find_name(mmd.object->pose, mmd.subtarget);
if (pchan) {
/* Bone target if there's a matching pose-channel. */
dmat = mmd.object->object_to_world() * float4x4(pchan->pose_mat);
}
}
else {
/* Just object target. */
dmat = mmd.object->object_to_world();
}
float4x4 use_mat = ob.world_to_object() * dmat * float4x4(mmd.parentinv);
auto get_weight = [&](const int point) {
const float weight = input_weights[point];
if (mmd.influence.flag & GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP) {
return 1.0f - weight;
}
return weight;
};
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
MutableSpan<float3> positions = curves.positions_for_write();
strokes.foreach_index(blender::GrainSize(128), [&](const int stroke) {
const IndexRange points_range = points_by_curve[stroke].index_range();
for (const int point_i : points_range) {
const int point = point_i + points_by_curve[stroke].first();
const float weight = get_weight(point);
if (weight < 0.0f) {
continue;
}
float fac;
if (use_falloff) {
float len_sq;
if (use_uniform) {
const float3 co_uniform = math::transform_point(mat_uniform, positions[point]);
len_sq = math::distance(cent, co_uniform);
}
else {
len_sq = math::distance(cent, positions[point]);
}
fac = hook_falloff(
falloff, falloff_type, falloff_sq, fac_orig, mmd.influence.custom_curve, len_sq);
}
else {
fac = fac_orig;
}
if (fac != 0.0f) {
const float3 co_tmp = math::transform_point(use_mat, positions[point]);
positions[point] = math::interpolate(positions[point], co_tmp, fac * weight);
}
}
});
drawing.tag_positions_changed();
}
static void modify_geometry_set(ModifierData *md,
const ModifierEvalContext *ctx,
bke::GeometrySet *geometry_set)
{
const GreasePencilHookModifierData *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
if (!geometry_set->has_grease_pencil()) {
return;
}
GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
const int current_frame = grease_pencil.runtime->eval_frame;
IndexMaskMemory mask_memory;
const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask(
grease_pencil, mmd->influence, mask_memory);
const Vector<bke::greasepencil::Drawing *> drawings =
modifier::greasepencil::get_drawings_for_write(grease_pencil, layer_mask, current_frame);
threading::parallel_for_each(drawings, [&](bke::greasepencil::Drawing *drawing) {
deform_drawing(*md, *ctx->object, *drawing);
});
}
static void panel_draw(const bContext *C, Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
PointerRNA hook_object_ptr = RNA_pointer_get(ptr, "object");
uiLayoutSetPropSep(layout, true);
uiLayout *col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
if (!RNA_pointer_is_null(&hook_object_ptr) &&
RNA_enum_get(&hook_object_ptr, "type") == OB_ARMATURE)
{
PointerRNA hook_object_data_ptr = RNA_pointer_get(&hook_object_ptr, "data");
uiItemPointerR(
col, ptr, "subtarget", &hook_object_data_ptr, "bones", IFACE_("Bone"), ICON_NONE);
}
uiItemR(layout, ptr, "strength", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
if (uiLayout *sub = uiLayoutPanelProp(C, layout, ptr, "open_falloff_panel", "Falloff")) {
uiLayoutSetPropSep(sub, true);
uiItemR(sub, ptr, "falloff_type", UI_ITEM_NONE, IFACE_("Type"), ICON_NONE);
bool use_falloff = RNA_enum_get(ptr, "falloff_type") != eWarp_Falloff_None;
uiLayout *row = uiLayoutRow(sub, false);
uiLayoutSetActive(row, use_falloff);
uiItemR(row, ptr, "falloff_radius", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(sub, ptr, "use_falloff_uniform", UI_ITEM_NONE, nullptr, ICON_NONE);
if (RNA_enum_get(ptr, "falloff_type") == eWarp_Falloff_Curve) {
uiTemplateCurveMapping(sub, ptr, "custom_curve", 0, false, false, false, false);
}
}
if (uiLayout *influence_panel = uiLayoutPanelProp(
C, layout, ptr, "open_influence_panel", "Influence"))
{
modifier::greasepencil::draw_layer_filter_settings(C, influence_panel, ptr);
modifier::greasepencil::draw_material_filter_settings(C, influence_panel, ptr);
modifier::greasepencil::draw_vertex_group_settings(C, influence_panel, ptr);
}
modifier_panel_end(layout, ptr);
}
static void panel_register(ARegionType *region_type)
{
modifier_panel_register(region_type, eModifierType_GreasePencilHook, panel_draw);
}
} // namespace blender
ModifierTypeInfo modifierType_GreasePencilHook = {
/*idname*/ "GreasePencilHookModifier",
/*name*/ N_("Hook"),
/*struct_name*/ "GreasePencilHookModifierData",
/*struct_size*/ sizeof(GreasePencilHookModifierData),
/*srna*/ &RNA_GreasePencilHookModifier,
/*type*/ ModifierTypeType::OnlyDeform,
/*flags*/
eModifierTypeFlag_AcceptsGreasePencil | eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode | eModifierTypeFlag_SupportsMapping,
/*icon*/ ICON_HOOK,
/*copy_data*/ blender::copy_data,
/*deform_verts*/ nullptr,
/*deform_matrices*/ nullptr,
/*deform_verts_EM*/ nullptr,
/*deform_matrices_EM*/ nullptr,
/*modify_mesh*/ nullptr,
/*modify_geometry_set*/ blender::modify_geometry_set,
/*init_data*/ blender::init_data,
/*required_data_mask*/ nullptr,
/*free_data*/ blender::free_data,
/*is_disabled*/ blender::is_disabled,
/*update_depsgraph*/ blender::update_depsgraph,
/*depends_on_time*/ nullptr,
/*depends_on_normals*/ nullptr,
/*foreach_ID_link*/ blender::foreach_ID_link,
/*foreach_tex_link*/ nullptr,
/*free_runtime_data*/ nullptr,
/*panel_register*/ blender::panel_register,
/*blend_write*/ blender::blend_write,
/*blend_read*/ blender::blend_read,
};

View File

@ -117,8 +117,6 @@ static void deform_drawing(const GreasePencilNoiseModifierData &mmd,
return;
}
const OffsetIndices<int> points_by_curve = strokes.points_by_curve();
int seed = mmd.seed;
/* Make sure different modifiers get different seeds. */
seed += BLI_hash_string(ob.id.name + 2);
@ -133,12 +131,17 @@ static void deform_drawing(const GreasePencilNoiseModifierData &mmd,
}
}
const OffsetIndices<int> points_by_curve = strokes.points_by_curve();
const VArray<float> vgroup_weights = modifier::greasepencil::get_influence_vertex_weights(
strokes, mmd.influence);
auto get_weight = [&](const IndexRange points, const int point_i) {
const float vertex_weight = vgroup_weights[points[point_i]];
if (!use_curve) {
return 1.0f;
return vertex_weight;
}
const float value = float(point_i) / float(points.size() - 1);
return BKE_curvemapping_evaluateF(mmd.influence.custom_curve, 0, value);
return vertex_weight * BKE_curvemapping_evaluateF(mmd.influence.custom_curve, 0, value);
};
auto get_noise = [](const Array<float> &noise_table, const float value) {

View File

@ -280,5 +280,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(GreasePencilWeightAngle);
INIT_TYPE(GreasePencilArray);
INIT_TYPE(GreasePencilWeightProximity);
INIT_TYPE(GreasePencilHook);
#undef INIT_TYPE
}

View File

@ -41,7 +41,7 @@ static void align_rotations_auto_pivot(const IndexMask &mask,
{
mask.foreach_index([&](const int64_t i) {
const float3 vector = vectors[i];
if (is_zero_v3(vector)) {
if (math::is_zero(vector)) {
output_rotations[i] = input_rotations[i];
return;
}
@ -53,10 +53,10 @@ static void align_rotations_auto_pivot(const IndexMask &mask,
const float3 new_axis = math::normalize(vector);
float3 rotation_axis = math::cross_high_precision(old_axis, new_axis);
if (is_zero_v3(rotation_axis)) {
if (math::is_zero(rotation_axis)) {
/* The vectors are linearly dependent, so we fall back to another axis. */
rotation_axis = math::cross_high_precision(old_axis, float3(1, 0, 0));
if (is_zero_v3(rotation_axis)) {
if (math::is_zero(rotation_axis)) {
/* This is now guaranteed to not be zero. */
rotation_axis = math::cross_high_precision(old_axis, float3(0, 1, 0));
}
@ -94,7 +94,7 @@ static void align_rotations_fixed_pivot(const IndexMask &mask,
}
const float3 vector = vectors[i];
if (is_zero_v3(vector)) {
if (math::is_zero(vector)) {
output_rotations[i] = input_rotations[i];
return;
}