Animation: Graph Editor - Don't draw curve points if they are too close to each other #110788

Merged
Christoph Lendenfeld merged 15 commits from ChrisLend/blender:graph_reduced_key_drawing into main 2023-09-05 14:18:40 +02:00

When viewing a curve with a lot of keys totally zoomed out,
the keys might be closer to each other than a pixel.
The code would still draw a line between them,
costing time in the draw code.

This PR skips any keys that are too close to each other in screen space.

Performance

The setup: 62 bones with 6000f of animation keyed on every frame. No keys displayed, just the curves.

- before after
zoomed in 11μs 17μs
zoomed out 55μs 30μs

So a small performance penalty when zoomed in in exchange for a big gain when zoomed out.

Visuals

There is a small change in visuals when zoomed out a lot. Because this change averages keys that are too close together, it results in a small loss of high frequency detail. If you look closely in the video you can see the detail appearing when the view is zoomed in.

before after
image image

The logic

If prevbezt and bezt are too close it will not draw, but extend a bounding box with prevbezt and bezt including handles if needed.
Eventually the keys will be far enough apart to draw. At this point, draw the center of the bounding box and reset it.
Now because there could be the case where bezt in the current loop is super far out (e.g 5 keys with 1f spacing and the 6th key is at f1000) we need to recalculate the bounding box again. In case the keys are far away, just draw normally. If it is close still, the same process repeats.

When viewing a curve with a lot of keys totally zoomed out, the keys might be closer to each other than a pixel. The code would still draw a line between them, costing time in the draw code. This PR skips any keys that are too close to each other in screen space. ## Performance The setup: 62 bones with 6000f of animation keyed on every frame. No keys displayed, just the curves. | - | before | after | | - | - | - | | zoomed in | 11μs | 17μs | | zoomed out | 55μs | 30μs | So a small performance penalty when zoomed in in exchange for a big gain when zoomed out. ## Visuals There is a small change in visuals when zoomed out a lot. Because this change averages keys that are too close together, it results in a small loss of high frequency detail. If you look closely in the video you can see the detail appearing when the view is zoomed in. | before | after | | - | - | | ![image](/attachments/5d457bc0-a29f-494e-bf92-63de8b1c5661) |![image](/attachments/508b481b-b9b1-4498-811a-8329cf2dd3e6) | <video src="/attachments/778c43e9-da08-49d2-a209-dceb3f54f2c1" controls></video> ## The logic If `prevbezt` and `bezt` are too close it will not draw, but extend a bounding box with `prevbezt` and `bezt` including handles if needed. Eventually the keys will be far enough apart to draw. At this point, draw the center of the bounding box and reset it. Now because there could be the case where `bezt` in the current loop is super far out (e.g 5 keys with 1f spacing and the 6th key is at f1000) we need to recalculate the bounding box again. In case the keys are far away, just draw normally. If it is close still, the same process repeats.
Christoph Lendenfeld added the
Module
Animation & Rigging
label 2023-08-04 10:58:17 +02:00
Christoph Lendenfeld added 3 commits 2023-08-04 10:58:28 +02:00
Christoph Lendenfeld added 1 commit 2023-08-04 11:02:20 +02:00
Christoph Lendenfeld added 1 commit 2023-08-04 11:03:29 +02:00
Christoph Lendenfeld added this to the Animation & Rigging project 2023-08-04 11:37:37 +02:00
First-time contributor

I think that such an optimization should be carried out and for dopesheet. it seems to me that in the simplest test by baking keys up to 4000 frames, it will help

I think that such an optimization should be carried out and for dopesheet. it seems to me that in the simplest test by baking keys up to 4000 frames, it will help <video src="/attachments/38011090-c43e-46c9-a25a-103e76f2ec8c" title="2023-08-07 12-51-01.mp4" controls></video>
Author
Member

@sanek122005 yes the dope sheet needs to be optimized, but it's not the drawing that is the issue. I ran a profiler on it and the bottleneck (95% the time spent) is the building of keylists. That is the datastructure that is used to draw and select keys. That is a bit harder to optimize though.

@sanek122005 yes the dope sheet needs to be optimized, but it's not the drawing that is the issue. I ran a profiler on it and the bottleneck (95% the time spent) is the building of keylists. That is the datastructure that is used to draw and select keys. That is a bit harder to optimize though.
Christoph Lendenfeld added 1 commit 2023-08-11 11:08:40 +02:00
Christoph Lendenfeld added 1 commit 2023-08-11 12:32:08 +02:00
Christoph Lendenfeld added 2 commits 2023-08-11 12:35:34 +02:00
Christoph Lendenfeld added 1 commit 2023-08-11 12:54:00 +02:00
Christoph Lendenfeld changed title from WIP: Animation: Graph Editor - Don't draw keys if they are too close to each other to Animation: Graph Editor - Don't draw keys if they are too close to each other 2023-08-11 12:55:44 +02:00
Christoph Lendenfeld requested review from Sybren A. Stüvel 2023-08-11 12:55:59 +02:00
Christoph Lendenfeld requested review from Nathan Vegdahl 2023-08-11 12:56:07 +02:00
Nathan Vegdahl requested changes 2023-08-14 15:10:23 +02:00
Nathan Vegdahl left a comment
Member

The idea here is great, but I think to make it reliable it needs to work a little differently. Details in my comment below.

