-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rotating 2D Palette effect #3683
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it though I do not know if replacing original mode_palette
is the best way.
Because of metadata changes of slider descriptions.
You should make sure it behaves exactly the same as the original function did in 1D mode (even on 1D segments on matrix).
Looks good on 32x16 and it would act as the old effect if the "Animation Rotation" is not checked and having |
It does not. (Differences are listed above.) I'll update the PR to be a new effect instead of replacing an old one. |
Then don't rush. Please make sure that effect behaves very much like the old one on strip and 1D segment. I think it is worth the effort to have it in one effect as you suggest instead of introducing a new one. |
I see. I believe it to be similar enough. But I'm probably not the one who will receive possible complaints either ^^ If I were to add a new effect: How would I handle its ID? The IDs seem grouped. I would think the effect belongs to the first group, but there aren't any gaps before the next group starts. Would I be shifting all IDs, put my effect at the end regardless of logical grouping, re-use a removed ID, or put it in the first group but using an ID from after the last group? |
As far as IDs go, I was over-voted and effect IDs from SoundReactive prevailed. So they are all Use existing gaps. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My second review is intended to clarify what I meant by saying that "using rotation on 1D" may be a good thing and could yield a nice enhancement to the Palette effect.
First off, it seems to me that you may have a few misconceptions regarding segment use. Also, effect function should never interact directly with anything strip
related (with a few notable exceptions that are there due to legacy reasons, such as strip.now
).
What I'd do is the following:
- use square canvas of
max(width,height)
- always perform palette paint in square 2D
- intersect segment with the canvas (at appropriate shift from top or left depending on the segment dimension)
- use intersection to paint segment
This could be optimised to reduce the painting only on the longest dimension to reduce the resources needed.
wled00/FX.cpp
Outdated
#endif | ||
const bool isMatrix = strip.isMatrix; | ||
const int cols = SEGMENT.virtualWidth(); | ||
const int rows = isMatrix ? SEGMENT.virtualHeight() : strip.getSegmentsNum(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not get it. How is this supposed to work?
getSegmentsNum()
will return the size of underlying vector which will have the size of the largest encountered segment count. I.e. I create can 10 segments then delete all but one (and adjust its dimensions) and the number returned by getSegmentsNum()
will return 10, not 1. Segments are not removed from vector unless low memory condition occurs.
If you need usable segments then use getActiveSegmentsNum()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its not like on the fly segment changes work particularly great anyway. You can only be sure of what the will actually look like if you store the config and reboot the device. So I'm not concerned with the vector being too long. I don't care about missing segments either, those segments will just not be filled by my effect.
Using getActiveSegmentsNum()
however would be incorrect, as I care for existing segments, not those that happen to be on. I also want to compare the segment ID to it, so the segment count must be greater than the segment ID. The segment count is my assumed matrix height for 2D emulation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getActiveSegments()
counts valid segments, not the segments that are on. There is no function to count on segments. Valid segments are segments that have length()>0
. To put it the other way: active segments are visible in UI, inactive segments are not.
Short update, just because I have the impression that you are moving rather quickly (even during the week): |
Life is too short. There is no time to slack. And you can always skip on sleep. 😉 I've updated the effect to work with |
Code tested and works beautifully. 2D or 1D or both at the same time. |
Would you mind sharing the code so that I don't have to start from scratch? |
Of course, I'll push directly to this PR. |
Verdict? |
Didn't try it yet, and probably won't today. At first glance I like most of the formatting changes, but I believe you removed some of the functionality I was going for. But as I said, I'm going to write a more detailed description about that tomorrow ^^ |
Updated description to include a new "2D Emulation" section. Hopefully that gets across my intentions with After trying your version, without looking into why:
So, assuming you don't have any fundamental issues with implementing 2D emulation, I'm going to have another look at 1D segments, but I would like to not adopt some of your changes. If you want, I can add some review comments on the lines I don't like. |
8a9fa6b
to
29af62f
Compare
@TripleWhy I've now thoroughly analysed code and tested (the adapted) version which includes your requirements and my modifications. I will take some of my comments back. They were premature without thorough code analysis. Indeed it is necessary to use My personal opinion regarding the use of |
After a lengthy discussion (on Discord) and thorough testing the updated Palette effect (from this PR) gets green light from my side (with a few minor adjustments that yet need to be done). The default behaviour of new effect may differ from original default behaviour if used from within existing presets (created prior to 0.13) so the change will need to be marked a BREAKING change. Discussion also uncovered that original Palette ( I would recommend to update Rainbow effect (slow it down and stop animation at speed 0) so that it could mimic behaviour of the old Palette effect if selected palette is not a Default one. So the impact would be less critical. The other option is to make this a new effect but then we'd have 3 effects capable of producing exactly the same output depending on the set parameters which I'd like to avoid. @Aircoookie I'd like your opinion on the matter. |
Limit rotation to +-90 deg (swapping sin/cos & limit angle) Shift palette shift
I implemented a new effect that is similar to Palette/Rainbow:
palette.webm
If you like it too, let's talk a bit about it:
Compatibility
I noticed that the Rainbow effect is almost a perfect superset of the Palette effect, so I replaced the Palette effect with my new effect. It provides similar functionality, but is not fully backwards compatible. So it might be better to make this a new effect ("Palette 2D" maybe?). I wanted to leave that judgement up to you.
Breaking changes are:
Parameter Description
I'm going to describe what each parameter does here, so you can come up with better names if you don't like mine:
Anamorphic Mode
For the setup I want to use this effect with, I have a set of LEDs that roughly cover a square area, but their numbers are not a square. There is a greater distance between LEDs in y than in x direction. So my setup is anamorphic, if you want.
Therefore, the Physical Square setting changes between assuming all physical LEDs are arranged in an equally spaced grid, and assuming the spacing is different in one direction than the other. There are other ways to look at this (and is interesting for equally spaced non-square setups as well) but this way of thinking made sense to me mathematically, when I implemented it.
This setting has no effect when the matrix has the same number of LEDs in x and y direction.
Here are two images at 45° that have identical settings apart from Physical Square.
![non-square mode](https://private-user-images.githubusercontent.com/2760830/296600258-5e7be8c6-4773-4880-95e9-8119920c03a9.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjUyMTUwOTQsIm5iZiI6MTcyNTIxNDc5NCwicGF0aCI6Ii8yNzYwODMwLzI5NjYwMDI1OC01ZTdiZThjNi00NzczLTQ4ODAtOTVlOS04MTE5OTIwYzAzYTkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDkwMSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA5MDFUMTgxOTU0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZjIwNmIzMTk2MzJkODY5MjhlYjIyOWEyZjIyNjlmMWQyYzU1ZmVjNTQxYjlmYzI0OGViYWVlZmUxNWRkZmU1NiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.criGK9-ik7PHra4EnvKJzAKCWfHzy_0_KAwtTnXi7mA)
Non-square mode:
Square mode:
![square mode](https://private-user-images.githubusercontent.com/2760830/296600283-3baff0cc-0d52-4af1-a67c-426a82edd316.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjUyMTUwOTQsIm5iZiI6MTcyNTIxNDc5NCwicGF0aCI6Ii8yNzYwODMwLzI5NjYwMDI4My0zYmFmZjBjYy0wZDUyLTRhZjEtYTY3Yy00MjZhODJlZGQzMTYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDkwMSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA5MDFUMTgxOTU0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NTM1ZTRmZjA0MTMwMmQ1ZDJlNGZmMTI2YzI0ZjE5YWE5YzRjMDNmMzdmMmNhNTQ1NTlhOGZlMDA3NTFjM2IwNCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.R_Vb4BFub9JlPmYUILzToebureLnWyGSRBndeK784kQ)
2D Emulation
Motivation
I have a setup with 6 strips of 115 LEDs each, they light my ceiling. The distance between the strips is roughly 70 cm, while the distance between LEDs on a strip is about 3 cm. I have been using an ESP8266 so far, starting from WLED 0.13. I managed to put some rainbows on it, both along the strip direction and orthogonal to it, but I always wanted a diagonal rainbow, too.
With WLED 0.14 came matrix setups, but my poor 8266 becomes unresponsive immediately when I try to set it up with the above dimensions. I'm planning to replace it with an ESP32, on which that is no issue.
But during the development of my effect, I realized that is is entirely possible to achieve the same result with my existing 1D setup.
1D Matrix Setup
Prior to 0.14, I assume this button in the segment setup was used to configure matrix displays:
![Repeat until the end](https://private-user-images.githubusercontent.com/2760830/298279322-453b7f94-74aa-4785-b7b7-56adb2be7799.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjUyMTUwOTQsIm5iZiI6MTcyNTIxNDc5NCwicGF0aCI6Ii8yNzYwODMwLzI5ODI3OTMyMi00NTNiN2Y5NC03NGFhLTQ3ODUtYjdiNy01NmFkYjJiZTc3OTkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDkwMSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA5MDFUMTgxOTU0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NWRhMTljOTFkNjE1Y2JlYTViYmIxMDI2YzZjZDg1NzUxMWI3MzgzNWIyY2Q4NDJmM2Y3MWZjZDdlYjI4YThhNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.PiDa0WXa5Nc7DwXkXcvAMTHaecmWuz-43dfjAt2WAes)
For me, this results in the following segmentation, which I have been using.
Click to expand
Obviously this is not the only way you can use segments. My 2D emulation assumes this kind of setup. It simply might not look correctly in other scenarios.
How it works
Now that we assume a certain anatomy of the setup, we can derive matrix dimensions from the number and length's of segments. We can also derive the y coordinate in the matrix from the current segment's index. Finally, the x coordinate is just the LED index in the current segment.
Laid out in one line, like the peek preview in the web UI does, a 45° rotation using
![line](https://private-user-images.githubusercontent.com/2760830/298279487-ea917c24-5219-4121-82c0-a0e9bf8a292e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjUyMTUwOTQsIm5iZiI6MTcyNTIxNDc5NCwicGF0aCI6Ii8yNzYwODMwLzI5ODI3OTQ4Ny1lYTkxN2MyNC01MjE5LTQxMjEtODJjMC1hMGU5YmY4YTI5MmUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDkwMSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA5MDFUMTgxOTU0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NTdhOGM2NmE0ZDgyNmI2YjM1ZmYyNjZjNzk3NmFhZThlNGU4YTAyNmU1NmVlOWJhNGVhYTNkNDIxMWUyNWJkOSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.115DHRbcFFMBMJM0SnKptIHN6rGQsvU9Xjz10L904kU)
color_wheel
with the setup described above looks like this:If we reverse every second segment, line them up vertically instead of horizontally, and scale them a bit (through the magic of gimp, or through the magic of having the LEDs physically ordered like that) we get this:
![2D emulation](https://private-user-images.githubusercontent.com/2760830/298279578-0ac99bae-3ff5-424c-9671-103b6353d931.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjUyMTUwOTQsIm5iZiI6MTcyNTIxNDc5NCwicGF0aCI6Ii8yNzYwODMwLzI5ODI3OTU3OC0wYWM5OWJhZS0zZmY1LTQyNGMtOTY3MS0xMDNiNjM1M2Q5MzEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDkwMSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA5MDFUMTgxOTU0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YWIxMGYwMjBjOTQ4NzlhZDQwZmMwNjIyNTkyN2E1NzkzMzhmOThjNGU3NTgxOWFiY2IwYmFlYTZkZGE1ZDllNCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.kCElq-OJAMvdiC9FiRjBLhyN_IYQZ4DzJWubk-zf77E)
Notes
strip.isMatrix
. Other effects use this information too, so I though it was fine.Floating Point Math
You will notice that my code is actually two versions, one for floating point math, one for integer math. I decided to use the float version on ESP32 for the better results, and the int version on ESP8266 for better performance.
I had to use two 64-bit multiplications in int mode to stay within the int range. It might be possible to get rid of them by halfing all other int sizes. But the int version already produces slightly lower quality results anyway, and I didn't want to further decrease quality, so I didn't try. (And besides the 64 bit multiplication appears to be only 2x slower than other int multiplications.)
The int version is a bit faster on the ESP32 and more so in the ESP8266 (which doesn't have an FPU I think?). I made some measurements, but I'm not sure what version of sin_t/cos_t they used. If you are interested in numbers, I can take some new measurements.
(The sin_t implementation is relevant because I when benchmarked different sin implementations, the Taylor version was about 24x (ESP32) / 11x (ESP8266) slower than the Arduino version. But there are only two trigonometry computations per call, so it might not matter that much. Btw. builds without the Taylor version are not only faster, but smaller too.)
Other Thoughts
This transformation of the Palette effect from 1D to 2D might be interesting as a general 1D FX expansion. However it would need parameters. I didn't see any expansions that have parameters at the moment, so I didn't look into that.