generator-shader.glsl 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. uniform float zLevel;
  2. uniform float numCells;
  3. vec3 hash3_New(vec3 p, float tileLength) {
  4. p = mod(p, vec3(tileLength));
  5. p = vec3(
  6. dot(p,vec3(127.1,311.7, 74.7)),
  7. dot(p,vec3(269.5,183.3,246.1)),
  8. dot(p,vec3(113.5,271.9,124.6)));
  9. return -1.0 + 2.0*fract(sin(p)*43758.5453123);
  10. }
  11. float voronoiSlow(float maxOffset, float cellsMult, float seed) {
  12. vec3 coords = vec3(vUvs * cellsMult, zLevel);
  13. vec3 seedHash = hash3(vec3(seed, seed * seed * 3.14159, seed * 1.17421));
  14. vec3 gridBasePosition = floor(coords);
  15. vec3 gridCoordOffset = fract(coords);
  16. float maxCellSearch = ceil(maxOffset) + 1.0;
  17. float closest = 1.0;
  18. for (float y = -maxCellSearch; y <= maxCellSearch; y += 1.0) {
  19. for (float x = -maxCellSearch; x <= maxCellSearch; x += 1.0) {
  20. for (float z = -maxCellSearch; z <= maxCellSearch; z += 1.0) {
  21. vec3 neighbourCellPosition = vec3(x, y, z);
  22. vec3 cellWorldPosition = gridBasePosition + neighbourCellPosition;
  23. cellWorldPosition.xy = mod(cellWorldPosition.xy, vec2(cellsMult));
  24. vec3 cellOffset = hash3(cellWorldPosition + seedHash);
  25. cellOffset *= maxOffset;
  26. float distToNeighbour = length(
  27. neighbourCellPosition + cellOffset - gridCoordOffset);
  28. closest = min(closest, distToNeighbour);
  29. }
  30. }
  31. }
  32. return saturate(closest);
  33. }
  34. float gradientNoise(vec3 p, float tileLength) {
  35. vec3 i = floor(p);
  36. vec3 f = fract(p);
  37. vec3 u = smootherstep3(vec3(0.0), vec3(1.0), f);
  38. /*
  39. * For 1D, the gradient of slope g at vertex u has the form h(x) = g * (x - u), where u
  40. * is an integer and g is in [-1, 1]. This is the equation for a line with slope g which
  41. * intersects the x-axis at u.
  42. * For N dimensional noise, use dot product instead of multiplication, and do
  43. * component-wise interpolation (for 3D, trilinear)
  44. */
  45. return mix( mix( mix( dot( hash3_New(i + vec3(0.0,0.0,0.0), tileLength), f - vec3(0.0,0.0,0.0)),
  46. dot( hash3_New(i + vec3(1.0,0.0,0.0), tileLength), f - vec3(1.0,0.0,0.0)), u.x),
  47. mix( dot( hash3_New(i + vec3(0.0,1.0,0.0), tileLength), f - vec3(0.0,1.0,0.0)),
  48. dot( hash3_New(i + vec3(1.0,1.0,0.0), tileLength), f - vec3(1.0,1.0,0.0)), u.x), u.y),
  49. mix( mix( dot( hash3_New(i + vec3(0.0,0.0,1.0), tileLength), f - vec3(0.0,0.0,1.0)),
  50. dot( hash3_New(i + vec3(1.0,0.0,1.0), tileLength), f - vec3(1.0,0.0,1.0)), u.x),
  51. mix( dot( hash3_New(i + vec3(0.0,1.0,1.0), tileLength), f - vec3(0.0,1.0,1.0)),
  52. dot( hash3_New(i + vec3(1.0,1.0,1.0), tileLength), f - vec3(1.0,1.0,1.0)), u.x), u.y), u.z );
  53. }
  54. // https://github.com/sebh/TileableVolumeNoise/blob/master/TileableVolumeNoise.cpp
  55. float tileableFBM(vec3 p, float tileLength) {
  56. const float persistence = 0.5;
  57. const float lacunarity = 2.0;
  58. const int octaves = 8;
  59. float amplitude = 0.5;
  60. float total = 0.0;
  61. float normalization = 0.0;
  62. for (int i = 0; i < octaves; ++i) {
  63. float noiseValue = gradientNoise(p, tileLength * lacunarity * 0.5) * 0.5 + 0.5;
  64. total += noiseValue * amplitude;
  65. normalization += amplitude;
  66. amplitude *= persistence;
  67. p = p * lacunarity;
  68. }
  69. total /= normalization;
  70. total = smootherstep(0.0, 1.0, total);
  71. return total;
  72. }
  73. // https://github.com/sebh/TileableVolumeNoise/blob/master/main.cpp
  74. vec4 PerlinWorleyDetails(float CELL_RANGE, float numCells, float mult) {
  75. float perlinWorley = 0.0;
  76. {
  77. float worley0 = 1.0 - voronoiSlow(CELL_RANGE, numCells * 2.0 * mult, 1.0);
  78. float worley1 = 1.0 - voronoiSlow(CELL_RANGE, numCells * 8.0 * mult, 2.0);
  79. float worley2 = 1.0 - voronoiSlow(CELL_RANGE, numCells * 16.0 * mult, 3.0);
  80. float worleyFBM = worley0 * 0.625 + worley1 * 0.25 + worley2 * 0.125;
  81. float tileLength = 8.0;
  82. float fbm0 = tileableFBM(vec3(vUvs * tileLength, zLevel) * mult, tileLength);
  83. perlinWorley = remap(fbm0, 0.0, 1.0, worleyFBM, 1.0);
  84. }
  85. float worley0 = 1.0 - voronoiSlow(CELL_RANGE, numCells * 1.0 * mult, 4.0);
  86. float worley1 = 1.0 - voronoiSlow(CELL_RANGE, numCells * 2.0 * mult, 5.0);
  87. float worley2 = 1.0 - voronoiSlow(CELL_RANGE, numCells * 4.0 * mult, 6.0);
  88. float worley3 = 1.0 - voronoiSlow(CELL_RANGE, numCells * 8.0 * mult, 7.0);
  89. float worley4 = 1.0 - voronoiSlow(CELL_RANGE, numCells * 16.0 * mult, 8.0);
  90. float worley5 = 1.0 - voronoiSlow(CELL_RANGE, numCells * 32.0 * mult, 9.0);
  91. float worleyFBM0 = worley1 * 0.625 + worley2 * 0.25 + worley3 * 0.125;
  92. float worleyFBM1 = worley2 * 0.625 + worley3 * 0.25 + worley4 * 0.125;
  93. float worleyFBM2 = worley3 * 0.625 + worley4 * 0.25 + worley5 * 0.125;
  94. float lowFreqFBM = worleyFBM0 * 0.625 + worleyFBM1 * 0.25 + worleyFBM2 * 0.125;
  95. float tileLength = 8.0;
  96. float perlinWorleyDetail = remap(perlinWorley, lowFreqFBM, 1.0, 0.0, 1.0);
  97. return vec4(perlinWorley, perlinWorleyDetail, 0.0, 0.0);
  98. }
  99. void main() {
  100. const float CELL_RANGE = 1.0;
  101. vec4 perlinWorleyDetail1 = PerlinWorleyDetails(CELL_RANGE, numCells, 1.0);
  102. gl_FragColor = perlinWorleyDetail1;
  103. }