godot icon indicating copy to clipboard operation
godot copied to clipboard

ViewportTextures work in-editor, appear solid purple in-game.

Open rlenhub opened this issue 2 years ago • 16 comments

Godot version

4.0.stable.official

System information

Windows 11, Forward+, Nvidia RTX 3060 (528.49)

Issue description

I have a SubViewportContainer and a sub-viewport. Inside this viewport, I have a MeshInstance with a ViewportTexture as the albedo, assigned another viewport containing some Control nodes. In the editor, it appears to correctly render the assigned viewport. However, when I run the scene, the texture turns into a solid purple.

viewporthierarchy

Steps to reproduce

  1. Create new 3D scene.
  2. Add a Control node under the root.
  3. Add a SubViewportContainer under the Control.
  4. Parent a SubViewport to the SubViewportContainer.
  5. Add a Camera3D and a MeshInstance3D to the SubViewport.
  6. Create another SubViewport under the first SubViewport.
  7. Add a Control node, along with some visible UI elements.
  8. Create a new material for the mesh instance, with a ViewportTexture as the albedo.
  9. Assign the lowest viewport to the texture.
  10. Observe the mesh properly rendering the viewport in the editor.
  11. Run the scene, observe that the viewport texture only works in the editor.

Alternatively, run the minimal reproduction project.

Minimal reproduction project

Minimal Reproduction Project

rlenhub avatar Mar 04 '23 00:03 rlenhub

It your MRP you use SubViewport as a Skeleton3D for the MeshInstance3D. But a SubViewport is not a Skeleton3D. Maybe it should be considered a bug, that non-Skeleton3D nodes can be assigned to a Skeleton3D?

image

Sauermann avatar Mar 04 '23 06:03 Sauermann

Unfortunately, it looks like that wasn't causing any problems. I added a skeleton and attached the mesh to it, and nothing seems to have changed.

rlenhub avatar Mar 04 '23 22:03 rlenhub

So... after some testing, I've discovered that it has nothing to do with nested subviewports. Turns out, ViewportTextures just straight up don't work anymore.

bru

rlenhub avatar Mar 05 '23 19:03 rlenhub

GL Compatibility renderer does not fix this problem.

glcompat

rlenhub avatar Mar 05 '23 19:03 rlenhub

It's not exclusive to Controls either.

no3deither

EDIT: 2D nodes do not work either. Nothing will render.

no2deither

rlenhub avatar Mar 05 '23 19:03 rlenhub

ERROR: Viewport Texture must be set to use it.
   at: get_height (scene/main/viewport.cpp:116)
ERROR: Viewport Texture must be set to use it.
   at: get_width (scene/main/viewport.cpp:111)
ERROR: Node not found: "Control/SubViewportContainer/SubViewport/SubViewport" (relative to "main").
   at: get_node (scene/main/node.cpp:1364)
ERROR: ViewportTexture: Path to node is invalid.
   at: setup_local_to_scene (scene/main/viewport.cpp:76)

This may have something to do with the order in which the nodes are entered, and whether and when they are redrawn.

nested_viewports-1.zip

Rindbee avatar Mar 06 '23 00:03 Rindbee

ERROR: Viewport Texture must be set to use it.
   at: get_height (scene/main/viewport.cpp:116)
ERROR: Viewport Texture must be set to use it.
   at: get_width (scene/main/viewport.cpp:111)
ERROR: Node not found: "Control/SubViewportContainer/SubViewport/SubViewport" (relative to "main").
   at: get_node (scene/main/node.cpp:1364)
ERROR: ViewportTexture: Path to node is invalid.
   at: setup_local_to_scene (scene/main/viewport.cpp:76)

This may have something to do with the order in which the nodes are entered, and whether and when they are redrawn.

nested_viewports-1.zip

Thank you so much! The texture seems to only be able to find it's viewport when it's mapped to the mesh via the renderer, and not via a scene-unique version of the mesh itself, as I was attempting. This is a good enough workaround.

rlenhub avatar Mar 06 '23 22:03 rlenhub

I had a similar issue and solved it by setting "Local to Scene" on the MeshInstance3D with the material using the Viewport Texture.

dimroc avatar Mar 16 '23 16:03 dimroc

During scene initialization, resources with resource_local_to_scene enabled will call setup_local_to_scene() after all nodes in the scene have been setup.

https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L464-L468

The same goes for subresources within resources. They may be cached in resources_local_to_scene when duplicating or configuring.

https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L317

https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L332

But the PROPERTY_USAGE_STORAGE flag must be enabled. Otherwise, setup_local_to_scene() on the subresource will not be called (Subresources are not cached).

https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/core/io/resource.cpp#L232-L234

https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/mesh.cpp#L1704-L1711

Rindbee avatar May 25 '23 07:05 Rindbee

I solved it with Local to Scene: On for the Mesh Resource, Material Resource, and Albedo Texture Resource as shown below.

