Merge branch 'blender-v4.4-release'
This commit is contained in:
@@ -30,6 +30,7 @@ set(SRC
|
||||
intern/grease_pencil_modes.cc
|
||||
intern/grease_pencil_ops.cc
|
||||
intern/grease_pencil_primitive.cc
|
||||
intern/grease_pencil_randomize.cc
|
||||
intern/grease_pencil_select.cc
|
||||
intern/grease_pencil_trim.cc
|
||||
intern/grease_pencil_undo.cc
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_rand.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
@@ -144,6 +145,14 @@ struct PrimitiveToolOperation {
|
||||
float4x2 texture_space;
|
||||
float4x4 local_transform;
|
||||
|
||||
RandomNumberGenerator rng;
|
||||
float stroke_random_radius_factor;
|
||||
float stroke_random_opacity_factor;
|
||||
float stroke_random_rotation_factor;
|
||||
float stroke_random_hue_factor;
|
||||
float stroke_random_sat_factor;
|
||||
float stroke_random_val_factor;
|
||||
|
||||
OperatorMode mode;
|
||||
float2 start_position_2d;
|
||||
int active_control_point_index;
|
||||
@@ -452,6 +461,7 @@ static void grease_pencil_primitive_update_curves(PrimitiveToolOperation &ptd)
|
||||
{
|
||||
const bool on_back = ptd.on_back;
|
||||
const int new_points_num = grease_pencil_primitive_curve_points_number(ptd);
|
||||
const bool use_random = (ptd.settings->flag & GP_BRUSH_GROUP_RANDOM) != 0;
|
||||
|
||||
bke::CurvesGeometry &curves = ptd.drawing->strokes_for_write();
|
||||
const int target_curve_index = on_back ? 0 : curves.curves_range().last();
|
||||
@@ -469,10 +479,22 @@ static void grease_pencil_primitive_update_curves(PrimitiveToolOperation &ptd)
|
||||
|
||||
MutableSpan<float> new_radii = ptd.drawing->radii_for_write().slice(curve_points);
|
||||
MutableSpan<float> new_opacities = ptd.drawing->opacities_for_write().slice(curve_points);
|
||||
MutableSpan<ColorGeometry4f> new_vertex_colors = ptd.drawing->vertex_colors_for_write().slice(
|
||||
curve_points);
|
||||
bke::SpanAttributeWriter<float> rotations;
|
||||
MutableSpan<float> new_rotations;
|
||||
if (use_random && ptd.settings->uv_random > 0.0f) {
|
||||
rotations = curves.attributes_for_write().lookup_or_add_for_write_span<float>(
|
||||
"rotation", bke::AttrDomain::Point);
|
||||
new_rotations = rotations.span.slice(curve_points);
|
||||
}
|
||||
|
||||
const ToolSettings *ts = ptd.vc.scene->toolsettings;
|
||||
const GP_Sculpt_Settings *gset = &ts->gp_sculpt;
|
||||
|
||||
/* Screen-space length along curve used as randomization parameter. */
|
||||
Array<float> lengths(new_points_num);
|
||||
|
||||
for (const int point : curve_points.index_range()) {
|
||||
float pressure = 1.0f;
|
||||
/* Apply pressure curve. */
|
||||
@@ -491,15 +513,41 @@ static void grease_pencil_primitive_update_curves(PrimitiveToolOperation &ptd)
|
||||
const float opacity = ed::greasepencil::opacity_from_input_sample(
|
||||
pressure, ptd.brush, ptd.settings);
|
||||
|
||||
new_radii[point] = radius;
|
||||
new_opacities[point] = opacity;
|
||||
}
|
||||
point_attributes_to_skip.add_multiple({"position", "radius", "opacity"});
|
||||
if (point == 0) {
|
||||
lengths[point] = 0.0f;
|
||||
}
|
||||
else {
|
||||
const float distance_2d = math::distance(positions_2d[point - 1], positions_2d[point]);
|
||||
lengths[point] = lengths[point - 1] + distance_2d;
|
||||
}
|
||||
|
||||
new_radii[point] = ed::greasepencil::randomize_radius(
|
||||
*ptd.settings, ptd.stroke_random_radius_factor, lengths[point], radius, pressure);
|
||||
new_opacities[point] = ed::greasepencil::randomize_opacity(
|
||||
*ptd.settings, ptd.stroke_random_opacity_factor, lengths[point], opacity, pressure);
|
||||
if (ptd.vertex_color) {
|
||||
new_vertex_colors[point] = ed::greasepencil::randomize_color(*ptd.settings,
|
||||
ptd.stroke_random_hue_factor,
|
||||
ptd.stroke_random_sat_factor,
|
||||
ptd.stroke_random_val_factor,
|
||||
lengths[point],
|
||||
*ptd.vertex_color,
|
||||
pressure);
|
||||
}
|
||||
if (rotations) {
|
||||
new_rotations[point] = ed::greasepencil::randomize_rotation(
|
||||
*ptd.settings, ptd.stroke_random_rotation_factor, lengths[point], pressure);
|
||||
}
|
||||
}
|
||||
|
||||
point_attributes_to_skip.add_multiple({"position", "radius", "opacity"});
|
||||
if (ptd.vertex_color) {
|
||||
ptd.drawing->vertex_colors_for_write().slice(curve_points).fill(*ptd.vertex_color);
|
||||
point_attributes_to_skip.add("vertex_color");
|
||||
}
|
||||
if (rotations) {
|
||||
point_attributes_to_skip.add("rotation");
|
||||
rotations.finish();
|
||||
}
|
||||
|
||||
/* Initialize the rest of the attributes with default values. */
|
||||
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
@@ -764,6 +812,17 @@ static int grease_pencil_primitive_invoke(bContext *C, wmOperator *op, const wmE
|
||||
ptd.texture_space = ed::greasepencil::calculate_texture_space(
|
||||
vc.scene, ptd.region, ptd.start_position_2d, ptd.placement);
|
||||
|
||||
const bool use_random = (ptd.settings->flag & GP_BRUSH_GROUP_RANDOM) != 0;
|
||||
if (use_random) {
|
||||
ptd.rng = RandomNumberGenerator::from_random_seed();
|
||||
ptd.stroke_random_radius_factor = ptd.rng.get_float() * 2.0f - 1.0f;
|
||||
ptd.stroke_random_opacity_factor = ptd.rng.get_float() * 2.0f - 1.0f;
|
||||
ptd.stroke_random_rotation_factor = ptd.rng.get_float() * 2.0f - 1.0f;
|
||||
ptd.stroke_random_hue_factor = ptd.rng.get_float() * 2.0f - 1.0f;
|
||||
ptd.stroke_random_sat_factor = ptd.rng.get_float() * 2.0f - 1.0f;
|
||||
ptd.stroke_random_val_factor = ptd.rng.get_float() * 2.0f - 1.0f;
|
||||
}
|
||||
|
||||
BLI_assert(grease_pencil->has_active_layer());
|
||||
ptd.local_transform = grease_pencil->get_active_layer()->local_transform();
|
||||
ptd.drawing = grease_pencil->get_editable_drawing_at(*grease_pencil->get_active_layer(),
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edgreasepencil
|
||||
*/
|
||||
|
||||
#include "BLI_noise.hh"
|
||||
#include "BLI_rand.hh"
|
||||
|
||||
#include "BKE_colortools.hh"
|
||||
|
||||
#include "ED_grease_pencil.hh"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
|
||||
namespace blender::ed::greasepencil {
|
||||
|
||||
float randomize_radius(const BrushGpencilSettings &settings,
|
||||
const float stroke_factor,
|
||||
const float distance,
|
||||
const float radius,
|
||||
const float pressure)
|
||||
{
|
||||
const bool use_random = (settings.flag & GP_BRUSH_GROUP_RANDOM) != 0;
|
||||
if (!use_random || !(settings.draw_random_press > 0.0f)) {
|
||||
return radius;
|
||||
}
|
||||
float random_factor = 0.0f;
|
||||
if ((settings.flag2 & GP_BRUSH_USE_PRESS_AT_STROKE) == 0) {
|
||||
/* TODO: This should be exposed as a setting to scale the noise along the stroke. */
|
||||
constexpr float noise_scale = 1 / 20.0f;
|
||||
random_factor = noise::perlin_signed(float2(distance * noise_scale, stroke_factor));
|
||||
}
|
||||
else {
|
||||
random_factor = stroke_factor;
|
||||
}
|
||||
|
||||
if ((settings.flag2 & GP_BRUSH_USE_PRESSURE_RAND_PRESS) != 0) {
|
||||
random_factor *= BKE_curvemapping_evaluateF(settings.curve_rand_pressure, 0, pressure);
|
||||
}
|
||||
|
||||
const float randomized_radius = math::interpolate(
|
||||
radius, radius * (1.0f + random_factor), settings.draw_random_press);
|
||||
return math::max(randomized_radius, 0.0f);
|
||||
}
|
||||
|
||||
float randomize_opacity(const BrushGpencilSettings &settings,
|
||||
const float stroke_factor,
|
||||
const float distance,
|
||||
const float opacity,
|
||||
const float pressure)
|
||||
{
|
||||
const bool use_random = (settings.flag & GP_BRUSH_GROUP_RANDOM) != 0;
|
||||
if (!use_random || !(settings.draw_random_strength > 0.0f)) {
|
||||
return opacity;
|
||||
}
|
||||
float random_factor = 0.0f;
|
||||
if ((settings.flag2 & GP_BRUSH_USE_STRENGTH_AT_STROKE) == 0) {
|
||||
/* TODO: This should be exposed as a setting to scale the noise along the stroke. */
|
||||
constexpr float noise_scale = 1 / 20.0f;
|
||||
random_factor = noise::perlin_signed(float2(distance * noise_scale, stroke_factor));
|
||||
}
|
||||
else {
|
||||
random_factor = stroke_factor;
|
||||
}
|
||||
|
||||
if ((settings.flag2 & GP_BRUSH_USE_STRENGTH_RAND_PRESS) != 0) {
|
||||
random_factor *= BKE_curvemapping_evaluateF(settings.curve_rand_strength, 0, pressure);
|
||||
}
|
||||
|
||||
const float randomized_opacity = math::interpolate(
|
||||
opacity, opacity + random_factor, settings.draw_random_strength);
|
||||
return math::clamp(randomized_opacity, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
float randomize_rotation(const BrushGpencilSettings &settings,
|
||||
const float stroke_factor,
|
||||
const float distance,
|
||||
const float pressure)
|
||||
{
|
||||
const bool use_random = (settings.flag & GP_BRUSH_GROUP_RANDOM) != 0;
|
||||
if (!use_random || !(settings.uv_random > 0.0f)) {
|
||||
return 0.0f;
|
||||
}
|
||||
float random_factor = 0.0f;
|
||||
if ((settings.flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) {
|
||||
/* TODO: This should be exposed as a setting to scale the noise along the stroke. */
|
||||
constexpr float noise_scale = 1 / 20.0f;
|
||||
random_factor = noise::perlin_signed(float2(distance * noise_scale, stroke_factor));
|
||||
}
|
||||
else {
|
||||
random_factor = stroke_factor;
|
||||
}
|
||||
|
||||
if ((settings.flag2 & GP_BRUSH_USE_UV_RAND_PRESS) != 0) {
|
||||
random_factor *= BKE_curvemapping_evaluateF(settings.curve_rand_uv, 0, pressure);
|
||||
}
|
||||
|
||||
const float random_rotation = random_factor * math::numbers::pi;
|
||||
return math::interpolate(0.0f, random_rotation, settings.uv_random);
|
||||
}
|
||||
|
||||
float randomize_rotation(const BrushGpencilSettings &settings,
|
||||
RandomNumberGenerator &rng,
|
||||
const float stroke_factor,
|
||||
const float pressure)
|
||||
{
|
||||
const bool use_random = (settings.flag & GP_BRUSH_GROUP_RANDOM) != 0;
|
||||
if (!use_random || !(settings.uv_random > 0.0f)) {
|
||||
return 0.0f;
|
||||
}
|
||||
float random_factor = 0.0f;
|
||||
if ((settings.flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) {
|
||||
random_factor = rng.get_float() * 2.0f - 1.0f;
|
||||
}
|
||||
else {
|
||||
random_factor = stroke_factor;
|
||||
}
|
||||
|
||||
if ((settings.flag2 & GP_BRUSH_USE_UV_RAND_PRESS) != 0) {
|
||||
random_factor *= BKE_curvemapping_evaluateF(settings.curve_rand_uv, 0, pressure);
|
||||
}
|
||||
|
||||
const float random_rotation = random_factor * math::numbers::pi;
|
||||
return math::interpolate(0.0f, random_rotation, settings.uv_random);
|
||||
}
|
||||
|
||||
ColorGeometry4f randomize_color(const BrushGpencilSettings &settings,
|
||||
const float stroke_hue_factor,
|
||||
const float stroke_saturation_factor,
|
||||
const float stroke_value_factor,
|
||||
const float distance,
|
||||
const ColorGeometry4f color,
|
||||
const float pressure)
|
||||
{
|
||||
const bool use_random = (settings.flag & GP_BRUSH_GROUP_RANDOM) != 0;
|
||||
if (!use_random || !(settings.random_hue > 0.0f || settings.random_saturation > 0.0f ||
|
||||
settings.random_value > 0.0f))
|
||||
{
|
||||
return color;
|
||||
}
|
||||
/* TODO: This should be exposed as a setting to scale the noise along the stroke. */
|
||||
constexpr float noise_scale = 1 / 20.0f;
|
||||
|
||||
float random_hue = 0.0f;
|
||||
if ((settings.flag2 & GP_BRUSH_USE_HUE_AT_STROKE) == 0) {
|
||||
random_hue = noise::perlin_signed(float2(distance * noise_scale, stroke_hue_factor));
|
||||
}
|
||||
else {
|
||||
random_hue = stroke_hue_factor;
|
||||
}
|
||||
|
||||
float random_saturation = 0.0f;
|
||||
if ((settings.flag2 & GP_BRUSH_USE_SAT_AT_STROKE) == 0) {
|
||||
random_saturation = noise::perlin_signed(
|
||||
float2(distance * noise_scale, stroke_saturation_factor));
|
||||
}
|
||||
else {
|
||||
random_saturation = stroke_saturation_factor;
|
||||
}
|
||||
|
||||
float random_value = 0.0f;
|
||||
if ((settings.flag2 & GP_BRUSH_USE_VAL_AT_STROKE) == 0) {
|
||||
random_value = noise::perlin_signed(float2(distance * noise_scale, stroke_value_factor));
|
||||
}
|
||||
else {
|
||||
random_value = stroke_value_factor;
|
||||
}
|
||||
|
||||
if ((settings.flag2 & GP_BRUSH_USE_HUE_RAND_PRESS) != 0) {
|
||||
random_hue *= BKE_curvemapping_evaluateF(settings.curve_rand_hue, 0, pressure);
|
||||
}
|
||||
if ((settings.flag2 & GP_BRUSH_USE_SAT_RAND_PRESS) != 0) {
|
||||
random_saturation *= BKE_curvemapping_evaluateF(settings.curve_rand_saturation, 0, pressure);
|
||||
}
|
||||
if ((settings.flag2 & GP_BRUSH_USE_VAL_RAND_PRESS) != 0) {
|
||||
random_value *= BKE_curvemapping_evaluateF(settings.curve_rand_value, 0, pressure);
|
||||
}
|
||||
|
||||
float3 hsv;
|
||||
rgb_to_hsv_v(color, hsv);
|
||||
|
||||
hsv += float3(random_hue * settings.random_hue,
|
||||
random_saturation * settings.random_saturation,
|
||||
random_value * settings.random_value);
|
||||
|
||||
/* Wrap hue. */
|
||||
if (hsv[0] > 1.0f) {
|
||||
hsv[0] -= 1.0f;
|
||||
}
|
||||
else if (hsv[0] < 0.0f) {
|
||||
hsv[0] += 1.0f;
|
||||
}
|
||||
|
||||
hsv[1] = math::clamp(hsv[1], 0.0f, 1.0f);
|
||||
hsv[2] = math::clamp(hsv[2], 0.0f, 1.0f);
|
||||
|
||||
ColorGeometry4f random_color;
|
||||
hsv_to_rgb_v(hsv, random_color);
|
||||
random_color.a = color.a;
|
||||
return random_color;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::greasepencil
|
||||
@@ -40,12 +40,13 @@ struct BVHTree;
|
||||
struct GreasePencilLineartModifierData;
|
||||
struct RV3DMatrixStore;
|
||||
|
||||
namespace blender::bke {
|
||||
namespace blender {
|
||||
struct RandomNumberGenerator;
|
||||
namespace bke {
|
||||
enum class AttrDomain : int8_t;
|
||||
class CurvesGeometry;
|
||||
namespace crazyspace {
|
||||
}
|
||||
} // namespace blender::bke
|
||||
} // namespace bke
|
||||
} // namespace blender
|
||||
|
||||
enum {
|
||||
LAYER_REORDER_ABOVE,
|
||||
@@ -929,4 +930,65 @@ void add_single_curve(bke::CurvesGeometry &curves, bool at_end);
|
||||
*/
|
||||
void resize_single_curve(bke::CurvesGeometry &curves, bool at_end, int new_points_num);
|
||||
|
||||
/**
|
||||
* Calculate a randomized radius value for a point.
|
||||
* \param stroke_factor Random seed value in [-1, 1] per stroke.
|
||||
* \param distance Screen-space length in pixels along the curve.
|
||||
* \param radius Base radius to be randomized.
|
||||
* \param pressure Pressure factor.
|
||||
*/
|
||||
float randomize_radius(const BrushGpencilSettings &settings,
|
||||
float stroke_factor,
|
||||
float distance,
|
||||
float radius,
|
||||
float pressure);
|
||||
/**
|
||||
* Calculate a randomized opacity value for a point.
|
||||
* \param stroke_factor Random seed value in [-1, 1] per stroke.
|
||||
* \param distance Screen-space length in pixels along the curve.
|
||||
* \param opacity Base opacity to be randomized.
|
||||
* \param pressure Pressure factor.
|
||||
*/
|
||||
float randomize_opacity(const BrushGpencilSettings &settings,
|
||||
float stroke_factor,
|
||||
float distance,
|
||||
float opacity,
|
||||
float pressure);
|
||||
/**
|
||||
* Calculate a randomized rotation for a point.
|
||||
* \param stroke_factor Random seed value in [-1, 1] per stroke.
|
||||
* \param distance Screen-space length in pixels along the curve.
|
||||
* \param pressure Pressure factor.
|
||||
*/
|
||||
float randomize_rotation(const BrushGpencilSettings &settings,
|
||||
float stroke_factor,
|
||||
float distance,
|
||||
float pressure);
|
||||
/**
|
||||
* Calculate a randomized rotation for a point.
|
||||
* \param rng Random number generator instance.
|
||||
* \param stroke_factor Random seed value in [-1, 1] per stroke.
|
||||
* \param pressure Pressure factor.
|
||||
*/
|
||||
float randomize_rotation(const BrushGpencilSettings &settings,
|
||||
blender::RandomNumberGenerator &rng,
|
||||
float stroke_factor,
|
||||
float pressure);
|
||||
/**
|
||||
* Calculate a randomized opacity value for a point.
|
||||
* \param stroke_hue_factor Random seed value in [-1, 1] per stroke for color hue.
|
||||
* \param stroke_saturation_factor Random seed value in [-1, 1] per stroke for color saturation.
|
||||
* \param stroke_value_factor Random seed value in [-1, 1] per stroke for color value.
|
||||
* \param distance Screen-space length in pixels along the curve.
|
||||
* \param color Base color to be randomized.
|
||||
* \param pressure Pressure factor.
|
||||
*/
|
||||
ColorGeometry4f randomize_color(const BrushGpencilSettings &settings,
|
||||
float stroke_hue_factor,
|
||||
float stroke_saturation_factor,
|
||||
float stroke_value_factor,
|
||||
float distance,
|
||||
ColorGeometry4f color,
|
||||
float pressure);
|
||||
|
||||
} // namespace blender::ed::greasepencil
|
||||
|
||||
@@ -258,159 +258,6 @@ struct PaintOperationExecutor {
|
||||
BLI_assert(drawing_ != nullptr);
|
||||
}
|
||||
|
||||
float randomize_radius(PaintOperation &self,
|
||||
const float distance,
|
||||
const float radius,
|
||||
const float pressure)
|
||||
{
|
||||
if (!use_settings_random_ || !(settings_->draw_random_press > 0.0f)) {
|
||||
return radius;
|
||||
}
|
||||
float random_factor = 0.0f;
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_PRESS_AT_STROKE) == 0) {
|
||||
/* TODO: This should be exposed as a setting to scale the noise along the stroke. */
|
||||
constexpr float noise_scale = 1 / 20.0f;
|
||||
random_factor = noise::perlin_signed(
|
||||
float2(distance * noise_scale, self.stroke_random_radius_factor_));
|
||||
}
|
||||
else {
|
||||
random_factor = self.stroke_random_radius_factor_;
|
||||
}
|
||||
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_PRESSURE_RAND_PRESS) != 0) {
|
||||
random_factor *= BKE_curvemapping_evaluateF(settings_->curve_rand_pressure, 0, pressure);
|
||||
}
|
||||
|
||||
const float randomized_radius = math::interpolate(
|
||||
radius, radius * (1.0f + random_factor), settings_->draw_random_press);
|
||||
return math::max(randomized_radius, 0.0f);
|
||||
}
|
||||
|
||||
float randomize_opacity(PaintOperation &self,
|
||||
const float distance,
|
||||
const float opacity,
|
||||
const float pressure)
|
||||
{
|
||||
if (!use_settings_random_ || !(settings_->draw_random_strength > 0.0f)) {
|
||||
return opacity;
|
||||
}
|
||||
float random_factor = 0.0f;
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_STRENGTH_AT_STROKE) == 0) {
|
||||
/* TODO: This should be exposed as a setting to scale the noise along the stroke. */
|
||||
constexpr float noise_scale = 1 / 20.0f;
|
||||
random_factor = noise::perlin_signed(
|
||||
float2(distance * noise_scale, self.stroke_random_opacity_factor_));
|
||||
}
|
||||
else {
|
||||
random_factor = self.stroke_random_opacity_factor_;
|
||||
}
|
||||
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_STRENGTH_RAND_PRESS) != 0) {
|
||||
random_factor *= BKE_curvemapping_evaluateF(settings_->curve_rand_strength, 0, pressure);
|
||||
}
|
||||
|
||||
const float randomized_opacity = math::interpolate(
|
||||
opacity, opacity + random_factor, settings_->draw_random_strength);
|
||||
return math::clamp(randomized_opacity, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
float randomize_rotation(PaintOperation &self, const float pressure)
|
||||
{
|
||||
if (!use_settings_random_ || !(settings_->uv_random > 0.0f)) {
|
||||
return 0.0f;
|
||||
}
|
||||
float random_factor = 0.0f;
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) {
|
||||
random_factor = self.rng_.get_float() * 2.0f - 1.0f;
|
||||
}
|
||||
else {
|
||||
random_factor = self.stroke_random_rotation_factor_;
|
||||
}
|
||||
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_UV_RAND_PRESS) != 0) {
|
||||
random_factor *= BKE_curvemapping_evaluateF(settings_->curve_rand_uv, 0, pressure);
|
||||
}
|
||||
|
||||
const float random_rotation = random_factor * math::numbers::pi;
|
||||
return math::interpolate(0.0f, random_rotation, settings_->uv_random);
|
||||
}
|
||||
|
||||
ColorGeometry4f randomize_color(PaintOperation &self,
|
||||
const float distance,
|
||||
const ColorGeometry4f color,
|
||||
const float pressure)
|
||||
{
|
||||
if (!use_settings_random_ ||
|
||||
!(settings_->random_hue > 0.0f || settings_->random_saturation > 0.0f ||
|
||||
settings_->random_value > 0.0f))
|
||||
{
|
||||
return color;
|
||||
}
|
||||
/* TODO: This should be exposed as a setting to scale the noise along the stroke. */
|
||||
constexpr float noise_scale = 1 / 20.0f;
|
||||
|
||||
float random_hue = 0.0f;
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_HUE_AT_STROKE) == 0) {
|
||||
random_hue = noise::perlin_signed(
|
||||
float2(distance * noise_scale, self.stroke_random_hue_factor_));
|
||||
}
|
||||
else {
|
||||
random_hue = self.stroke_random_hue_factor_;
|
||||
}
|
||||
|
||||
float random_saturation = 0.0f;
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_SAT_AT_STROKE) == 0) {
|
||||
random_saturation = noise::perlin_signed(
|
||||
float2(distance * noise_scale, self.stroke_random_sat_factor_));
|
||||
}
|
||||
else {
|
||||
random_saturation = self.stroke_random_sat_factor_;
|
||||
}
|
||||
|
||||
float random_value = 0.0f;
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_VAL_AT_STROKE) == 0) {
|
||||
random_value = noise::perlin_signed(
|
||||
float2(distance * noise_scale, self.stroke_random_val_factor_));
|
||||
}
|
||||
else {
|
||||
random_value = self.stroke_random_val_factor_;
|
||||
}
|
||||
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_HUE_RAND_PRESS) != 0) {
|
||||
random_hue *= BKE_curvemapping_evaluateF(settings_->curve_rand_hue, 0, pressure);
|
||||
}
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_SAT_RAND_PRESS) != 0) {
|
||||
random_saturation *= BKE_curvemapping_evaluateF(
|
||||
settings_->curve_rand_saturation, 0, pressure);
|
||||
}
|
||||
if ((settings_->flag2 & GP_BRUSH_USE_VAL_RAND_PRESS) != 0) {
|
||||
random_value *= BKE_curvemapping_evaluateF(settings_->curve_rand_value, 0, pressure);
|
||||
}
|
||||
|
||||
float3 hsv;
|
||||
rgb_to_hsv_v(color, hsv);
|
||||
|
||||
hsv += float3(random_hue * settings_->random_hue,
|
||||
random_saturation * settings_->random_saturation,
|
||||
random_value * settings_->random_value);
|
||||
|
||||
/* Wrap hue. */
|
||||
if (hsv[0] > 1.0f) {
|
||||
hsv[0] -= 1.0f;
|
||||
}
|
||||
else if (hsv[0] < 0.0f) {
|
||||
hsv[0] += 1.0f;
|
||||
}
|
||||
|
||||
hsv[1] = math::clamp(hsv[1], 0.0f, 1.0f);
|
||||
hsv[2] = math::clamp(hsv[2], 0.0f, 1.0f);
|
||||
|
||||
ColorGeometry4f random_color;
|
||||
hsv_to_rgb_v(hsv, random_color);
|
||||
random_color.a = color.a;
|
||||
return random_color;
|
||||
}
|
||||
|
||||
void process_start_sample(PaintOperation &self,
|
||||
const bContext &C,
|
||||
const InputSample &start_sample,
|
||||
@@ -442,18 +289,30 @@ struct PaintOperationExecutor {
|
||||
start_location,
|
||||
self.placement_.to_world_space(),
|
||||
settings_);
|
||||
start_radius = randomize_radius(self, 0.0f, start_radius, start_sample.pressure);
|
||||
start_radius = ed::greasepencil::randomize_radius(
|
||||
*settings_, self.stroke_random_radius_factor_, 0.0f, start_radius, start_sample.pressure);
|
||||
|
||||
float start_opacity = ed::greasepencil::opacity_from_input_sample(
|
||||
start_sample.pressure, brush_, settings_);
|
||||
start_opacity = randomize_opacity(self, 0.0f, start_opacity, start_sample.pressure);
|
||||
start_opacity = ed::greasepencil::randomize_opacity(*settings_,
|
||||
self.stroke_random_opacity_factor_,
|
||||
0.0f,
|
||||
start_opacity,
|
||||
start_sample.pressure);
|
||||
|
||||
/* Do not allow pressure opacity when drawing tool was invoked temporarily. */
|
||||
const float fill_opacity = (!self.temp_draw_) ? start_opacity : 1.0f;
|
||||
|
||||
const float start_rotation = randomize_rotation(self, start_sample.pressure);
|
||||
const float start_rotation = ed::greasepencil::randomize_rotation(
|
||||
*settings_, self.rng_, self.stroke_random_rotation_factor_, start_sample.pressure);
|
||||
if (use_vertex_color_) {
|
||||
vertex_color_ = randomize_color(self, 0.0f, vertex_color_, start_sample.pressure);
|
||||
vertex_color_ = ed::greasepencil::randomize_color(*settings_,
|
||||
self.stroke_random_hue_factor_,
|
||||
self.stroke_random_sat_factor_,
|
||||
self.stroke_random_val_factor_,
|
||||
0.0f,
|
||||
vertex_color_,
|
||||
start_sample.pressure);
|
||||
}
|
||||
|
||||
Scene *scene = CTX_data_scene(&C);
|
||||
@@ -825,11 +684,18 @@ struct PaintOperationExecutor {
|
||||
curves.positions_for_write()[last_active_point] = position;
|
||||
}
|
||||
if (use_settings_random_ && settings_->draw_random_press > 0.0f) {
|
||||
radius = randomize_radius(self, self.accum_distance_, radius, extension_sample.pressure);
|
||||
radius = ed::greasepencil::randomize_radius(*settings_,
|
||||
self.stroke_random_radius_factor_,
|
||||
self.accum_distance_,
|
||||
radius,
|
||||
extension_sample.pressure);
|
||||
}
|
||||
if (use_settings_random_ && settings_->draw_random_strength > 0.0f) {
|
||||
opacity = randomize_opacity(
|
||||
self, self.accum_distance_, opacity, extension_sample.pressure);
|
||||
opacity = ed::greasepencil::randomize_opacity(*settings_,
|
||||
self.stroke_random_opacity_factor_,
|
||||
self.accum_distance_,
|
||||
opacity,
|
||||
extension_sample.pressure);
|
||||
}
|
||||
drawing_->radii_for_write()[last_active_point] = math::max(radius, prev_radius);
|
||||
drawing_->opacities_for_write()[last_active_point] = math::max(opacity, prev_opacity);
|
||||
@@ -872,8 +738,12 @@ struct PaintOperationExecutor {
|
||||
/* Randomize radii. */
|
||||
if (use_settings_random_ && settings_->draw_random_press > 0.0f) {
|
||||
for (const int i : IndexRange(new_points_num)) {
|
||||
new_radii[i] = randomize_radius(
|
||||
self, self.accum_distance_ + max_spacing_px * i, radius, extension_sample.pressure);
|
||||
new_radii[i] = ed::greasepencil::randomize_radius(*settings_,
|
||||
self.stroke_random_radius_factor_,
|
||||
self.accum_distance_ +
|
||||
max_spacing_px * i,
|
||||
radius,
|
||||
extension_sample.pressure);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -883,8 +753,12 @@ struct PaintOperationExecutor {
|
||||
/* Randomize opacities. */
|
||||
if (use_settings_random_ && settings_->draw_random_strength > 0.0f) {
|
||||
for (const int i : IndexRange(new_points_num)) {
|
||||
new_opacities[i] = randomize_opacity(
|
||||
self, self.accum_distance_ + max_spacing_px * i, opacity, extension_sample.pressure);
|
||||
new_opacities[i] = ed::greasepencil::randomize_opacity(*settings_,
|
||||
self.stroke_random_opacity_factor_,
|
||||
self.accum_distance_ +
|
||||
max_spacing_px * i,
|
||||
opacity,
|
||||
extension_sample.pressure);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -898,7 +772,11 @@ struct PaintOperationExecutor {
|
||||
{
|
||||
const MutableSpan<float> new_rotations = rotations.span.slice(new_points);
|
||||
for (const int i : IndexRange(new_points_num)) {
|
||||
new_rotations[i] = randomize_rotation(self, extension_sample.pressure);
|
||||
new_rotations[i] = ed::greasepencil::randomize_rotation(
|
||||
*settings_,
|
||||
self.rng_,
|
||||
self.stroke_random_rotation_factor_,
|
||||
extension_sample.pressure);
|
||||
}
|
||||
point_attributes_to_skip.add("rotation");
|
||||
rotations.finish();
|
||||
@@ -911,10 +789,14 @@ struct PaintOperationExecutor {
|
||||
new_points);
|
||||
if (use_settings_random_ || attributes.contains("vertex_color")) {
|
||||
for (const int i : IndexRange(new_points_num)) {
|
||||
new_vertex_colors[i] = randomize_color(self,
|
||||
self.accum_distance_ + max_spacing_px * i,
|
||||
vertex_color_,
|
||||
extension_sample.pressure);
|
||||
new_vertex_colors[i] = ed::greasepencil::randomize_color(*settings_,
|
||||
self.stroke_random_hue_factor_,
|
||||
self.stroke_random_sat_factor_,
|
||||
self.stroke_random_val_factor_,
|
||||
self.accum_distance_ +
|
||||
max_spacing_px * i,
|
||||
vertex_color_,
|
||||
extension_sample.pressure);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1570,6 +1570,27 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* Handles shift-key active smooth toggling during a grease pencil stroke. */
|
||||
if (mode == PaintMode::GPencil) {
|
||||
if (event->modifier & KM_SHIFT) {
|
||||
stroke->stroke_mode = BRUSH_STROKE_SMOOTH;
|
||||
if (!stroke->stroke_cursor) {
|
||||
stroke->stroke_cursor = WM_paint_cursor_activate(SPACE_TYPE_ANY,
|
||||
RGN_TYPE_ANY,
|
||||
paint_brush_cursor_poll,
|
||||
paint_draw_smooth_cursor,
|
||||
stroke);
|
||||
}
|
||||
}
|
||||
else {
|
||||
stroke->stroke_mode = BRUSH_STROKE_NORMAL;
|
||||
if (stroke->stroke_cursor != nullptr) {
|
||||
WM_paint_cursor_end(static_cast<wmPaintCursor *>(stroke->stroke_cursor));
|
||||
stroke->stroke_cursor = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float2 mouse;
|
||||
if (event->type == stroke->event_type && !first_modal) {
|
||||
if (event->val == KM_RELEASE) {
|
||||
|
||||
Reference in New Issue
Block a user