热门标签 | 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







推荐阅读
  • Python处理Word文档的高效技巧
    本文详细介绍了如何使用Python处理Word文档,涵盖从基础操作到高级功能的各种技巧。我们将探讨如何生成文档、定义样式、提取表格数据以及处理超链接和图片等内容。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
  • 本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ... [详细]
  • 作者:守望者1028链接:https:www.nowcoder.comdiscuss55353来源:牛客网面试高频题:校招过程中参考过牛客诸位大佬的面经,但是具体哪一块是参考谁的我 ... [详细]
  • 尽管深度学习带来了广泛的应用前景,其训练通常需要强大的计算资源。然而,并非所有开发者都能负担得起高性能服务器或专用硬件。本文探讨了如何在有限的硬件条件下(如ARM CPU)高效运行深度神经网络,特别是通过选择合适的工具和框架来加速模型推理。 ... [详细]
  • 本文详细介绍了如何解压并安装MySQL集群压缩包,创建用户和组,初始化数据库,配置环境变量,并启动相关服务。此外,还提供了详细的命令行操作步骤和常见问题的解决方案。 ... [详细]
  • 深入探讨CPU虚拟化与KVM内存管理
    本文详细介绍了现代服务器架构中的CPU虚拟化技术,包括SMP、NUMA和MPP三种多处理器结构,并深入探讨了KVM的内存虚拟化机制。通过对比不同架构的特点和应用场景,帮助读者理解如何选择最适合的架构以优化性能。 ... [详细]
  • 本文探讨了 Spring Boot 应用程序在不同配置下支持的最大并发连接数,重点分析了内置服务器(如 Tomcat、Jetty 和 Undertow)的默认设置及其对性能的影响。 ... [详细]
  • 本文详细介绍了Linux系统中init进程的作用及其启动过程,解释了运行级别的概念,并提供了调整服务启动顺序的具体步骤和实例。通过了解这些内容,用户可以更好地管理系统的启动流程和服务配置。 ... [详细]
  • dotnet 通过 Elmish.WPF 使用 F# 编写 WPF 应用
    本文来安利大家一个有趣而且强大的库,通过F#和C#混合编程编写WPF应用,可以在WPF中使用到F#强大的数据处理能力在GitHub上完全开源Elmis ... [详细]
  • jQuery HooRay:一款自创的实用 jQuery 工具插件
    这款插件主要由作者在工作中积累的常用功能开发而成,旨在解决现有插件间的冲突及浏览器兼容性问题。通过整合和优化现有插件,确保其稳定性和高效性。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • Hadoop发行版本选择指南:技术解析与应用实践
    本文详细介绍了Hadoop的不同发行版本及其特点,帮助读者根据实际需求选择最合适的Hadoop版本。内容涵盖Apache Hadoop、Cloudera CDH等主流版本的特性及应用场景。 ... [详细]
  • Coursera ML 机器学习
    2019独角兽企业重金招聘Python工程师标准线性回归算法计算过程CostFunction梯度下降算法多变量回归![选择特征](https:static.oschina.n ... [详细]
  • 嵌入式开发环境搭建与文件传输指南
    本文详细介绍了如何为嵌入式应用开发搭建必要的软硬件环境,并提供了通过串口和网线两种方式将文件传输到开发板的具体步骤。适合Linux开发初学者参考。 ... [详细]
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社区 版权所有