Example #1
0
//-----------------------------------------------------------------------------------------------
float Compute2dFractalNoise( float posX, float posY, float scale, unsigned int numOctaves, float octavePersistence, float octaveScale, bool renormalize, unsigned int seed )
{
	const float OCTAVE_OFFSET = 0.636764989593174f; // Translation/bias to add to each octave

	float totalNoise = 0.f;
	float totalAmplitude = 0.f;
	float currentAmplitude = 1.f;
	float invScale = (1.f / scale);
	Vector2 currentPos( posX * invScale, posY * invScale );

	for( unsigned int octaveNum = 0; octaveNum < numOctaves; ++ octaveNum )
	{
		// Determine noise values at nearby integer "grid point" positions
		Vector2 cellMins( FastFloor( currentPos.x ), FastFloor( currentPos.y ) );
		int indexWestX = (int) cellMins.x;
		int indexSouthY = (int) cellMins.y;
		int indexEastX = indexWestX + 1;
		int indexNorthY = indexSouthY + 1;
		float valueSouthWest = Get2dNoiseZeroToOne( indexWestX, indexSouthY, seed );
		float valueSouthEast = Get2dNoiseZeroToOne( indexEastX, indexSouthY, seed );
		float valueNorthWest = Get2dNoiseZeroToOne( indexWestX, indexNorthY, seed );
		float valueNorthEast = Get2dNoiseZeroToOne( indexEastX, indexNorthY, seed );

		// Do a smoothed (nonlinear) weighted average of nearby grid point values
		Vector2 displacementFromMins = currentPos - cellMins;
		float weightEast  = SmoothStep( displacementFromMins.x );
		float weightNorth = SmoothStep( displacementFromMins.y );
		float weightWest  = 1.f - weightEast;
		float weightSouth = 1.f - weightNorth;

		float blendSouth = (weightEast * valueSouthEast) + (weightWest * valueSouthWest);
		float blendNorth = (weightEast * valueNorthEast) + (weightWest * valueNorthWest);
		float blendTotal = (weightSouth * blendSouth) + (weightNorth * blendNorth);
		float noiseThisOctave = 2.f * (blendTotal - 0.5f); // Map from [0,1] to [-1,1]

		// Accumulate results and prepare for next octave (if any)
		totalNoise += noiseThisOctave * currentAmplitude;
		totalAmplitude += currentAmplitude;
		currentAmplitude *= octavePersistence;
		currentPos *= octaveScale;
		currentPos.x += OCTAVE_OFFSET; // Add "irrational" offsets to noise position components
		currentPos.y += OCTAVE_OFFSET; //	at each octave to break up their grid alignment
		++ seed; // Eliminates octaves "echoing" each other (since each octave is uniquely seeded)
	}

	// Re-normalize total noise to within [-1,1] and fix octaves pulling us far away from limits
	if( renormalize && totalAmplitude > 0.f )
	{
		totalNoise /= totalAmplitude;				// Amplitude exceeds 1.0 if octaves are used
		totalNoise = (totalNoise * 0.5f) + 0.5f;	// Map to [0,1]
		totalNoise = SmoothStep( totalNoise );		// Push towards extents (octaves pull us away)
		totalNoise = (totalNoise * 2.0f) - 1.f;		// Map back to [-1,1]
	}

	return totalNoise;
}
Example #2
0
    void ShortCircuitBridge::QueueAbandon(UInt2 uberMins, UInt2 uberMaxs)
    {
        // look for overlapping cells
        for (const auto&i:_cells) {
            const auto& r = i.second;
            if (    r._uberMins[0] >= uberMaxs[0] || r._uberMaxs[0] < uberMins[0]
                ||  r._uberMins[1] >= uberMaxs[1] || r._uberMaxs[1] < uberMins[1])
                continue;

            // remove any pending updates -- because they've all be abandoned now.
            auto compare = CellRegion { i.first, Float2(0.f, 0.f), Float2(0.f, 0.f) };
            auto range = std::equal_range(
                _pendingUpdates.begin(), _pendingUpdates.end(), 
                compare, CompareCellHash);
            _pendingUpdates.erase(range.first, range.second);

            // queue a new abandon event
            Float2 cellMins(
                (int(uberMins[0]) - int(r._uberMins[0])) / float(r._uberMaxs[0] - r._uberMins[0]),
                (int(uberMins[1]) - int(r._uberMins[1])) / float(r._uberMaxs[1] - r._uberMins[1]));
            Float2 cellMaxs(
                (int(uberMaxs[0]) - int(r._uberMins[0])) / float(r._uberMaxs[0] - r._uberMins[0]),
                (int(uberMaxs[1]) - int(r._uberMins[1])) / float(r._uberMaxs[1] - r._uberMins[1]));
            cellMins[0] = std::max(cellMins[0], 0.f);
            cellMins[1] = std::max(cellMins[1], 0.f);
            cellMaxs[0] = std::min(cellMaxs[0], 1.f);
            cellMaxs[1] = std::min(cellMaxs[1], 1.f);

            auto q = std::lower_bound(
                _pendingAbandons.begin(), _pendingAbandons.end(), 
                compare, CompareCellHash);

            // we can choose to insert this as a separate event, or just combine it with
            // what is already there.
            if (q != _pendingAbandons.end() && q->_cellHash == i.first) {
                q->_cellMins[0] = std::min(q->_cellMins[0], cellMins[0]);
                q->_cellMins[1] = std::min(q->_cellMins[1], cellMins[1]);
                q->_cellMaxs[0] = std::max(q->_cellMaxs[0], cellMaxs[0]);
                q->_cellMaxs[1] = std::max(q->_cellMaxs[1], cellMaxs[1]);
            } else {
                CellRegion region { i.first, cellMins, cellMaxs };
                _pendingAbandons.insert(q, region);
            }
        }
    }
Example #3
0
    void ShortCircuitBridge::QueueShortCircuit(UInt2 uberMins, UInt2 uberMaxs)
    {
        for (const auto&i:_cells) {
            const auto& r = i.second;
            if (    r._uberMins[0] >= uberMaxs[0] || r._uberMaxs[0] < uberMins[0]
                ||  r._uberMins[1] >= uberMaxs[1] || r._uberMaxs[1] < uberMins[1])
                continue;

            // queue a new update event
            Float2 cellMins(
                (int(uberMins[0]) - int(r._uberMins[0])) / float(r._uberMaxs[0] - r._uberMins[0]),
                (int(uberMins[1]) - int(r._uberMins[1])) / float(r._uberMaxs[1] - r._uberMins[1]));
            Float2 cellMaxs(
                (int(uberMaxs[0]) - int(r._uberMins[0])) / float(r._uberMaxs[0] - r._uberMins[0]),
                (int(uberMaxs[1]) - int(r._uberMins[1])) / float(r._uberMaxs[1] - r._uberMins[1]));
            cellMins[0] = std::max(cellMins[0], 0.f);
            cellMins[1] = std::max(cellMins[1], 0.f);
            cellMaxs[0] = std::min(cellMaxs[0], 1.f);
            cellMaxs[1] = std::min(cellMaxs[1], 1.f);

            auto compare = CellRegion { i.first, Float2(0.f, 0.f), Float2(0.f, 0.f) };
            auto q = std::lower_bound(
                _pendingUpdates.begin(), _pendingUpdates.end(), 
                compare, CompareCellHash);

            // we can choose to insert this as a separate event, or just combine it with
            // what is already there.
            if (q != _pendingUpdates.end() && q->_cellHash == i.first) {
                q->_cellMins[0] = std::min(q->_cellMins[0], cellMins[0]);
                q->_cellMins[1] = std::min(q->_cellMins[1], cellMins[1]);
                q->_cellMaxs[0] = std::max(q->_cellMaxs[0], cellMaxs[0]);
                q->_cellMaxs[1] = std::max(q->_cellMaxs[1], cellMaxs[1]);
            } else {
                CellRegion region { i.first, cellMins, cellMaxs };
                _pendingUpdates.insert(q, region);
            }
        }
    }
