If I understand correctly, if I was to set TEXTURE_MIN_FILTER to NEAREST then there's not much difference between sampler2DArray/TEXTURE_2D_ARRAY and sampler3D/TEXTURE_3D
The differences seem to be
GenerateMipmap will blend cross layers with 3D textures but not 2D arrays
the Z coordinate passed to texture in GLSL is 0 to 1 with 3D textures but an 0 to N (depth) in 2D arrays.
If filtering is not NEAREST 3D will blend across layers, 2D array will not.
Correct?
Incorrect. There's one more difference: mipmap sizes.
In a 3D texture, the width, height, and depth all decrease at lower mipmap sizes. In a 2D array texture, every mipmap level has the same number of array layers; only width and height decrease.
It's not just a matter of blending and some texture coordinate oddities; the very size of the texture data is different. It is very much a different kind of texture, as different from 3D textures as 2D textures are from 1D textures.
This is also why you cannot create a view texture of a 3D texture that is a 2D array, or vice-versa.
Apart from the answer already given, there is another difference worth noting: The size limits are also quite different. A single layer of an array texture may be as big as an standard 2D texture, and there is an extra limit on the number of layers, while for 3D textures, there is a limit constraining the maximum size in all dimensions.
For example, OpenGL 4.5 guarantees the following minimal values:
GL_MAX_TEXTURE_SIZE 16384
GL_MAX_ARRAY_TEXTURE_LAYERS 2048
GL_MAX_3D_TEXTURE_SIZE 2048
So a 16384 x 16384 x 16 array texture is fine (and should also fit into memory for every GL 4.5 capable GPU found in the real world), while a 3D texture of the same dimensions would be unsupported on most of todays implementations (even though the complete mipmap pyramid would consume less memory in the 3D texture case).
Related
If I understand correctly, if I was to set TEXTURE_MIN_FILTER to NEAREST then there's not much difference between sampler2DArray/TEXTURE_2D_ARRAY and sampler3D/TEXTURE_3D
The differences seem to be
GenerateMipmap will blend cross layers with 3D textures but not 2D arrays
the Z coordinate passed to texture in GLSL is 0 to 1 with 3D textures but an 0 to N (depth) in 2D arrays.
If filtering is not NEAREST 3D will blend across layers, 2D array will not.
Correct?
Incorrect. There's one more difference: mipmap sizes.
In a 3D texture, the width, height, and depth all decrease at lower mipmap sizes. In a 2D array texture, every mipmap level has the same number of array layers; only width and height decrease.
It's not just a matter of blending and some texture coordinate oddities; the very size of the texture data is different. It is very much a different kind of texture, as different from 3D textures as 2D textures are from 1D textures.
This is also why you cannot create a view texture of a 3D texture that is a 2D array, or vice-versa.
Apart from the answer already given, there is another difference worth noting: The size limits are also quite different. A single layer of an array texture may be as big as an standard 2D texture, and there is an extra limit on the number of layers, while for 3D textures, there is a limit constraining the maximum size in all dimensions.
For example, OpenGL 4.5 guarantees the following minimal values:
GL_MAX_TEXTURE_SIZE 16384
GL_MAX_ARRAY_TEXTURE_LAYERS 2048
GL_MAX_3D_TEXTURE_SIZE 2048
So a 16384 x 16384 x 16 array texture is fine (and should also fit into memory for every GL 4.5 capable GPU found in the real world), while a 3D texture of the same dimensions would be unsupported on most of todays implementations (even though the complete mipmap pyramid would consume less memory in the 3D texture case).
A 2D Texture has two coordinates, x and y. To store a 2D array in 1D memory, the two possible formats are [x + y * width] and [x * height + y]. OpenGL has various confusing row-major/column-major conventions so I am unsure which of the two formats it uses. This is relevant because if a texture is used to store multiple images, such as in a sprite sheet or atlas, it is better to have the parts of an image located close together in memory. For example, if the format is [x + y * width] and we are using a very wide texture, then the GPU will have to skip through long parts of memory to find the texels it needs.
Thus: is a tall texture atlas superior to a wide texture atlas, or is it the other way around? Or do GPUs have no memory locality benefits?
The most important aspect of a texture atlas is how many images can fit inside it. Even when it comes to texture atlases, you are far more likely to access adjacent texels than distant ones.
Think about it. Say you render 2 32x32 sprites. So that's 2 quads, in a single rendering call. Each quad will take up 32x32 pixels on the screen; that's 1024 pixels.
Locality matters; you're rendering from 1024 locally adjacent texels, then rendering from a different set of 1024 locally adjacent texels.
In any case, OpenGL does not expose you to the details of the GPU's image formats. You can ask for a particular size of texel and a number of channels. But you don't get any more details than that. The data you provide will be appropriately converted by the driver into the actual internal GPU data.
Typically, GPUs will swizzle textures in memory. This means rearranging data so that locality is preserved. That is, instead of storing texels as either x + y * width or x * height + y, they get stored in a more complex arrangement.
For example, the first 4 values would be texels 0,0; 0,1; 1,0; and 1,1. So a 2x2 block of texels is store in a single contiguous array of memory. That's an example of how swizzled texture storage works.
But this is all an implementation detail; there's nothing you can do to influence or affect this, and not even a low-level API like Vulkan allows you to directly load pre-swizzled texel data.
Question:
Why does the same amount of pixels take dramatically less video memory if stored in a square texture than in a long rectangular texture?
Example:
I'm creating 360 4x16384 size textures with the glTexImage2D command. Internal format is GL_RGBA. Video memory: 1328 MB.
If I'm creating 360 256x256 textures with the same data, the memory usage is less than 100MB.
Using an integrated Intel HD4000 GPU.
It's not about the texture being rectangular. It's about one of the dimensions being extremely small.
In order to select texels from textures in an optimal fashion, hardware will employ what's known as swizzling. The general idea is that it will restructure the bytes in the texture so that pixels that neighbor each other in 2 dimensions will be neighbors in memory too. But doing this requires that the texture be of a certain minimum size in both dimensions.
Now, the texture filtering hardware can ignore this minimum size and only fetch from pixels within the texture's actual size is. But that extra storage is still there, taking up space to no useful purpose.
Given what you're seeing, there's a good chance that Intel's swizzling hardware has a base minimum size of 32 or 64 pixels.
In OpenGL, there's not much you can do to detect this incongruity other than what you've done here.
What is the difference between glTexImage2D() and glTexImage1D()? Actually, I can't imagine 1D texturing. How can something have a 1D texture?
A texture is not a picture you draw onto triangles. A texture is a look-up table of values, which your shaders can access and get data from. You can use textures as "pictures you draw onto triangles", but you should not limit your thinking to just that.
A 1D texture is a texture with only one dimension: width. It's a line. It is a function of one dimension: f(x). You provide one texture coordinate, and you get a value.
A 2D texture is a texture with two dimensions: width and height. It is a rectangle. It is a function of two dimensions: f(x, y). You provide two texture coordinates, and you get a value.
A 1D texture can be used for a discrete approximation of any one-dimensional function. You could precompute some Fresnel specular factors and access a 1D texture to get them, rather than computing them in the shader. A 1D texture could represent the Gaussian specular term, as I do in the first chapter on texturing in my book.
A 1D texture can be any one-dimensional function.
A 2D texture has both height and width whereas a 1D texture has a height of just 1 pixel. This basically means that the texture is a line of pixels. They are frequently used when we want to map some numeric value to a colour or map colour to a different colour (as in cell-shading techniques).
In case of 3D textures,
For three-dimensional textures, the z index refers to the third dimension.
What does this exactly mean?
For two-dimensional array textures, the z index refers to the slice index.
is it like if we have 4 layers of 2D textures, then if z=2, it will refer to 2nd 2D texture slice.?
So what is difference when we have targets GL_TEXTURE_3D and GL_TEXTURE_2D_ARRAY except diff between texture cordinates?
For three-dimensional textures, the z index refers to the third dimension. What does this exactly mean?
Whatever you want it to mean.
A texture is nothing more than a lookup table. The index of this lookup table is called a texture coordinate. What a texture coordinate means depends entirely on how you intend to use it. It could be a position in space. It could be the XYZ of a function of three dimensions. It could be a lot of things.
Stop thinking of textures as pictures.
In a 2D texture, the S and T components of the texture coordinate represent how far along the X and Y axes of the texture to access. If S is 1, then it means the right side. If S is 0, it means the left side. And so forth.
The same goes for a 3D texture and the STP coordinates. If P is 0, then it means the "farthest" depth of the 3D texture. If P is 1, it means the "nearest" depth.
In terms of the data you upload, it always works based on a right-handed coordinate system. So the bottom/left/back is the (0, 0, 0) point, and the top/right/front is the (1, 1, 1) point. The first depth layer you provide in your data is the farthest depth layer, the next layer is the second-farthest, etc.
For two-dimensional array textures, the z index refers to the slice index. is it like if we have 4 layers of 2D textures, then if z=2, it will refer to 2nd 2D texture slice.?
No, it will refer to the third. Zero-based index, just like everything else in C/C++.
So what is difference when we have targets GL_TEXTURE_3D and GL_TEXTURE_2D_ARRAY except diff between texture cordinates?
There is no filtering between layers of a 2D array. If you use GL_TEXTURE_MAG_FILTER with GL_LINEAR in a 3D texture, it will sample values from 8 texels and interpolate in all 3 directions. If you do that with a 2D array, it will pick a specific Z-layer to sample from, and pick 4 texels within that layer to interpolate between.
Mipmaps work differently. A 3D texture contains 3D images. Therefore, each mipmap is 3D as well. Therefore, mipmap reduction works three-dimensionally. If the base layer is 32x32x32, then the next mipmap will be 16x16x16.
2D array textures contain 2D images. They contain an array of 2D images, but that's an implementation detail; it's just a collection of 2D images. Each 2D image has its own mipmaps, but these are 2D mipmaps. Therefore, each mipmap of a 2D array texture uses the same number of images as all of the others. Thus, if the base layer of a 2D array uses 32x32 2D images, and there are 32 of these images, the next mipmap layer will use 16x16 2D images, but there will still be 32 of them.
Array textures use integer values for the third component of the texture coordinate (the array layer to fetch from). 3D textures use normalized values for all three components.
In short, except for the functions you use to upload data to them, they have nothing at all in common.
Find out more by looking at the various pages on the OpenGL wiki about textures.
The 3D texture can interpolate in all three dimensions while the 2D array of textures only interpolates in the two image dimensions, not across the slices.