//----------------------------------------------------------------------------------------------- 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; }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------ f32 SmoothStepPingPong(f32 in_x) { CS_ASSERT(in_x >= 0.0f && in_x <= 1.0f, "x must always be in the range 0.0 to 1.0 in Interpolate functions."); if (in_x < 0.5f) { return SmoothStep(in_x * 2.0f); } else { return SmoothStep(2.0f * (1.0f - in_x)); } }
//----------------------------------------------------------------------------------------------- // Perlin noise is fractal noise with "gradient vector smoothing" applied. // // In 1D, the gradients are trivial: -1.0 or 1.0, so resulting noise is boring at one octave. // float Compute1dPerlinNoise( float position, 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 float gradients[2] = { -1.f, 1.f }; // 1D unit "gradient" vectors; one back, one forward float totalNoise = 0.f; float totalAmplitude = 0.f; float currentAmplitude = 1.f; float currentPosition = position * (1.f / scale); for( unsigned int octaveNum = 0; octaveNum < numOctaves; ++ octaveNum ) { // Determine random "gradient vectors" (just +1 or -1 for 1D Perlin) for surrounding corners float positionFloor = (float) FastFloor( currentPosition ); int indexWest = (int) positionFloor; int indexEast = indexWest + 1; float gradientWest = gradients[ Get1dNoiseUint( indexWest, seed ) & 0x00000001 ]; float gradientEast = gradients[ Get1dNoiseUint( indexEast, seed ) & 0x00000001 ]; // Dot each point's gradient with displacement from point to position float displacementFromWest = currentPosition - positionFloor; // always positive float displacementFromEast = displacementFromWest - 1.f; // always negative float dotWest = gradientWest * displacementFromWest; // 1D "dot product" is... multiply float dotEast = gradientEast * displacementFromEast; // Do a smoothed (nonlinear) weighted average of dot results float weightEast = SmoothStep( displacementFromWest ); float weightWest = 1.f - weightEast; float blendTotal = (weightWest * dotWest) + (weightEast * dotEast); float noiseThisOctave = 2.f * blendTotal; // 1D 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; currentPosition *= octaveScale; currentPosition += 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; }
float Wood::WoodFunc(Point3 p) { float r; float px = p.x/size; float py = p.y/size; float pz = p.z/size; px += WoodNoise(px)*r1; py += WoodNoise(py)*r1; pz += WoodNoise(pz)*r1; r = (float) sqrt(py*py+pz*pz); r += WoodNoise(r)+r2*WoodNoise(px/4.0f); r = (float)fmod((double)r, 1.0); /* be periodic */ r = SmoothStep(0.0f, 0.8f, r) - SmoothStep(0.83f, 1.0f, r); return(r); }
//debug single parquetShader parts extern "C" void test_parquetShader(DataStruct* data) { float m = data->f; //should be 1 float l = m -10; float r = m +10; data->fa[0] = Mod(l,r); data->fa[1] = Mod(r,l); data->fa[2] = Mod(r,m); data->fa[3] = Step(l,r); data->fa[4] = Step(r,l); data->fa[5] = SmoothStep(l,r,m); data->fa[6] = SmoothStep(l,r,100*m); data->fa[7] = SmoothStep(l,r,-200*m); data->fa[8] = Mix(l,r,m); }
Float Turbulence(const Point3f &p, const Vector3f &dpdx, const Vector3f &dpdy, Float omega, int maxOctaves) { // Compute number of octaves for antialiased FBm Float len2 = std::max(dpdx.LengthSquared(), dpdy.LengthSquared()); Float foctaves = Clamp(-1.f - .5f * Log2(len2), 0, maxOctaves); int octaves = std::floor(foctaves); // Compute sum of octaves of noise for turbulence Float sum = 0.f, lambda = 1.f, o = 1.f; for (int i = 0; i < octaves; ++i) { sum += o * std::abs(Noise(lambda * p)); lambda *= 1.99f; o *= omega; } // Account for contributions of clamped octaves in turbulence Float partialOctave = foctaves - octaves; sum += o * Lerp(SmoothStep(.3f, .7f, partialOctave), 0.2, std::abs(Noise(lambda * p))); for (int i = octaves; i < maxOctaves; ++i) { sum += o * 0.2f; o *= omega; } return sum; }
//----------------------------------------------------------------------------------------------- float Compute1dFractalNoise( float position, 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 currentPosition = position * (1.f / scale); for( unsigned int octaveNum = 0; octaveNum < numOctaves; ++ octaveNum ) { // Determine noise values at nearby integer "grid point" positions float positionFloor = FastFloor( currentPosition ); int indexWest = (int) positionFloor; int indexEast = indexWest + 1; float valueWest = Get1dNoiseZeroToOne( indexWest, seed ); float valueEast = Get1dNoiseZeroToOne( indexEast, seed ); // Do a smoothed (nonlinear) weighted average of nearby grid point values float distanceFromWest = currentPosition - positionFloor; float weightEast = SmoothStep( distanceFromWest ); // Gives rounder (nonlinear) results float weightWest = 1.f - weightEast; float noiseZeroToOne = (valueWest * weightWest) + (valueEast * weightEast); float noiseThisOctave = 2.f * (noiseZeroToOne - 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; currentPosition *= octaveScale; currentPosition += 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; }
//--------------------------------------------------------------------------- // Computes a random Perlin noise value based on a 2D input <position> and // Perlin noise parameters. Recursive (for additional octaves). // // <perlinNoiseGridCellSize>: Noise density. Larger values produce longer // wavelength noise (e.g. gentle, sweeping hills). // <numOctaves>: 0 is flat, 1 is simple smoothed noise. Values of 2+ add one // or more additional "octave" harmonics. Each additional octave has // double the frequency/density but only a fraction of the amplitude of // the base noise. // <baseAmplitude>: The minimum (-amplitude) and maximum (+amplitude) values // produced by the first octave of the noise. Note that adding // additional octaves can push the final total Perlin noise values above // or below the maximum base amplitude; the noise can be "normalized" by // the caller (omitted from this function for optimization purposes) via: // noise *= A / (A + (A * P)) // ...where A is the <baseAmplitude> and P is the <persistance>. // <persistance>: The fraction of amplitude of each subsequent octave, based on the amplitude of the previous octave. For // example, with a persistance of 0.3, each octave is only 30% as strong as the previous octave. // float ComputePerlinNoiseValueAtPosition2D( const Vector2& position, float perlinNoiseGridCellSize, int numOctaves, float baseAmplitude, float persistance, int randomSeed ) { int numOctavesRemaining = numOctaves; float amplitude = baseAmplitude; float gridSize = perlinNoiseGridCellSize; float totalPerlinNoise = 0.0f; while( numOctavesRemaining > 0 ) { Vector2 perlinPosition = position / gridSize; Vector2 perlinPositionFloor( floor( perlinPosition.x ), floor( perlinPosition.y ) ); IntVec2 perlinCell( (int) perlinPositionFloor.x, (int) perlinPositionFloor.y ); Vector2 perlinPositionUV = perlinPosition - perlinPositionFloor; Vector2 perlinPositionAntiUV( perlinPositionUV.x - 1.f, perlinPositionUV.y - 1.f ); float eastWeight = SmoothStep( perlinPositionUV.x ); float northWeight = SmoothStep( perlinPositionUV.y ); float westWeight = 1.f - eastWeight; float southWeight = 1.f - northWeight; Vector2 southwestNoiseGradient = GetPseudoRandomNoiseUnitVector2D( perlinCell.x, perlinCell.y, randomSeed ); Vector2 southeastNoiseGradient = GetPseudoRandomNoiseUnitVector2D( perlinCell.x + 1, perlinCell.y, randomSeed ); Vector2 northeastNoiseGradient = GetPseudoRandomNoiseUnitVector2D( perlinCell.x + 1, perlinCell.y + 1, randomSeed ); Vector2 northwestNoiseGradient = GetPseudoRandomNoiseUnitVector2D( perlinCell.x, perlinCell.y + 1, randomSeed ); float southwestDot = DotProduct( southwestNoiseGradient, perlinPositionUV ); float southeastDot = DotProduct( southeastNoiseGradient, Vector2( perlinPositionAntiUV.x, perlinPositionUV.y ) ); float northeastDot = DotProduct( northeastNoiseGradient, perlinPositionAntiUV ); float northwestDot = DotProduct( northwestNoiseGradient, Vector2( perlinPositionUV.x, perlinPositionAntiUV.y ) ); float southBlend = (eastWeight * southeastDot) + (westWeight * southwestDot); float northBlend = (eastWeight * northeastDot) + (westWeight * northwestDot); float fourWayBlend = (southWeight * southBlend) + (northWeight * northBlend); float perlinNoiseAtThisOctave = amplitude * fourWayBlend; -- numOctavesRemaining; totalPerlinNoise += perlinNoiseAtThisOctave; amplitude *= persistance; gridSize *= 0.5f; } return totalPerlinNoise; }
//----------------------------------------------------------------------------------------------- float Generate2DNoise( float x, float y, float gridSize ) { float INVERSE_GRID_SIZE = 1.0f / gridSize; //Find location in grid space float xWithRespectToGridSize = x * INVERSE_GRID_SIZE; float yWithRespectToGridSize = y * INVERSE_GRID_SIZE; int gridX = static_cast< int >( floor( xWithRespectToGridSize ) ); int gridY = static_cast< int >( floor( yWithRespectToGridSize ) ); float xInGrid = xWithRespectToGridSize - gridX; float yInGrid = yWithRespectToGridSize - gridY; //Smooth values FloatVector2 gridPosition( SmoothStep( xInGrid ), SmoothStep( yInGrid ) ); //Create Random Gradients FloatVector2 gradient00 = GeneratePseudoRandomUnitVectorAtPosition( gridX, gridY ); FloatVector2 gradientX0 = GeneratePseudoRandomUnitVectorAtPosition( gridX + 1, gridY ); FloatVector2 gradient0Y = GeneratePseudoRandomUnitVectorAtPosition( gridX, gridY + 1 ); FloatVector2 gradientXY = GeneratePseudoRandomUnitVectorAtPosition( gridX + 1, gridY + 1 ); FloatVector2 vectorToCorner00( gridPosition.x, gridPosition.y ); FloatVector2 vectorToCornerX0( gridPosition.x - 1.f, gridPosition.y ); FloatVector2 vectorToCorner0Y( gridPosition.x, gridPosition.y - 1.f ); FloatVector2 vectorToCornerXY( gridPosition.x - 1.f, gridPosition.y - 1.f ); //Dot Product float influence00 = DotProduct( gradient00, vectorToCorner00 ); float influenceX0 = DotProduct( gradientX0, vectorToCornerX0 ); float influence0Y = DotProduct( gradient0Y, vectorToCorner0Y ); float influenceXY = DotProduct( gradientXY, vectorToCornerXY ); //Weighted Average float influenceLowerSide = influence00 + gridPosition.x * ( influenceX0 - influence00 ); float influenceUpperSide = influence0Y + gridPosition.x * ( influenceXY - influence0Y ); float influenceCenter = influenceLowerSide + gridPosition.y * ( influenceUpperSide - influenceLowerSide ); assert( influenceCenter <= 1.f); assert( influenceCenter >= -1.f); return influenceCenter; }
void Camera::MovingCamera(DirectX::XMFLOAT3 p_pos) { float moveX, moveY, centerX, centerY, posX, posY; centerX = GLOBAL::GetInstance().CURRENT_SCREEN_WIDTH * 0.5f; centerY = GLOBAL::GetInstance().CURRENT_SCREEN_HEIGHT * 0.5f; posX = InputManager::GetInstance()->GetMousePositionX() - centerX; posY = InputManager::GetInstance()->GetMousePositionY() - centerY; float procX = posX / 440; float procY = posY / 352; // 512 *0,68 //0.68 = 440/640; if (procX > 1.0) procX = 1.0; if (procX < -1.0) procX = -1.0; if (procY > 1.0) procY = 1.0; if (procY < -1.0) procY = -1.0; moveX = 8 * procX; moveY = 8 * procY; DirectX::XMFLOAT3 position, target, finalPos; DirectX::XMFLOAT3 playerPosition = p_pos; position = DirectX::XMFLOAT3(playerPosition.x + moveX, playerPosition.y + 30.0f, playerPosition.z - moveY - 15.0f); target = DirectX::XMFLOAT3(playerPosition.x + moveX, 0, playerPosition.z - moveY); DirectX::XMStoreFloat3(&finalPos, SmoothStep(DirectX::XMLoadFloat3(&m_oldPosition), DirectX::XMLoadFloat3(&position), 0.25f)); // Set max limits if (finalPos.x < -38) finalPos.x = -38; if (finalPos.x > 38) finalPos.x = 38; if (finalPos.z > 35) finalPos.z = 35; if (finalPos.z < -58) finalPos.z = -58; target = DirectX::XMFLOAT3(finalPos.x, 0, finalPos.z + 15.0f); UpdatePosition(finalPos); UpdateTarget(target); UpdateViewMatrix(); UpdateProjectionMatrix(false); GraphicsEngine::SetViewAndProjection(GetViewMatrix(), GetProjectionMatrix()); m_oldPosition = finalPos; SetOutliningRayPosition(finalPos); SetOutliningRayTarget(playerPosition); };
//--------------------------------------------------------------------------- // Computes a random Perlin noise value based on a 2D input <position> and // Perlin noise parameters. Recursive (for additional octaves). // // <perlinNoiseGridCellSize>: Noise density. Larger values produce longer // wavelength noise (e.g. gentle, sweeping hills). // <numOctaves>: 0 is flat, 1 is simple smoothed noise. Values of 2+ add one // or more additional "octave" harmonics. Each additional octave has // double the frequency/density but only a fraction of the amplitude of // the base noise. // <baseAmplitude>: The minimum (-amplitude) and maximum (+amplitude) values // produced by the first octave of the noise. Note that adding // additional octaves can push the final total Perlin noise values above // or below the maximum base amplitude; the noise can be "normalized" by // the caller (omitted from this function for optimization purposes) via: // noise *= A / (A + (A * P)) // ...where A is the <baseAmplitude> and P is the <persistance>. // <persistance>: The fraction of amplitude of each subsequent octave, based on the amplitude of the previous octave. For // example, with a persistance of 0.3, each octave is only 30% as strong as the previous octave. // float ComputePerlinNoiseValueAtPosition2D( const Vector2& position, float perlinNoiseGridCellSize, int numOctaves, float baseAmplitude, float persistance ) { if( numOctaves == 0 ) return 0.f; Vector2 perlinPosition = position / perlinNoiseGridCellSize; Vector2 perlinPositionFloor(floor(perlinPosition.x), floor(perlinPosition.y)); Vector2Int perlinCell((int)perlinPositionFloor.x, (int)perlinPositionFloor.y); Vector2 perlinPositionUV = perlinPosition - perlinPositionFloor; Vector2 perlinPositionAntiUV(perlinPositionUV.x - 1.f, perlinPositionUV.y - 1.f); float eastWeight = SmoothStep(perlinPositionUV.x); float northWeight = SmoothStep(perlinPositionUV.y); float westWeight = 1.f - eastWeight; float southWeight = 1.f - northWeight; Vector2 southwestNoiseGradient = GetPseudoRandomNoiseUnitVector2D( perlinCell.x, perlinCell.y ); Vector2 southeastNoiseGradient = GetPseudoRandomNoiseUnitVector2D( perlinCell.x + 1, perlinCell.y ); Vector2 northeastNoiseGradient = GetPseudoRandomNoiseUnitVector2D( perlinCell.x + 1, perlinCell.y + 1 ); Vector2 northwestNoiseGradient = GetPseudoRandomNoiseUnitVector2D( perlinCell.x, perlinCell.y + 1 ); float southwestDot = MathUtils::Dot( southwestNoiseGradient, perlinPositionUV ); float southeastDot = MathUtils::Dot( southeastNoiseGradient, Vector2( perlinPositionAntiUV.x, perlinPositionUV.y ) ); float northeastDot = MathUtils::Dot( northeastNoiseGradient, perlinPositionAntiUV ); float northwestDot = MathUtils::Dot( northwestNoiseGradient, Vector2( perlinPositionUV.x, perlinPositionAntiUV.y ) ); float southBlend = (eastWeight * southeastDot) + (westWeight * southwestDot); float northBlend = (eastWeight * northeastDot) + (westWeight * northwestDot); float fourWayBlend = (southWeight * southBlend) + (northWeight * northBlend); float perlinNoiseAtThisOctave = baseAmplitude * fourWayBlend; float perlinNoiseFromAllHigherOctaves = ComputePerlinNoiseValueAtPosition2D( position, 0.5f * perlinNoiseGridCellSize, numOctaves - 1, baseAmplitude * persistance, persistance ); float totalPerlinNoise = perlinNoiseAtThisOctave + perlinNoiseFromAllHigherOctaves; return totalPerlinNoise; }
HRESULT EndgameUpdate(double deltaTime) { static short* velocityBuf = (short*)g_slots; static const uint numVels = g_numSlots/2; static double absoluteTime = 0; const float timeLimit = 5.0f; // 5 seconds absoluteTime += deltaTime; for (uint i = 0; i < g_numNodes; i++) { float velx = velocityBuf[2*(i%numVels)] / MAX_SSHORTF; float vely = velocityBuf[2*(i%numVels)+1] / MAX_SSHORTF; velx = SmoothStep(velx, 0.0f, float(absoluteTime)/timeLimit); vely = SmoothStep(vely, 0.0f, float(absoluteTime)/timeLimit); g_nodes[i].position.setX(float(g_nodes[i].position.getX() + velx * deltaTime)); g_nodes[i].position.setY(float(g_nodes[i].position.getY() + vely * deltaTime)); } if (absoluteTime > timeLimit) { g_endgame = false; g_numActiveNodes = g_numNodes; absoluteTime = 0; for (uint i = 0; i < g_numNodes; i++) { g_nodes[i].attribs.hasChild = false; g_nodes[i].attribs.hasParent = false; } } return S_OK; }
Float FBm(const Point3f &p, const Vector3f &dpdx, const Vector3f &dpdy, Float omega, int maxOctaves) { // Compute number of octaves for antialiased FBm Float len2 = std::max(dpdx.LengthSquared(), dpdy.LengthSquared()); Float n = Clamp(-1 - .5f * Log2(len2), 0, maxOctaves); int nInt = std::floor(n); // Compute sum of octaves of noise for FBm Float sum = 0, lambda = 1, o = 1; for (int i = 0; i < nInt; ++i) { sum += o * Noise(lambda * p); lambda *= 1.99f; o *= omega; } Float nPartial = n - nInt; sum += o * SmoothStep(.3f, .7f, nPartial) * Noise(lambda * p); return sum; }
float FBm(const Point &P, const Vector &dpdx, const Vector &dpdy, float omega, int maxOctaves) { // Compute number of octaves for antialiased FBm float s2 = max(dpdx.LengthSquared(), dpdy.LengthSquared()); float foctaves = min((float)maxOctaves, 1.f - .5f * Log2(s2)); int octaves = Floor2Int(foctaves); // Compute sum of octaves of noise for FBm float sum = 0., lambda = 1., o = 1.; for (int i = 0; i < octaves; ++i) { sum += o * Noise(lambda * P); lambda *= 1.99f; o *= omega; } float partialOctave = foctaves - octaves; sum += o * SmoothStep(.3f, .7f, partialOctave) * Noise(lambda * P); return sum; }
Float FBm(const Point3f &p, const Vector3f &dpdx, const Vector3f &dpdy, Float omega, int maxOctaves) { // Compute number of octaves for antialiased FBm Float len2 = std::max(dpdx.LengthSquared(), dpdy.LengthSquared()); Float foctaves = Clamp(-1.f - .5f * Log2(len2), 0, maxOctaves); int octaves = std::floor(foctaves); // Compute sum of octaves of noise for FBm Float sum = 0.f, lambda = 1.f, o = 1.f; for (int i = 0; i < octaves; ++i) { sum += o * Noise(lambda * p); lambda *= 1.99f; o *= omega; } Float partialOctave = foctaves - octaves; sum += o * SmoothStep(.3f, .7f, partialOctave) * Noise(lambda * p); return sum; }
float Turbulence(const Point &P, const Vector &dpdx, const Vector &dpdy, float omega, int maxOctaves) { // Compute number of octaves for antialiased FBm float s2 = max(dpdx.LengthSquared(), dpdy.LengthSquared()); float foctaves = min((float)maxOctaves, 1.f - .5f * Log2(s2)); int octaves = Floor2Int(foctaves); // Compute sum of octaves of noise for turbulence float sum = 0., lambda = 1., o = 1.; for (int i = 0; i < octaves; ++i) { sum += o * fabsf(Noise(lambda * P)); lambda *= 1.99f; o *= omega; } float partialOctave = foctaves - octaves; sum += o * SmoothStep(.3f, .7f, partialOctave) * fabsf(Noise(lambda * P)); // finally, add in value to account for average value of fabsf(Noise()) // (~0.2) for the remaining octaves... sum += (maxOctaves - foctaves) * 0.2f; return sum; }
//----------------------------------------------------------------------------------------------- // 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; }
//----------------------------------------------------------------------------------------------- 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; }
//----------------------------------------------------------------------------------------------- // 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; }
//----------------------------------------------------------------------------------------------- // 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; }
Spectrum IGIIntegrator::Li(const Scene *scene, const RayDifferential &ray, const Sample *sample, float *alpha) const { Spectrum L(0.); Intersection isect; if (scene->Intersect(ray, &isect)) { if (alpha) *alpha = 1.; Vector wo = -ray.d; // Compute emitted light if ray hit an area light source L += isect.Le(wo); // Evaluate BSDF at hit point BSDF *bsdf = isect.GetBSDF(ray); const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; L += UniformSampleAllLights(scene, p, n, wo, bsdf, sample, lightSampleOffset, bsdfSampleOffset, bsdfComponentOffset); // Compute indirect illumination with virtual lights u_int lSet = min(u_int(sample->oneD[vlSetOffset][0] * nLightSets), nLightSets-1); for (u_int i = 0; i < virtualLights[lSet].size(); ++i) { const VirtualLight &vl = virtualLights[lSet][i]; // Add contribution from _VirtualLight_ _vl_ // Ignore light if it's too close to current point float d2 = DistanceSquared(p, vl.p); //if (d2 < .8 * minDist2) continue; float distScale = SmoothStep(.8 * minDist2, 1.2 * minDist2, d2); // Compute virtual light's tentative contribution _Llight_ Vector wi = Normalize(vl.p - p); Spectrum f = distScale * bsdf->f(wo, wi); if (f.Black()) continue; float G = AbsDot(wi, n) * AbsDot(wi, vl.n) / d2; Spectrum Llight = indirectScale * f * G * vl.Le / virtualLights[lSet].size(); Llight *= scene->Transmittance(Ray(p, vl.p - p)); // Possibly skip shadow ray with Russian roulette if (Llight.y() < rrThreshold) { float continueProbability = .1f; if (RandomFloat() > continueProbability) continue; Llight /= continueProbability; } static StatsCounter vlsr("IGI Integrator", "Shadow Rays to Virtual Lights"); //NOBOOK ++vlsr; //NOBOOK if (!scene->IntersectP(Ray(p, vl.p - p, RAY_EPSILON, 1.f - RAY_EPSILON))) L += Llight; } // Trace rays for specular reflection and refraction if (specularDepth++ < maxSpecularDepth) { Vector wi; // Trace rays for specular reflection and refraction Spectrum f = bsdf->Sample_f(wo, &wi, BxDFType(BSDF_REFLECTION | BSDF_SPECULAR)); if (!f.Black()) { // Compute ray differential _rd_ for specular reflection RayDifferential rd(p, wi); rd.hasDifferentials = true; rd.rx.o = p + isect.dg.dpdx; rd.ry.o = p + isect.dg.dpdy; // Compute differential reflected directions Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx + bsdf->dgShading.dndv * bsdf->dgShading.dvdx; Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy + bsdf->dgShading.dndv * bsdf->dgShading.dvdy; Vector dwodx = -ray.rx.d - wo, dwody = -ray.ry.d - wo; float dDNdx = Dot(dwodx, n) + Dot(wo, dndx); float dDNdy = Dot(dwody, n) + Dot(wo, dndy); rd.rx.d = wi - dwodx + 2 * Vector(Dot(wo, n) * dndx + dDNdx * n); rd.ry.d = wi - dwody + 2 * Vector(Dot(wo, n) * dndy + dDNdy * n); L += scene->Li(rd, sample) * f * AbsDot(wi, n); } f = bsdf->Sample_f(wo, &wi, BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR)); if (!f.Black()) { // Compute ray differential _rd_ for specular transmission RayDifferential rd(p, wi); rd.hasDifferentials = true; rd.rx.o = p + isect.dg.dpdx; rd.ry.o = p + isect.dg.dpdy; float eta = bsdf->eta; Vector w = -wo; if (Dot(wo, n) < 0) eta = 1.f / eta; Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx + bsdf->dgShading.dndv * bsdf->dgShading.dvdx; Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy + bsdf->dgShading.dndv * bsdf->dgShading.dvdy; Vector dwodx = -ray.rx.d - wo, dwody = -ray.ry.d - wo; float dDNdx = Dot(dwodx, n) + Dot(wo, dndx); float dDNdy = Dot(dwody, n) + Dot(wo, dndy); float mu = eta * Dot(w, n) - Dot(wi, n); float dmudx = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdx; float dmudy = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdy; rd.rx.d = wi + eta * dwodx - Vector(mu * dndx + dmudx * n); rd.ry.d = wi + eta * dwody - Vector(mu * dndy + dmudy * n); L += scene->Li(rd, sample) * f * AbsDot(wi, n); } } --specularDepth; } else { // Handle ray with no intersection if (alpha) *alpha = 0.; for (u_int i = 0; i < scene->lights.size(); ++i) L += scene->lights[i]->Le(ray); if (alpha && !L.Black()) *alpha = 1.; return L; } return L; }