godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.6k stars 21.1k forks source link

Three layers of Viewports for post processing leads to previous frames being drawn #44908

Open quexten opened 3 years ago

quexten commented 3 years ago

Godot version:

3.2.3 Stable

OS/device including version:

GLES 3, GTX 1050, Linux with 5.10.3 Kernel.

Issue description:

I was making a glow effect for a 2D game using a chain of Viewports as follows: -Scene |-SceenViewportContainer ||-Viewport |||-Camera + World |-GlowViewportContainer (for additive blending) ||-Viewport |||-BlurHorizontalViewportContainer ||||-Viewport |||||-BlurVerticalViewportContainer ||||||-Viewport |||||||-Sprite (showing the ScreenViewportContainer as a texture)

When testing this, I noticed the glow seemed to lag behind the scene so I changed the shaders of the Viewport Containers to just pass the color through and applied subtractive blending mode to the top most Viewport. If everything works as expected this would just show a black picture (since the images would be the same). However, when there was motion, there was indeed pixels lighting up (showing that the triple-layered Viewports are lagging a frame behind). Just using 2 layers of Viewports does not have this issue.

Steps to reproduce: Apply three layers of Viewports, the third layer will have a delay of a frame. In the attached project there is a particle effect showing the movement and a still object to show that the layers are not just misaligned.

Minimal reproduction project:

project.zip

Anixias commented 2 years ago

I've just encountered this issue myself in 3.5 RC6. It seems to not only be when 3 viewports are nested. In my case, simply having more than 3 viewports in a scene causes all of them to render the previous frame, regardless of the contents of each viewport.

EDIT: Just tested it, and having 3 viewports nested (even those that are part of a child scene's hierarchy) anywhere causes them to render the previous frame, with the exception of the root viewport.

adamlesinski commented 1 year ago

I too am experiencing this issue on 3.5.1.stable, Windows 11, GLES 3 backend.

I am generating an outline of an object by rendering that object alone (using camera cull masks) into a viewport, then doing multiple separable blur passes and compositing that with the regular scene rendered to another viewport.

The outline lags behind by one frame, confirmed with NVIDIA Nsight tools. I also checked that the camera transforms in both viewports are synced in the VisualServer pre_frame signal callback.

Calinou commented 1 year ago

Does this occur when V-Sync is disabled?

adamlesinski commented 1 year ago

Yes, it still happens with V-Sync disabled. I will put together a repro case and upload it today.

adamlesinski commented 1 year ago

Here is a repro project. The camera will animate and demonstrate the one-frame lag. You can toggle which object has the outline with spacebar. selection.zip

Kukuschi commented 5 months ago

I ran into a similar (or the same?) problem in 4.3 dev snapshot 5. In my (3D) scene I have multiple SubViewports with 3D cameras as child (steered by a remoteTransform3D) used as inputs for a complex compositor effect. It all works fine and synchronized when the Player_Camera renders to the root viewport, but as ViewportTexture in a Sprite2D something starts to lag behind and the different steps in the compositor effect are out of sync.

SubViewport Update Modes are set to always, V-Sync is disabled, framerate is roughly 500.

(unfortunately I cannot provide the project files)

rendered in root viewport without problems: https://github.com/godotengine/godot/assets/64613417/50a50fcb-b388-46ac-8470-2c74ada9fe6b

rendered in a Sprite2D as ViewportTexture, edge detection is out of sync: https://github.com/godotengine/godot/assets/64613417/36fa90c6-1ec0-47b3-8597-2bd55a8e910f

Node setup: setup (the Player_Camera and the PostProcess_Camera are identical and have the compositor effect attached. The Player camera will be replaced by a Node3D when i can get this working)