Viewport texture returns blank data

uaknightuaknight Posts: 40Member

I'm trying to make an image of the content of a viewport, but fail. It appears to be a bug with ViewportTexture.get_data(). Before I post it in the issue tracker, I'll just check if someone else has had the same problem.

extends Node2D

func _ready():
    # Setting sprite texture directly to the viewport's texture works
    var vp_texture = $Viewport.get_texture() 
    $ViaTextureSprite.texture = vp_texture # works, the content from the viewport shows up in the sprite

    # Getting the data doesn't work 
    var image = vp_texture.get_data() # returns blank data
    print(image.data["data"].hex_encode()) # prints all zeros

    # Creating an image texture in this way works (I have tested by creating an Image from scratch)
    # However, here it gets feed a blank image
    var image_texture = ImageTexture.new()
    image_texture.create_from_image(image)
    $ViaGetDataSprite.texture = image_texture # blank image in sprite
    pass 

Comments

  • MegalomaniakMegalomaniak Posts: 2,768Admin

    Think you have to lock the image before you can read the data from it iirc.

    https://docs.godotengine.org/en/stable/classes/class_image.html#class-image-method-lock

  • uaknightuaknight Posts: 40Member

    I tried to put in lock and unlock, but it didn't help.

        var image = vp_texture.get_data()
        image.lock()
        print(image.data["data"].hex_encode()) 
        var image_texture = ImageTexture.new()
        image_texture.create_from_image(image)
        image.unlock()
    

    To lock the image, it must first exist. And it get's created in the vp_texture.get_data() call. However, the error seems to be in that function, get_data(), since it returns all zeros. And get_data() is a function of the ViewportTexture class, to retrieve (supposedly) the bytes making up the texture drawn on the viewport canvas.

    The Image class also has a get_data() but that's just a getter for it's data poperty.

    I think lock (and unlock) is only used in conjunction with the Image functions set_pixel and get_pixel, in order to manually set the content of the image.

  • TwistedTwiglegTwistedTwigleg Posts: 2,847Admin

    You may need to add:

    $Viewport.set_clear_mode(Viewport.CLEAR_MODE_ONLY_NEXT_FRAME)
    yield(get_tree(), "idle_frame")
    yield(get_tree(), "idle_frame")

    so the Viewport has a bit to take populate the viewport texture. The code above also sets the Viewport to update in the next frame, which may or may not be necessary. You will want to make sure the Viewport update mode is set to something where it will update prior to trying to get the data though, as otherwise there won't be a texture to grab.

  • uaknightuaknight Posts: 40Member
    edited August 1

    Thanks, that didn't work at first but when I changed to Viewport.UPDATE_ALWAYS, it worked. So it was the update mode which needed to be changed ,and the two extra yields added. I tested to remove them after the addition of UPDATE_ALWAYS, but then it stopped working. And only removing one also made it fail, so both of them are needed. Strange, I would never had found that solution!

    So this code works:

    extends Node2D
    
    func _ready():
        # Setting sprite texture directly to the viewport's texture works
        var vp_texture = $Viewport.get_texture() 
        $ViaTextureSprite.texture = vp_texture 
    
        $Viewport.set_update_mode(Viewport.UPDATE_ALWAYS)
        yield(get_tree(), "idle_frame")
        yield(get_tree(), "idle_frame") 
    
        # Getting the data and creating an image texture for the sprite 
        var image = vp_texture.get_data() 
        var image_texture = ImageTexture.new()
        image_texture.create_from_image(image)
        $ViaGetDataSprite.texture = image_texture        
    
  • uaknightuaknight Posts: 40Member
    edited August 1

    I may add that the reason for using the second method via the image texture is that the first method, by setting the viewport's texture directly to the sprite's texture, seems to be dynamic in nature. If you change the content of the viewport and set another sprite to this, then the first sprite has changed as well which may not be what you want.

Sign In or Register to comment.