博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实施vertex compression所遇到的各种问题和解决办法
阅读量:6440 次
发布时间:2019-06-23

本文共 2897 字,大约阅读时间需要 9 分钟。

关于顶点压缩,好处是可以减少带宽,一定程度提高加载速度,可以提高约5-10%的fps,特别是mobile上,简单描述就是:

压缩之前(32字节)

position float3 12

normal float3 12
texcoord0 float2 8

压缩之后(16字节)

position short4 8

normal ubyte4 4
texcoord0 short2 4

 

压缩的方法,其实就是在bounding box内分65536份,用"-32767.5"到"32767.5"描述。

参考文章:“Vertex Decompression using Vertex Shaders Part 2” by Dean Calve @ShaderX Programming

示例代码如下:

// 计算position的范围    oiram::vec3 posCenter(    (mMesh.boundingBox.pmax.x + mMesh.boundingBox.pmin.x) * 0.5f,                             (mMesh.boundingBox.pmax.y + mMesh.boundingBox.pmin.y) * 0.5f,                             (mMesh.boundingBox.pmax.z + mMesh.boundingBox.pmin.z) * 0.5f),                posExtent(    (mMesh.boundingBox.pmax.x - mMesh.boundingBox.pmin.x) * 0.5f,                            (mMesh.boundingBox.pmax.y - mMesh.boundingBox.pmin.y) * 0.5f,                            (mMesh.boundingBox.pmax.z - mMesh.boundingBox.pmin.z) * 0.5f);
if (vertexDeclaration & oiram::Ves_Position)                {                    oiram::vec4 norm((vertex.vec3Position.x - posCenter.x) / posExtent.x,                                     (vertex.vec3Position.y - posCenter.y) / posExtent.y,                                     (vertex.vec3Position.z - posCenter.z) / posExtent.z,                                     1.0f);                    vertex.short4Position = oiram::short4(norm);                }
inline short packF32ToS16(float f)    {        return static_cast
(f * 32767.5f);; } struct short4 { short s[4]; short4() {} short4(const oiram::vec4& v) { s[0] = packF32ToS16(v.x); s[1] = packF32ToS16(v.y); s[2] = packF32ToS16(v.z); s[3] = packF32ToS16(v.w); } };

这样,position的xyz就从float压缩到short中了。接下来,要在vs中进行解压,那么同样需要传入center和extent:

float4 position = float4(iPosition.xyz / 32767.5 * positionExtent + positionCenter, 1);

当然,这里可以直接将positionExtent除以32767.5之后再传入,减少一次不必要的除法操作,这属于自行研发优化的范畴之内,不累述。

接下来,同理可以将uv也进行压缩,因为uv是2个值的缘故,所以center和extent可以合并在一起,只占用一个float4即可,同上理不累述。

float4 texcoord0 = float4(iTexCoord0.xyzw * uvExtentCenter.xyxy + uvExtentCenter.zwzw);

 

需要注意的是,因为必须依赖vs进行解压,而且center和extent的值必须正确。有意思的是,如果美术曾经将一个展分过uv的大模型,摘取其中某一块,然后merge到一个新的模型中,那么就容易出现混乱的uv值,比如u = 1.234567e+28, v = 1.234567e-44#DEN之类的。如果打开3dsmax里的UV map观察,整个face的3个vertex都在uv上的同一个"点"上。无奈的是,获取这些数据的函数都正确返回了,而且uv数值也是正常的float,无法通过isNAN神码的来判断是否有效。唯一能想到的办法就是,检查uv的绝对值,如果小于0.00001,或者大于10000,就将其重置为0。

还有一个在顶点压缩之前不容易察觉的情况,因为某种原因,部分faces的material为空,即没有附上材质。这一些顶点之前可能安全地藏在模型的体内,肉眼无法察觉。但现在经过压缩之后,如果vs没有照顾到它们,将其正确得解压的话,因为是以short形式记录的,于是你会发现场景中出现一些奇异的巨形的模型,附着奇怪的贴图。

既然选择了programmable pipeline代替Fixed Function,那么意味着,你的shader在解压数据之余,渲染效果必须保持与之前FF的一致。可以想象的是,这并不是一件简单的事情,比如一个模型中,一部分submesh是用diffuse map渲染,另一部分submesh只用到了diffuse color。那么好吧,你的shader可要准备好了才行。

 

结论:一篇paper,一个算法,一种优化,往往看上去很简单很美好。当你往具体项目中加入时,通常不会像demo中执行得那么顺利,尤其是遇上大量的数据,甚至是各种奇葩数据,从而出现各种诡异现象的时候,那时候估计你就会跟我一样,很难笑得出来了。

 

 

转载地址:http://amdwo.baihongyu.com/

你可能感兴趣的文章
不同包下,相同数据结构的两个类进行转换
查看>>
软件安装(linux)
查看>>
TeamPlain for VSTS - Web Access for Team System-TFS 跨平台的客户端
查看>>
面对前车之鉴的AR,现在的VR要做些什么?
查看>>
vscode 换行符\n 变成\r\n
查看>>
一个绘制虚线的非常规函数(常规方法,打印机上绘制不出虚线)
查看>>
获得本机的IP,掩码和网关
查看>>
大数据之 ZooKeeper原理及其在Hadoop和HBase中的应用
查看>>
Delphi中将XML文件数据装入DataSet
查看>>
你刚才在淘宝上买了一件东西
查看>>
发布一个 Linux 下的 C++ 多线程库
查看>>
Python序列类型
查看>>
再谈ThinkPHP
查看>>
Hibernate问题浅析
查看>>
出现访问apache资源直接下载php文件的解决办法-----yum 安装 php mysql
查看>>
七种Mysql表类型
查看>>
归并与归并排序
查看>>
linux和windows互传文件、用户配置文件和密码配置文件、用户组管理、用户管理...
查看>>
spark 应用程序性能优化经验
查看>>
基于Zabbix IPMI监控服务器硬件状况
查看>>