关于顶点压缩,好处是能够减小带宽,必定程度提升加载速度,能够提升约5-10%的fps,特别是mobile上,简单描述就是:算法
压缩以前(32字节)安全
position float3 12
normal float3 12
texcoord0 float2 8函数
压缩以后(16字节)优化
position short4 8
normal ubyte4 4
texcoord0 short2 4spa
压缩的方法,其实就是在bounding box内分65536份,用"-32767.5"到"32767.5"描述。3d
参考文章:“Vertex Decompression using Vertex Shaders Part 2” by Dean Calve @ShaderX Programmingcode
示例代码以下:orm
// 计算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<short>(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:blog
float4 position = float4(iPosition.xyz / 32767.5 * positionExtent + positionCenter, 1);
固然,这里能够直接将positionExtent除以32767.5以后再传入,减小一次没必要要的除法操做,这属于自行研发优化的范畴以内,不累述。ip
接下来,同理能够将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中执行得那么顺利,尤为是赶上大量的数据,甚至是各类奇葩数据,从而出现各类诡异现象的时候,那时候估计你就会跟我同样,很难笑得出来了。