GPv3: Fill gradient tool
This adds a gradient tool allowing the user to specify a gradient by dragging from a start to a end point. This behaves the same as most gradient tool in other softwares. Pull Request: https://projects.blender.org/blender/blender/pulls/120121
This commit is contained in:
committed by
Falk David
parent
5eeb5cd164
commit
1b6220a4ba
@@ -8897,6 +8897,19 @@ def km_3d_view_tool_sculpt_gpencil_select_lasso(params):
|
||||
{"items": _template_items_tool_select_actions("gpencil.select_lasso", **params.tool_tweak_event)},
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Grease Pencil: Texture Gradient Tool
|
||||
|
||||
|
||||
def km_3d_view_tool_edit_grease_pencil_texture_gradient(params):
|
||||
return (
|
||||
"3D View Tool: Edit Grease Pencil, Gradient",
|
||||
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
|
||||
{"items": [
|
||||
("grease_pencil.texture_gradient", params.tool_maybe_tweak_event, None),
|
||||
]},
|
||||
)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Tool System (Sequencer, Generic)
|
||||
@@ -9382,6 +9395,7 @@ def generate_keymaps(params=None):
|
||||
*(km_sequencer_editor_tool_generic_select_box_preview(params, fallback=fallback)
|
||||
for fallback in (False, True)),
|
||||
km_3d_view_tool_paint_grease_pencil_trim(params),
|
||||
km_3d_view_tool_edit_grease_pencil_texture_gradient(params),
|
||||
km_sequencer_editor_tool_generic_cursor(params),
|
||||
km_sequencer_editor_tool_blade(params),
|
||||
km_sequencer_editor_tool_sample(params),
|
||||
|
||||
@@ -2213,6 +2213,16 @@ class _defs_grease_pencil_edit:
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def texture_gradient():
|
||||
return dict(
|
||||
idname="builtin.texture_gradient",
|
||||
label="Gradient",
|
||||
icon="ops.paint.weight_gradient",
|
||||
widget=None,
|
||||
keymap=(),
|
||||
)
|
||||
|
||||
|
||||
class _defs_image_generic:
|
||||
|
||||
@@ -3553,6 +3563,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
|
||||
None,
|
||||
_defs_grease_pencil_edit.interpolate,
|
||||
None,
|
||||
_defs_grease_pencil_edit.texture_gradient,
|
||||
None,
|
||||
*_tools_annotate,
|
||||
],
|
||||
'PARTICLE': [
|
||||
|
||||
@@ -3142,6 +3142,188 @@ static void GREASE_PENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot)
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static float4x3 expand_4x2_mat(float4x2 strokemat)
|
||||
{
|
||||
float4x3 strokemat4x3 = float4x3(strokemat);
|
||||
|
||||
/*
|
||||
* We need the diagonal of ones to start from the bottom right instead top left to properly
|
||||
* apply the two matrices.
|
||||
*
|
||||
* i.e.
|
||||
* # # # # # # # #
|
||||
* We need # # # # Instead of # # # #
|
||||
* 0 0 0 1 0 0 1 0
|
||||
*
|
||||
*/
|
||||
strokemat4x3[2][2] = 0.0f;
|
||||
strokemat4x3[3][2] = 1.0f;
|
||||
|
||||
return strokemat4x3;
|
||||
}
|
||||
|
||||
static int grease_pencil_texture_gradient_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
Object *object = CTX_data_active_object(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
std::atomic<bool> changed = false;
|
||||
const Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(*scene, grease_pencil);
|
||||
threading::parallel_for_each(drawings, [&](const MutableDrawingInfo &info) {
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask strokes = ed::greasepencil::retrieve_editable_and_selected_strokes(
|
||||
*object, info.drawing, info.layer_index, memory);
|
||||
if (strokes.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bke::greasepencil::Layer &layer = grease_pencil.layer(info.layer_index);
|
||||
const float4x4 layer_space_to_world_space = layer.to_world_space(*object);
|
||||
|
||||
/* Calculate screen space points. */
|
||||
const float2 screen_start(RNA_int_get(op->ptr, "xstart"), RNA_int_get(op->ptr, "ystart"));
|
||||
const float2 screen_end(RNA_int_get(op->ptr, "xend"), RNA_int_get(op->ptr, "yend"));
|
||||
const float2 screen_direction = screen_end - screen_start;
|
||||
const float2 screen_tangent = screen_start + float2(-screen_direction[1], screen_direction[0]);
|
||||
|
||||
const bke::CurvesGeometry &curves = info.drawing.strokes();
|
||||
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
const Span<float3> positions = curves.positions();
|
||||
const Span<float3> normals = info.drawing.curve_plane_normals();
|
||||
const VArray<int> materials = *curves.attributes().lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Curve, 0);
|
||||
|
||||
Array<float4x2> texture_matrices(strokes.size());
|
||||
|
||||
strokes.foreach_index([&](const int curve_i, const int pos) {
|
||||
const int material_index = materials[curve_i];
|
||||
|
||||
const MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(object,
|
||||
material_index + 1);
|
||||
const bool is_radial = gp_style->gradient_type == GP_MATERIAL_GRADIENT_RADIAL;
|
||||
|
||||
const float texture_angle = gp_style->texture_angle;
|
||||
const float2 texture_scale = float2(gp_style->texture_scale);
|
||||
const float2 texture_offset = float2(gp_style->texture_offset);
|
||||
|
||||
const float2x2 texture_rotation = math::from_rotation<float2x2>(
|
||||
math::AngleRadian(texture_angle));
|
||||
|
||||
const float3 point = math::transform_point(layer_space_to_world_space,
|
||||
positions[points_by_curve[curve_i].first()]);
|
||||
const float3 normal = math::transform_direction(layer_space_to_world_space,
|
||||
normals[curve_i]);
|
||||
|
||||
const float4 plane = float4(normal, -math::dot(normal, point));
|
||||
|
||||
float3 start;
|
||||
float3 tangent;
|
||||
float3 end;
|
||||
ED_view3d_win_to_3d_on_plane(region, plane, screen_start, false, start);
|
||||
ED_view3d_win_to_3d_on_plane(region, plane, screen_tangent, false, tangent);
|
||||
ED_view3d_win_to_3d_on_plane(region, plane, screen_end, false, end);
|
||||
|
||||
const float3 origin = start;
|
||||
/* Invert the length by dividing by the length squared. */
|
||||
const float3 u_dir = (end - origin) / math::length_squared(end - origin);
|
||||
float3 v_dir = math::cross(u_dir, normal);
|
||||
|
||||
/* Flip the texture if need so that it is not mirrored. */
|
||||
if (math::dot(tangent - start, v_dir) < 0.0f) {
|
||||
v_dir = -v_dir;
|
||||
}
|
||||
|
||||
/* Calculate the texture space before the texture offset transformation. */
|
||||
const float4x2 base_texture_space = math::transpose(float2x4(
|
||||
float4(u_dir, -math::dot(u_dir, origin)), float4(v_dir, -math::dot(v_dir, origin))));
|
||||
|
||||
float3x2 offset_matrix = float3x2::identity();
|
||||
|
||||
if (is_radial) {
|
||||
/* Radial gradients are scaled down by a factor of 2 and have the center at 0.5 */
|
||||
offset_matrix *= 0.5f;
|
||||
offset_matrix[2] += float2(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
/* For some reason 0.5 is added to the offset before being rendered, so remove it here. */
|
||||
offset_matrix[2] -= float2(0.5f, 0.5f);
|
||||
|
||||
offset_matrix = math::from_scale<float2x2>(texture_scale) * offset_matrix;
|
||||
offset_matrix = texture_rotation * offset_matrix;
|
||||
offset_matrix[2] -= texture_offset;
|
||||
|
||||
texture_matrices[pos] = (offset_matrix * expand_4x2_mat(base_texture_space)) *
|
||||
layer_space_to_world_space;
|
||||
});
|
||||
|
||||
info.drawing.set_texture_matrices(texture_matrices, strokes);
|
||||
|
||||
changed.store(true, std::memory_order_relaxed);
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
|
||||
}
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int grease_pencil_texture_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
int ret = WM_gesture_straightline_modal(C, op, event);
|
||||
|
||||
/* Check for mouse release. */
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) != 0 && event->type == LEFTMOUSE && event->val == KM_RELEASE)
|
||||
{
|
||||
WM_gesture_straightline_cancel(C, op);
|
||||
ret &= ~OPERATOR_RUNNING_MODAL;
|
||||
ret |= OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int grease_pencil_texture_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
/* Invoke interactive line drawing (representing the gradient) in viewport. */
|
||||
const int ret = WM_gesture_straightline_invoke(C, op, event);
|
||||
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) != 0) {
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
if (region->regiontype == RGN_TYPE_WINDOW && event->type == LEFTMOUSE &&
|
||||
event->val == KM_PRESS)
|
||||
{
|
||||
wmGesture *gesture = static_cast<wmGesture *>(op->customdata);
|
||||
gesture->is_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_texture_gradient(wmOperatorType *ot)
|
||||
{
|
||||
/* Identifiers. */
|
||||
ot->name = "Texture Gradient";
|
||||
ot->idname = "GREASE_PENCIL_OT_texture_gradient";
|
||||
ot->description = "Draw a line to set the fill material gradient for the selected strokes";
|
||||
|
||||
/* Api callbacks. */
|
||||
ot->invoke = grease_pencil_texture_gradient_invoke;
|
||||
ot->modal = grease_pencil_texture_gradient_modal;
|
||||
ot->exec = grease_pencil_texture_gradient_exec;
|
||||
ot->poll = editable_grease_pencil_poll;
|
||||
ot->cancel = WM_gesture_straightline_cancel;
|
||||
|
||||
/* Flags. */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -3484,4 +3666,5 @@ void ED_operatortypes_grease_pencil_edit()
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_set_curve_resolution);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_set_handle_type);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_reset_uvs);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_texture_gradient);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user