+1 vote

Hi is it possible to get the mipmap data from a texture? I'm trying to get a low resolution version of a texture. I was thinking of copying the texture and resizing it, but if there's a way to access the mipmap that might be better.

Is there a way to do this?

in Engine by (33 points)

1 Answer

+1 vote

There are only a few corner cases where it makes sense to directly access the mipmaps.
Normally you'd want to let godot handle it automatically for you.

But for the interested and since i just had the same need:

func _get_bytes_per_pixel(format):
    # This will only work for uncompressed formats
    # where each pixel has the same ammount of bytes.
    var tmp = Image.new()
    tmp.create(1, 1, false, format)
    return tmp.get_data().size()

func get_mipmap(img, level, bytes_per_pix=null):
    # Supports all MIP levels,
    # but has some limitations regarding formats.
    assert img.has_mipmaps()
    if img.is_compressed():
        img.decompress()
    if bytes_per_pix == null:
        bytes_per_pix = _get_bytes_per_pixel(img.get_format())
    var mip_offset = img.get_mipmap_offset(level)
    var size = img.get_size()
    var new_width = int(size.x / pow(2, level))
    var new_height = int(size.y / pow(2, level))
    var buffer = img.get_data().subarray(mip_offset, mip_offset + bytes_per_pix * new_width * new_height - 1)
    var mip = Image.new()
    mip.create_from_data(new_width, new_height, false, img.get_format(), buffer)
    assert mip.get_size() == Vector2(new_width, new_height)
    return mip

func _get_mipmap(img, level):
    # Doesn't need to care about formats,
    # but can't handle the smallest MIP level.
    assert img.has_mipmaps()
    if img.is_compressed():
        img.decompress()
    var mip_offset = img.get_mipmap_offset(level)
    var next_offset = img.get_mipmap_offset(level + 1)
    assert mip_offset >= 0 and next_offset > 0
    var size = img.get_size()
    var new_width = int(size.x / pow(2, level))
    var new_height = int(size.y / pow(2, level))
    var buffer = img.get_data().subarray(mip_offset, next_offset - 1)
    var mip = Image.new()
    mip.create_from_data(new_width, new_height, false, img.get_format(), buffer)
    assert mip.get_size() == Vector2(new_width, new_height)
    return mip

One can also access the mipmaps from fragment shaders via the textureLod function.

by (121 points)

Worked for me perfectly. Thank you.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.