Created
August 12, 2021 21:26
-
-
Save psema4/bee2614208944f08f5c4640ff582c611 to your computer and use it in GitHub Desktop.
An implementation of the Squirrel3 Noise-based RNG
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
// Based on the GDC 2017 talk "Math for Game Programmers: Noise-Based RNG" | |
// https://www.youtube.com/watch?v=LWFzPP8ZbdU&ab_channel=GDC | |
const BIT_NOISE1 = 0xB5297A4D | |
const BIT_NOISE2 = 0x68E31DA4 | |
const BIT_NOISE3 = 0x1B56C4E9 | |
const PRIME1 = 198491317 | |
const PRIME2 = 6542989 | |
class Squirrel3 { | |
constructor() { | |
} | |
// get1d(), get2d() and get3d() each return an integer | |
get1d(x=0, seed=0) { | |
let mangled = x | |
mangled *= BIT_NOISE1 | |
mangled += seed | |
mangled ^= (mangled >> 8) | |
mangled += BIT_NOISE2 | |
mangled ^= (mangled << 8) | |
mangled *= BIT_NOISE3 | |
mangled ^= (mangled >> 8) | |
return mangled | |
} | |
get2d(x=0, y=0, seed=0) { | |
return this.get1d(x + (PRIME1 * y), seed) | |
} | |
get3d(x=0, y=0, z=0, seed=0) { | |
return this.get1d(x + (PRIME1 * y) + (PRIME2 * z), seed) | |
} | |
// get1df(), get2df() and get3df() each return a float between 0 and 1 | |
// (assumes we're working with int32's) | |
get1df(x=0, seed=0) { | |
return this.get1d(x, seed) / 0xFFFFFFFF | |
} | |
get2df(x=0, y=0, seed=0) { | |
return this.get2d(x, y, seed) / 0xFFFFFFFF | |
} | |
get3df(x=0, y=0, z=0, seed=0) { | |
return this.get3d(x, y, z, seed) / 0xFFFFFFFF | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This needs to account for the fact that Javascript treats all bitwise arguments as signed, not unsigned as the original C does. As a result, the range of the returned numbers is cut in half to 0 - 0xFFFF. To account for this, you need to use either use the unsigned version of shift (>>>) or convert back to unsigned after each operation (the easiest way to do so being >>> 0). There may be other issues, but this was good enough of a fix for my purposes: