Und weil ich das so knöfte finde, hier der Code der Noise-Funktion und der Fractal Brownian Motion-Funktion
Code: Alles auswählen
float MakeSomeNoise( TVektor3 pos) noexcept
{
__m128 p = _mm_set_ps( 0.0f, pos.z, pos.y, pos.x);
__m128 ip = _mm_floor_ps(p);
auto dp = _mm256_set_m128( ip, ip);
// 4x (2x vec4) bilden, wo jeweils die untere Lane X+0 und die obere Lane x+1 hat
static constexpr float OffsetWerte[8] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f };
auto offset = _mm256_load_ps( OffsetWerte);
auto p01 = _mm256_add_ps(dp, _mm256_permute_ps( offset, 0b00'01'00'00)); // +0000 0100
auto p23 = _mm256_add_ps(dp, _mm256_permute_ps( offset, 0b00'01'00'10)); // +0010 0101
auto p45 = _mm256_add_ps(dp, _mm256_permute_ps( offset, 0b00'01'10'00)); // +0100 0110
auto p67 = _mm256_add_ps(dp, _mm256_permute_ps( offset, 0b00'01'10'10)); // +0110 0111
// 4x (2x float4) jeweils punktprodukten zu 4x2 float
static constexpr float SkalWerte[8] = { 0.29575f, 0.72357f, 0.471205f, 0.0f, 0.29575f, 0.72357f, 0.471205f, 0.0f };
auto skal = _mm256_load_ps( SkalWerte);
auto dp01 = _mm256_dp_ps( _mm256_mul_ps( p01, p01), skal, 0b0111'1111); // Punktprodukt "xxxx = 0xyz dot skal" auf beiden Lanes
auto dp23 = _mm256_dp_ps( _mm256_mul_ps( p23, p23), skal, 0b0111'1111);
auto dp45 = _mm256_dp_ps( _mm256_mul_ps( p45, p45), skal, 0b0111'1111);
auto dp67 = _mm256_dp_ps( _mm256_mul_ps( p67, p67), skal, 0b0111'1111);
// Zusammenmischen, so dass jedes Punktprodukt-Ergebnis in einem der 8x float landet
auto zufall8 = _mm256_blend_ps( _mm256_blend_ps( dp01, dp23, 0b1010'1010), _mm256_blend_ps( dp45, dp67, 0b1010'1010), 0b1100'1100);
// der Nachkomma-Anteil ist der Zufall
zufall8 = _mm256_sub_ps( zufall8, _mm256_floor_ps( zufall8));
// Nachkomma-Anteil. Den müssen wir jetzt in v und 1.0f-v auftrennen und gleichmäßig auf alle 8 Werte verteilen
__m128 lp = _mm_sub_ps( p, ip);
static constexpr float PlusMinusWerte[8] = { 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f };
static constexpr float EinsNullWerte[8] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f };
auto plusMinus = _mm256_load_ps( PlusMinusWerte);
auto einsNull = _mm256_load_ps( EinsNullWerte);
auto spx = _mm256_broadcastss_ps( lp); // +1 -1 +1 -1 +1 -1 +1 -1 0 1 0 1 0 1 0 1
spx = _mm256_fmadd_ps( spx, _mm256_permute_ps( plusMinus, 0b00'11'00'11), _mm256_permute_ps( einsNull, 0b00'11'00'11));
auto spy = _mm256_broadcastss_ps( _mm_shuffle_ps( lp, lp, 1)); // +1 +1 -1 -1 +1 +1 -1 -1 0 0 1 1 0 0 1 1
spy = _mm256_fmadd_ps( spy, _mm256_permute_ps( plusMinus, 0b00'00'11'11), _mm256_permute_ps( einsNull, 0b00'00'11'11));
auto spz = _mm256_broadcastss_ps( _mm_shuffle_ps( lp, lp, 2)); // +1 +1 +1 +1 -1 -1 -1 -1 0 0 0 0 1 1 1 1
spz = _mm256_fmadd_ps( spz, _mm256_permute_ps( plusMinus, 0b10'10'10'10), _mm256_permute_ps( einsNull, 0b10'10'10'10));
auto gewichte = _mm256_mul_ps( spx, _mm256_mul_ps( spy, spz));
// 4xfloat Punktprodukt | 4xfloat Punktprodukt, wir schreiben das Ergebnis jeweils in alle 4 floats
auto punktProdukt4 = _mm256_dp_ps( zufall8, gewichte, 0b1111'1111);
// und dann ziehen wir wahllos einen Float aus den oberen 4float und einen aus den unteren 4float und summieren
auto erg = _mm_cvtss_f32( _mm256_extractf128_ps( punktProdukt4, 0)) + _mm_cvtss_f32( _mm256_extractf128_ps( punktProdukt4, 1));
return erg;
}
static constexpr TMatrix4x4 NoiseTransform[8] = {
TMatrix4x4 { 0.2506f, 0.2779f, 0.4035f, 0.0125f,
-0.2134f, 0.4699f, -0.1912f, 5.6359f,
-0.4411f, -0.0694f, 0.3217f, 1.9330f,
0.0000f, 0.0000f, 0.0000f, 1.0000f },
TMatrix4x4 { -0.7059f, 0.1936f, -0.7067f, 8.9596f,
-0.7324f, -0.1580f, 0.6883f, 8.2284f,
0.0212f, 0.9862f, 0.2490f, 7.4660f,
0.0000f, 0.0000f, 0.0000f, 1.0000f },
TMatrix4x4 { 1.1198f, 0.8200f, 1.4891f, 3.0399f,
-1.6983f, 0.6172f, 0.9372f, 0.1498f,
-0.0739f, -1.7579f, 1.0236f, 0.9140f,
0.0000f, 0.0000f, 0.0000f, 1.0000f },
TMatrix4x4 { 2.7346f, -2.6272f, -0.7243f, 4.4569f,
2.1789f, 2.7241f, -1.6543f, 1.1908f,
1.6368f, 0.7630f, 3.4123f, 0.0467f,
0.0000f, 0.0000f, 0.0000f, 1.0000f },
TMatrix4x4 { -6.5153f, -1.4712f, 4.5432f, 6.0176f,
-4.4642f, 4.6056f, -4.9106f, 6.0717f,
-1.6959f, -6.4714f, -4.5277f, 1.6623f,
0.0000f, 0.0000f, 0.0000f, 1.0000f },
TMatrix4x4 { 11.0403f, 10.5473f, -3.4436f, 6.0768f,
-1.3244f, -3.5705f, -15.1819f, 7.8332f,
-11.0159f, 11.0000f, -1.6260f, 8.0261f,
0.0000f, 0.0000f, 0.0000f, 1.0000f },
TMatrix4x4 { -23.9722f, 0.6439f, -17.4160f, 9.5590f,
17.3036f, -2.6512f, -23.9155f, 9.2572f,
-2.0775f, -29.5119f, 1.7685f, 5.3935f,
0.0000f, 0.0000f, 0.0000f, 1.0000f },
TMatrix4x4 { -49.1905f, 0.0925f, -39.5407f, 2.0960f,
-25.5453f, -48.2477f, 31.6666f, 7.7966f,
-30.1814f, 40.6857f, 37.6422f, 8.4365f,
0.0000f, 0.0000f, 0.0000f, 1.0000f },
};
float MakeNoise( TVektor3 pos)
{
float v = 0.0f;
for( int a = 0; a < 8; ++a )
v += pow( 0.50946f, float( a + 1)) * MakeSomeNoise( NoiseTransform[a] * pos);
return v;
}
Noise ist immer ein bissl Rumspielsache.