ASTC textures

article/2025/11/10 7:45:04

ASTC textures

原文:https://arm-software.github.io/opengl-es-sdk-for-android/astc_textures.html

This document describes usage of compressed ASTC textures.

Introduction

This tutorial shows how Adaptive Scalable Texture Compression (ASTC) can be easily used in simple scene, which is a textured sphere spinning in 3D space. It simulates an earth globe lighted from one side with a camera zooming in and out on its surface.

Warning

In order to use ASTC formats you need to run your application on hardware which supports corresponding OpenGL ES extension(s):

  • GL_KHR_texture_compression_astc_ldr or
  • GL_KHR_texture_compression_astc_hdr.

Otherwise, you will be getting messages about invalid format/internalformat passing through glCompressedTex* function to underlying graphics driver.

What is ASTC?

The ASTC algorithm represents a group of lossy block-based compressed texture image formats. For information on why texture compression is needed see chapter Why use texture compression? Two and three dimensional textures may be encoded using low or heigh dynamic range. In this demonstrating example we take under consideration only 2D, LDR textures. Basic concept of encoding relies on division the compressed image into a number of blocks with a uniform size. Each block is stored with a fixed 16-bytes footprint, regardless of the block’s dimensions. That’s why it can represent a varying number of texels and bit rate is determined by block size (see below table), which allows content developers to fine-tune the tradeoff of space against quality.

Block sizeBit rate
4x48.00 bpp
5x46.40 bpp
5x55.12 bpp
6x54.27 bpp
6x63.56 bpp
8x53.20 bpp
8x62.67 bpp
8x82.00 bpp
10x52.56 bpp
10x62.13 bpp
10x81.60 bpp
10x101.28 bpp
12x101.07 bpp
12x120.89 bpp

ASTC offers also support for 1 to 4 color channels, together with modes for uncorrelated channels for use in mask textures and normal maps. Decoding one texel requires data from a single block only, which highly simplifies cache design, reduces bandwidth and improves encoder throughput. Despite this, ASTC achieves peak signal-to-noise ratios (PSNR) better than or comparable to existing texture compression algorithms (e.g. ETC1/ETC2).

Note

​ For more details on ASTC algorithm visit1

Texture preview

You can preview and analyse your texture image how it looks like after decompression using Texture Compression Tool (TCT):

  1. Download and install TCT from2

  2. Open your existing image file.

  3. Specify compression options in the ASTC tab which appears after pressing F7.

    TCTastcTab.png

  4. Confirm compression set up with OK. Preview is generated automatically.

Texture encoding

You can compress your texture image to ASTC format using command line interface:

  1. Download and install ASTC evaluation codec from3

  2. Compress you input image file to ASTC format using following syntax:

    astcenc.exe -c <inputfile> <outputfile> <rate> [options]

Note

​ For more information on how to use ASTC encoder just type:astcenc.exe

Texture loading

In this sample sphere is covered with color that is result of combining colors from three texture units: cloud and gloss unit, day time unit and night time unit. Hence, firstly all compressed ASTC textures have to be decoded and specified for targets in order to generate texture bindings that will be next bound to particular texture units. For doing it load_texture() function is responsible, which follows the steps:

  • Texture image file is opened and loaded into local memory buffer.
  • Local buffer is mapped on ASTC header in order to extract texture image properties like ASTC block dimensions and sizes.
/* ASTC header declaration. */
typedef struct
{unsigned char magic[4];unsigned char blockdim_x;unsigned char blockdim_y;unsigned char blockdim_z;unsigned char xsize[3];unsigned char ysize[3];unsigned char zsize[3];
} astc_header;
  • Based on extracted texture properties the values of arguments passed to glCompressedTexImage2D are computed. Total number of bytes to be used by this call is computed by multiplying number of bytes per block and number of blocks which stands for:
