Topic was automatically imported from the old Question2Answer platform.
Asked By
Juxxec
Greetings,
Is there a way to render a scene to a texture, free the scene and then use the texture as image.
I have some custom GraphNodes. I want to generate preview images for each node automatically when the game starts. I want to use these textures as items in an ItemList. I tried the following:
The scene I am trying to render to a texture has the following hierarchy.
I have a script attached to an ItemList node in another scene (my main scene). In the _ready method of the ItemList node I use get_texture to get the texture from the Viewport of the instantiated scene I wish to render to a texture and then I try to add an item to the ItemList using the texture I just created. This is the script I am using in the ItemList node:
extends ItemList
func _ready():
var scene = load("res://Scenes/Previews/Vector3NodePreview.tscn").instance()
var imageTexture = ImageTexture.new()
var image = scene.get_node("Viewport").get_texture().get_data()
imageTexture.create_from_image(image)
add_item(scene.get_node("Viewport/Node").title, imageTexture)
pass
The only way I got it to render to a texture was to have the ViewportContainer be a child of my main scene. Then the code above works. However, the ViewportContainer renders ontop of my main scene as well. If I set the Visible property to false of the ViewportContainer, then the texture becomes empty. If I make the ViewportContainer render behind it’s parent, then touches stop working.
What am I doing wrong and how can I achieve the effect I desire?
To put it into more simple words: I want to render a single frame of a scene to a texture and then use that texture as am ItemList item.
You can query the image data from the viewport texture.
var img = viewport.get_texture().get_data()
and assign it to another texture (here assigned to a TextureRect control):
var tex=ImageTexture.new()
tex.create_from_image(img)
aTextureRectNode.texture=tex
I use it for transferring a viewport over the network (remote controlling an app). It should work.
Greeting wombatstampede,
I tried what you suggest, but it is still not working. I updated my question with more details.
Juxxec | 2019-04-04 19:22
Greetings!
I managed to solve my problems, though I do not fully understand why my code works.
I chaned the script attached to the ItemList to this:
extends ItemList
var preview_generated = false
func _ready():
pass
func _process(delta):
if (!preview_generated):
generate_previews(["res://Scenes/Previews/Vector3NodePreview.tscn"])
preview_generated = true
func generate_previews(nodes):
for node in nodes:
var scene : Node = load(node).instance()
add_child(scene)
yield(get_tree(), "idle_frame")
var imageTexture = ImageTexture.new()
var image = Image.new()
image.copy_from(scene.get_node("Viewport").get_texture().get_data())
imageTexture.create_from_image(image)
add_item(scene.get_node("Viewport/Node").title, imageTexture)
remove_child(scene)
scene.queue_free()
Without the add_chiild / remove_child lines the script does not work. Without the yield(get_tree(), “idle_frame”) the code does not work ether.
Does anyone know why?
Juxxec | 2019-04-04 19:52
First of all:
Good idea to use image.copy_from. That eliminates the possibility that the data from get_data() is shared. (I’m unsure about that though())
You’re loading a scene and then instanciating it. Probably it won’t render (to the viewport) unless it is part of the scenetree. Therefore adding it as a child helps.