projectM-visualizer / projectm

projectM - Cross-platform Music Visualization Library. Open-source and Milkdrop-compatible.
https://discord.gg/mMrxAqaa3W
GNU Lesser General Public License v2.1
3.25k stars 369 forks source link

Add flag to C API to start newly loaded presets with a clean canvas if set #298

Open milkdropper opened 4 years ago

milkdropper commented 4 years ago

Hi All - is there a way to disable Smooth Transitions (ie. the previous preset merging into the new preset)? I found that setting Smooth Transition Duration to 0 has no effect. I am happy to try to fix this if someone can point me in the right direction.

Example: The left frame is the first idle preset, and the second frame on the right is the first preset that is loaded. I would like to / should be able to have the second preset load fresh without any transition between the two.

image

kblaschke commented 2 years ago

If you still want to go down that rabbit hole, as of commit 8446784 there are two main points of interest to get you started:

Browsing through all the connected functions that are called on preset switching, no matter if manual, automatic, hard or soft cut, it is clear that projectM is completely lacking a real transition effect. It basically switches to the next preset in the frame it's switched and starts rendering the new one on top of the framebuffer the previous preset left behind.

Milkdrop has a rather complex blending logic that can select which features of the new and old presets are rendered during a transition. Search for m_pOldState in the same file to see the other blending-related code. Implementing this in projectM would certainly be a really nice addition and improve user experience, but might require some heavy refactoring.

The main issue here is that the Renderer class has no direct relation to the presets, it simply renders an ordered list of RenderItem-based classes. Composite and warp shaders are compiled and rendered directly by the Renderer class supporting only one shader each. During a transition, the output of both the old and new preset's shaders should be mixed with a weight in a third shader depending on the transition time passed, and might even include some fancier effects than simple linear blending.

kblaschke commented 1 year ago

As the topic was recently discussed on Discord and I've barely got the transition code to work again, here's the current state:

Transitions are currently very simple, only some very basic blending happening between the two presets. Shaders, if used, are switched immediately halfway through the transition, which is more a sudden switch than smooth blending.

Disabling smooth transitions would be possible. To have a clean start as requested by the OP, clearing the render texture will be necessary. Currently, it's always copied over from the last frame, creating a ghosting effect depending on how much the new preset draws over it.

As such a change doesn't require an API change (setting the duration to 0 should suffice), it's not something to expect in the upcoming 4.0 release, but we'll see about implementing it at a later time.

kblaschke commented 1 year ago

As I'm currently reworking the rendering code, including transitions, I think there's three possible transitions which may take place, including the suggestion by the OP:

Both smooth and hard transitions will use the composited output of the previous preset as their starting background. To elaborate: presets render all their stuff except for the composite shader. Then the output is stored as the image that is then warped on the next frame. On this output, the composite shader is applied on top and the result is then presented to the user, but not saved. When switching presets, this may introduce a "jump" effect if the previous preset used a heavy post-processing shader for compositing. Using the composited output will simply make the new preset warp the last user-visible frame instead of just the non-processed render result.

Clean transitions would not be affected. Introducing clean transitions would require adding a new setting, which we could do in the upcoming 4.1 release. The current master rendering code doesn't really provide us a quick fix opportunity, so I'd wait until the rest of the rendering code is refactored and the new expression parser is working.

There's also the idea of giving users the ability to add their own transition shaders in GLSL, similar (or even compatible to) Shadertoy code. It would provide the two preset textures as samplers, plus a few parameters for blending like blend progress, blend time and so on. The output would simply be the final image, so the shader could just blend both images together or even add more effects on top, like some kind of burning/flame effect on the transition edge etc.

kblaschke commented 5 months ago

Another update:

Smooth transitions have been reimplemented as stated in my last comment, using (mostly) Shadertoy-compatible fragment shaders. On any preset switch, hard or soft, projectM will now copy the last output image of the previous preset into the "main" image texture of the newly loaded preset, still exposing the behaviour described in the initial report. This will remain the default behavior, as otherwise every preset starts black and this makes many transitions go from "colorful" to "pitch black" instead of nicely dissolving the previous preset.

We can add new API functions to set/get a boolean flag which controls whether the previous preset image will be used or not in the 4.2 release. this is easy to do and doesn't introduce breaking API changes. Will edit the title accordingly and add the appropriate labels/milestones.