Fix #134606: Grease Pencil: Randomization of attributes in primitive tools
Primitive tools were not using the brush randomization options. This moves the randomization functions into the editor utilities for Grease Pencil and enables primitive curve generation to use them. Pull Request: https://projects.blender.org/blender/blender/pulls/135454
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,
|
||||
@@ -936,4 +937,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
|
||||
|
||||
@@ -257,159 +257,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,
|
||||
@@ -441,18 +288,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);
|
||||
@@ -824,11 +683,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);
|
||||
@@ -871,8 +737,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 {
|
||||
@@ -882,8 +752,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 {
|
||||
@@ -897,7 +771,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();
|
||||
@@ -910,10 +788,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 {
|
||||
|
||||
Reference in New Issue
Block a user