我想在 2D 中实现简单的、古老的 boid 算法,但作为 HLSL 中的计算着色器(主机程序 VVVV)。现在我的问题是:在我发现的所有 2D 示例应用程序中,boid 一次更新一个。这会导致一些抖动,从而导致典型的“随机”结果。方向变化等
我不确定我的实现是否正确,但如果我单独测试每个规则,我的结果看起来像其他参考。但是,如果我将这些规则一起应用(几乎可以以任何组合方式),我的 boid 很快就会进入稳定状态,它们会形成一个固定的编队并朝某个特定方向飞行。改变视野半径会影响编队的大小和数量,但不会引入任何“混乱”或类似群的东西,只是几秒钟后的静态束。
是否存在实现问题,或者这只是您必须补偿的并行计算的一个属性(不知何故?
相关代码:
void CS(uint3 tid : SV_DispatchThreadID){
if (tid.x >= elementCount)
return;
if(reset){
OutputBuffer[tid.x].x = random(float2(rand.x + 12,tid.x-4)); // PosXY
OutputBuffer[tid.x].y = random(float2(tid.x + 16,rand.y*6));
OutputBuffer[tid.x].z = random(float2(tid.x,tid.x * 2)) / 100; //VelXY
OutputBuffer[tid.x].w = random(float2(tid.x * 16, tid.x / 4))/ 100;
}else{
float maxSpeed = 0.01;
float2 myPos = OutputBuffer[tid.x].xy;
float2 myVel = OutputBuffer[tid.x].zw;
float2 myAcc = 0;
float2 steerAlign = 0;
float2 steerCohesion = 0;
float2 steerAvoid = 0;
int alignCount = 0;
int cohesionCount = 0;
int avoidCount = 0;
for(uint i = 0; i < elementCount; i++){
if(i != tid.x){
float2 iPos = OutputBuffer[i].xy;
float2 iVel = OutputBuffer[i].wz;
float dist = distance(iPos,myPos);
if(dist < range / 2){
steerAlign += iVel;
alignCount++;
}
if(dist < range * 3){
steerCohesion += iPos - myPos;
cohesionCount++;
}
if(dist < range){
float2 diff = myPos - iPos;
diff /= dist * dist;
steerAvoid += diff;
avoidCount++;
}
}
}
if(alignCount > 0 && steerAlign.x != 0){
steerAlign /= alignCount;
steerAlign = normalize(steerAlign) * maxForce;
}
if(cohesionCount > 0){
steerCohesion /= cohesionCount;
steerCohesion = normalize(steerCohesion) * maxForce;
}
if(avoidCount > 0){
steerAvoid /= avoidCount;
steerAvoid = normalize(steerAvoid) * maxForce;
}
if(myPos.x < -1){
myPos.x = 1;
}
if(myPos.x > 1){
myPos.x = -1;
}
if(myPos.y < -1){
myPos.y = 1;
}
if(myPos.y > 1){
myPos.y = -1;
}
myAcc = (steerAlign * alignFx) + (steerCohesion * cohesionFx) + (steerAvoid * seperationFx);
myAcc = clamp(myAcc, -maxForce, maxForce);
myVel += myAcc;
myVel = clamp(myVel,-maxSpeed,maxSpeed);
myPos += myVel;
OutputBuffer[tid.x].xy = myPos;
OutputBuffer[tid.x].zw = myVel;
}
}