从零开始学习导航网格#10 recast迷惑代码大赏

疫情隔离的日子里重新开始看recast项目的代码。本篇对项目中一些相对奇怪的代码片段做一个总结

代码1:获取不小于参数v的最小的2的整数次幂

例如:
输入1输出1
输入3输出4
输入5输出8

inline unsigned int nextPow2(unsigned int v)
{
    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v++;
    return v;
}

原理:
如果一个数不是2的整数次幂,比如13(二进制1101),
a.先把它的从最高位的1向下的所有位都补为1(得到1111)
b.再加1,就得到了想要的值(10000)
那么如何把所有位都补为1呢?
首先每个数总有一个最高位为1,把这个1复制一份放到右边,就得到了两个相邻的1。把这两个1复制一份再放到右边,就得到了4个相邻的1。以此类推。而对于32位整数来说,只要重复执行5次就足够处理所有情况了。
以100000为例
100000->110000->111100->111111

对于本身就是2的整数次幂的数来说,把它先减1,就可以和上面的情况统一起来了

代码2:获取参数v取2为底的对数的整数部分
inline unsigned int ilog2(unsigned int v)
{
    unsigned int r;
    unsigned int shift;
    r = (v > 0xffff) << 4; v >>= r;
    shift = (v > 0xff) << 3; v >>= shift; r |= shift;
    shift = (v > 0xf) << 2; v >>= shift; r |= shift;
    shift = (v > 0x3) << 1; v >>= shift; r |= shift;
    r |= (v >> 1);
    return r;
}

原理:其实就是找到最高位的1,二分法
对于0~0xffffffff的数来说
先跟0xffff比,如果大于,则至log2之后至少为1<<4,剩下的看左半边就行;如果不大于,则左半边全是0,只要看右半边就行
这样就把一个32位的问题退化到了一个16位的问题。以此类推,累计求值得到结果。

以上两个函数配合使用,可以求出要表示一个数值,至少需要多少二进制位

m_tileBits = dtIlog2(dtNextPow2((unsigned int)params->maxTiles));
代码3:将参数x对齐到它最接近的4的整数倍

例如:
输入0得到0
输入1得到4
输入5得到8
输入9得到12

inline int dtAlign4(int x) { return (x+3) & ~3; }
代码4:得到某个编号在8邻域中对位的编号

对应关系:
0-4
1-5
2-6
3-7

inline int dtOppositeTile(int side) { return (side+4) & 0x7; }
8邻域
代码5:将3维坐标hash映射到1<<12的范围内
static const int VERTEX_BUCKET_COUNT = (1<<12);

inline int computeVertexHash(int x, int y, int z)
{
    const unsigned int h1 = 0x8da6b343; // Large multiplicative constants;
    const unsigned int h2 = 0xd8163841; // here arbitrarily chosen primes
    const unsigned int h3 = 0xcb1ab31f;
    unsigned int n = h1 * x + h2 * y + h3 * z;
    return (int)(n & (VERTEX_BUCKET_COUNT-1));
}
代码6:获取[-1,1]之间的随机数(近似随机),用来做采样抖动
inline float getJitterX(const int i)
{
    return (((i * 0x8da6b343) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
}

inline float getJitterY(const int i)
{
    return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
}
代码7:对32位整数做hash映射
inline unsigned int dtHashRef(dtPolyRef a)
{
    a += ~(a<<15);
    a ^=  (a>>10);
    a +=  (a<<3);
    a ^=  (a>>6);
    a += ~(a<<11);
    a ^=  (a>>16);
    return (unsigned int)a;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容