Hex Tiling Cover

在地形贴图混合时使用六边形平铺

动机 最近看到了三角洲行动介绍的在虚幻引擎4中实现的地形渲染方案,感觉受益匪浅。不过在Unity中要想实现一个即插即用的虚拟贴图的技术应该有些困难,于是我把目光放在了最一开始所介绍的对地形贴图做混合的方案上。 三角洲行动提出的方案是这样的,在地形计算的时候,从对材质ID图的四个像素采样退化成对三个像素采样,这样一来既能减少地形混合的时候的采样次数,二来相较于采样四个像素,三个像素多了一个斜向45度的效果,能够减轻一些地形的块面感。不过他们也有语焉不详的地方,虽然只采样三个像素能够提供斜向45度,但是对于斜向-45度,仅使用同一种方式采样三个像素是不能消除这个方向的块面感的,当然想必他们也有对应的解决方案就是了。此外他们声称材质ID图是一张R8的贴图,但这张贴图里面怎么会有5bit的下层ID,5bit的上层ID,再有3bit的权重值呢?我只能认为这张材质ID图实际上只包含了一个5bit的材质ID和3bit的权重了,这个3bit的权重值会在和另外几个像素混合时使用到。 不过三次采样倒是让我想起了Hex Tiling。在Practical Real-Time Hex-Tiling里介绍了一种通过六边形平铺来降低平铺时纹理重复感的算法,这种算法正巧需要对主贴图采样三次(不考虑随机采样的话)。Github中也能找到参考的代码。 这样一来我们就能在三角洲行动的方案上再提出一种新的地形混合的方法了。我们同样是采样三个像素,不过我们在地形中会将这三个像素用等边三角形的方式排布,而不是目前所用的直角三角形。所以我们的流程是,先将当前的世界空间或者uv做一次三角形格点的变换,使用变换后的格点采样材质ID图获得三个材质ID和权重,再使用获得的数据和本身的六边形平铺的权重进行混合,就能得到我们最终的混合后的地形材质了。如果把我们的材质ID图平铺到世界空间,看上去应该是这样的: 生成材质ID图 为了快速生成材质ID图(我可不想手画),我们考虑使用Compute Shader通过Perlin Noise生成材质ID,使用普通的hash生成权重。为了使我们的材质ID图也能正常的平铺,我们在计算Perlin Noise的时候,要注意使用取模的运算将计算的uv值限制在同一个范围内。 我们只需要一个8bit的数据,但是由于Unity保存贴图的种种限制,我们可以将R8_Uint的数据除以255转换成R8_UNorm类型的数据再储存到贴图中。 GenerateMatIDComputeShader.compute #pragma kernel MatIDGenMain RWTexture2D<float> _RW_MatIDTex; float4 _TextureSize; // https://www.shadertoy.com/view/4djSRW float hash12(float2 p) { float3 p3 = frac(float3(p.xyx) * .1031); p3 += dot(p3, p3.yzx + 33.33); return frac((p3.x + p3.y) * p3.z); } float2 repeat(float2 coord, float2 size, float2 offset) { return coord - floor(coord / size) * size + offset; } float encode(int weight, int index) { int encoded = (weight << 5) | index; return float(encoded) / 255....

March 19, 2024 · zznewclear13
zznewclear13 技术美术 图形学 个人博客 technical art computer graphics