/* Merge x,y,z-sizes from 3 chars into one integer value. */
xsize = astc_data_ptr->xsize[0] + (astc_data_ptr->xsize[1] << 8) + (astc_data_ptr->xsize[2] << 16);
ysize = astc_data_ptr->ysize[0] + (astc_data_ptr->ysize[1] << 8) + (astc_data_ptr->ysize[2] << 16);
zsize = astc_data_ptr->zsize[0] + (astc_data_ptr->zsize[1] << 8) + (astc_data_ptr->zsize[2] << 16);/* Compute number of blocks in each direction. */
xblocks = (xsize + astc_data_ptr->blockdim_x - 1) / astc_data_ptr->blockdim_x;
yblocks = (ysize + astc_data_ptr->blockdim_y - 1) / astc_data_ptr->blockdim_y;
zblocks = (zsize + astc_data_ptr->blockdim_z - 1) / astc_data_ptr->blockdim_z;/* Each block is encoded on 16 bytes, so calculate total compressed image data size. */
n_bytes_to_read = xblocks * yblocks * zblocks << 4;
  • Finally, glCompressedTexImage2D is invoked.
GL_CHECK(glGenTextures(1, &to_id));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, to_id));/* Upload texture data to ES. */
GL_CHECK(glCompressedTexImage2D(GL_TEXTURE_2D,0,compressed_data_internal_format,xsize,ysize,0,n_bytes_to_read,(const GLvoid*) astc_data_ptr));

After a new texture ID has been generated texture object can be bound to target. Then, compressed data may be passed to driver.

  • Texture parameters are set up for GL_TEXTURE_2D target.
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     GL_REPEAT));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     GL_REPEAT));

Texture magnification and minification function are set to GL_LINEAR, which correspond to linear filtering. Texture filtering is a process of calculating color fragments from streched or shrunken texture map. Linear filtering works by applying the weighted average of the texels surrounding the texture coordinates. Texture wrapping modes are set to GL_REPEAT, which means that the textures will be repeated across the object.

Texture updating

Once we have got all texture bindings for GL_TEXTURE_2D target we are able to use and switch them at our convenience. It’s a job of update_texture_bindings() function.

/* Update texture units with new bindings. */
GL_CHECK(glActiveTexture(GL_TEXTURE0));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_ids[current_texture_set_id].cloud_and_gloss_texture_id));
GL_CHECK(glActiveTexture(GL_TEXTURE1));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_ids[current_texture_set_id].earth_color_texture_id));
GL_CHECK(glActiveTexture(GL_TEXTURE2));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_ids[current_texture_set_id].earth_night_texture_id));

In each 5 sec texture bindings for texture units are refreshed following block size order from the table in section What is ASTC?

Visual output

You should see visual output similar to:

AstcTextures.png

Appendix: Mesh data flow

Generating vertex positions, texture coordinates and normal vectors is implemented based on spherical coordinate system. All mesh data are produced by solid sphere constructor.

class SolidSphere
{
public:SolidSphere(const float radius, const unsigned int rings, const unsigned int sectors);/* Mesh data accessors. */float* getSphereVertexData(int* vertex_data_size);float* getSphereNormalData(int* normal_data_size);float* getSphereTexcoords (int* texcoords_size);unsigned short* getSphereIndices(int* n_indices);private:float* sphere_vertices;float* sphere_normals;float* sphere_texcoords;unsigned short* sphere_indices;int sphere_vertex_data_size;int sphere_normal_data_size;int sphere_texcoords_size;int sphere_n_indices;
};

User is responsible for passing radius, number of rings (parallels) and sectors (meridians) to the constructor. It computes coordinates for each vertex according to formulas:

sphericalCoordinates.png

In such defined model space Φ Φ Φ changes from 0 to 360 degrees and Θ Θ Θ from 0 to 180 degrees. As it is depicted on figure, Θ Θ Θ range has to be divided by the number of rings and the range of Φ ​ Φ​ Φ by the number of sectors. Smooth appearance of the sphere surface depends on a number of vertices.

const float R = 1.0f / (float)(rings - 1);
const float S = 1.0f / (float)(sectors - 1);
for (r = 0; r < rings; r++)
{for (s = 0; s < sectors; s++){const float x = sinf(M_PI * r * R) * cosf(2 * M_PI * s * S);const float y = sinf(-M_PI_2 + M_PI * r * R);const float z = sinf(2.0f * M_PI * s * S) * sinf(M_PI * r * R);texcoords++ = s * S;texcoords++ = r * R;vertices++ = x * radius;vertices++ = y * radius;vertices++ = z * radius;normals++ = x;normals++ = y;normals++ = z;}
}

