OpenGL - Asymmetric Textures - opengl

Assume I have several images that I would like to pack into a single texture. The size of one dimension of every image is the same (I.E. All images have the same width but have different heights, or all images have the same height but varying widths). Would there be any advantages/disadvantages to packing all of the images into a very wide or very tall texture as opposed to packing the images into a square texture via a binary tree packing algorithm? For example, would it be a bad idea to use a texture with a size of 32x8192 as opposed to a texture with a size of 512x512? Technically, both textures would contain 262,144 pixels so I'm curious to know if they would perform equally well.

Related

Create texture array [duplicate]

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).

Texture compression from 4096 to 512 without losing quality

I baked texture on a 4k image and I downscaled it to 512 using Gimp but the quality is bad in Unity 3D. The image format is png.
Is it a good idea to bake texture on a 4k image and to downscale to 512 for mobile game?
What can I do to keep a good quality on baked texture with small size (512 or below) for mobile game development?
In general, you can expect to sacrifice some texture quality if you use a smaller texture. It makes sense: with less data, something must be lost, and that's usually fine details and sharp edges. There are some strategies available, though, to get the most out of your texture data:
Make sure your model's UVs are laid out as efficiently as possible. Parts where detail is important -- like faces -- should be given more UV space than parts where detail is unimportant -- like low-frequency clothing or the undersides of models. Minimize unused texture space.
Where feasible, you can use overlapping UVs to reuse similar portions of your UV space. If your model is exactly symmetrical, you could map the halves to the same space. Or if your model is a crate with identical sides, you could map each side to the same UV square.
See if you can decompose your texture into multiple textures that are less sensitive to downsizing, then layer them together. For instance, a landscape texture might be decomposable into a low-frequency color texture and a high-frequency noise texture. In that case, the low-frequency texture could be scaled much smaller without loss of quality, while the high-frequency texture might be replaceable with a cropped, tiled texture, or procedurally generated in the shader.
Experiment with different resizing algorithms. Most image editors have an option to resize using bicubic or bilinear methods. Bicubic does a better job preserving edges, while bilinear can sometimes be a better match for some content/shaders. You may also be able to improve a resized texture with careful use of blur or sharpen filters.
If the hardware targeted by your game supports it, you should evaluate using hardware compression formats, like ETC2 or ASTC. The ETC2 format, for example, can compress 24-bit RGB texture data to be six times smaller while still having the same image dimensions. The compression is lossy, so some image information is lost and there are some artifacts, but for some content it can look better than raw textures rescaled to a similar data size. Depending on content, some combination of resizing and hardware texture compression may get you closest to your desired quality/size tradeoff. The Unity manual claims it automatically picks a good default texture format when exporting, but you can try other ones in the export options.
Usually, the motivation for using smaller textures is to consume less video memory and improve performance. However, if the motivation is simply to reduce the download size of the game, you could try alternate image formats. JPG, for instance, lets you choose an image quality value to get a smaller file size. It's rarely used for games, though, because it takes up as much video memory as a similarly sized PNG, can have artifacts, and doesn't support alpha.

opengl tall texture vs wide texture for memory locality

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.

Understanding the difference between a 2D texture array and a 3D texture?

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).

Texturing Opengl Terrain?

What is the best way to texture terrain made from quads in OpenGL? I have around 30 different textures I want to have for my terrains (1 texture per terrain type, so 30 terrain types) and would like to have smooth transitions between any two of the terrains.
I have been doing some browsing on the web and found that there are many different methods, including 3d texturing, Alpha channels, blending, and using shaders. However, which of these is the most efficient and can handle the amount of textures I am looking to use? For example: This popular answer describes how to use some techniques, but since the mixmap only has 4 properties (RGBA) and so can only support 4 textures.
I should also note that I know nothing about shaders, so non-shader required techniques would be preferable.
Since you linked to an answer that describes texture splatting, and its question mentions the game Oblivion, I can provide some additional insight into that.
Basic texture splatting with an RGBA mixmap only supports four textures per terrain quad, but you can use different sets of textures for different quads. Oblivion divides its terrain into squares (called "cells") of 32 grid points (192 feet) per side, and each cell defines its own set of four terrain textures. So you can't have lots of texture diversity within a small area, but you can easily vary your textures over larger regions. If you prefer, you can define texture sets for smaller regions, even individual quads, at the expense of using more memory.
If you really need more than four textures in a quad, you can use multiple mixmaps. For each additional one, you just do another texture lookup to get four more blending factors, and blend in four more textures on top of the results from the previous mixmap. You can scale up to as many textures as you want, again at the expense of memory.
Texture splatting can be tricky to combine with with LOD techniques on the height map, because when a single low-detail terrain quad represents a group of high-detail quads, you have to sample several different mixmaps for different regions of the big quad. Oblivion sidesteps that problem by using texture splatting only for full-detail terrain; distant cells, rendered at lower resolution, use precomputed textures produced by the editor, which does the splatting and downscaling in advance.
One alternative to texture splatting is to use a clipmap to render a "megatexture". With this approach, you have a single large texture that represents your entire terrain, and you avoid filling up your RAM by loading different parts of it with only as much detail as is actually needed to render it based on the viewer's current position. (Distant parts of the terrain can't be seen at full detail, so there's no need to load them at full detail.)
The advantage of this approach is its artistic freedom: you can place fine details anywhere you want in the texture, without regard to the vertex grid. The disadvantage is that it's rather complex to implement, and the entire clipmap has to be stored somewhere, probably in a big file on disk, so that you can load parts of it into RAM as needed.