Animation: Graph Editor curve drawing performance improvement #110301

Merged
Christoph Lendenfeld merged 18 commits from ChrisLend/blender:graph_draw_performance into main 2023-08-03 14:43:29 +02:00

In current blender, when drawing curves in the Graph Editor,
it always iterates over the whole curve.
From first to last vertex no matter what is shown on screen.
Instead of that, find the bounding keyframes and iterate within them.

Additionally to that, break apart the logic into two sections

  • first iterate over keyframes and add float2 into a Vector
  • then iterate over all those points and draw them

The second optimization is to make the Bezier resolution
dependent on the keyframe distance in screenspace.
Previously it just went off the distance between keys in frames,
but that doesn't make sense if you are zoomed out.

Performance Numbers

The following performance numbers are the
average time per curve on a mocap file of 6000f (each frame has a key).
The numbers were generated without showing keyframes to only focus
on the performance of this patch.
Also they are from a debug build, so they just make sense relative to each other

- before after
zoomed in ~1000μs ~77μs
zoomed out ~1000μs ~430μs

This only affects the actual curves.
Keyframe and handle drawing can likely still be improved


Future improvement ideas

  • currently there are two drawing functions, draw_fcurve_curve_bezts and draw_fcurve_curve. That is because the former doesn't deal with all key types currently, so the latter is called which samples the fcurve. But I think we can implement a fallback in draw_fcurve_curve_bezts that uses samples if needed. Then we'd save a check that potentially iterates the whole fcurve: fcurve_can_use_simple_bezt_drawing

Video Demo

In current blender, when drawing curves in the Graph Editor, it always iterates over the whole curve. From first to last vertex no matter what is shown on screen. Instead of that, find the bounding keyframes and iterate within them. Additionally to that, break apart the logic into two sections * first iterate over keyframes and add `float2` into a `Vector` * then iterate over all those points and draw them The second optimization is to make the Bezier resolution dependent on the keyframe distance in screenspace. Previously it just went off the distance between keys in frames, but that doesn't make sense if you are zoomed out. ## Performance Numbers The following performance numbers are the average time **per curve** on a mocap file of 6000f (each frame has a key). The numbers were generated **without** showing keyframes to only focus on the performance of this patch. Also they are from a debug build, so they just make sense relative to each other | - | before | after | | - | - | - | | zoomed in | ~1000μs | ~77μs | | zoomed out | ~1000μs | ~430μs | This only affects the actual curves. Keyframe and handle drawing can likely still be improved --------------------- Future improvement ideas * currently there are two drawing functions, `draw_fcurve_curve_bezts` and `draw_fcurve_curve`. That is because the former doesn't deal with all key types currently, so the latter is called which samples the fcurve. But I think we can implement a fallback in `draw_fcurve_curve_bezts` that uses samples if needed. Then we'd save a check that potentially iterates the whole fcurve: `fcurve_can_use_simple_bezt_drawing` ## Video Demo <video src="/attachments/52453f35-e3ad-493f-92e0-de979bf0ec42" title="Graph Editor Curve Drawing Speed" controls></video>
Christoph Lendenfeld added the
Module
Animation & Rigging
label 2023-07-20 14:43:27 +02:00
Christoph Lendenfeld added 2 commits 2023-07-20 14:43:38 +02:00
Christoph Lendenfeld added 2 commits 2023-07-20 17:51:17 +02:00
Christoph Lendenfeld added 1 commit 2023-07-20 17:59:44 +02:00
Christoph Lendenfeld changed title from WIP: Animation: Graph Editor draw performance improvement to WIP: Animation: Graph Editor curve drawing performance improvement 2023-07-20 18:00:24 +02:00
Christoph Lendenfeld added 3 commits 2023-07-21 12:32:15 +02:00
Christoph Lendenfeld changed title from WIP: Animation: Graph Editor curve drawing performance improvement to Animation: Graph Editor curve drawing performance improvement 2023-07-21 15:35:34 +02:00
Christoph Lendenfeld requested review from Sybren A. Stüvel 2023-07-21 15:36:01 +02:00
Christoph Lendenfeld added this to the Animation & Rigging project 2023-07-21 15:36:05 +02:00
Christoph Lendenfeld added 1 commit 2023-07-21 16:13:34 +02:00
Christoph Lendenfeld added 1 commit 2023-07-21 16:54:31 +02:00
Sybren A. Stüvel requested changes 2023-07-24 12:01:37 +02:00
Sybren A. Stüvel left a comment
Member

