Accessing a screen texture from a SubViewport

Godot Version

4.5.1

Question

I have been trying to access a screen texture where the game is visible to implement a custom CRT shader. To test whether I can access it from a ping-pong buffer, I simply try to output a screen texture as COLOR, which doesn’t work and displays a pitch black screen.

When the shader is self-contained within a ping-pong buffer, it works efficiently, however, I have implemented it specifically to be able a screen texture.

Am I missing something or doesn’t documentation make it clear on how I can get a game screen texture in the main viewport?

You need to share the World2D resource between the root SubViewport and all other SubViewport nodes. Explained here:

At the script attached to the Game node, I have added these statements in func _ready():

	buffer_a.world_2d = get_world_2d()
	buffer_b.world_2d = get_world_2d()

However, it returns this error in a debugger, which doesn’t appear when these lines don’t exist/are commented out.

E 0:00:01:162   draw_list_bind_uniform_set: Attempted to use the same texture in framebuffer attachment and a uniform (set: 3, binding: 0), this is not allowed.
  <C++ Error>   Condition "attachable_ptr[i].texture == bound_ptr[j]" is true.
  <C++ Source>  servers/rendering/rendering_device.cpp:4656 @ draw_list_bind_uniform_set()

I’m not sure what’s the problem there and I would like to know how can I solve this problem.

I’m not sure it’ll work but Can you try this instead?

buffer_a.world_2d = get_tree().current_scene.get_viewport().world_2d
buffer_b.world_2d = get_tree().current_scene.get_viewport().world_2d

Unfortunately, I get the same error when using these lines of code.

E 0:00:01:667   draw_list_bind_uniform_set: Attempted to use the same texture in framebuffer attachment and a uniform (set: 3, binding: 0), this is not allowed.
  <C++ Error>   Condition "attachable_ptr[i].texture == bound_ptr[j]" is true.
  <C++ Source>  servers/rendering/rendering_device.cpp:4656 @ draw_list_bind_uniform_set()

If it’s important, I use macOS Sequoia 15.7.3 as my OS. I have to check whether it runs properly on Windows and Linux.

I just found this. I think it’s the same error you are getting. It’s worth to check it.

I have found another instance of the problem:

It might be caused by this as well.

I think sharing the world has nothing to do with screen texture. Afaik the main screen texture cannot be attained from within sub viewports. Likely because sub viewport are drawn before the main viewport.

You’re definitely overcomplicating things. You certainly do not need to be doing your own texture buffering. You also do not need to use a SubViewport at all unless you have 3D elements in your game.

Just make a ColorRect, set the Anchors Preset to Full Rect, and put a ShaderMaterial in the Material slot.

Then set the Shader Parameters.

This example is from my game Skele-Tom which embeds a CRT shader over Controls inside a 3D TV model, and then had a 3D world inside that. And I only used one SubViewPort node.

1 Like

I want to implement a phosphor decay effect like it’s visible on this video, and that’s why I decided to use the ping-pong buffer to implement it.

In this case, it makes sense to make my own texture buffering.

1 Like

You could do that with a tween and modulate the alpha value.

var tween: Tween = create_tween()
tween.tween_property(self, "modulate:a", 0.0, 0.5)

This would cause it to fade out over half a second.

I understand that it may makes sense to you based on your existing knowledge of Godot, but you ware making things very hard on yourself.

Sorry for being imprecise, but I thought that you would notice the specific trails that are caused by the characteristics of that specific CRT:

This is an implementation using shaders which influenced the way I wanted to implement these trails:

However, in my case, it has been greatly simplified in order to fit more to my game, and I’ve also used the ping-pong buffer approach that was implemented in the code.

I have converted the TextureRects into ColorRects with the exception of the Display rect, and as long as I don’t try to refer to the BufferB in the BufferA’s ColorRect and vice versa, everything works, as it’s my intention to store the contents of a previous frame.

In this case, I have this error:

E 0:00:01:942   draw_list_bind_uniform_set: Attempted to use the same texture in framebuffer attachment and a uniform (set: 1, binding: 1), this is not allowed.
  <C++ Error>   Condition "attachable_ptr[i].texture == bound_ptr[j]" is true.
  <C++ Source>  servers/rendering/rendering_device.cpp:4656 @ draw_list_bind_uniform_set()

I suppose I’m referencing the SubViewport texture wrong, however, I’m not entirely sure on how I can solve this problem.

1 Like

There was a thread recently about accumulating using a sub viewport:

1 Like

Given the issues I’ve had with setting up a frame accumulation effect, I have provided the details about my problematic setup there:

Any help would be appreciated.

Don’t render the world into both sub viewports. Only the first sub viewport renders the world. The second sub viewport just does the accumulation of first sub viewport’s texture.

I’ve solved it by making sure that the currently unused ColorRect becomes hidden:

	if use_a:
		color_rect_a.visible = true
		color_rect_b.visible = false
	else:
		color_rect_a.visible = false
		color_rect_b.visible = true

This has got rid of the error in my case.

Why do you use two color rect. The whole idea is to not ping-pong anything. Just render the scene normally into viewport 1, mix that in viewport 2 and display that in the main viewport. Do the same things into same viewports every frame. It’s simple.

1 Like