Example #4
0
//-----------------------------------------------------------------------------------------------
// Perlin noise is fractal noise with "gradient vector smoothing" applied.
//
// In 4D, gradients are unit-length hyper-vectors in random (4D) directions.
//
float Compute4dPerlinNoise( float posX, float posY, float posZ, float posT, float scale, unsigned int numOctaves, float octavePersistence, float octaveScale, bool renormalize, unsigned int seed )
{
	const float OCTAVE_OFFSET = 0.636764989593174f; // Translation/bias to add to each octave

	const Vector4 gradients[ 16 ] = // Hard to tell if this is any better in 4D than just having 8
	{
		Vector4( +0.5f, +0.5f, +0.5f, +0.5f ), // Normalized unit 4D vectors pointing toward each
		Vector4( -0.5f, +0.5f, +0.5f, +0.5f ), //  of the 16 hypercube corners, so components are
		Vector4( +0.5f, -0.5f, +0.5f, +0.5f ), //  all sqrt(4)/4, i.e. one-half.
		Vector4( -0.5f, -0.5f, +0.5f, +0.5f ), // 
		Vector4( +0.5f, +0.5f, -0.5f, +0.5f ), // It's hard to tell whether these are any better
		Vector4( -0.5f, +0.5f, -0.5f, +0.5f ), //  or worse than vectors facing axes (1,0,0,0) or
		Vector4( +0.5f, -0.5f, -0.5f, +0.5f ), //  3D edges (.7,.7,0,0) or 4D edges (.57,.57,.57,0)
		Vector4( -0.5f, -0.5f, -0.5f, +0.5f ), //  but less-axial gradients looked a little better
		Vector4( +0.5f, +0.5f, +0.5f, -0.5f ), //  with 2D and 3D noise so I'm assuming this is as
		Vector4( -0.5f, +0.5f, +0.5f, -0.5f ), //  good or better as any other gradient-selection
		Vector4( +0.5f, -0.5f, +0.5f, -0.5f ), //  scheme (and is crazy-fast).  *shrug*
		Vector4( -0.5f, -0.5f, +0.5f, -0.5f ), // 
		Vector4( +0.5f, +0.5f, -0.5f, -0.5f ), // Plus, we want a power-of-two number of evenly-
		Vector4( -0.5f, +0.5f, -0.5f, -0.5f ), //  distributed gradients, so we can cheaply select
		Vector4( +0.5f, -0.5f, -0.5f, -0.5f ), //  one from bit-noise (use bit-mask, not modulus).
		Vector4( -0.5f, -0.5f, -0.5f, -0.5f )  // 
	};

	float totalNoise = 0.f;
	float totalAmplitude = 0.f;
	float currentAmplitude = 1.f;
	float invScale = (1.f / scale);
	Vector4 currentPos( posX * invScale, posY * invScale, posZ * invScale, posT * invScale );

	for( unsigned int octaveNum = 0; octaveNum < numOctaves; ++ octaveNum )
	{
		// Determine random unit "gradient vectors" for 16 surrounding 4D (hypercube) cell corners
		Vector4 cellMins( FastFloor( currentPos.x ), FastFloor( currentPos.y ), FastFloor( currentPos.z ), FastFloor( currentPos.w ) );
		Vector4 cellMaxs( cellMins.x + 1.f, cellMins.y + 1.f, cellMins.z + 1.f, cellMins.w + 1.f );
		int indexWestX   = (int) cellMins.x;
		int indexSouthY  = (int) cellMins.y;
		int indexBelowZ  = (int) cellMins.z;
		int indexBeforeT = (int) cellMins.w;
		int indexEastX  = indexWestX   + 1;
		int indexNorthY = indexSouthY  + 1;
		int indexAboveZ = indexBelowZ  + 1;
		int indexAfterT = indexBeforeT + 1;

		// "BeforeBSW" stands for "BeforeBelowSouthWest" below (i.e. 4D hypercube mins), etc.
		unsigned int noiseBeforeBSW = Get4dNoiseUint( indexWestX, indexSouthY, indexBelowZ, indexBeforeT, seed );
		unsigned int noiseBeforeBSE = Get4dNoiseUint( indexEastX, indexSouthY, indexBelowZ, indexBeforeT, seed );
		unsigned int noiseBeforeBNW = Get4dNoiseUint( indexWestX, indexNorthY, indexBelowZ, indexBeforeT, seed );
		unsigned int noiseBeforeBNE = Get4dNoiseUint( indexEastX, indexNorthY, indexBelowZ, indexBeforeT, seed );
		unsigned int noiseBeforeASW = Get4dNoiseUint( indexWestX, indexSouthY, indexAboveZ, indexBeforeT, seed );
		unsigned int noiseBeforeASE = Get4dNoiseUint( indexEastX, indexSouthY, indexAboveZ, indexBeforeT, seed );
		unsigned int noiseBeforeANW = Get4dNoiseUint( indexWestX, indexNorthY, indexAboveZ, indexBeforeT, seed );
		unsigned int noiseBeforeANE = Get4dNoiseUint( indexEastX, indexNorthY, indexAboveZ, indexBeforeT, seed );
		unsigned int noiseAfterBSW = Get4dNoiseUint( indexWestX, indexSouthY, indexBelowZ, indexAfterT, seed );
		unsigned int noiseAfterBSE = Get4dNoiseUint( indexEastX, indexSouthY, indexBelowZ, indexAfterT, seed );
		unsigned int noiseAfterBNW = Get4dNoiseUint( indexWestX, indexNorthY, indexBelowZ, indexAfterT, seed );
		unsigned int noiseAfterBNE = Get4dNoiseUint( indexEastX, indexNorthY, indexBelowZ, indexAfterT, seed );
		unsigned int noiseAfterASW = Get4dNoiseUint( indexWestX, indexSouthY, indexAboveZ, indexAfterT, seed );
		unsigned int noiseAfterASE = Get4dNoiseUint( indexEastX, indexSouthY, indexAboveZ, indexAfterT, seed );
		unsigned int noiseAfterANW = Get4dNoiseUint( indexWestX, indexNorthY, indexAboveZ, indexAfterT, seed );
		unsigned int noiseAfterANE = Get4dNoiseUint( indexEastX, indexNorthY, indexAboveZ, indexAfterT, seed );

		Vector4 gradientBeforeBSW = gradients[ noiseBeforeBSW & 0x0000000F ];
		Vector4 gradientBeforeBSE = gradients[ noiseBeforeBSE & 0x0000000F ];
		Vector4 gradientBeforeBNW = gradients[ noiseBeforeBNW & 0x0000000F ];
		Vector4 gradientBeforeBNE = gradients[ noiseBeforeBNE & 0x0000000F ];
		Vector4 gradientBeforeASW = gradients[ noiseBeforeASW & 0x0000000F ];
		Vector4 gradientBeforeASE = gradients[ noiseBeforeASE & 0x0000000F ];
		Vector4 gradientBeforeANW = gradients[ noiseBeforeANW & 0x0000000F ];
		Vector4 gradientBeforeANE = gradients[ noiseBeforeANE & 0x0000000F ];
		Vector4 gradientAfterBSW = gradients[ noiseAfterBSW & 0x0000000F ];
		Vector4 gradientAfterBSE = gradients[ noiseAfterBSE & 0x0000000F ];
		Vector4 gradientAfterBNW = gradients[ noiseAfterBNW & 0x0000000F ];
		Vector4 gradientAfterBNE = gradients[ noiseAfterBNE & 0x0000000F ];
		Vector4 gradientAfterASW = gradients[ noiseAfterASW & 0x0000000F ];
		Vector4 gradientAfterASE = gradients[ noiseAfterASE & 0x0000000F ];
		Vector4 gradientAfterANW = gradients[ noiseAfterANW & 0x0000000F ];
		Vector4 gradientAfterANE = gradients[ noiseAfterANE & 0x0000000F ];

		// Dot each corner's gradient with displacement from corner to position
		Vector4 displacementFromBeforeBSW( currentPos.x - cellMins.x, currentPos.y - cellMins.y, currentPos.z - cellMins.z, currentPos.w - cellMins.w );
		Vector4 displacementFromBeforeBSE( currentPos.x - cellMaxs.x, currentPos.y - cellMins.y, currentPos.z - cellMins.z, currentPos.w - cellMins.w );
		Vector4 displacementFromBeforeBNW( currentPos.x - cellMins.x, currentPos.y - cellMaxs.y, currentPos.z - cellMins.z, currentPos.w - cellMins.w );
		Vector4 displacementFromBeforeBNE( currentPos.x - cellMaxs.x, currentPos.y - cellMaxs.y, currentPos.z - cellMins.z, currentPos.w - cellMins.w );
		Vector4 displacementFromBeforeASW( currentPos.x - cellMins.x, currentPos.y - cellMins.y, currentPos.z - cellMaxs.z, currentPos.w - cellMins.w );
		Vector4 displacementFromBeforeASE( currentPos.x - cellMaxs.x, currentPos.y - cellMins.y, currentPos.z - cellMaxs.z, currentPos.w - cellMins.w );
		Vector4 displacementFromBeforeANW( currentPos.x - cellMins.x, currentPos.y - cellMaxs.y, currentPos.z - cellMaxs.z, currentPos.w - cellMins.w );
		Vector4 displacementFromBeforeANE( currentPos.x - cellMaxs.x, currentPos.y - cellMaxs.y, currentPos.z - cellMaxs.z, currentPos.w - cellMins.w );
		Vector4 displacementFromAfterBSW( currentPos.x - cellMins.x, currentPos.y - cellMins.y, currentPos.z - cellMins.z, currentPos.w - cellMaxs.w );
		Vector4 displacementFromAfterBSE( currentPos.x - cellMaxs.x, currentPos.y - cellMins.y, currentPos.z - cellMins.z, currentPos.w - cellMaxs.w );
		Vector4 displacementFromAfterBNW( currentPos.x - cellMins.x, currentPos.y - cellMaxs.y, currentPos.z - cellMins.z, currentPos.w - cellMaxs.w );
		Vector4 displacementFromAfterBNE( currentPos.x - cellMaxs.x, currentPos.y - cellMaxs.y, currentPos.z - cellMins.z, currentPos.w - cellMaxs.w );
		Vector4 displacementFromAfterASW( currentPos.x - cellMins.x, currentPos.y - cellMins.y, currentPos.z - cellMaxs.z, currentPos.w - cellMaxs.w );
		Vector4 displacementFromAfterASE( currentPos.x - cellMaxs.x, currentPos.y - cellMins.y, currentPos.z - cellMaxs.z, currentPos.w - cellMaxs.w );
		Vector4 displacementFromAfterANW( currentPos.x - cellMins.x, currentPos.y - cellMaxs.y, currentPos.z - cellMaxs.z, currentPos.w - cellMaxs.w );
		Vector4 displacementFromAfterANE( currentPos.x - cellMaxs.x, currentPos.y - cellMaxs.y, currentPos.z - cellMaxs.z, currentPos.w - cellMaxs.w );

		float dotBeforeBSW = MathUtils::Dot( gradientBeforeBSW, displacementFromBeforeBSW );
		float dotBeforeBSE = MathUtils::Dot( gradientBeforeBSE, displacementFromBeforeBSE );
		float dotBeforeBNW = MathUtils::Dot( gradientBeforeBNW, displacementFromBeforeBNW );
		float dotBeforeBNE = MathUtils::Dot( gradientBeforeBNE, displacementFromBeforeBNE );
		float dotBeforeASW = MathUtils::Dot( gradientBeforeASW, displacementFromBeforeASW );
		float dotBeforeASE = MathUtils::Dot( gradientBeforeASE, displacementFromBeforeASE );
		float dotBeforeANW = MathUtils::Dot( gradientBeforeANW, displacementFromBeforeANW );
		float dotBeforeANE = MathUtils::Dot( gradientBeforeANE, displacementFromBeforeANE );
		float dotAfterBSW =  MathUtils::Dot( gradientAfterBSW, displacementFromAfterBSW );
		float dotAfterBSE =  MathUtils::Dot( gradientAfterBSE, displacementFromAfterBSE );
		float dotAfterBNW =  MathUtils::Dot( gradientAfterBNW, displacementFromAfterBNW );
		float dotAfterBNE =  MathUtils::Dot( gradientAfterBNE, displacementFromAfterBNE );
		float dotAfterASW =  MathUtils::Dot( gradientAfterASW, displacementFromAfterASW );
		float dotAfterASE =  MathUtils::Dot( gradientAfterASE, displacementFromAfterASE );
		float dotAfterANW =  MathUtils::Dot( gradientAfterANW, displacementFromAfterANW );
		float dotAfterANE =  MathUtils::Dot( gradientAfterANE, displacementFromAfterANE );

		// Do a smoothed (nonlinear) weighted average of dot results
		float weightEast  = SmoothStep( displacementFromBeforeBSW.x );
		float weightNorth = SmoothStep( displacementFromBeforeBSW.y );
		float weightAbove = SmoothStep( displacementFromBeforeBSW.z );
		float weightAfter = SmoothStep( displacementFromBeforeBSW.w );
		float weightWest   = 1.f - weightEast;
		float weightSouth  = 1.f - weightNorth;
		float weightBelow  = 1.f - weightAbove;
		float weightBefore = 1.f - weightAfter;

		// 16-way blend (16 -> 8 -> 4 -> 2 -> 1)
		float blendBeforeBelowSouth	= (weightEast * dotBeforeBSE) + (weightWest * dotBeforeBSW);
		float blendBeforeBelowNorth	= (weightEast * dotBeforeBNE) + (weightWest * dotBeforeBNW);
		float blendBeforeAboveSouth	= (weightEast * dotBeforeASE) + (weightWest * dotBeforeASW);
		float blendBeforeAboveNorth	= (weightEast * dotBeforeANE) + (weightWest * dotBeforeANW);
		float blendAfterBelowSouth  = (weightEast * dotAfterBSE)  + (weightWest * dotAfterBSW);
		float blendAfterBelowNorth  = (weightEast * dotAfterBNE)  + (weightWest * dotAfterBNW);
		float blendAfterAboveSouth  = (weightEast * dotAfterASE)  + (weightWest * dotAfterASW);
		float blendAfterAboveNorth  = (weightEast * dotAfterANE)  + (weightWest * dotAfterANW);
		float blendBeforeBelow = (weightSouth * blendBeforeBelowSouth) + (weightNorth * blendBeforeBelowNorth);
		float blendBeforeAbove = (weightSouth * blendBeforeAboveSouth) + (weightNorth * blendBeforeAboveNorth);
		float blendAfterBelow  = (weightSouth * blendAfterBelowSouth)  + (weightNorth * blendAfterBelowNorth);
		float blendAfterAbove  = (weightSouth * blendAfterAboveSouth)  + (weightNorth * blendAfterAboveNorth);
		float blendBefore = (weightBelow * blendBeforeBelow) + (weightAbove * blendBeforeAbove);
		float blendAfter  = (weightBelow * blendAfterBelow) + (weightAbove * blendAfterAbove);
		float blendTotal = (weightBefore * blendBefore) + (weightAfter * blendAfter);
		float noiseThisOctave = 1.6f * blendTotal; // 4D Perlin is in ~[-.5,.5]; map to ~[-1,1]

		// Accumulate results and prepare for next octave (if any)
		totalNoise += noiseThisOctave * currentAmplitude;
		totalAmplitude += currentAmplitude;
		currentAmplitude *= octavePersistence;
		currentPos *= octaveScale;
		currentPos.x += OCTAVE_OFFSET; // Add "irrational" offset to de-align octave grids
		currentPos.y += OCTAVE_OFFSET; // Add "irrational" offset to de-align octave grids
		currentPos.z += OCTAVE_OFFSET; // Add "irrational" offset to de-align octave grids
		currentPos.w += OCTAVE_OFFSET; // Add "irrational" offset to de-align octave grids
		++ seed; // Eliminates octaves "echoing" each other (since each octave is uniquely seeded)
	}

	// Re-normalize total noise to within [-1,1] and fix octaves pulling us far away from limits
	if( renormalize && totalAmplitude > 0.f )
	{
		totalNoise /= totalAmplitude;				// Amplitude exceeds 1.0 if octaves are used
		totalNoise = (totalNoise * 0.5f) + 0.5f;	// Map to [0,1]
		totalNoise = SmoothStep( totalNoise );		// Push towards extents (octaves pull us away)
		totalNoise = (totalNoise * 2.0f) - 1.f;		// Map back to [-1,1]
	}

	return totalNoise;
}
Example #5
0
//-----------------------------------------------------------------------------------------------
// Perlin noise is fractal noise with "gradient vector smoothing" applied.
//
// In 3D, gradients are unit-length vectors in random (3D) directions.
//
float Compute3dPerlinNoise( float posX, float posY, float posZ, float scale, unsigned int numOctaves, float octavePersistence, float octaveScale, bool renormalize, unsigned int seed )
{
	const float OCTAVE_OFFSET = 0.636764989593174f; // Translation/bias to add to each octave

	const Vector3 gradients[ 8 ] = // Traditional "12 edges" requires modulus and isn't any better.
	{
		Vector3( +fSQRT_3_OVER_3, +fSQRT_3_OVER_3, +fSQRT_3_OVER_3 ), // Normalized unit 3D vectors
		Vector3( -fSQRT_3_OVER_3, +fSQRT_3_OVER_3, +fSQRT_3_OVER_3 ), //  pointing toward cube
		Vector3( +fSQRT_3_OVER_3, -fSQRT_3_OVER_3, +fSQRT_3_OVER_3 ), //  corners, so components
		Vector3( -fSQRT_3_OVER_3, -fSQRT_3_OVER_3, +fSQRT_3_OVER_3 ), //  are all sqrt(3)/3, i.e.
		Vector3( +fSQRT_3_OVER_3, +fSQRT_3_OVER_3, -fSQRT_3_OVER_3 ), // 0.5773502691896257645091f.
		Vector3( -fSQRT_3_OVER_3, +fSQRT_3_OVER_3, -fSQRT_3_OVER_3 ), // These are slightly better
		Vector3( +fSQRT_3_OVER_3, -fSQRT_3_OVER_3, -fSQRT_3_OVER_3 ), // than axes (1,0,0) and much
		Vector3( -fSQRT_3_OVER_3, -fSQRT_3_OVER_3, -fSQRT_3_OVER_3 )  // faster than edges (1,1,0).
	};

	float totalNoise = 0.f;
	float totalAmplitude = 0.f;
	float currentAmplitude = 1.f;
	float invScale = (1.f / scale);
	Vector3 currentPos( posX * invScale, posY * invScale, posZ * invScale );

	for( unsigned int octaveNum = 0; octaveNum < numOctaves; ++ octaveNum )
	{
		// Determine random unit "gradient vectors" for surrounding corners
		Vector3 cellMins( FastFloor( currentPos.x ), FastFloor( currentPos.y ), FastFloor( currentPos.z ) );
		Vector3 cellMaxs( cellMins.x + 1.f, cellMins.y + 1.f, cellMins.z + 1.f );
		int indexWestX  = (int) cellMins.x;
		int indexSouthY = (int) cellMins.y;
		int indexBelowZ = (int) cellMins.z;
		int indexEastX  = indexWestX  + 1;
		int indexNorthY = indexSouthY + 1;
		int indexAboveZ = indexBelowZ + 1;

		unsigned int noiseBelowSW = Get3dNoiseUint( indexWestX, indexSouthY, indexBelowZ, seed );
		unsigned int noiseBelowSE = Get3dNoiseUint( indexEastX, indexSouthY, indexBelowZ, seed );
		unsigned int noiseBelowNW = Get3dNoiseUint( indexWestX, indexNorthY, indexBelowZ, seed );
		unsigned int noiseBelowNE = Get3dNoiseUint( indexEastX, indexNorthY, indexBelowZ, seed );
		unsigned int noiseAboveSW = Get3dNoiseUint( indexWestX, indexSouthY, indexAboveZ, seed );
		unsigned int noiseAboveSE = Get3dNoiseUint( indexEastX, indexSouthY, indexAboveZ, seed );
		unsigned int noiseAboveNW = Get3dNoiseUint( indexWestX, indexNorthY, indexAboveZ, seed );
		unsigned int noiseAboveNE = Get3dNoiseUint( indexEastX, indexNorthY, indexAboveZ, seed );

		Vector3 gradientBelowSW = gradients[ noiseBelowSW & 0x00000007 ];
		Vector3 gradientBelowSE = gradients[ noiseBelowSE & 0x00000007 ];
		Vector3 gradientBelowNW = gradients[ noiseBelowNW & 0x00000007 ];
		Vector3 gradientBelowNE = gradients[ noiseBelowNE & 0x00000007 ];
		Vector3 gradientAboveSW = gradients[ noiseAboveSW & 0x00000007 ];
		Vector3 gradientAboveSE = gradients[ noiseAboveSE & 0x00000007 ];
		Vector3 gradientAboveNW = gradients[ noiseAboveNW & 0x00000007 ];
		Vector3 gradientAboveNE = gradients[ noiseAboveNE & 0x00000007 ];

		// Dot each corner's gradient with displacement from corner to position
		Vector3 displacementFromBelowSW( currentPos.x - cellMins.x, currentPos.y - cellMins.y, currentPos.z - cellMins.z );
		Vector3 displacementFromBelowSE( currentPos.x - cellMaxs.x, currentPos.y - cellMins.y, currentPos.z - cellMins.z );
		Vector3 displacementFromBelowNW( currentPos.x - cellMins.x, currentPos.y - cellMaxs.y, currentPos.z - cellMins.z );
		Vector3 displacementFromBelowNE( currentPos.x - cellMaxs.x, currentPos.y - cellMaxs.y, currentPos.z - cellMins.z );
		Vector3 displacementFromAboveSW( currentPos.x - cellMins.x, currentPos.y - cellMins.y, currentPos.z - cellMaxs.z );
		Vector3 displacementFromAboveSE( currentPos.x - cellMaxs.x, currentPos.y - cellMins.y, currentPos.z - cellMaxs.z );
		Vector3 displacementFromAboveNW( currentPos.x - cellMins.x, currentPos.y - cellMaxs.y, currentPos.z - cellMaxs.z );
		Vector3 displacementFromAboveNE( currentPos.x - cellMaxs.x, currentPos.y - cellMaxs.y, currentPos.z - cellMaxs.z );

		float dotBelowSW = MathUtils::Dot( gradientBelowSW, displacementFromBelowSW );
		float dotBelowSE = MathUtils::Dot( gradientBelowSE, displacementFromBelowSE );
		float dotBelowNW = MathUtils::Dot( gradientBelowNW, displacementFromBelowNW );
		float dotBelowNE = MathUtils::Dot( gradientBelowNE, displacementFromBelowNE );
		float dotAboveSW = MathUtils::Dot( gradientAboveSW, displacementFromAboveSW );
		float dotAboveSE = MathUtils::Dot( gradientAboveSE, displacementFromAboveSE );
		float dotAboveNW = MathUtils::Dot( gradientAboveNW, displacementFromAboveNW );
		float dotAboveNE = MathUtils::Dot( gradientAboveNE, displacementFromAboveNE );

		// Do a smoothed (nonlinear) weighted average of dot results
		float weightEast  = SmoothStep5( displacementFromBelowSW.x );
		float weightNorth = SmoothStep5( displacementFromBelowSW.y );
		float weightAbove = SmoothStep5( displacementFromBelowSW.z );
		float weightWest  = 1.f - weightEast;
		float weightSouth = 1.f - weightNorth;
		float weightBelow = 1.f - weightAbove;

		// 8-way blend (8 -> 4 -> 2 -> 1)
		float blendBelowSouth = (weightEast * dotBelowSE) + (weightWest * dotBelowSW);
		float blendBelowNorth = (weightEast * dotBelowNE) + (weightWest * dotBelowNW);
		float blendAboveSouth = (weightEast * dotAboveSE) + (weightWest * dotAboveSW);
		float blendAboveNorth = (weightEast * dotAboveNE) + (weightWest * dotAboveNW);
		float blendBelow = (weightSouth * blendBelowSouth) + (weightNorth * blendBelowNorth);
		float blendAbove = (weightSouth * blendAboveSouth) + (weightNorth * blendAboveNorth);
		float blendTotal = (weightBelow * blendBelow) + (weightAbove * blendAbove);
		float noiseThisOctave = 1.66666666f * blendTotal; // 3D Perlin is ~[-.6,.6]; map to ~[-1,1]

		// Accumulate results and prepare for next octave (if any)
		totalNoise += noiseThisOctave * currentAmplitude;
		totalAmplitude += currentAmplitude;
		currentAmplitude *= octavePersistence;
		currentPos *= octaveScale;
		currentPos.x += OCTAVE_OFFSET; // Add "irrational" offset to de-align octave grids
		currentPos.y += OCTAVE_OFFSET; // Add "irrational" offset to de-align octave grids
		currentPos.z += OCTAVE_OFFSET; // Add "irrational" offset to de-align octave grids
		++ seed; // Eliminates octaves "echoing" each other (since each octave is uniquely seeded)
	}

	// Re-normalize total noise to within [-1,1] and fix octaves pulling us far away from limits
	if( renormalize && totalAmplitude > 0.f )
	{
		totalNoise /= totalAmplitude;				// Amplitude exceeds 1.0 if octaves are used
		totalNoise = (totalNoise * 0.5f) + 0.5f;	// Map to [0,1]
		totalNoise = SmoothStep( totalNoise );		// Push towards extents (octaves pull us away)
		totalNoise = (totalNoise * 2.0f) - 1.f;		// Map back to [-1,1]
	}

	return totalNoise;
}
Example #6
0
//-----------------------------------------------------------------------------------------------
// Perlin noise is fractal noise with "gradient vector smoothing" applied.
//
// In 2D, gradients are unit-length vectors in various directions with even angular distribution.
//
float Compute2dPerlinNoise( float posX, float posY, float scale, unsigned int numOctaves, float octavePersistence, float octaveScale, bool renormalize, unsigned int seed )
{
	const float OCTAVE_OFFSET = 0.636764989593174f; // Translation/bias to add to each octave
	const Vector2 gradients[ 8 ] = // Normalized unit vectors in 8 quarter-cardinal directions
	{
		Vector2( +0.923879533f, +0.382683432f ), // 22.5 degrees
		Vector2( +0.382683432f, +0.923879533f ), // 67.5 degrees
		Vector2( -0.382683432f, +0.923879533f ), // 112.5 degrees
		Vector2( -0.923879533f, +0.382683432f ), // 157.5 degrees
		Vector2( -0.923879533f, -0.382683432f ), // 202.5 degrees
		Vector2( -0.382683432f, -0.923879533f ), // 247.5 degrees
		Vector2( +0.382683432f, -0.923879533f ), // 292.5 degrees
		Vector2( +0.923879533f, -0.382683432f )	 // 337.5 degrees
	};

	float totalNoise = 0.f;
	float totalAmplitude = 0.f;
	float currentAmplitude = 1.f;
	float invScale = (1.f / scale);
	Vector2 currentPos( posX * invScale, posY * invScale );

	for( unsigned int octaveNum = 0; octaveNum < numOctaves; ++ octaveNum )
	{
		// Determine random unit "gradient vectors" for surrounding corners
		Vector2 cellMins( FastFloor( currentPos.x ), FastFloor( currentPos.y ) );
		Vector2 cellMaxs( cellMins.x + 1.f, cellMins.y + 1.f );
		int indexWestX  = (int) cellMins.x;
		int indexSouthY = (int) cellMins.y;
		int indexEastX  = indexWestX  + 1;
		int indexNorthY = indexSouthY + 1;

		unsigned int noiseSW = Get2dNoiseUint( indexWestX, indexSouthY, seed );
		unsigned int noiseSE = Get2dNoiseUint( indexEastX, indexSouthY, seed );
		unsigned int noiseNW = Get2dNoiseUint( indexWestX, indexNorthY, seed );
		unsigned int noiseNE = Get2dNoiseUint( indexEastX, indexNorthY, seed );

		Vector2 gradientSW = gradients[ noiseSW & 0x00000007 ];
		Vector2 gradientSE = gradients[ noiseSE & 0x00000007 ];
		Vector2 gradientNW = gradients[ noiseNW & 0x00000007 ];
		Vector2 gradientNE = gradients[ noiseNE & 0x00000007 ];

		// Dot each corner's gradient with displacement from corner to position
		Vector2 displacementFromSW( currentPos.x - cellMins.x, currentPos.y - cellMins.y );
		Vector2 displacementFromSE( currentPos.x - cellMaxs.x, currentPos.y - cellMins.y );
		Vector2 displacementFromNW( currentPos.x - cellMins.x, currentPos.y - cellMaxs.y );
		Vector2 displacementFromNE( currentPos.x - cellMaxs.x, currentPos.y - cellMaxs.y );

		float dotSouthWest = MathUtils::Dot( gradientSW, displacementFromSW );
		float dotSouthEast = MathUtils::Dot( gradientSE, displacementFromSE );
		float dotNorthWest = MathUtils::Dot( gradientNW, displacementFromNW );
		float dotNorthEast = MathUtils::Dot( gradientNE, displacementFromNE );

		// Do a smoothed (nonlinear) weighted average of dot results
		float weightEast = SmoothStep5( displacementFromSW.x );
		float weightNorth = SmoothStep5( displacementFromSW.y );
		float weightWest = 1.f - weightEast;
		float weightSouth = 1.f - weightNorth;

		float blendSouth = (weightEast * dotSouthEast) + (weightWest * dotSouthWest);
		float blendNorth = (weightEast * dotNorthEast) + (weightWest * dotNorthWest);
		float blendTotal = (weightSouth * blendSouth) + (weightNorth * blendNorth);
		float noiseThisOctave = 1.5f * blendTotal; // 2D Perlin is in ~[-.66,.66]; map to ~[-1,1]
		
		// Accumulate results and prepare for next octave (if any)
		totalNoise += noiseThisOctave * currentAmplitude;
		totalAmplitude += currentAmplitude;
		currentAmplitude *= octavePersistence;
		currentPos *= octaveScale;
		currentPos.x += OCTAVE_OFFSET; // Add "irrational" offset to de-align octave grids
		currentPos.y += OCTAVE_OFFSET; // Add "irrational" offset to de-align octave grids
		++ seed; // Eliminates octaves "echoing" each other (since each octave is uniquely seeded)
	}

	// Re-normalize total noise to within [-1,1] and fix octaves pulling us far away from limits
	if( renormalize && totalAmplitude > 0.f )
	{
		totalNoise /= totalAmplitude;				// Amplitude exceeds 1.0 if octaves are used
		totalNoise = (totalNoise * 0.5f) + 0.5f;	// Map to [0,1]
		totalNoise = SmoothStep( totalNoise );		// Push towards extents (octaves pull us away)
		totalNoise = (totalNoise * 2.0f) - 1.f;		// Map back to [-1,1]
	}

	return totalNoise;
}
Example #7
0
//-----------------------------------------------------------------------------------------------
float Compute4dFractalNoise( float posX, float posY, float posZ, float posT, float scale, unsigned int numOctaves, float octavePersistence, float octaveScale, bool renormalize, unsigned int seed )
{
	const float OCTAVE_OFFSET = 0.636764989593174f; // Translation/bias to add to each octave

	float totalNoise = 0.f;
	float totalAmplitude = 0.f;
	float currentAmplitude = 1.f;
	float invScale = (1.f / scale);
	Vector4 currentPos( posX * invScale, posY * invScale, posZ * invScale, posT * invScale );

	for( unsigned int octaveNum = 0; octaveNum < numOctaves; ++ octaveNum )
	{
		// Determine noise values at nearby integer "grid point" positions
		Vector4 cellMins( FastFloor( currentPos.x ), FastFloor( currentPos.y ), FastFloor( currentPos.z ), FastFloor( currentPos.w ) );
		int indexWestX   = (int) cellMins.x;
		int indexSouthY  = (int) cellMins.y;
		int indexBelowZ  = (int) cellMins.z;
		int indexBeforeT = (int) cellMins.w;
		int indexEastX  = indexWestX + 1;
		int indexNorthY = indexSouthY + 1;
		int indexAboveZ = indexBelowZ + 1;
		int indexAfterT = indexBeforeT + 1;

		// Noise grid cell has 16 "corners" in 4D
		float beforeBelowSW = Get4dNoiseZeroToOne( indexWestX, indexSouthY, indexBelowZ, indexBeforeT, seed );
		float beforeBelowSE = Get4dNoiseZeroToOne( indexEastX, indexSouthY, indexBelowZ, indexBeforeT, seed );
		float beforeBelowNW = Get4dNoiseZeroToOne( indexWestX, indexNorthY, indexBelowZ, indexBeforeT, seed );
		float beforeBelowNE = Get4dNoiseZeroToOne( indexEastX, indexNorthY, indexBelowZ, indexBeforeT, seed );
		float beforeAboveSW = Get4dNoiseZeroToOne( indexWestX, indexSouthY, indexAboveZ, indexBeforeT, seed );
		float beforeAboveSE = Get4dNoiseZeroToOne( indexEastX, indexSouthY, indexAboveZ, indexBeforeT, seed );
		float beforeAboveNW = Get4dNoiseZeroToOne( indexWestX, indexNorthY, indexAboveZ, indexBeforeT, seed );
		float beforeAboveNE = Get4dNoiseZeroToOne( indexEastX, indexNorthY, indexAboveZ, indexBeforeT, seed );

		float afterBelowSW = Get4dNoiseZeroToOne( indexWestX, indexSouthY, indexBelowZ, indexAfterT, seed );
		float afterBelowSE = Get4dNoiseZeroToOne( indexEastX, indexSouthY, indexBelowZ, indexAfterT, seed );
		float afterBelowNW = Get4dNoiseZeroToOne( indexWestX, indexNorthY, indexBelowZ, indexAfterT, seed );
		float afterBelowNE = Get4dNoiseZeroToOne( indexEastX, indexNorthY, indexBelowZ, indexAfterT, seed );
		float afterAboveSW = Get4dNoiseZeroToOne( indexWestX, indexSouthY, indexAboveZ, indexAfterT, seed );
		float afterAboveSE = Get4dNoiseZeroToOne( indexEastX, indexSouthY, indexAboveZ, indexAfterT, seed );
		float afterAboveNW = Get4dNoiseZeroToOne( indexWestX, indexNorthY, indexAboveZ, indexAfterT, seed );
		float afterAboveNE = Get4dNoiseZeroToOne( indexEastX, indexNorthY, indexAboveZ, indexAfterT, seed );

		// Do a smoothed (nonlinear) weighted average of nearby grid point values
		Vector4 displacementFromMins = currentPos - cellMins;

		float weightEast	= SmoothStep( displacementFromMins.x );
		float weightNorth	= SmoothStep( displacementFromMins.y );
		float weightAbove	= SmoothStep( displacementFromMins.z );
		float weightAfter	= SmoothStep( displacementFromMins.w );
		float weightWest	= 1.f - weightEast;
		float weightSouth	= 1.f - weightNorth;
		float weightBelow	= 1.f - weightAbove;
		float weightBefore	= 1.f - weightAfter;

		// 16-way blend (16 -> 8 -> 4 -> 2 -> 1)
		float blendBeforeBelowSouth	= (weightEast * beforeBelowSE) + (weightWest * beforeBelowSW);
		float blendBeforeBelowNorth	= (weightEast * beforeBelowNE) + (weightWest * beforeBelowNW);
		float blendBeforeAboveSouth	= (weightEast * beforeAboveSE) + (weightWest * beforeAboveSW);
		float blendBeforeAboveNorth	= (weightEast * beforeAboveNE) + (weightWest * beforeAboveNW);
		float blendAfterBelowSouth  = (weightEast * afterBelowSE)  + (weightWest * afterBelowSW);
		float blendAfterBelowNorth  = (weightEast * afterBelowNE)  + (weightWest * afterBelowNW);
		float blendAfterAboveSouth  = (weightEast * afterAboveSE)  + (weightWest * afterAboveSW);
		float blendAfterAboveNorth  = (weightEast * afterAboveNE)  + (weightWest * afterAboveNW);
		float blendBeforeBelow = (weightSouth * blendBeforeBelowSouth) + (weightNorth * blendBeforeBelowNorth);
		float blendBeforeAbove = (weightSouth * blendBeforeAboveSouth) + (weightNorth * blendBeforeAboveNorth);
		float blendAfterBelow  = (weightSouth * blendAfterBelowSouth)  + (weightNorth * blendAfterBelowNorth);
		float blendAfterAbove  = (weightSouth * blendAfterAboveSouth)  + (weightNorth * blendAfterAboveNorth);
		float blendBefore = (weightBelow * blendBeforeBelow) + (weightAbove * blendBeforeAbove);
		float blendAfter  = (weightBelow * blendAfterBelow) + (weightAbove * blendAfterAbove);
		float blendTotal = (weightBefore * blendBefore) + (weightAfter * blendAfter);
		float noiseThisOctave = 2.f * (blendTotal - 0.5f); // Map from [0,1] to [-1,1]

		// Accumulate results and prepare for next octave (if any)
		totalNoise += noiseThisOctave * currentAmplitude;
		totalAmplitude += currentAmplitude;
		currentAmplitude *= octavePersistence;
		currentPos *= octaveScale;
		currentPos.x += OCTAVE_OFFSET; // Add "irrational" offsets to noise position components
		currentPos.y += OCTAVE_OFFSET; //	at each octave to break up their grid alignment
		currentPos.z += OCTAVE_OFFSET;
		currentPos.w += OCTAVE_OFFSET;
		++ seed; // Eliminates octaves "echoing" each other (since each octave is uniquely seeded)
	}

	// Re-normalize total noise to within [-1,1] and fix octaves pulling us far away from limits
	if( renormalize && totalAmplitude > 0.f )
	{
		totalNoise /= totalAmplitude;				// Amplitude exceeds 1.0 if octaves are used
		totalNoise = (totalNoise * 0.5f) + 0.5f;	// Map to [0,1]
		totalNoise = SmoothStep( totalNoise );		// Push towards extents (octaves pull us away)
		totalNoise = (totalNoise * 2.0f) - 1.f;		// Map back to [-1,1]
	}

	return totalNoise;
}