Nice work!

There's something going wrong with the 'Hello, my name is Amy' scene though:

Before After
image image
Nice work! There's something going wrong with the ['Hello, my name is Amy' scene](https://studio.blender.org/characters/5f1ed640e9115ed35ea4b3fb/showcase/1/) though: | Before | After | | --- | --- | | ![image](/attachments/c44226ec-a034-47cc-a179-23155b71a146) | ![image](/attachments/36153829-7c72-4605-b7c1-cc51a2bbb047) |
@ -876,0 +868,4 @@
const int resolution_x = (int)((bezt->vec[1][0] - prevbezt->vec[1][0]) * resolution_scale[0]);
const int resolution_y = (int)(fabs(bezt->vec[1][1] - prevbezt->vec[1][1]) *
resolution_scale[1]);
return resolution_x + resolution_y;

What's the idea behind adding the two together? Would be good to have a comment that explains.

What's the idea behind adding the two together? Would be good to have a comment that explains.
Member

I think it might make sense to do this differently anyway. In particular, this doesn't take into account the handles of the f-curve segment. For example, you could have two keys that are very close together, but with handles that extend very far vertically, creating a tall narrow hump (like in this image). Drawing that accurately requires a lot more resolution than just the key frame distance would suggest.

I think the simplest robust thing to do would be to take the bounding box of the segment's four control points (i.e. the keys and inner handles) and base the resolution on the maximum dimension of that bounding box in viewport space.

I also suspect we'll want to keep a maximum resolution, and maybe add a minimum resolution. But they can probably just be hard-coded rather than being a parameter.

The maximum resolution is useful because in practice beyond a certain number of samples you're very unlikely to visually approximate the cubic curve any better at any "reasonable" scale. And it would help prevent unexpected performance drops when a really long/tall segment just barely peeks into the viewport range. Blender's 3d bezier curves cap the resolution at a maximum of 1024, so maybe use the same here. Although probably just 256 or even 128 would be reasonable.

The minimum resolution could be as low as 2 points, just to avoid accidentally doing something degenerate. But I think 4 points is a good default, since that way it can always at least reflect the possible points of inflection of the cubic curve.

I think it might make sense to do this differently anyway. In particular, this doesn't take into account the handles of the f-curve segment. For example, you could have two keys that are very close together, but with handles that extend very far vertically, creating a tall narrow hump (like in [this image](https://perm.cessen.com/2023/blender_dev/tall_curve.jpg)). Drawing that accurately requires a lot more resolution than just the key frame distance would suggest. I think the simplest robust thing to do would be to take the bounding box of the segment's four control points (i.e. the keys and inner handles) and base the resolution on the maximum dimension of that bounding box in viewport space. ~~I also suspect we'll want to keep a maximum resolution, and maybe add a minimum resolution. But they can probably just be hard-coded rather than being a parameter.~~ ~~The maximum resolution is useful because in practice beyond a certain number of samples you're very unlikely to visually approximate the cubic curve any better at any "reasonable" scale. And it would help prevent unexpected performance drops when a *really* long/tall segment just barely peeks into the viewport range. Blender's 3d bezier curves cap the resolution at a maximum of 1024, so maybe use the same here. Although probably just 256 or even 128 would be reasonable.~~ ~~The minimum resolution could be as low as 2 points, just to avoid accidentally doing something degenerate. But I think 4 points is a good default, since that way it can always at least reflect the possible points of inflection of the cubic curve.~~
Member

Re: maximums and minimums, never mind. It looks like those are in add_bezt_vertices(), which probably makes more sense.