So it wasn't a bug. But the way to show the UI in 3D space is more complicated than in other engines.

Anyway, thanks.

Gui3D | +- SubViewport | +- MeshInstance3D

MeshInstance3D

Mesh > Resource Local to Scene: On

> Material
  > Resource
    Local to Scene: On

  > Albedo Texture (ViewportTexture)
    > Viewport Path: /Gui3D/SubViewport
    > Resource
      Local to Scene: On

2023년 5월 25일 (목) 오후 4:14, 风青山 @.***>님이 작성:

During scene initialization, resources with resource_local_to_scene enabled will call setup_local_to_scene() after all scene nodes have been setup.

https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L464-L468

The same goes for subresources within resources. They may be cached in resources_local_to_scene when duplicating or configuring.

https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L317

https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L332

But the PROPERTY_USAGE_STORAGE flag must be enabled. Otherwise, setup_local_to_scene() on the subresource will not be called.

https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/core/io/resource.cpp#L232-L234

— Reply to this email directly, view it on GitHub https://github.com/godotengine/godot/issues/74331#issuecomment-1562398079, or unsubscribe https://github.com/notifications/unsubscribe-auth/AU7XGOQ5MQPAAB5QMZFSPKLXH4BFHANCNFSM6AAAAAAVPGILKE . You are receiving this because you commented.Message ID: @.***>

SouthBear77 avatar Jun 02 '23 09:06 SouthBear77

I solved it with Local to Scene: On for the Mesh Resource, Material Resource, and Albedo Texture Resource as shown below.

This solution works for other mesh types. Not available for the case in ArrayMesh (the type of mesh used in MRP). The surface_0/material property does not have PROPERTY_USAGE_STORAGE enabled.

Rindbee avatar Jun 02 '23 13:06 Rindbee

I solved it with Local to Scene: On for the Mesh Resource, Material Resource, and Albedo Texture Resource as shown below. So it wasn't a bug. But the way to show the UI in 3D space is more complicated than in other engines. Anyway, thanks. Gui3D | +- SubViewport | +- MeshInstance3D MeshInstance3D Mesh Resource Local to Scene: On Material Resource Local to Scene: On Albedo Texture (ViewportTexture) Viewport Path: /Gui3D/SubViewport Resource Local to Scene: On 2023년 5월 25일 (목) 오후 4:14, 风青山 @.>님이 작성: During scene initialization, resources with resource_local_to_scene enabled will call setup_local_to_scene() after all scene nodes have been setup. https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L464-L468 The same goes for subresources within resources. They may be cached in resources_local_to_scene when duplicating or configuring. https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L317 https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L332 But the PROPERTY_USAGE_STORAGE flag must be enabled. Otherwise, setup_local_to_scene() on the subresource will not be called. https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/core/io/resource.cpp#L232-L234 — Reply to this email directly, view it on GitHub <#74331 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AU7XGOQ5MQPAAB5QMZFSPKLXH4BFHANCNFSM6AAAAAAVPGILKE . You are receiving this because you commented.Message ID: @.>

Confirmed, this works to fix the purple in 4.1.1, but I'm not using a material override, I'm using a PlaneMesh with viewport texture as a material: image

elvisish avatar Oct 08 '23 21:10 elvisish

The solution turned out to be much simpler than it seemed. All you have to do is move the material to GeometryInstance3D Знімок екрана з 2024-04-09 21-20-14

tsikavo avatar Apr 09 '24 18:04 tsikavo

I solved it with Local to Scene: On for the Mesh Resource, Material Resource, and Albedo Texture Resource as shown below. So it wasn't a bug. But the way to show the UI in 3D space is more complicated than in other engines. Anyway, thanks. Gui3D | +- SubViewport | +- MeshInstance3D MeshInstance3D Mesh Resource Local to Scene: On Material Resource Local to Scene: On Albedo Texture (ViewportTexture) Viewport Path: /Gui3D/SubViewport Resource Local to Scene: On 2023년 5월 25일 (목) 오후 4:14, 风青山 @.>님이 작성: During scene initialization, resources with resource_local_to_scene enabled will call setup_local_to_scene() after all scene nodes have been setup. https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L464-L468 The same goes for subresources within resources. They may be cached in resources_local_to_scene when duplicating or configuring. https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L317 https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/scene/resources/packed_scene.cpp#L332 But the PROPERTY_USAGE_STORAGE flag must be enabled. Otherwise, setup_local_to_scene() on the subresource will not be called. https://github.com/godotengine/godot/blob/4c677c88e918e22ad696f225d189124444f9665e/core/io/resource.cpp#L232-L234 — Reply to this email directly, view it on GitHub <#74331 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AU7XGOQ5MQPAAB5QMZFSPKLXH4BFHANCNFSM6AAAAAAVPGILKE . You are receiving this because you commented.Message ID: @.>

This did it for me, when using a MeshInstance3D adding a SubViewport to it and a Control node to the SubViewport to show 2D UI on a 3D mesh, make sure to enable Local to Scene on all of the Resource checkboxes! Having even one of the 3 Local to Scene checkboxes unchecked will make it show as purple in-game.

