Created
November 4, 2021 21:52
-
-
Save stormrook/7ed1019332718879bec2722bf970405a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define USE_MULTIPOINT | |
| using System; | |
| using System.Collections; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using Unity.Mathematics; | |
| using UnityEngine; | |
| public static class UberNoise2DSampler | |
| { | |
| public static float3 Sample(float2 pos, | |
| int octaves, | |
| float persistence, | |
| float lacunarity, | |
| float perturbFeatures, | |
| float sharpness, | |
| float sharpnessEnhance, | |
| float amplification, | |
| float altitudeErosion, | |
| float ridgeErosion, | |
| float slopeErosion) | |
| { | |
| float amplitude = 1.0f; | |
| float frequency = 1.0f; | |
| float3 accumulator = new float3(0.0f); | |
| float max = 0; | |
| float3 fistOctave = new float3(0.0f); | |
| float3 lastOctave = new float3(0.0f); | |
| float3 previousOctave = new float3(0.0f); | |
| float3 previousAccumulator = new float3(0.0f); | |
| for (int o = 0; o < octaves; o++) | |
| { | |
| max += amplitude; | |
| float2 oPos = (pos * frequency) + (perturbFeatures * accumulator.yz); | |
| #if USE_MULTIPOINT | |
| // Expand the noise out to the central point and 4 surrounding points | |
| // 2 on either side on the x any y (noise) axis | |
| float[] expandedNoiseData = new float[5]; | |
| expandedNoiseData[0] = noise.srnoise(oPos + new float2(0.0f, 0.0f)); | |
| expandedNoiseData[1] = noise.srnoise(oPos + new float2(0.1f * frequency, 0.0f)); | |
| expandedNoiseData[2] = noise.srnoise(oPos + new float2(-0.1f * frequency, 0.0f)); | |
| expandedNoiseData[3] = noise.srnoise(oPos + new float2(0.0f, 0.1f * frequency)); | |
| expandedNoiseData[4] = noise.srnoise(oPos + new float2(0.0f, -0.1f * frequency)); | |
| // Generate billow (abs(x)) and ridge (1-abs(x)) noise for each point | |
| float[] expandedBillow = Array.ConvertAll(expandedNoiseData, s => math.abs(s)); | |
| float[] expandedRidge = Array.ConvertAll(expandedBillow, s => 1.0f - s); | |
| // Blend between billow and ridge as required for all points | |
| expandedNoiseData = expandedNoiseData.Zip(expandedRidge, (n, r) => math.lerp(n, r, math.max(0.0f, sharpness))).ToArray(); | |
| expandedNoiseData = expandedNoiseData.Zip(expandedBillow, (n, b) => math.lerp(n, b, -math.min(0.0f, sharpness))).ToArray(); | |
| // Enhance Sharpness for all points | |
| // | |
| // Strength is basically just X to a power, but we don't want strange things when | |
| // strength is negative so we multiply x by abs(x) to a power which means the sign is | |
| // stable | |
| expandedNoiseData = Array.ConvertAll(expandedNoiseData, n => n * math.pow(math.abs(n), sharpnessEnhance)); | |
| // Slope erosion | |
| // | |
| // Basically additional octaves count less the steaper the previous layers are | |
| // | |
| // We're using the accumulated derivative here which is technically only correct | |
| // for the central point, but things are close enough together for this to work | |
| // reasonably well. | |
| float slopeErosionStrength = 1.0f / (1.0f + math.dot(accumulator.yz * slopeErosion, accumulator.yz * slopeErosion)); | |
| float dampedAltitude = amplitude * (1.0f - (ridgeErosion / (1.0f + math.dot(accumulator.yz, accumulator.yz)))); | |
| expandedNoiseData = Array.ConvertAll(expandedNoiseData, n => n * dampedAltitude * slopeErosionStrength); | |
| // Build noiseData (noise at central point with reconstructed partial derivatives) | |
| float3 noiseData = RecalculateDerivatives(expandedNoiseData); | |
| // Add to our accumulators | |
| accumulator.x += noiseData.x; | |
| accumulator.yz += noiseData.yz; | |
| // Altitude erosion | |
| // | |
| // Basically our amplitude falls off faster the lower the current accumulator value | |
| // with the strength controlled by altitudeErosion | |
| amplitude = amplitude | |
| * math.lerp(persistence, persistence * math.smoothstep(0.0f, 1.0f, accumulator.x), altitudeErosion); | |
| #else | |
| // We're using the unity mathematics package noise functions | |
| // as we can get back an analytical derivative (noise slope) from it | |
| float3 noiseData = noise.srdnoise(oPos); | |
| // Generate billow noise | |
| // | |
| // strength is just the abs value, the derivative is similar but | |
| // if the noise strength is 0 we also want the slope to be 0 | |
| float3 billowNoise = new float3(math.abs(noiseData.x), | |
| math.sign(noiseData.x) * noiseData.y, | |
| math.sign(noiseData.x) * noiseData.z); | |
| // Generate ridge noise | |
| // | |
| // strength is 1-x, but derivatives are just flipped | |
| float3 ridgeNoise = new float3(1.0f - billowNoise.x, | |
| -billowNoise.y, | |
| -billowNoise.z); | |
| // Switch between billow (rolling hills) and ridge (high sharp peaks) | |
| // based on sharpness | |
| // | |
| // Q: Can we lerp the derivatives like this? | |
| noiseData = math.lerp(noiseData, ridgeNoise, math.max(0.0f, sharpness)); | |
| noiseData = math.lerp(noiseData, billowNoise, -math.min(0.0f, sharpness)); | |
| // Enhance sharpness | |
| // | |
| // Strength is basically just X to a power, but we don't want strange things when | |
| // strength is negative so we multiply x by abs(x) to a power which means the sign is | |
| // stable | |
| // | |
| // Derivatives: Q: I've no idea if this is correct, but I'm assuming that as the | |
| // derivative of X^2 is 2X I can just multiply by the sharpnessEnhance | |
| noiseData.x = noiseData.x * math.pow(math.abs(noiseData.x), sharpnessEnhance); | |
| noiseData.yz *= 1.0f + sharpnessEnhance; | |
| // Slope erosion - Basically additional octaves count less the steaper the previous layers are | |
| float slopeErosionStrength = 1.0f / (1.0f + math.dot(accumulator.yz * slopeErosion, accumulator.yz * slopeErosion)); | |
| float dampedAltitude = amplitude * (1.0f - (ridgeErosion / (1.0f + math.dot(accumulator.yz, accumulator.yz)))); | |
| noiseData.x *= slopeErosionStrength * dampedAltitude; | |
| noiseData.yz *= slopeErosionStrength * dampedAltitude; // Q: What to do with derivatives this doesn't seem right | |
| // Add to our accumulators | |
| // | |
| // Scale the derivatives by frequency as we're squishing the noise so the slope is steaper | |
| accumulator.x += noiseData.x; | |
| accumulator.yz += noiseData.yz; | |
| // Altitude erosion | |
| // | |
| // Basically our amplitude falls off faster the lower the current accumulator value | |
| // with the strength controlled by altitudeErosion | |
| amplitude = amplitude | |
| * math.lerp(persistence, persistence * math.smoothstep(0.0f, 1.0f, accumulator.x), altitudeErosion); | |
| #endif | |
| persistence += amplification; | |
| frequency *= lacunarity; | |
| } | |
| // We also scale the derivatives here. We're squashing the | |
| // world so the slopes get squashed too | |
| //return lastOctave / max; | |
| //return new float3(lastOctave.x, previousAccumulator.y, previousAccumulator.z) / max; | |
| return accumulator / max; | |
| } | |
| #if USE_MULTIPOINT | |
| private static float3 RecalculateDerivatives(float[] expanded) | |
| { | |
| float3 retVal = new float3(); | |
| retVal.x = expanded[0]; // Noise Value | |
| if (math.sign(expanded[1]) != math.sign(expanded[2])) | |
| { | |
| // We've crossed a peak, can't risk a single pixel zero partial derivative | |
| retVal.y = math.max(expanded[1], expanded[2]); | |
| } | |
| else | |
| { | |
| retVal.y = (expanded[1] - expanded[2]) / 0.2f; // X partial derivative | |
| } | |
| if (math.sign(expanded[3]) != math.sign(expanded[4])) | |
| { | |
| // We've crossed a peak, can't risk a single pixel zero partial derivative | |
| retVal.y = math.max(expanded[3], expanded[4]); | |
| } | |
| else | |
| { | |
| retVal.z = (expanded[3] - expanded[4]) / 0.2f; // Y partial derivative | |
| } | |
| return retVal; | |
| } | |
| #endif | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment