カーネルを 9 つの座標の出力に適用する 2 つのバージョンの平滑化関数を作成しました。
float PerlinHeightMapGenerator::defaultSmooth(int x, int z, const float kernel[9])
{
const float top = defaultNoise(x - 1, z + 1) * kernel[0] + defaultNoise(x, z + 1) * kernel[1] + defaultNoise(x + 1, z + 1) * kernel[2];
const float middle = defaultNoise(x - 1, z) * kernel[3] + defaultNoise(x, z) * kernel[4] + defaultNoise(x + 1, z) * kernel[5];
const float bottom = defaultNoise(x - 1, z - 1) * kernel[6] + defaultNoise(x, z - 1) * kernel[7] + defaultNoise(x + 1, z - 1) * kernel[8];
const float total = (top + middle + bottom);
return total;
}
float PerlinHeightMapGenerator::defaultSmooth(int x, int z, const XMVECTOR kernel[3])
{
const XMVECTOR top = XMVector3Dot(XMVectorSet(defaultNoise(x - 1, z + 1), defaultNoise(x, z + 1), defaultNoise(x + 1, z+ 1), 0), kernel[0]);
const XMVECTOR middle = XMVector3Dot(XMVectorSet(defaultNoise(x - 1, z), defaultNoise(x, z), defaultNoise(x + 1, z), 0), kernel[1]);
const XMVECTOR bottom = XMVector3Dot(XMVectorSet(defaultNoise(x - 1, z - 1), defaultNoise(x, z - 1), defaultNoise(x + 1, z - 1), 0), kernel[2]);
XMFLOAT4 answer;
XMStoreFloat4(&answer, XMVectorAdd(top, XMVectorAdd(middle, bottom)));
return answer.x;
}
2 番目のバージョンはベクトル命令を使用しますが、私が使用している入力は大幅に遅くなります (プログラム全体の合計実行時間に約 200 ミリ秒が追加されます)。一度に 3 つの "defaultNoise" を呼び出すことができ、同時に乗算も実行できるため、ベクトル化されたバージョンの方が高速ではないでしょうか?
関連する場合、「defaultNoise(x,z)」は次のことを行います。
float PerlinHeightMapGenerator::defaultNoise(int x, int z)
{
int n = x + z * 57;
n = (n<<13) ^ n;
return static_cast<float>( 1.0f - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
};
編集:私は理解できない結果でさらにいくつかのテストを試みました。まず、ベクトル化された関数が 9 個の float の配列を取り、それらを関数内のベクトルにコピーするように変更してみました。何もしません。
次に、カーネル ベクトルが実際に使用されていない場合に何が起こるかを確認するために、コードを変更してみました。まず、kernel のすべてのインスタンスを XMVectorSet(1, 2, 3, 4) に置き換えます。コードは次のようになります。
const XMVECTOR top = XMVector3Dot(XMVectorSet(defaultNoise(x - 1, z + 1), defaultNoise(x, z + 1), defaultNoise(x + 1, z+ 1), 0), XMVectorSet(1, 2, 3, 4));
const XMVECTOR middle = XMVector3Dot(XMVectorSet(defaultNoise(x - 1, z), defaultNoise(x, z), defaultNoise(x + 1, z), 0), XMVectorSet(1, 2, 3, 4));
const XMVECTOR bottom = XMVector3Dot(XMVectorSet(defaultNoise(x - 1, z - 1), defaultNoise(x, z - 1), defaultNoise(x + 1, z - 1), 0), XMVectorSet(1, 2, 3, 4));
これにより、プログラムの実行時間が 4 秒から 2 秒未満に短縮されました (50% 短縮)。
次に、最初の XMVectorSet(1, 2, 3, 4) をカーネル [0] に戻そうとしましたが、これにより実行時間が約 2100 ミリ秒に増加しました。2 番目の XMVectorSet(1, 2, 3, 4) を kernel[1] に置き換えると、時間が 2700 ミリ秒に増加しました。最後の 3 番目のベクトルを置き換えると、時間が 4 秒に戻りました。
呼び出される前ではなく、関数内のベクトルにフロートをコピーしようとしましたが、結果は同じです。
EDIT 2: XMVectorSet(1, 2, 3, 4) は特殊なケースのようです。4 int であるため、おそらく高速です。XMVectorSet(.0357143f, 0.0714286f, 0.0357143f, 0) に置き換えると、元の速度に戻ります。
ただし、ベクトル化されたバージョンが遅い理由はまだわかりません。