Last active
January 2, 2024 09:52
-
-
Save avrahamy/bed45af9d09046a02fa8ce9b3b5b4099 to your computer and use it in GitHub Desktop.
Logarithmic Binning shader code to be used in a Custom Function Node in Shader Graph (in Unity). LogBinNoise_float uses Logarithmic Binning to calculate the weights of gradient noise functions with different scales. Implemented according to the description in this GDC talk by Sean Feeley on his work on God of War: https://www.youtube.com/watch?v…
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
// Taken from GradientNoiseNode.cs from the Shader Graph package. | |
float2 GradientNoise_Dir_float(float2 p) { | |
// Permutation and hashing used in webgl-nosie goo.gl/pX7HtC | |
p = p % 289; | |
// need full precision, otherwise half overflows when p > 1 | |
float x = float(34 * p.x + 1) * p.x % 289 + p.y; | |
x = (34 * x + 1) * x % 289; | |
x = frac(x / 41) * 2 - 1; | |
return normalize(float2(x - floor(x + 0.5), abs(x) - 0.5)); | |
} | |
// Taken from GradientNoiseNode.cs from the Shader Graph package. | |
float GradientNoise_float(float2 UV, float Scale) { | |
float2 p = UV * Scale; | |
float2 ip = floor(p); | |
float2 fp = frac(p); | |
float d00 = dot(GradientNoise_Dir_float(ip), fp); | |
float d01 = dot(GradientNoise_Dir_float(ip + float2(0, 1)), fp - float2(0, 1)); | |
float d10 = dot(GradientNoise_Dir_float(ip + float2(1, 0)), fp - float2(1, 0)); | |
float d11 = dot(GradientNoise_Dir_float(ip + float2(1, 1)), fp - float2(1, 1)); | |
fp = fp * fp * fp * (fp * (fp * 6 - 15) + 10); | |
return lerp(lerp(d00, d01, fp.y), lerp(d10, d11, fp.y), fp.x) + 0.5; | |
} | |
void LogBinNoise_float(float2 uv, float scale, out float res) { | |
const float scaleIndex = log2(max(0.001, scale)); | |
const int index = floor(scaleIndex); | |
float firstScale = pow(2, index - 1); | |
res = GradientNoise_float(uv, firstScale) * (1 - scaleIndex + index) | |
+ GradientNoise_float(uv, firstScale * 2) * (2 - scaleIndex + index) | |
+ GradientNoise_float(uv, firstScale * 4) * (1 + scaleIndex - index) | |
+ GradientNoise_float(uv, firstScale * 8) * (scaleIndex - index); | |
res *= 0.25; | |
} | |
// This can be used to get the weights for a custom noise function. | |
// The out variables match the octaves of the noise scales: | |
// 1/16, 1/8, 1/4, 1/2, 1, 2, 4, 8, 16 | |
// val should be between 1/8 and 4 | |
void LogBin_float( | |
float scale, | |
out float _1_16, | |
out float _1_8, | |
out float _1_4, | |
out float _1_2, | |
out float _1, | |
out float _2, | |
out float _4, | |
out float _8, | |
out float _16) { | |
const float scaleIndex = clamp(log2(scale), -3, 2); | |
const int index = floor(scaleIndex); | |
float res[9] = {0,0,0,0,0,0,0,0,0}; | |
res[index + 3] = 1 - scaleIndex + index; | |
res[index + 4] = 2 - scaleIndex + index; | |
res[index + 5] = 1 + scaleIndex - index; | |
res[index + 6] = scaleIndex - index; | |
_1_16 = res[0]; | |
_1_8 = res[1]; | |
_1_4 = res[2]; | |
_1_2 = res[3]; | |
_1 = res[4]; | |
_2 = res[5]; | |
_4 = res[6]; | |
_8 = res[7]; | |
_16 = res[8]; | |
} |
YOU'RE BREATHTAKING!
If the weights are based on triangle area, shouldn't the weight formulas all be parabolas?
Oh I realize now you calculate the height of the triangle at 4 spots, not the sub-areas.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Instructions on how to use it can be found here: https://twitter.com/oravrahamy/status/1494052608822108167
More details on how it works here: https://www.reddit.com/r/proceduralgeneration/comments/sul19s/stable_scalable_noise/