How to generate a texture2darray for shader

My shader need a texture2darray but I don’t know how to construct a valid object. Though texture class in panda3d provides setup2dTextureArray(), I have no thought how to fill the data.
TexturePool class has a load2dTextureArray method, but I want to create it using existing texture in memory, instead of in disk.
I have tried concatenating texture datas as following:

            a_textures_array = Texture()
            a_textures_array.setup2dTextureArray(750, 750, texture_amount, Texture.T_float, Texture.F_rgba)  # 750, 750 is the pixel amount of the textures I intend to use
            ptr = a_textures_array.modifyRamImage()
            size = 786465  # bytes
            for n, texture in enumerate(list_of_textures):  # This list contains several textures
                ptr.setSubdata(n * size, size, texture.getRamImage().getData())

However, running this code would get a error, which comes from function graphicsEngine.renderFrame, saying AssertionError: image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n).
And I found texture2darray object has a strange size as 33 when texture_amount == 0 and 9000033 when texture_amount == 1, while a single texture occupy 786465 bytes.
There is another topic with the same question, but it has not been properly answered:

So I am asking again for a solution. Any help would be greatly appreciated.

It’s easy but you have to use the advanced load() method to specify which index of the array you are loading :

        tex = Texture()
        for (page, texture) in enumerate(textures):
                image = texture.create_image()
                tex.load(image, z=page, n=0)
        return tex

Here textures is an array of texture generators and create_image() returns a PNMImage containing the ram image.

1 Like

You set it up as a float (4-byte) rgba (4 component) texture, so this comes down to 750 * 750 * 4 * 4 = 9000000 bytes.

The method you are using should work fine, if you have the right size for the format you have selected. You can get the expected size for an individual page using tex.getExpectedRamMipmapPageSize().

I think you are getting the assertion because you are calling clear() on the image.

Thank you for helping again. But when I run the code, I have a AttributeError: ‘panda3d.core.Texture’ object has no attribute ‘create_image’. I am using panda3d 1.10.5,

Thank you for replying. I get a size of 786432 still for a single image using tex.getExpectedRamMipmapPageSize() or tex.getExpectedRamImageSize(). And UncompressedRamImage has the same size which really confuses me.
The image may be resized to 512x512, and 512x512x3(jpg file)=786432, but I can’t explain absence of float size (4).
Changing texture array size to 512x512 has no effect.
And clear() of the pointer seems be unrelated to the error: same error occurs after I comment that.

Sorry, I wrote that in a hurry and did not explain it correctly. in my example the textures list does not contain Texture objects but objects that have a method create_image() that returns a PNMImage instance. Instead you could simply have a list of PNMImage.

Sadly Panda has methods to directly load mipmap levels directly from the ram, but it’s not possible for array pages, so you have to use PNMImage or manipulate the memory as you do.

1 Like

If they are loaded from jpg files, perhaps your images are actually using TUnsignedByte instead of TFloat?

Also, it would be good to set textures-power-2 none in Config.prc to make sure Panda isn’t rescaling your textures to a power-of-2 size.

1 Like

Yes, thank you for that. After setting data type to unsignedbyte and turning off auto rescaling I got the
expected result.