Re: maximums and minimums, never mind. It looks like those are in `add_bezt_vertices()`, which probably makes more sense.
Author
Member

how about I move the call to calculate_bezt_draw_resolution into add_bezt_vertices
that way it is in the same place as the clamping happens. I would then just pass the float2 resolution_scale to add_bezt_vertices
regarding the bounding box including the handles, good idea. Will add that

how about I move the call to `calculate_bezt_draw_resolution` into `add_bezt_vertices` that way it is in the same place as the clamping happens. I would then just pass the `float2 resolution_scale` to `add_bezt_vertices` regarding the bounding box including the handles, good idea. Will add that
Member

I think I slightly prefer the call being in draw_fcurve_curve_bezts() as it is now. It keeps things a little "flatter" (you aren't chasing functions that call functions that call functions).

But I don't think it matters much either way. In this case, my mis-comment was just me being a goof ball and not reading the whole PR before submitting my comments.

I think I slightly prefer the call being in `draw_fcurve_curve_bezts()` as it is now. It keeps things a little "flatter" (you aren't chasing functions that call functions that call functions). But I don't think it matters much either way. In this case, my mis-comment was just me being a goof ball and not reading the whole PR before submitting my comments.
Author
Member

added a comment and included the handles in the calculations

added a comment and included the handles in the calculations
nathanvegdahl marked this conversation as resolved
@ -883,0 +878,4 @@
static void add_bezt_vertices(BezTriple *bezt,
BezTriple *prevbezt,
int resolution,
blender::Vector<blender::float2> &curve_vertices)

Add a comment that explains that the vertices are added to curve_vertices.

Add a comment that explains that the vertices are added to `curve_vertices`.
ChrisLend marked this conversation as resolved
@ -894,0 +892,4 @@
float prev_key[2], prev_handle[2], bez_handle[2], bez_key[2];
/* Allocation needs +1 on resolution because BKE_curve_forward_diff_bezier uses it to iterate
* inclusively. */
float *data = static_cast<float *>(

What is data?

What is `data`?
Author
Member

I kept the name from how it was previously
but good point. very non telling name. changed it

I kept the name from how it was previously but good point. very non telling name. changed it
nathanvegdahl marked this conversation as resolved
@ -919,0 +939,4 @@
return {first, last};
}
static void get_extrapolation_point_left(FCurve *fcu,

This is already much of an improvement over having this functionality inline as part of some other code. I'm still amazed that this was part of the drawing code, though -- it's likely to be copied into other areas as well. Let's refactor that some other time ;-)

This is already much of an improvement over having this functionality inline as part of some other code. I'm still amazed that this was part of the drawing code, though -- it's likely to be copied into other areas as well. Let's refactor that some other time ;-)
Member

I'm not sure I agree. (I've used a lot of words below, but I don't actually feel strongly about this, so feel free to ignore. I just wanted to present a different point of view in case it's useful.)

If it returned a point + slope pair (or something similar) which could be used for arbitrary evaluation of the extrapolated line then I could see it being used elsewhere (e.g. when evaluating f-curves for animation). And it could certainly make sense to break that part of the code out into a function that can be used elsewhere, to ensure that extrapolation evaluation is consistent everywhere. But as-is this function computes and adds a viewport-bound point to an in-construction list of evaluated f-curve points, which seems pretty narrow in scope and unlikely to be used elsewhere.

As an out-of-context stand-alone function it also left me scratching my head a bit trying to figure out what it was for, and it wasn't until I looked at the call site that its purpose became clear. And similarly, I think if I had started at the call site, I would have needed to come read the code of this function to understand what was happening as well. That could just be me, of course. But to me that's usually a sign to leave something inline (unless you already have another place to use it, at least).

I'm not sure I agree. (I've used a lot of words below, but I don't actually feel strongly about this, so feel free to ignore. I just wanted to present a different point of view in case it's useful.) If it returned a point + slope pair (or something similar) which could be used for arbitrary evaluation of the extrapolated line then I could see it being used elsewhere (e.g. when evaluating f-curves for animation). And it could certainly make sense to break *that* part of the code out into a function that can be used elsewhere, to ensure that extrapolation evaluation is consistent everywhere. But as-is this function computes and adds a viewport-bound point to an in-construction list of evaluated f-curve points, which seems pretty narrow in scope and unlikely to be used elsewhere. As an out-of-context stand-alone function it also left me scratching my head a bit trying to figure out what it was for, and it wasn't until I looked at the call site that its purpose became clear. And similarly, I *think* if I had started at the call site, I would have needed to come read the code of this function to understand what was happening as well. That could just be me, of course. But to me that's usually a sign to leave something inline (unless you already have another place to use it, at least).

@nathanvegdahl I think a big chunk of your confusion comes from C/C++ being old-fasioned, and functions needing either a declaration or their definition before they can be used. This means that often a function is first seen out of context (when reading a file from top to bottom) and only then do you see where it was used in its higher-level context.

Still, IMO it's good to have this code in a separate function.

@nathanvegdahl I think a big chunk of your confusion comes from C/C++ being old-fasioned, and functions needing either a declaration or their definition before they can be used. This means that often a function is first seen out of context (when reading a file from top to bottom) and only then do you see where it was used in its higher-level context. Still, IMO it's good to have this code in a separate function.
Member

That's fair. I think we have a bit different sensibilities here, but that's fine. And as I said, I don't feel strongly about it.

That's fair. I think we have a bit different sensibilities here, but that's fine. And as I said, I don't feel strongly about it.
Author
Member

I think part of the confusion also comes from the fact that the function is called get_extrapolation_point_... but it doesn't actually return anything.
How do you guys feel about returning float2 here?

I think part of the confusion also comes from the fact that the function is called `get_extrapolation_point_...` but it doesn't actually return anything. How do you guys feel about returning `float2` here?
Member

Oh, that's a good point. But rather than changing what they return, I wonder if just changing the names to add_extrapolation_point_left/right would make sense. Then they're consistent with add_bezt_vertices(), which has the same behavior and is used in the same way.

Oh, that's a good point. But rather than changing what they return, I wonder if just changing the names to `add_extrapolation_point_left/right` would make sense. Then they're consistent with `add_bezt_vertices()`, which has the same behavior and is used in the same way.
Member

I have an itchy finger just waiting to hit "approve". 😉 Just waiting on these function renames.

I have an itchy finger just waiting to hit "approve". 😉 Just waiting on these function renames.
Author
Member

done now :)

