啊这,如果要归一化的话就不需要再乘0.5了,感谢指正。
不过我仔细看了一下,发现这一块的代码是有问题的,并不需要做归一化。可以看一下这个新的工程:
sdfDemo.zip (996.1 KB)
代码更新
calGradient(pos:Vec3):Vec3{
var delta=1;
var dis0 = this.calPointDis(new Vec3(pos.x+delta,0,pos.z));
var dis1 = this.calPointDis(new Vec3(pos.x-delta,0,pos.z));
var dis2 = this.calPointDis(new Vec3(pos.x,0,pos.z+delta));
var dis3 = this.calPointDis(new Vec3(pos.x,0,pos.z-delta));
var result = new Vec3(dis0-dis1,0,dis2-dis3).multiplyScalar(0.5);
//console.log(StringUtils.format("dis0=%s,dis1=%s,dis2=%s,dis3=%s,result=%s",dis0,dis1,dis2,dis3,result));
return result;
}
这样写才符合求导公式
因为delta=1,所以最后可以直接*0.5
加上归一化是错的。可以看到去除归一化后,角色贴墙移动比原先稳定了许多。
==================================
第二个问题,这段我直接copy了《腾讯游戏开发精粹》的相关代码:
我的理解是,角色触碰墙壁进行位置修正后,可能会遇到修正后点的SD依然小于自身体积的情况(例如90度的转角),这时会试图沿着法线向量“退回”到安全区域。但是如前面的公式所示,法线计算的结果并不精准,有可能计算出来的结果依然不处于安全区域,这时候需要进行多次回退计算。计算的次数越多,目标点落在安全区域的概率就越大。
当然,每帧总计4轮的计算确实是一笔挺大的开销,我试过把迭代次数设为1,似乎也没有出什么问题。不过安全起见最后我还是保留了最多3次的循环验证。