Medie1 avatar Jul 07 '24 16:07 Medie1

Please note, that there is also #96816 which sets the NodePath of the ViewportTexture incorrectly when you instance a scene containing a Node that uses a ViewportTexture into another scene. So you have to set resource_local_to_scene on all materials that directly or indirectly use a ViewportTexture as described above, and if these materials are on a node that are part of an instanced scene, you also have to make them recursively unique, for them to become local to the new scene they are used in. So this is just a complete mess right now basically ^^'

Grandro avatar Sep 13 '24 11:09 Grandro

It is not possible to determine if the ViewportTextures really "work" in-editor given the screenshots provided. The editor will still show a non-purple image even if the setup becomes invalid. It should become purple tho when reloading the scene.

I have done some digging, and I found another issue with editable_children. Here I assume that all resources containing a ViewportTexture have resource_local_to_scene checked! I believe that it is the viewport_path property of the ViewportTexture that causes this issue. It happens as follows:

  1. The user sets the viewport_path of a ViewportTexture to be the NodePath to a Viewport relative to the local scene root via the editor
  2. On playtest the Viewport receives a notification and calls Viewport::_update_viewport_path()

This is where things get interesting: https://github.com/godotengine/godot/blob/db66bd35af704fe0d83ba9348b8c50a48e51b2ba/scene/main/viewport.cpp#L491-L506 The basic idea is, that a Viewport has a reference to an array of ViewportTextures that it wants to keep the paths up to date. The NodePath is always stored relative to the owner of the Viewport. If the Viewport was saved to file, it uses itself as the owner, else it gets the owner using get_owner().

This works if either the the owner of the Viewport is the local scene root, or if the Viewport itself is the local scene root. If we instantiate a scene A containing a Viewport into another scene B this is still fine, because scene A is the owner and the local scene root for the Viewport. But if we enable editable_children on scene A now, scene A stays the owner but is not the local scene root anymore. We can fix this issue by doing:

void Viewport::_update_viewport_path() {
	if (viewport_textures.is_empty()) {
		return;
	}

	Node *scene_root = this;
	if (get_scene_file_path().is_empty()) {
		while (scene_root->get_owner() != nullptr)  {
			scene_root = scene_root->get_owner();
		}
	}

	if (!scene_root && is_inside_tree()) {
		scene_root = get_tree()->get_edited_scene_root();
	}
	if (scene_root && (scene_root == this || scene_root->is_ancestor_of(this))) {
		NodePath path_in_scene = scene_root->get_path_to(this);
		for (ViewportTexture *E : viewport_textures) {
			E->path = path_in_scene;
		}
	}
}

This gets the owner of the Viewport recursively, until we find a node that itself has no owner anymore. This doesn't feel like the right way to fix this, and Viewport::_update_viewport_path() also doesn't get called everytime we would have to update the path this way (For example when enabling editable_children of the owner). But of course, storing the NodePath relative to the owner also doesn't work in this scenario.

This issue is very annoying, because you have to fix the NodePath everytime Viewport::_update_viewport_path() is called, which would make it more convenient if this method didn't exist at all.

Grandro avatar Oct 05 '24 01:10 Grandro

Just hopping in here to confirm that this is happening in Mobile renderer as well

Lexpeartha avatar Oct 16 '24 21:10 Lexpeartha

Hello. Just wanted to mention I currently have this problem as well 4.4.1 on Arch Linux. though perhaps with some slight differences. I was trying to create a mirror.

I have a scene in which the hierarchy is MeshInstance3d as root, then SubViewport as child, and a Camera3d as a child of the SubViewport. The mesh has a material using ViewportTexture

In its own scene, the mesh3d acts as a mirror using a viewport texture. However, when brought into a scene as instance, the camera will not move with the mesh as the subviewport has no transform coordinates in 3d. If I click edible children, I can move the camera but this breaks the viewport material for some reason and it fails to work when running current scene. Obviously turning off edible children destroys the transform on the camera.

All materials and textures are set to local to scene.

It seems the easiest fix would be to have a script move the camera to where the mesh is, but for now it appears all mirrors and cameras using a viewport texture have to be created within the scene and cannot be placed as instances.

Perhaps a bugfix would be allowing SubViewport nodes to have coordinates so that they can move with their parents and children camera? Just a suggestion.

For now, a simple script matching coordinates between the mesh and camera will have to do.

Cringewalker avatar Apr 07 '25 00:04 Cringewalker

@Cringewalker Focusing on the point related to this issue, that toggling editable_children breaks the ViewportTexture NodePath, this sounds like its fixed by the aforementioned https://github.com/godotengine/godot/pull/97861 (If thats what you mean by "viewport material"). The problem is that the NodePath is updated wrongly internally when editable_children is toggled.

Grandro avatar Apr 07 '25 09:04 Grandro