done now :)
nathanvegdahl marked this conversation as resolved
Nathan Vegdahl reviewed 2023-07-24 17:12:18 +02:00
@ -892,2 +886,4 @@
}
/* If the resolution goes too high the line will not end exactly at the keyframe. Probably due to
* accumulating floating point issues in BKE_curve_forward_diff_bezier.*/
Member

Definitely doesn't need to be part of this PR, but it sounds to me like either using Kahan summation or simply switching to doubles (just for the computations) in the forward differencing code would make sense. Then we won't need to have an arbitrary and (IMO) too-low maximum here.

Definitely doesn't need to be part of this PR, but it sounds to me like either using [Kahan summation](https://en.wikipedia.org/wiki/Kahan_summation_algorithm) or simply switching to doubles (just for the computations) in the forward differencing code would make sense. Then we won't need to have an arbitrary and (IMO) too-low maximum here.
Author
Member

I never heard of Kahan summation before so thanks for pointing that out :)
btw the max resolution is now double than what it was before. Not sure we will ever run into artifacts with it

I never heard of Kahan summation before so thanks for pointing that out :) btw the max resolution is now double than what it was before. Not sure we will ever run into artifacts with it
nathanvegdahl marked this conversation as resolved
Nathan Vegdahl requested changes 2023-07-24 20:45:18 +02:00
Nathan Vegdahl left a comment
Member

Over all this looks great! Just some minor comments, and a suggestion about how to compute curve resolution a bit more robustly.