For a given vector position P P P on the sphere who’s center is C C C, the normal is equal to n o r m ( P − C ) norm(P - C) norm(PC), where norm normalizes the vector. Our sphere center is located at point C ( 0 , 0 , 0 ) C(0,0,0) C(0,0,0), which stands for n o r m a l ( P − C ) = n o r m ( P ) = v e r t i c e s ( x , y , z ) / r a d i u s = ( x , y , z ) normal(P - C) = norm(P) = vertices(x,y,z) / radius = (x,y,z) normal(PC)=norm(P)=vertices(x,y,z)/radius=(x,y,z). The reason why we generate normal vectors needed for light calculation is introduced in details here Normals

Texture coordinates indicating how to map an image onto mesh primitives are precisely covered in section Load Texture Function

Solid sphere constructor is also responsible for generating indices required for glDrawElements function. It has been assumed that each four vertices form two triangle primitives (GL_TRIANGLES mode), so glDrawElements call needs six vertex indices to construct them:

for (r = 0; r < rings; r++)
{for (s = 0; s < sectors; s++){/* First triangle. */indices++ = r       * sectors + s;indices++ = r       * sectors + (s + 1);indices++ = (r + 1) * sectors + s;/* Second triangle. */indices++ = r       * sectors + (s + 1);indices++ = (r + 1) * sectors + (s + 1);indices++ = (r + 1) * sectors + s;}
}

In the next step generated vertex positions, normals and texture coordinates are loaded into buffer object.

/* Load generated mesh data from SolidSphere object. */
float* sphere_vertices  = solid_sphere->getSphereVertexData(&sphere_vertices_size);
float* sphere_normals   = solid_sphere->getSphereNormalData(&sphere_normals_size);
float* sphere_texcoords = solid_sphere->getSphereTexcoords(&sphere_texcoords_size);/* Size of the entire buffer. */
GLsizei buffer_total_size = sphere_vertices_size + sphere_normals_size + sphere_texcoords_size;/* Create buffer object to hold all mesh data. */
GL_CHECK(glGenBuffers(1, &bo_id));
GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, bo_id));
GL_CHECK(glBufferData(GL_ARRAY_BUFFER, buffer_total_size, NULL, GL_STATIC_DRAW));

After the above listing has executed, bo_id contains the unique ID of a buffer object that has been initialized to represent buffer_total_size bytes of storage. Passing GL_ARRAY_BUFFER as a binding point to refer to the buffer object suggests to OpenGL ES that we are about to put data in order to feed vertex attributes. Expected usage pattern of the data store is set to GL_STATIC_DRAW which signalizes graphics driver that buffer content will be set once, but used frequently for drawing.

Then, place the mesh data into the buffer object at the corresponding offsets:

/* Upload subsets of mesh data to buffer object. */
GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER, 0, sphere_vertices_size, sphere_vertices));buffer_offset += sphere_vertices_size;GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER, buffer_offset, sphere_normals_size, sphere_normals));buffer_offset += sphere_normals_size;GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER, buffer_offset, sphere_texcoords_size, sphere_texcoords));

Note
In this step the data are copied from a local memory storage to update buffer object’s content. Immediately after this, memory pointed by the sphere_vertices, sphere_normals and sphere_texcoords pointers may be freed.

Before we can go on, let’s create a vertex array object to store vertex array state.

GL_CHECK(glGenVertexArrays(1, &vao_id));
GL_CHECK(glBindVertexArray(vao_id));

Once it is generated and bound, we are able to fill in its content. The goal is to determine OpenGL ES to connect vertex attributes values directly with the data stored in the supplied buffer object.

GL_CHECK(glEnableVertexAttribArray(position_location));
GL_CHECK(glEnableVertexAttribArray(normal_location));
GL_CHECK(glEnableVertexAttribArray(texture_coords_location)));buffer_offset = 0;/* Populate attribute for position. */
GL_CHECK(glVertexAttribPointer(position_location, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) buffer_offset));buffer_offset += sphere_vertices_size;/* Populate attribute for normals. */
GL_CHECK(glVertexAttribPointer(normal_location, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) buffer_offset));buffer_offset += sphere_normals_size;/* Populate attribute for texture coordinates. */
GL_CHECK(glVertexAttribPointer(texture_coords_location, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) buffer_offset));

Automatic filling of the attributes is enabled with glEnableVertexAttribArray calls. Next, we have to inform graphics driver where the data is and turn on vertex fetching for all attributes. Whereas a non-zero buffer is currently bound to the GL_ARRAY_BUFFER target, last argument in glVertexAttribPointer function specifies an offset in the data store of that buffer.

Sphere lighting

This sample uses Phong lighting model which has been explained in details in section Lighting

References


  1. http://www.khronos.org/registry/gles/extensions/KHR/texture_compression_astc_hdr.txt ↩︎

  2. http://malideveloper.arm.com/develop-for-mali/tools/asset-creation/mali-gpu-texture-compression-tool/ ↩︎

  3. http://malideveloper.arm.com/develop-for-mali/tools/astc-evaluation-codec ↩︎


http://chatgpt.dhexx.cn/article/memFx8qO.shtml

相关文章

[图形学]ASTC纹理压缩格式

纹理压缩的目的 1&#xff0c;降低内存&#xff0c;特别是移动端应用&#xff0c;内存占用不应过大&#xff0c;否则低端机很容易崩溃 2&#xff0c;降低带宽&#xff0c;手游类应用&#xff0c;在渲染时会有大量贴图传输到GPU&#xff0c;不限制的话不仅会严重影响渲染性能&a…

ASTC纹理压缩格式(Adaptive Scalable Texture Compression)

原文&#xff1a;这是一个pdf的下载链接 介绍 Adaptive Scalable Texture Compression(ASTC)是一种世界领先的新型纹理压缩格式。这种压缩格式已经加入Khronos标准&#xff0c;并已在某些硬件平台中提供。本文介绍了它的工作原理、使用方法和如何最大程度地使用它。更深入的信…

ASTC纹理压缩格式介绍

一、ASTC纹理压缩格式介绍 ASTC是在OpenGL ES 3.0出现后&#xff0c;在2012年中产生的一种业界领先的纹理压缩格式&#xff0c;它的压缩分块从4x4到12x12最终可以压缩到每个像素占用1bit以下&#xff0c;压缩比例有多种可选。ASTC格式支持RGBA&#xff0c;且适用于2的幂次方长宽…

选择软件人力外包公司看这几点没错

近几年&#xff0c;大数据、云计算等各种互联网技术飞速发展&#xff0c;深入到我们工作生活的各个角落。很多企业为了提升竞争力也加快了信息化建设的步伐&#xff0c;而信息化建设的关键就是软件人才&#xff0c;谁能快速构建真正高效的软件开发团队&#xff0c;谁就能先一步…

10 个Web3 设计灵感网站

10 个Web3 设计灵感网站&#xff1a;Cosmos、Axies Infinity、DeSo Foundation、Foundation App、Llama、Snapshot、Juicebox、Alchemy、RabbitHole 正如Twitter前首席执行官Jack Dorsey最近发的一条推文“你不拥有web3&#xff0c;但风险投资家拥有”&#xff0c;而Marc Andre…

web 服务器有哪些

<1>什么是web服务器 "网络服务"&#xff08;Web Service&#xff09;的本质&#xff0c;就是通过网络调用其他网站的资源。 Web Service架构和云 如果一个软件的主要部分采用了"网络服务"&#xff0c;即它把存储或计算环节"外包"给其他…

要不要进外包?

互联网行业的估计都听过这句话:外包&#xff0c;你是外包&#xff0c;麻烦不要偷吃公司零食&#xff0c;注意素质&#xff01; 事情是这样的:她说自己被外派到一家大公司上班&#xff0c;因为那家公司是大公司&#xff0c;在休息的时候还提供零食和下午茶。大家都知道女生爱吃…

为什么程序员做外包会被瞧不起?

二哥&#xff0c;有个事想询问下您的意见&#xff0c;您觉得应届生值得去外包吗&#xff1f;公司虽然挺大的&#xff0c;中xx&#xff0c;但待遇感觉挺低&#xff0c;马上要报到&#xff0c;挺纠结的。 以上是读者小 K 给我发的私信。除此之外&#xff0c;还有个读者 down 也问…

被迫选择了到了外包公司

即使大厂裁员下来的员工愿意被迫选择了到了外包公司&#xff0c;迫不得已做外包的工作&#xff0c;那么&#xff0c;中小型企业那势必也得裁员&#xff0c;为了接收从大厂下来的&#xff0c;有大厂背景的员工&#xff0c;那么就会裁掉自己公司的员工。 这样看来&#xff0c;这…