The idea here is great, but I think to make it reliable it needs to work a little differently. Details in my comment below.
@ -1023,0 +1024,4 @@
static float calculate_pixel_distance(BezTriple *a, BezTriple *b, blender::float2 pixels_per_unit)
{
return ((b->vec[1][0] - a->vec[1][0]) * pixels_per_unit[0]) +
Member

I think this is another case where we're going to want to take into account the handles. Because although the keys may be within a pixel, their handles can potentially extend high up or high down, making the curve between those two keys something we would want to make sure to draw.

Or in other words, the units of data we should be working with here aren't keys, but the curve segments formed by two keys:

Key A -> Key A right handle -> Key B left handle -> Key B

I think the over-all algorithm we want here is to maintain a bounding box that gets grown with each segment, and then just before the bounding box exceeds the size threshold in either dimension, we draw a curve formed from the first and last keys that went into that bounding box. And then we start again, beginning with the segment that was going to make the bounding box exceed the threshold.

I think this is another case where we're going to want to take into account the handles. Because although the keys may be within a pixel, their handles can potentially extend high up or high down, making the curve between those two keys something we would want to make sure to draw. Or in other words, the units of data we should be working with here aren't keys, but the curve segments formed by two keys: ``` Key A -> Key A right handle -> Key B left handle -> Key B ``` I think the over-all algorithm we want here is to maintain a bounding box that gets grown with each segment, and then *just before* the bounding box exceeds the size threshold in either dimension, we draw a curve formed from the first and last keys that went into that bounding box. And then we start again, beginning with the segment that was going to make the bounding box exceed the threshold.
nathanvegdahl marked this conversation as resolved
Christoph Lendenfeld added 1 commit 2023-08-17 10:51:19 +02:00
Christoph Lendenfeld added 1 commit 2023-08-17 11:51:25 +02:00
Author
Member

@nathanvegdahl I changed the code to include the handles of bezier keys
I need to rerun the performance test though since this added a few calculations that need to run on every key.

@nathanvegdahl I changed the code to include the handles of bezier keys I need to rerun the performance test though since this added a few calculations that need to run on every key.
Christoph Lendenfeld requested review from Nathan Vegdahl 2023-08-17 11:53:40 +02:00
Christoph Lendenfeld added 1 commit 2023-08-17 14:45:41 +02:00
Author
Member

good news
the change only cost about 2μs

good news the change only cost about 2μs
Nathan Vegdahl reviewed 2023-08-21 15:53:23 +02:00
@ -1065,0 +1089,4 @@
first_key->vec[1][0], first_key->vec[1][1], first_key->vec[1][0], first_key->vec[1][1]};
/* Used when skipping keys. */
bool has_skipped_keys = false;
const float min_pixel_distance = 3.0f;
Member

What is the rationale for this constant? Intuitively I would expect it to be something like 1.0 or 1.5, to only merge sub-pixel details.

What is the rationale for this constant? Intuitively I would expect it to be something like 1.0 or 1.5, to only merge sub-pixel details.
nathanvegdahl marked this conversation as resolved
Member

This basically looks ready to land to me. Just curious about that one constant.

This basically looks ready to land to me. Just curious about that one constant.
Author
Member

This basically looks ready to land to me. Just curious about that one constant.

I found this to be a reasonable value during testing. It's a tradeoff between accuracy and performance, but if you look at the video and compare the pictures there is almost no difference at a value of 3

In a future patch I plan to move a few constants to user preferences, this is one of them. It gives the user control over performance/fidelity

> This basically looks ready to land to me. Just curious about that one constant. I found this to be a reasonable value during testing. It's a tradeoff between accuracy and performance, but if you look at the video and compare the pictures there is almost no difference at a value of 3 In a future patch I plan to move a few constants to user preferences, this is one of them. It gives the user control over performance/fidelity
Nathan Vegdahl approved these changes 2023-08-24 13:40:51 +02:00
Nathan Vegdahl left a comment
Member

Looks good to me!

Looks good to me!
Christoph Lendenfeld changed title from Animation: Graph Editor - Don't draw keys if they are too close to each other to Animation: Graph Editor - Don't draw curve points if they are too close to each other 2023-08-25 10:13:13 +02:00
Author
Member

renamed the PR because I realized it is a bit confusing
it's not about keyframes but curve points

renamed the PR because I realized it is a bit confusing it's not about keyframes but curve points
Sybren A. Stüvel approved these changes 2023-09-05 14:01:18 +02:00
Sybren A. Stüvel left a comment
Member

LGTM, just tiny remarks that can be handled when landing.

LGTM, just tiny remarks that can be handled when landing.
@ -1022,6 +1022,28 @@ static blender::float2 calculate_pixels_per_unit(View2D *v2d)
return pixels_per_unit;
}
static float calculate_pixel_distance(rctf &bounds, blender::float2 pixels_per_unit)

The parameters aren't modified, so can be const.

The parameters aren't modified, so can be `const`.
@ -1025,0 +1028,4 @@
BLI_rctf_size_y(&bounds) * pixels_per_unit[1];
}
static void expand_key_bounds(BezTriple *left_key, BezTriple *right_key, rctf &bounds)

The input beztriples aren't modified, so should be const.

The input beztriples aren't modified, so should be `const`.
Christoph Lendenfeld added 2 commits 2023-09-05 14:11:33 +02:00
Christoph Lendenfeld merged commit d7e3961a82 into main 2023-09-05 14:18:40 +02:00
Christoph Lendenfeld deleted branch graph_reduced_key_drawing 2023-09-05 14:18:42 +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
4 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#110788
No description provided.