GPv3: Initial drawing tool #110093

Merged
Falk David merged 78 commits from filedescriptor/blender:gpv3-drawing-operator into main 2023-10-06 10:50:04 +02:00
Member

This PR implements an initial drawing tool with the following implemented features:

  • Pressure support for radius and opacity.
  • Material color and vertex color support
  • Active smoothing algorithm
  • Simplify algorithm as a post-process step

It also changes some things in the UI to make the drawing process more usable.

How to use it:
You will need to download a build and the startup file. Make sure to enable Grease Pencil v3 Preferences > Interface > check Developer Extras, then Experimental > check Grease Pencil 3.0. Restart Blender.

This PR implements an initial drawing tool with the following implemented features: * Pressure support for radius and opacity. * Material color and vertex color support * Active smoothing algorithm * Simplify algorithm as a post-process step It also changes some things in the UI to make the drawing process more usable. How to use it: You will need to [download a build](https://builder.blender.org/download/patch/PR110093) and the [startup file](https://projects.blender.org/attachments/d7eb3be0-fd3e-4e4d-b4ba-fcb66705f5b9). Make sure to enable Grease Pencil v3 `Preferences` > `Interface` > check `Developer Extras`, then `Experimental` > check `Grease Pencil 3.0`. Restart Blender.
Falk David added this to the Grease Pencil project 2023-07-14 11:09:18 +02:00
Falk David force-pushed gpv3-drawing-operator from add144c6f0 to 9dde8af4c7 2023-07-14 11:17:59 +02:00 Compare
Falk David force-pushed gpv3-drawing-operator from bfbc6c47c5 to de42110dd4 2023-07-18 14:09:39 +02:00 Compare
Falk David force-pushed gpv3-drawing-operator from fec6f4ee8f to 1064dd03bd 2023-07-20 15:34:24 +02:00 Compare
Falk David force-pushed gpv3-drawing-operator from 1064dd03bd to bdc3a95341 2023-07-21 16:25:37 +02:00 Compare
Author
Member

@blender-bot package

@blender-bot package
Member

Package build started. Download here when ready.

Package build started. [Download here](https://builder.blender.org/download/patch/PR110093) when ready.
Falk David force-pushed gpv3-drawing-operator from 4100146739 to cc2175f63e 2023-07-24 12:58:51 +02:00 Compare
Author
Member

@blender-bot package

@blender-bot package
Member

Package build started. Download here when ready.

Package build started. [Download here](https://builder.blender.org/download/patch/PR110093) when ready.
Author
Member

Test file: startup_gpv3.blend

Test file: [startup_gpv3.blend](/attachments/d7eb3be0-fd3e-4e4d-b4ba-fcb66705f5b9)
Falk David changed title from WIP: GPv3: Initial drawing tool to GPv3: Initial drawing tool 2023-07-24 14:08:53 +02:00
Author
Member

@blender-bot package

@blender-bot package
Member

Package build started. Download here when ready.

Package build started. [Download here](https://builder.blender.org/download/patch/PR110093) when ready.
Falk David force-pushed gpv3-drawing-operator from 0ad79de634 to d21034c364 2023-08-01 15:51:42 +02:00 Compare
Falk David force-pushed gpv3-drawing-operator from d21034c364 to ff5cebbb56 2023-08-02 18:10:05 +02:00 Compare
Falk David force-pushed gpv3-drawing-operator from ff5cebbb56 to 73e2248c5d 2023-08-03 15:43:56 +02:00 Compare
Falk David force-pushed gpv3-drawing-operator from cfa0ae0629 to c7eaddbf48 2023-08-07 13:45:23 +02:00 Compare
Author
Member

@blender-bot package

@blender-bot package
Member

Package build started. Download here when ready.

Package build started. [Download here](https://builder.blender.org/download/patch/PR110093) when ready.
Author
Member

@blender-bot package

@blender-bot package
Member

Package build started. Download here when ready.

Package build started. [Download here](https://builder.blender.org/download/patch/PR110093) when ready.
Falk David force-pushed gpv3-drawing-operator from 7471e25306 to 3d79364b22 2023-08-07 16:27:13 +02:00 Compare
Author
Member

@blender-bot package

@blender-bot package
Member

Package build started. Download here when ready.

Package build started. [Download here](https://builder.blender.org/download/patch/PR110093) when ready.
Falk David force-pushed gpv3-drawing-operator from 5831301dda to d9e759b26a 2023-08-08 12:59:11 +02:00 Compare
Falk David force-pushed gpv3-drawing-operator from d9e759b26a to 27ea06c1a8 2023-08-08 16:48:46 +02:00 Compare
Hans Goudey requested changes 2023-08-09 07:53:33 +02:00
Hans Goudey left a comment
Member

I wasn't so thorough this time, but here are some high level comments:

  • Overall approach seems reasonable
  • StrokeCache seems redundant-- just storing this as a CurvesGeometry would be simpler and would make code more generic and easier to extend in the future
  • There's existing code in blender::length_parameterize that looks similar to some of the stuff here and is hopefully reusable.
  • It would be nice to have an overview of why the various smoothing/simplifying passes are done on the output, and a comparison to other methods (or mention future improvements too, I noticed discussion of drawing speed in chat).
  • Some changes like adding cursor drawing could probably be split to separate commits?
I wasn't so thorough this time, but here are some high level comments: - Overall approach seems reasonable - `StrokeCache` seems redundant-- just storing this as a `CurvesGeometry` would be simpler and would make code more generic and easier to extend in the future - There's existing code in `blender::length_parameterize` that looks similar to some of the stuff here and is hopefully reusable. - It would be nice to have an overview of _why_ the various smoothing/simplifying passes are done on the output, and a comparison to other methods (or mention future improvements too, I noticed discussion of drawing speed in chat). - Some changes like adding cursor drawing could probably be split to separate commits?
@ -476,0 +475,4 @@
[positions, radii](int64_t first_index, int64_t last_index, int64_t index) {
const float dist_position = dist_to_line_v3(
positions[index], positions[first_index], positions[last_index]);
/* We devide the distance by 2000.0f to convert from "pixels" to an actual distance.
Member
  • devide -> divide
  • storkes -> strokes?
- `devide` -> `divide` - `storkes` -> `strokes`?
filedescriptor marked this conversation as resolved
@ -0,0 +28,4 @@
if (align_flag & GP_PROJECT_CURSOR) {
return float3(scene->cursor.location);
}
else {
Member

else after return

else after return
filedescriptor marked this conversation as resolved
@ -0,0 +62,4 @@
/* Use an (arbitrary) screen space offset in the x direction to measure the size. */
const int x_offest = 64;
const float brush_size = static_cast<float>(BKE_brush_size_get(scene, brush));
Member

static_cast<float>(...) -> float(...)

`static_cast<float>(...)` -> `float(...)`
filedescriptor marked this conversation as resolved
@ -128,0 +146,4 @@
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
return OPERATOR_CANCELLED;
}
else {
Member

else after return

else after return
filedescriptor marked this conversation as resolved
@ -22,0 +30,4 @@
static constexpr int64_t STOKE_CACHE_ALLOCATION_CHUNK_SIZE = 1024;
/** Forward differencing of a bezier curve segment (q0,q1,q2,q3). Steps are written to \a r_p.
Member

Rather than re-implementing this, it probably makes sense to make bke::curves::evaluate_segment into a template and add explicit instantiations of the float2 and float3 types in the cc file.

Rather than re-implementing this, it probably makes sense to make `bke::curves::evaluate_segment` into a template and add explicit instantiations of the float2 and float3 types in the cc file.
filedescriptor marked this conversation as resolved
@ -22,0 +76,4 @@
}
return points;
}
Member

Didn't have a ton of time to dig into this function, but on the surface it looks like it has the same goal as the code in blender::length_parameterize. If so, I'd really hope that could be reused, since this stuff is pretty fiddly, especially with floating point error (though it looks like you're doing a good job dealing with that here :)

Didn't have a ton of time to dig into this function, but on the surface it looks like it has the same goal as the code in `blender::length_parameterize`. If so, I'd really hope that could be reused, since this stuff is pretty fiddly, especially with floating point error (though it looks like you're doing a good job dealing with that here :)
filedescriptor marked this conversation as resolved
@ -58,0 +255,4 @@
const float max_radius_px = 30.0f;
const int64_t max_samples = 64;
const float angle_threshold = 0.6f;
IndexMask corner_mask = blender::ed::greasepencil::polyline_detect_corners(
Member

Unnecessary blender::?

Unnecessary `blender::`?
filedescriptor marked this conversation as resolved
Falk David force-pushed gpv3-drawing-operator from 27ea06c1a8 to 30dd25aefa 2023-08-09 14:55:03 +02:00 Compare
Falk David force-pushed gpv3-drawing-operator from 08caa165e8 to 1508ad175b 2023-08-09 16:59:02 +02:00 Compare
Author
Member

@HooglyBoogly About switching to use CurvesGeometry. I somewhat agree, and I already started a refactor for this. But here are some pain-points:

  • We will need to resize the stroke_buffer on every drawing update. I was planning on reducing the number of reallocations by using blender::Vector::reserve to reserve memory beforehand (say 1024 elements). Ideally, for smaller strokes, we don't need to reallocate ever. I'm not sure how this will work with curves.resize and calling that every update.
  • Using the attributes API for some of the refactor has been a pain. Like simply getting the previous point. Working with VArrays all the time makes the code much less readable IMHO.
@HooglyBoogly About switching to use `CurvesGeometry`. I somewhat agree, and I already started a refactor for this. But here are some pain-points: * We will need to resize the `stroke_buffer` on every drawing update. I was planning on reducing the number of reallocations by using `blender::Vector::reserve` to reserve memory beforehand (say 1024 elements). Ideally, for smaller strokes, we don't need to reallocate ever. I'm not sure how this will work with `curves.resize` and calling that every update. * Using the attributes API for some of the refactor has been a pain. Like simply getting the previous point. Working with `VArrays` all the time makes the code much less readable IMHO.
Falk David force-pushed gpv3-drawing-operator from 1508ad175b to 04826e6917 2023-08-16 17:01:09 +02:00 Compare
Falk David force-pushed gpv3-drawing-operator from 04826e6917 to b4891dba8a 2023-09-13 16:18:25 +02:00 Compare
Falk David added 1 commit 2023-09-13 16:20:34 +02:00
Member

I think I'd still push for using CurvesGeometry here, instead of another data structure. I think the future benefits of treating the currently drawn stroke as just another curves (drawing, geometry processing, etc) will make it worth it. To address the points you brought up:

  • Resizing: Theoretically we could add a "capacity" to curves-- that would be stored in runtime data, and could skip reallocating customdata if possible. That should have minimal interaction with everything else. But I'm guessing it wouldn't make a big difference unless people are drawing very long strokes-- we're not dealing with that much data
  • Attribute API: I guess I'd have to see it to make some suggestsions, but I feel like there would be ways to address this.
I think I'd still push for using `CurvesGeometry` here, instead of another data structure. I think the future benefits of treating the currently drawn stroke as just another curves (drawing, geometry processing, etc) will make it worth it. To address the points you brought up: - Resizing: Theoretically we could add a "capacity" to curves-- that would be stored in runtime data, and could skip reallocating customdata if possible. That should have minimal interaction with everything else. But I'm guessing it wouldn't make a big difference unless people are drawing very long strokes-- we're not dealing with that much data - Attribute API: I guess I'd have to see it to make some suggestsions, but I feel like there would be ways to address this.
Author
Member

I haven't gotten back to refactoring this. Something else that I thought of yesterday is that it would be nice if we could do depsgraph updates while drawing. This would be slower and not really useful for normal drawing (just grease pencil), but if there are modifiers.
E.g. if there is some custom geo nodes curves->mesh "brush" then you wouldn't get live interaction at the moment, the result would pop up after the stroke is done.
I'd like to experiment with a "live" mode. But for that especially it would be nice to have some capacity on the CurvesGeometry. Since copying all of it everytime a new point is added would be very slow I presume.

I haven't gotten back to refactoring this. Something else that I thought of yesterday is that it would be nice if we could do depsgraph updates while drawing. This would be slower and not really useful for normal drawing (just grease pencil), but if there are modifiers. E.g. if there is some custom geo nodes curves->mesh "brush" then you wouldn't get live interaction at the moment, the result would pop up after the stroke is done. I'd like to experiment with a "live" mode. But for that especially it would be nice to have some capacity on the `CurvesGeometry`. Since copying all of it everytime a new point is added would be very slow I presume.
Falk David added 1 commit 2023-09-26 16:36:56 +02:00
Falk David added 6 commits 2023-09-29 13:06:11 +02:00
Author
Member

Ok I refactored the code to completely remove StrokeCache and to draw into the CurvesGeometry of the active drawing directly.
This is probably less efficient (not that the previous code was really optimized) but I would prefer to do any optimizations in subsequent PRs.

Ok I refactored the code to completely remove `StrokeCache` and to draw into the `CurvesGeometry` of the active drawing directly. This is probably less efficient (not that the previous code was really optimized) but I would prefer to do any optimizations in subsequent PRs.
Falk David requested review from Hans Goudey 2023-09-29 13:09:43 +02:00
Hans Goudey requested changes 2023-09-29 16:28:24 +02:00
Hans Goudey left a comment
Member

There's definitely room to optimize this, but seems like the main logic is there. My one larger comment is about reusing the existing length parameterization code.

There's definitely room to optimize this, but seems like the main logic is there. My one larger comment is about reusing the existing length parameterization code.
@ -22,0 +42,4 @@
const Span<float2> curve_segments = curve_points.drop_front(1).drop_back(1);
for (const int64_t segment_i : IndexRange(num_segments)) {
IndexRange segment_range(segment_i * resolution, resolution);
bke::curves::bezier::evaluate_segment(curve_segments[segment_i * 3 + 0],
Member

Rather than evaluating a single segment at a time from here, how about giving the whole curve_points span to bke::curves::bezier? That's generally aligned with the goal of that module, to handle more than one thing at a time wherever possible.

Rather than evaluating a single segment at a time from here, how about giving the whole `curve_points` span to `bke::curves::bezier`? That's generally aligned with the goal of that module, to handle more than one thing at a time wherever possible.
Author
Member

If I am not mistaken that module currently only works with float3s.

If I am not mistaken that module currently only works with `float3`s.
Member

Pretty sure you're mistaken :P It's all templated. Even the tests use float2 sometimes.

Pretty sure you're mistaken :P It's all templated. Even the tests use `float2` sometimes.
Author
Member

I just added a threading::parallel_for for now.

I just added a `threading::parallel_for` for now.
filedescriptor marked this conversation as resolved
@ -22,0 +52,4 @@
}
/** Interpolate \a dst such that the points in \a dst lie evenly distributed on \a src. */
static void interp_polyline_to_polyline(Span<float2> src, MutableSpan<float2> dst)
Member

This still looks like it has the same goal as the code in BLI_length_parameterize.hh. I'd really like that to be reused here, this is too much tricky logic to duplicate IMO.

This still looks like it has the same goal as the code in `BLI_length_parameterize.hh`. I'd really like that to be reused here, this is too much tricky logic to duplicate IMO.
filedescriptor marked this conversation as resolved
@ -58,0 +191,4 @@
return proj_point;
}
ScreenSpacePoint point_from_input_sample(const InputSample &sample)
Member

Better not to mix this data together in a single struct IMO. It's clearer if the code is consistent about handling them separately. In practice, the way this function is used, the struct is just immediately unpacked anyway.

Since this code really does have to process just one point at a time, I'd suggest just separating radius, opacity, and colors into separate functions.

Better not to mix this data together in a single struct IMO. It's clearer if the code is consistent about handling them separately. In practice, the way this function is used, the struct is just immediately unpacked anyway. Since this code really does have to process just one point at a time, I'd suggest just separating radius, opacity, and colors into separate functions.
filedescriptor marked this conversation as resolved
@ -65,0 +254,4 @@
const int64_t corner_max_samples = 64;
const float corner_angle_threshold = 0.6f;
IndexMaskMemory memory;
IndexMask corner_mask = ed::greasepencil::polyline_detect_corners(
Member

IndexMask corner_mask -> const IndexMask corner_mask

`IndexMask corner_mask` -> `const IndexMask corner_mask`
filedescriptor marked this conversation as resolved
@ -65,0 +353,4 @@
bke::CurvesGeometry &curves = drawing_->strokes_for_write();
float2 prev_co = self.screen_space_coordinates_.last();
Member

Declare variables const

Declare variables const
filedescriptor marked this conversation as resolved
@ -65,0 +388,4 @@
new_coordinates[i] = bke::attribute_math::mix2<float2>(factor, prev_co, point.co);
new_radii[i] = bke::attribute_math::mix2<float>(factor, prev_radius, point.radius);
new_opacities[i] = bke::attribute_math::mix2<float>(factor, prev_opacity, point.opacity);
new_vertex_colors[i] = bke::attribute_math::mix2<ColorGeometry4f>(
Member

Seems like it would be simpler to mix these directly into the new slice of the attribute.

Seems like it would be simpler to mix these directly into the new slice of the attribute.
filedescriptor marked this conversation as resolved
@ -76,0 +491,4 @@
void PaintOperation::simplify_stroke(bke::greasepencil::Drawing &drawing, const float epsilon_px)
{
const int stroke_index = drawing.strokes().curves_range().last();
const IndexRange points_range = drawing.strokes().points_by_curve()[stroke_index];
Member

points_range -> points (the standard name for this sort of variable)

`points_range` -> `points` (the standard name for this sort of variable)
filedescriptor marked this conversation as resolved
@ -76,0 +498,4 @@
/* Distance function for `ramer_douglas_peucker_simplify`. */
const Span<float2> positions_2d = this->screen_space_smoothed_coordinates_.as_span();
const auto dist_function =
[points_range, positions_2d, radii](int64_t first_index, int64_t last_index, int64_t index) {
Member

Use simple reference capture: [&]. It should amount to the same thing here.

Use simple reference capture: `[&]`. It should amount to the same thing here.
filedescriptor marked this conversation as resolved
@ -76,0 +514,4 @@
return math::max(dist_position_px, dist_radii_px);
};
Array<bool> points_to_delete(curves.points_num(), false);
Member

Feels important not to create arrays that are the size of the entire curves geometry, but it looks like that would require changes to ramer_douglas_peucker_simplify. Could be done later.

Feels important not to create arrays that are the size of the entire curves geometry, but it looks like that would require changes to `ramer_douglas_peucker_simplify`. Could be done later.
@ -76,0 +532,4 @@
/* Remove points at the end that have a radius close to 0. */
int64_t points_to_remove = 0;
for (int64_t index = points_range.last(); index >= points_range.first(); index--) {
if (drawing.radii()[index] < 1e-5f) {
Member

Put the .radii() in a span outside the loop.

Put the `.radii()` in a span outside the loop.
filedescriptor marked this conversation as resolved
Falk David added 7 commits 2023-10-05 11:51:12 +02:00
Falk David added 3 commits 2023-10-05 11:54:06 +02:00
Falk David added 1 commit 2023-10-05 12:13:50 +02:00
Falk David requested review from Hans Goudey 2023-10-05 12:14:29 +02:00
Hans Goudey requested changes 2023-10-05 12:47:44 +02:00
Hans Goudey left a comment
Member

Just some cleanup stuff now.

Just some cleanup stuff now.
@ -0,0 +82,4 @@
{
Array<int32_t> indices(corner_mask.size());
corner_mask.to_indices(indices.as_mutable_span());
uint *indicies_ptr = (corner_mask.size() > 0) ? reinterpret_cast<uint *>(indices.data()) :
Member

uint *indicies_ptr = corner_mask.is_empty() ? nullptr : reinterpret_cast<uint *>(indices.data());

` uint *indicies_ptr = corner_mask.is_empty() ? nullptr : reinterpret_cast<uint *>(indices.data());`
filedescriptor marked this conversation as resolved
@ -0,0 +45,4 @@
float brush_radius_world_space(bContext &C, int x, int y)
{
using namespace blender;
Member

This is unnecessary, the function is already in blender::ed::greasepencil

This is unnecessary, the function is already in `blender::ed::greasepencil`
filedescriptor marked this conversation as resolved
@ -124,2 +126,4 @@
FunctionRef<float(int64_t, int64_t, int64_t)> dist_function,
MutableSpan<bool> dst);
Array<float2> fit_curve_polyline_2d(Span<float2> points,
Member

Suggest renaming these two functions for consistency:

polyline_fit_curve
polyline_detect_corners

Suggest renaming these two functions for consistency: `polyline_fit_curve` `polyline_detect_corners`
filedescriptor marked this conversation as resolved
@ -126,0 +133,4 @@
IndexMask polyline_detect_corners(Span<float2> points,
float radius_min,
float radius_max,
int64_t samples_max,
Member

int64_t -> int?

`int64_t` -> `int`?
filedescriptor marked this conversation as resolved
@ -22,0 +29,4 @@
static constexpr float POINT_OVERRIDE_THRESHOLD_PX = 3.0f;
static constexpr float POINT_RESAMPLE_MIN_DISTANCE_PX = 10.0f;
static constexpr int64_t STOKE_CACHE_ALLOCATION_CHUNK_SIZE = 1024;
Member

STOKE_CACHE_ALLOCATION_CHUNK_SIZE is unused

`STOKE_CACHE_ALLOCATION_CHUNK_SIZE` is unused
filedescriptor marked this conversation as resolved
@ -22,0 +32,4 @@
static constexpr int64_t STOKE_CACHE_ALLOCATION_CHUNK_SIZE = 1024;
/** Sample a bezier curve at a fixed resolution and return the sampled points in an array. */
static Array<float2> sample_curve_2d(Span<float2> curve_points, const int64_t resolution)
Member

I'd suggest:
Span<float2> curve_points -> Span<float2> positions

I'd suggest: `Span<float2> curve_points` -> `Span<float2> positions`
filedescriptor marked this conversation as resolved
@ -22,0 +41,4 @@
Array<float2> points(num_points);
const Span<float2> curve_segments = curve_points.drop_front(1).drop_back(1);
threading::parallel_for(IndexRange(num_segments), 512 * resolution, [&](const IndexRange range) {
Member

512 * 32 is 16k, that's huge, large enough that multithreading will probably never be used. What about 32 * resolution?

512 * 32 is 16k, that's huge, large enough that multithreading will probably never be used. What about `32 * resolution`?
filedescriptor marked this conversation as resolved
@ -65,0 +258,4 @@
Array<float2> coords_smoothed(screen_space_coords_smooth_slice.size());
morph_points_to_curve(screen_space_coords_smooth_slice, sampled_curve_points, coords_smoothed);
MutableSpan<float2> smoothed_coordinates_slice =
Member

I'd suggest consistently abbreviating "coordinates" to "coords"

I'd suggest consistently abbreviating "coordinates" to "coords"
filedescriptor marked this conversation as resolved
@ -65,0 +334,4 @@
int new_points_num = 1;
const float distance_px = math::distance(position, prev_position);
if (distance_px > POINT_RESAMPLE_MIN_DISTANCE_PX) {
const int subdivisions = static_cast<int>(
Member

static_cast<int> -> int(...)

Same for float

`static_cast<int>` -> `int(...)` Same for float
filedescriptor marked this conversation as resolved
@ -65,0 +355,4 @@
const float step = 1.0f / static_cast<float>(new_points_num);
float factor = step;
for (const int64_t i : new_range.index_range()) {
new_screen_space_coordinates[i] = bke::attribute_math::mix2<float2>(
Member

How about copying this from the subdivide curves node?

template<typename T>
static inline void linear_interpolation(const T &a, const T &b, MutableSpan<T> dst)
{
  dst.first() = a;
  const float step = 1.0f / dst.size();
  for (const int i : dst.index_range().drop_front(1)) {
    dst[i] = bke::attribute_math::mix2(i * step, a, b);
  }
}

With the same name reused everywhere it's easy to extract to some common header later on.

How about copying this from the subdivide curves node? ``` template<typename T> static inline void linear_interpolation(const T &a, const T &b, MutableSpan<T> dst) { dst.first() = a; const float step = 1.0f / dst.size(); for (const int i : dst.index_range().drop_front(1)) { dst[i] = bke::attribute_math::mix2(i * step, a, b); } } ``` With the same name reused everywhere it's easy to extract to some common header later on.
filedescriptor marked this conversation as resolved
@ -65,0 +383,4 @@
}
/* Active smoothing is done in a window at the end of the new stroke. */
const IndexRange smooth_window(self.active_smooth_index_,
Member

points.index_range().drop_front(self.active_smooth_index_) maybe?

`points.index_range().drop_front(self.active_smooth_index_)` maybe?
filedescriptor marked this conversation as resolved
@ -125,2 +448,2 @@
SpanAttributeWriter<int> materials = attributes.lookup_or_add_for_write_span<int>(
"material_index", ATTR_DOMAIN_CURVE);
if (dist1 + dist2 > 1e-5f) {
const float interpolated_val = interpf(valB, valA, dist1 / (dist1 + dist2));
Member

math::interpolate

`math::interpolate`
filedescriptor marked this conversation as resolved
Falk David added 1 commit 2023-10-05 15:12:54 +02:00
Falk David requested review from Hans Goudey 2023-10-05 15:14:18 +02:00
Hans Goudey approved these changes 2023-10-06 10:22:37 +02:00
Falk David merged commit 7e87435cf4 into main 2023-10-06 10:50:04 +02:00
Falk David deleted branch gpv3-drawing-operator 2023-10-06 10:50:06 +02:00
Sign in to join this conversation.
No reviewers
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#110093
No description provided.