Hi there,

I have been trying to set up an old-school inventory system with 3D spinning slots. So far, the 3D part has been going smoothly :

However, I am having issues regarding the subviewport usage : it keeps generating errors about the Subviewport not being set, no matter how much I try to check if it is set before interacting with it in-code.

err_print_viewport_not_set: Viewport Texture must be set to use it.
<Source C++> scene/main/viewport.cpp:180 @ _err_print_viewport_not_set()

Here is my inventory slot scene structure:

Here is the code of the InventorySlot script:

extends Button
class_name InventorySlot

@export var max_size : Enums.SIZE = Enums.SIZE.XL
@export var inventory_type : Enums.CLOTHING :
	set(new_value) :
		%EmptyTexture.texture = Texture.new()
		%EmptyTexture.texture
@onready var full_texture : TextureRect = %FullTexture


@export var inventory_item : InventoryItem :
	set(new_value):
		if new_value == null:
			%EmptyTexture.visible = true
			%FullTexture.visible = false
			%RenderedMesh.mesh = null
			inventory_item = null
		else:
			%EmptyTexture.visible = false
			%FullTexture.visible = true
			%RenderedMesh.mesh = new_value.mesh
			inventory_item = new_value
			new_value.on_mesh_changed.connect(_on_inventory_item_mesh_changed)



# Called when the node enters the scene tree for the first time.

func _on_inventory_item_mesh_changed(new_mesh : Mesh) -> void:
	%RenderedMesh.mesh = new_mesh

func _ready() -> void:
	pass


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	pass

I did dig up similar errors known in past versions that were supposed to be corrected with this PR:
https://github.com/godotengine/godot/pull/97029

How would I be able to make it work?

Thank you in advance for your help.

Gromnax Seems that the code formatting kinda glitched, sorry.

To make the code look right, you need to put ``` above and below the code. Or select the whole section of the code and press "Insert code" </>.

```
code
```

If I understand correctly, you're trying to do something like this. Maybe some of the ideas here will help you.

SceneTexture - Icon/Thumbnail Generation

It's always better to publish MRP.

Hi, thank you so much for your quick answer!

I corrected the code formatting. I also uploaded a MRP here : https://github.com/Gromnax/Godot-MRP-Bug---Viewports
My sincere apologizes for not doing so in my first message.
To reproduce, simply open the project. You can also reproduce at will by clearing the output logs and opening the PlayerInventory scene.

The addon you linked looks exactly like what I am trying to achieve, I will definitely check it out, thank you. I am still wondering where the issue I am facing is coming from, though. Even forcing a check on wether the viewport actually exists before accessing it, as well as forcing the update mode to always through code, do not seem to correct the issue :

extends Button
class_name InventorySlot

@export var max_size : Enums.SIZE = Enums.SIZE.XL
@export var inventory_type : Enums.CLOTHING :
	set(new_value) :
		#print(Enums.CLOTHING_ICON[new_value])
		%EmptyTexture.texture = load(Enums.CLOTHING_ICON[new_value])
		inventory_type = new_value
@onready var full_texture : TextureRect = %FullTexture


@export var inventory_item : InventoryItem :
	set(new_value):
		if not %ObjectViewer3D.is_node_ready():
			pass
		if new_value == null:
			%EmptyTexture.visible = true
			%FullTexture.visible = false
			%RenderedMesh.mesh = null
			inventory_item = null
		else:
			%EmptyTexture.visible = false
			%FullTexture.visible = true
			%RenderedMesh.mesh = new_value.mesh
			inventory_item = new_value
			new_value.on_mesh_changed.connect(_on_inventory_item_mesh_changed)



# Called when the node enters the scene tree for the first time.

func _on_inventory_item_mesh_changed(new_mesh : Mesh) -> void:
	if %ObjectViewer3D.is_node_ready():
		%RenderedMesh.mesh = new_mesh

func _ready() -> void:
	%ObjectViewer3D.render_target_update_mode = %ObjectViewer3D.UPDATE_ALWAYS


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	pass

    Gromnax I am still wondering where the issue I am facing is coming from, though. Even forcing a check on wether the viewport actually exists before accessing it, as well as forcing the update mode to always through code, do not seem to correct the issue :

    I can only speculate. A texture cannot be set in the same frame in which it is received. Only in the next. Perhaps you need to introduce a delay of one frame between receiving a texture and its installation. Probably in the plugin you can find a hint how to do it.

    I have checked a bit the plugin, it seems it only allows for static images and acts as if it was taking a screenshot of the scene. It does not seem that it would allow for the 3D effect I am trying to achieve.
    This user on reddit did achieve what I want to do and used the same hierarchy as I did in my original project: .

    I couldn't find anything about his own projects beside that. I might send him a message to ask him how he did it.

      Gromnax I might send him a message to ask him how he did it.

      Yeah, that would be interesting. I'm going to look into it more closely in a little while.

        Tomcat Yeah, that would be interesting. I'm going to look into it more closely in a little while.

        I really appreciate the efforts, thank you very much. Updating as soon as I have more info, though the reddit thread is 10 months old, so it might take a while.

        Tomcat For any future people reading this, I made a public mvp of this system and shared it on Github: https://github.com/exiskra/godot-3D-UI

        Also made a post on reddit where people pointed out some mistakes I may have made, that make the current system too performance intensive and complicated, maybe worth a read:

          5 days later

          can we have someone translate it into readable gdscript?

          Performance question, more out of curiosity. If only rotation of an item in inventory is needed. Is subviewport a fairly lightweight solution, or does it make sense to generate preview files sequentially as video (and update if the item changes).

          • Edited

          It looks like an internal engine error. As you can see, a completely simple scene with a working subviewport and texture from it also gives the same error.

          It's very strange. After saving and restarting the project, the error disappeared.

          It turned out to be even more interesting than it looked at first glance. And, the idea of creating a video preview and inserting it into an item slot doesn't seem as crazy as it did at first.

          This line doesn't seem to transfer the texture into the main scene:

          @onready var full_texture : TextureRect = %FullTexture