WIP: Brush assets project #106303
|
@ -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')
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue