热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ETC纹理压缩和Alpha通道处理

转自:http:malideveloper.arm.comcndevelop-for-malisample-codeetcv1-texture-compression-and-alpha-

转自:http://malideveloper.arm.com/cn/develop-for-mali/sample-code/etcv1-texture-compression-and-alpha-channels/

简介

就如压缩 JPEG 图像可以让更多图像装入磁盘一样,纹理压缩也可让更多纹理装入图形硬件中,这在移动平台上尤其重要。 Mali GPU 内建了硬件纹理压缩,允许纹理在图形硬件中保持压缩状态,在所需的样本上实时解压缩。 通过在应用程序中利用压缩纹理,可以大幅减少所需的内存带宽量,因而能提高应用程序性能,降低功耗。

ETC

Ericsson 纹理压缩或 ETC 是由 Khronos 支持的开放标准,在移动平台中广泛采用。 它是一种为感知质量设计的有损算法,其依据是人眼对亮度改变的反应要高于色度改变。

ETC v1 具有一个小缺陷,以这种格式压缩的纹理会丢失任何 Alpha 通道信息,而且也没有透明区域。 由于在纹理中使用 Alpha 通道可以实现许多更聪明、更有趣的做法,许多开发人员因此采用其他纹理压缩算法,其中很多为硬件支持有限的专有格式。

支持 ALPHA 通道

下文阐述的所有方法和技巧都可在 OpenGL ES SDK for Linux on ARM 和 OpenGL ES SDK for Android 中找到,其中提供了完整的源代码。

有许多技巧可供选用,以便在应用程序中支持透明并且依然采用 ETC 压缩。 本页阐述这些技巧。

提取 ALPHA 通道

这些方法中的第一步是从纹理中提取 Alpha 通道。 由于 Alpha 通道并不包装在压缩纹理中,因此必须与压缩纹理一起交付。 虽然大部分图形程序都可用于提取 Alpha 通道,但由于执行该任务比较费力,因此Mali GPU Texture Compression Tool 中提供了相应的支持。 您可以通过在“压缩选项”对话框中选择 Alpha 处理选项,来选择是否提取 Alpha 通道和如何进行提取。


方法 1: 纹理拼图

Alpha 通道转换为可见的灰度图像,然后串联到原始纹理上,使得总体纹理图形更高。

纹理拼图

益处

只有一个文件(对纹理加载代码的更改最少)

着色器代码改动需要较少(缩放)

缺点
纹理样本只能在一个方向上正确包裹。

缩放会减慢着色器执行

方法

这是最容易实施的方法,因为在纹理拼图图像压缩后,代码中唯一需要的更改是在着色器中重新映射纹理坐标,例如:

1 gl_FragColor = texture2D(u_s2dTexture, v_v2TexCoord);

变为

123 vec4v4Colour=texture2D(u_s2dTexture,v_v2TexCoord);v4Colour.a= texture2D(u_s2dTexture,v_v2TexCoord *vec2(1.0,0.5)+v_v2TexCoord *vec2(0.0,0.5)).r;gl_FragColor=v4Colour;

这会缩放纹理坐标,以便使用图像的上半部分,然后移到下半部分以获取 Alpha 通道所处的第二样本。 本示例使用图像蒙版的红色通道来设置 Alpha 通道。

更为实际的做法是,可以向顶点着色器添加一个第二可变值。

让顶点着色器变为如下所示:

1234567891011 attribute vec4 a_v4Position;attribute vec2 a_v2TexCoord;varying vec2 v_v2TexCoord;varying vec2 v_v2AlphaCoord; void main(){    v_v2TexCoord = a_v2TexCoord * vec2(1.0, 0.5);    v_v2AlphaCoord = v_v2TexCoord + vec2(0.0, 0.5);    gl_Position = a_v4Position;}

片段着色器接着可以使用这两个可变坐标:

1234567891011 precisionmediumpfloat; uniformsampler2Du_s2dTexture;varyingvec2v_v2TexCoord;varyingvec2v_v2AlphaCoord;voidmain(){    vec4v4Colour=texture2D(u_s2dTexture,v_v2TexCoord);    v4Colour.a=texture2D(u_s2dTexture,v_v2AlphaCoord).r;    gl_FragColor=v4Colour;}

这会将稍微多一点带宽用于额外的可变 vec2,但管线利用会更佳,尤其是大多数开发人员更加倾向于操作其片段着色器,而不是顶点着色器。 通过这些细小更改,大多数应用程序都能使用纹理拼图文件正常运行。

OpenGL ES SDK 示例“ETCAtlasAlpha”中提供了本示例的完整源代码列表。

不过,您可能会在某些情形中希望保留将纹理包裹到较大区域的能力。 下文中阐述了可实现此目的的其他两种方法。

方法 2: 单独包装 ALPHA

Alpha 通道作为第二包装的纹理交付。 两个纹理在着色代码中组合。

单独包装 ALPHA

 

益处

更加灵活,允许混合和匹配 Alpha/颜色通道

允许以两个方向包裹纹理

缺点

着色器中需要第二个纹理采样器。

方法
要创建适合用于此方法的压缩图像,请在纹理压缩工具中选择“创建单独压缩的图像”。

在加载第二个纹理时,请在 glBindTexture 和 glCompressedTexImage2D 之前调用 glActiveTexture(GL_TEXTURE1),以确保在不同的硬件纹理插槽中分配 Alpha 通道。

1234 glActiveTexture(GL_TEXTURE0);loadCompressedMipmaps(TEXTURE_FILE, TEXTURE_FILE_SUFFIX, &iTexName);glActiveTexture(GL_TEXTURE1);loadCompressedMipmaps(ALPHA_FILE, TEXTURE_FILE_SUFFIX, &iAlphaName);

在设置着色器统一变量时,分配第二个纹理采样器,再绑定到第二纹理单元上:

1234 iLocSampler=glGetUniformLocation(iProgName,"u_s2dTexture");glUniform1i(iLocSampler,0);iLocSamplerAlpha=glGetUniformLocation(iProgName,"u_s2dAlpha");glUniform1i(iLocSamplerAlpha,1);

然后在片段着色器中,再一次合并这两个样本,这一次从不同的纹理执行。

123 vec4 colour = texture2D(u_s2dTexture, v_v2TexCoord);colour.a = texture2D(u_s2dAlpha, v_v2TexCoord).r;gl_FragColor = colour;

OpenGL ES SDK 示例“ETCCompressedAlpha”中提供了本示例的完整源代码列表。

方法 3: 单独的原始 ALPHA

Alpha 通道作为原始的 8 位单通道图像提供,在着色器中和纹理数据合并。

单独的原始 ALPHA

 

优势

更加灵活,允许混合和匹配 Alpha/颜色信息

允许未经压缩的 Alpha,因为有损 ETC1 压缩中会导致失真

缺点

着色器中需要第二个纹理采样器

与压缩相比,未压缩的 Alpha 会占用更多空间和内存带宽(尽管与未压缩 RGBA 纹理相比要少得多)

方法

要创建适合用于此方法的压缩图像,请在纹理压缩工具中选择“创建单独压缩的图像”。 根据所选的其他选项,这会生成单个 PGM 文件,或者每个纹理映射级别一个 PGM 文件,或者在一个 KTX 文件中包含作为未压缩数据的所有纹理映射级别。

PGM 格式在 http://netpbm.sourceforge.net/doc/pgm.html 予以介绍。而 KTX 格式则在http://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ 中予以说明。

实施新方法来加载和绑定此纹理,但基于纹理的未压缩本质,其加载是比较琐碎的:

123456789101112131415161718192021222324252627282930313233343536373839404142 FILE *pFile=NULL;unsignedchar*pTexData=NULL;unsignedintiWidth=0;unsignedintiHeight=0;size_tresult=0; pFile=fopen(pFilename,"rb"); // Read the header. The header is text. Fields are magic number, width, height,// maximum gray value.// See http://netpbm.sourceforge.net/doc/pgm.html for format details. unsignedintiRange=0;intiReadCount=fscanf(pFile,"P5 %d %d %d",&iWidth,&iHeight,&iRange);if(iReadCount!=3){    LOGE("Error reading file header of %s",pFilename);    exit(1);}if(iRange!=255){    // We can only handle a maximum gray/alpha value of 255, as generated by    // the Texture Compression Tool    LOGE("Alpha file %s has wrong maximum gray value, must be 255",pFilename);exit(1);} // Read and thow away the single header terminating characterfgetc(pFile); pTexData=(unsignedchar*)calloc(iWidth *iHeight,sizeof(unsignedchar));result=fread(pTexData,sizeof(unsignedchar),iWidth *iHeight,pFile);if(result!=iWidth *iHeight){    LOGE("Error reading %s",pFilename);    exit(1);}GL_CHECK(glGenTextures(1,pTexName));GL_CHECK(glBindTexture(GL_TEXTURE_2D,*pTexName));GL_CHECK(glTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE,iWidth,iHeight,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,pTexData));GL_CHECK(glGenerateMipmap(GL_TEXTURE_2D));free(pTexData);

与以前一样,允许纹理加载到独立的活动纹理中:

1234 glActiveTexture(GL_TEXTURE0);loadCompressedMipmaps(TEXTURE_FILE, TEXTURE_FILE_SUFFIX, &iTexName);glActiveTexture(GL_TEXTURE1);loadRawLuminance(ALPHA_FILE, &iAlphaName);

再一次将它们单独加载到片段着色器中:

1234 iLocSampler=glGetUniformLocation(iProgName,"u_s2dTexture");glUniform1i(iLocSampler,0);iLocSamplerAlpha=glGetUniformLocation(iProgName,"u_s2dAlpha");glUniform1i(iLocSamplerAlpha,1);

然后在片段着色器中,合并这两个样本,还是从两个不同的纹理进行:

123 vec4colour=texture2D(u_s2dTexture,v_v2TexCoord);colour.a=texture2D(u_s2dAlpha,v_v2TexCoord).r;gl_FragColor=colour;

OpenGL ES SDK 示例“ETCUncompressedAlpha”中提供了本示例的完整源代码列表。

 

OpenGL ES SDKs







推荐阅读
  • 主调|大侠_重温C++ ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 嵌入式开发环境搭建与文件传输指南
    本文详细介绍了如何为嵌入式应用开发搭建必要的软硬件环境,并提供了通过串口和网线两种方式将文件传输到开发板的具体步骤。适合Linux开发初学者参考。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 本文详细分析了Hive在启动过程中遇到的权限拒绝错误,并提供了多种解决方案,包括调整文件权限、用户组设置以及环境变量配置等。 ... [详细]
  • MySQL 数据库迁移指南:从本地到远程及磁盘间迁移
    本文详细介绍了如何在不同场景下进行 MySQL 数据库的迁移,包括从一个硬盘迁移到另一个硬盘、从一台计算机迁移到另一台计算机,以及解决迁移过程中可能遇到的问题。 ... [详细]
  • 在创建新的Android项目时,您可能会遇到aapt错误,提示无法打开libstdc++.so.6共享对象文件。本文将探讨该问题的原因及解决方案。 ... [详细]
  • 云函数与数据库API实现增删查改的对比
    本文将深入探讨使用云函数和数据库API实现数据操作(增删查改)的不同方法,通过详细的代码示例帮助读者更好地理解和掌握这些技术。文章不仅提供代码实现,还解释了每种方法的特点和适用场景。 ... [详细]
  • 深入理解ExtJS:从入门到精通
    本文详细介绍了ExtJS的功能及其在大型企业前端开发中的应用。通过实例和详细的文件结构解析,帮助初学者快速掌握ExtJS的核心概念,并提供实用技巧和最佳实践。 ... [详细]
  • 本文探讨了在iOS平台上开发BLE(蓝牙低功耗)应用程序时遇到的挑战,特别是如何实现应用在后台模式下仍能持续扫描并连接蓝牙设备。文章提供了具体的配置方法和常见的问题解决方案。 ... [详细]
  • cJinja:C++编写的轻量级HTML模板引擎
    本文介绍了cJinja,这是一个用C++编写的轻量级HTML模板解析库。它利用ejson来处理模板中的数据替换(即上下文),其语法与Django Jinja非常相似,功能强大且易于学习。 ... [详细]
  • 本文针对初学者在创建Android项目时遇到的R.java文件错误提供了解决方案,通过实际案例和详细的日志分析,帮助读者快速定位并解决问题。 ... [详细]
  • QNX 微内核(procnto-instr)的监测版本内置了高级跟踪与分析工具,能够实现实时系统监控。该模块适用于单处理器及多处理器系统。 ... [详细]
author-avatar
欠你的情意
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有