Over all this looks great! Just some minor comments, and a suggestion about how to compute curve resolution a bit more robustly.
@ -877,4 +873,4 @@
/**
* Draw a segment from `prevbezt` to `bezt` at the given `resolution`.
* #immBeginAtMost is expected to be called with enough space for this function to run.
Member

I believe this note about immBeginAtMost should now be moved to draw_fcurve_curve_bezts(), since this function no longer makes any graphics calls.

(And just generally this doc comment can be updated to reflect what the function actually does now, but Sybren mentioned that already.)

I believe this note about `immBeginAtMost` should now be moved to `draw_fcurve_curve_bezts()`, since this function no longer makes any graphics calls. (And just generally this doc comment can be updated to reflect what the function actually does now, but Sybren mentioned that already.)
Author
Member

good point. updated the comment

good point. updated the comment
nathanvegdahl marked this conversation as resolved
@ -986,3 +1056,2 @@
vertex_position[1] = prevbezt->vec[1][1];
immVertex2fv(pos, vertex_position);
curve_vertices.append({fcu->bezt[0].vec[1][0], fcu->bezt[0].vec[1][1]});
}
Member

Is this redundant with the code in the if (bounding_indices[0] == bounding_indices[1]) block below? Or rather, I think that code handles a superset of this code. If there's only one vertex, then bounding_indices[0] == bounding_indices[1] will be true (I think?) and it will be added there anyway.

Is this redundant with the code in the `if (bounding_indices[0] == bounding_indices[1])` block below? Or rather, I think that code handles a superset of this code. If there's only one vertex, then `bounding_indices[0] == bounding_indices[1]` will be true (I think?) and it will be added there anyway.
Author
Member

actually you are right, removed this if now

actually you are right, removed this if now
nathanvegdahl marked this conversation as resolved
@ -990,0 +1059,4 @@
const int2 bounding_indices = get_bounding_bezt_indices(fcu, v2d->cur.xmin, v2d->cur.xmax);
if (bounding_indices[0] == bounding_indices[1]) {
BezTriple *bezt = &fcu->bezt[bounding_indices[0]];
Member

It took me a bit of thinking to realize the conditions that this handles:

  1. There is only a single vertex in the fcurve.
  2. The curve is completely outside the view (either to the left or right).

Might be worth adding a brief comment mentioning that, so people don't need to puzzle it out.

It took me a bit of thinking to realize the conditions that this handles: 1. There is only a single vertex in the fcurve. 2. The curve is completely outside the view (either to the left or right). Might be worth adding a brief comment mentioning that, so people don't need to puzzle it out.
Author
Member

good idea. done that

good idea. done that
nathanvegdahl marked this conversation as resolved
Christoph Lendenfeld added 6 commits 2023-07-27 11:32:26 +02:00
Author
Member
  • fixed the drawing issue sybren mentioned. I was adding a point using the x value for both x and y...
  • calculate the resolution using the handles. this only applies to the y-resolution because handles can never pass their neighbor key on the x axis
  • remove the if only_one_key since it was already handled by if (bounding_indices[0] == bounding_indices[1])
  • added comments
* fixed the drawing issue sybren mentioned. I was adding a point using the x value for both x and y... * calculate the resolution using the handles. this only applies to the y-resolution because handles can never pass their neighbor key on the x axis * remove the `if only_one_key` since it was already handled by `if (bounding_indices[0] == bounding_indices[1])` * added comments
Christoph Lendenfeld requested review from Sybren A. Stüvel 2023-07-27 11:40:56 +02:00
Christoph Lendenfeld requested review from Nathan Vegdahl 2023-07-27 11:41:00 +02:00
Nathan Vegdahl reviewed 2023-07-27 14:43:46 +02:00
@ -876,0 +875,4 @@
const int resolution_y = (int)((max_y - min_y) * resolution_scale[1]);
/* The resolution should be the distance between the two keys, but to save the square root
* calculation use an approximation by the two values. */
return resolution_x + resolution_y;
Member

I was puzzling if this or max(resolution_x, resolution_y) makes more sense. And I've come to the tentative conclusion that summing is probably not only better than max but actually even better than the square-root (Euclidean) distance calculation.