测试应届生是去自研小公司好还是外包公司好?

我不知道当年怎么想的&#xff0c;能在一个外包公司一干就是3年&#xff0c;后来终于跳出来了&#xff0c;现在的公司虽然不是什么大厂吧&#xff0c;但至少是个正经的互联网企业&#xff0c;待遇也不错。其实很多地方的朋友都有提到外包公司的一些弊端。 外包公司&#xff1a…

网站建设公司该不该把web前端外包出来!精辟

如今的网站建设公司其实过的并不好&#xff0c;一些建站平台、模板建站、仿站等都对网站定制造成了比较大的影响&#xff0c;网站建设公司如何降低用人成本、灵活的整合第三方资源成为度过“特殊时期”的重要手段&#xff0c;迎接下一波春天的到来。 网站建设公司该不该把前端…

外包公司面试门槛高吗?软件测试员进外包公司容易吗?

虽然很多测试人员都抵制外包&#xff0c;但实际情况则是依旧有大量软件测试员&#xff0c;选择加入到外包这个圈子。外包公司面试门槛高吗?外包公司容易进吗?本篇来解答一下这个问题。 外包公司面试门槛高吗&#xff1f; 外包的面试门槛&#xff0c;相对大厂要低很多。尤其…

我的web前端工作日记11------在腾讯外包的这一年

说在前面的话 本文只是大概说一下自己在腾讯做了一年前端外包的收获和一些心得感悟&#xff0c;希望自己能客观的描述&#xff0c;能给一些后来者参考取舍&#xff0c;看是否值得去腾讯做外包。写的没啥逻辑&#xff0c;都是想到啥就写啥&#xff0c;所以大家将就着看看。 一…

进程平均周转时间的计算

题目&#xff1a; 有4个进程A,B,C,D,设它们依次进入就绪队列&#xff0c;因相差时间很短可视为同时到达。4个进程按轮转法分别运行11,7,2,和4个时间单位&#xff0c;设时间片为1。四个进程的平均周转时间为 &#xff08;&#xff09;&#xff1f; 分析 要理解周转时间的含义&am…

操作系统进程完成时间,周转时间,带权周转时间, 平均周转时间, 带权平均周转时间计算

计算规则 周转时间作业完成时刻-作业到达时刻&#xff1b; 带权周转时间周转时间/服务时间&#xff1b; 平均周转时间作业周转总时间/作业个数&#xff1b; 平均带权周转时间带权周转总时间/作业个数&#xff1b;

平均周转时间和平均带权周转时间怎么算?

周转时间&#xff1a;从作业被提交给系统开始&#xff0c;到作业完成为止的这段时间间隔称为作业周转时间。 带权周转时间&#xff1a;即作业的周转时间T与系统为它提供服务的时间Ts之比&#xff0c;即W  T/Ts 周转时间 作业完成时刻 - 作业到达时刻带权周转时间 周转时间…

操作系统:周转时间和其他时间

1&#xff0c;周转时间 周转时间&#xff1a;作业被提交给系统开始&#xff0c;到作业完成为止的这段时间间隔。 包括&#xff1a;&#xff08;1&#xff09;作业在外存后备队列上的等待作业调度的时间。&#xff08;2&#xff09;进程在就绪队列上等待进程调度的时间。&#x…

多种调度算法的平均周转时间算例

有5个批处理的作业&#xff08;A、B、C、D和E&#xff09;几乎同时到达一个计算中心&#xff0c;估计的运行时间分别为2、4、6、8、10分钟&#xff0c;它们的优先数分别为1、2、3、4、5&#xff08;1为最低优先级&#xff09;。对下面的每种调度算法&#xff0c;分别计算作业的…

FCFS计算周转时间、带权周转时间、平均周转时间和平均带权周转时间。

#include<stdio.h> #include<string.h> #include<conio.h> main() {char pn[10][10],t[10];int arr[10],bur[10],star[10],finish[10],tat[10],wt[10],i,j,n,temp;int totwt0,tottat0; //clrscr();printf("请输入进程数量:");scanf("%d"…

周转时间 平均周转时间 带权周转时间 平均带权周转时间

1.周转时间 2.平均周转时间 平均周转时间是对n个而言的 3.带权周转时间 真正的运行时间指的是进程占有处理机的时间 4.平均带权周转时间 即n个平均的带权周转时间