Get mipmap data from texture?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By keenfoong

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?

:bust_in_silhouette: Reply From: sleepprogger

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.

Worked for me perfectly. Thank you.

JohnMeadow1 | 2020-07-27 12:37