Basically, the Euclidean distance effectively computes what the resolution would need to be for a straight diagonal line between the corners of the bounding box. But that is frequently very far from the case with bezier curves. Bezier curves will often be bending towards one corner or the other, which actually makes the length of the curve somewhere between the euclidean distance and the simple sum.

In other words, I think the sum isn't even an optimization, it's just being more conservative, which also makes it more correct in a way.

(Incidentally, this kind of sum can be called the Manhattan distance. So you could start the comment with "We use the Manhattan distance rather than Euclidean distance because...". Although I think it's pretty clear either way, so not a big deal.)

This also has me thinking that there are probably further improvements we can make to this metric that would still be pretty cheap to compute. But I think we should land this as-is, and if we feel like it needs further improvements we can do those in a future PR.

I was puzzling if this or `max(resolution_x, resolution_y)` makes more sense. And I've come to the tentative conclusion that summing is probably not only better than max but actually even better than the square-root (Euclidean) distance calculation. Basically, the Euclidean distance effectively computes what the resolution would need to be for a straight diagonal line between the corners of the bounding box. But that is frequently very far from the case with bezier curves. Bezier curves will often be bending towards one corner or the other, which actually makes the length of the curve somewhere between the euclidean distance and the simple sum. In other words, I think the sum isn't even an optimization, it's just being more conservative, which also makes it more correct in a way. (Incidentally, this kind of sum can be called the [Manhattan distance](https://en.wikipedia.org/wiki/Taxicab_geometry). So you could start the comment with "We use the Manhattan distance rather than Euclidean distance because...". Although I think it's pretty clear either way, so not a big deal.) This also has me thinking that there are probably further improvements we can make to this metric that would still be pretty cheap to compute. But I think we should land this as-is, and if we feel like it needs further improvements we can do those in a future PR.
Author
Member

ha I've read Manhattan distance in blenders code before and I didn't know what it was, the name makes so much sense now

I'd actually prefer to not use this specific term just because I wasn't aware of what it meant, and there might be others reading the code that never heard of it either.

I thought about using max() as well, but came to the same conclusion as you.

I'd love to hear of other ways to compute the resolution though :)

ha I've read Manhattan distance in blenders code before and I didn't know what it was, the name makes so much sense now I'd actually prefer to not use this specific term just because I wasn't aware of what it meant, and there might be others reading the code that never heard of it either. I thought about using `max()` as well, but came to the same conclusion as you. I'd love to hear of other ways to compute the resolution though :)
Member

and there might be others reading the code that never heard of it either.

Totally fair! And indeed, you not knowing what it meant is probably a good indication to avoid the math jargon here.

I thought about using max() as well, but came to the same conclusion as you.

Makes sense! I think it would be good to change the comment to explain that the simple sum is actually a better metric, then. Right now the comment makes it sound like it's just to avoid the sqrt at the expense of accuracy.

> and there might be others reading the code that never heard of it either. Totally fair! And indeed, you not knowing what it meant is probably a good indication to avoid the math jargon here. > I thought about using max() as well, but came to the same conclusion as you. Makes sense! I think it would be good to change the comment to explain that the simple sum is actually a better metric, then. Right now the comment makes it sound like it's just to avoid the sqrt at the expense of accuracy.
nathanvegdahl marked this conversation as resolved
Christoph Lendenfeld added 1 commit 2023-07-27 15:52:30 +02:00
Christoph Lendenfeld added 1 commit 2023-08-01 11:05:34 +02:00
Nathan Vegdahl approved these changes 2023-08-01 11:17:50 +02:00
Nathan Vegdahl left a comment
Member

Looks good to me!

Looks good to me!
Christoph Lendenfeld merged commit 0d7b0045c6 into main 2023-08-03 14:43:29 +02:00
Christoph Lendenfeld deleted branch graph_draw_performance 2023-08-03 14:43:30 +02:00
Sign in to join this conversation.
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 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#110301
No description provided.