NoiseTextureAtlas.glsl.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /*
  2. All material copyright ESRI, All Rights Reserved, unless otherwise specified.
  3. See https://js.arcgis.com/4.25/esri/copyright.txt for details.
  4. */
  5. import{f as e}from"./vec2f64.js";import{NoiseTextureRenderMode as o}from"../views/3d/environment/NoiseTextureAtlasConfiguration.js";import{TILE_ROWS as t,WEATHER_TILE_SIZE as r,WEATHER_MAP_SIZE as a,TILE_SIZE as l,ATLAS_SIZE as i}from"../views/3d/environment/NoiseTextureAtlasDimensions.js";import{ScreenSpacePass as d}from"../views/3d/webgl-engine/core/shaderLibrary/ScreenSpacePass.js";import{Float2PassUniform as f}from"../views/3d/webgl-engine/core/shaderModules/Float2PassUniform.js";import{NoParameters as n,glsl as p}from"../views/3d/webgl-engine/core/shaderModules/interfaces.js";import{ShaderBuilder as c}from"../views/3d/webgl-engine/core/shaderModules/ShaderBuilder.js";class s extends n{constructor(){super(...arguments),this.weatherTile=e(0,0)}}function u(e){const n=new c;if(n.include(d,!1),n.fragment.code.add(p`float remap(float x, float low1, float high1, float low2, float high2) {
  6. return low2 + (x - low1) * (high2 - low2) / (high1 - low1);
  7. }`),e.mode===o.Full){const e=2,o=8;n.fragment.code.add(p`
  8. float saturate(float x) {
  9. return clamp(x, 0.0, 1.0);
  10. }
  11. // Safer modulo for positive and negative values
  12. vec3 modulo(vec3 m, float n){
  13. return mod(mod(m, n) + n, n);
  14. }
  15. vec3 hash(vec3 p3, float frequency){
  16. p3 = modulo(p3, frequency);
  17. p3 = fract(p3 * vec3(0.1031, 0.1030, 0.0973));
  18. p3 += dot(p3, p3.yxz + 33.33);
  19. return -1.0 + 2.0 * fract((p3.xxy + p3.yxx) * p3.zyx);
  20. }
  21. // 5th order polynomial interpolation
  22. vec3 fade(vec3 t){
  23. return (t * t * t) * (t * (t * 6.0 - 15.0) + 10.0);
  24. }
  25. float gradientNoise(vec3 p, float frequency){
  26. // Cell point is in
  27. vec3 i = floor(p);
  28. // Position in the cell in [0, 1]
  29. vec3 f = fract(p);
  30. // Interpolation value for gradient mixing
  31. vec3 u = fade(f);
  32. // Trilinear interpolation of gradients at cube vertices around point
  33. return mix( mix( mix( dot( hash( i + vec3(0.0,0.0,0.0), frequency), f - vec3(0.0,0.0,0.0) ),
  34. dot( hash( i + vec3(1.0,0.0,0.0), frequency), f - vec3(1.0,0.0,0.0) ), u.x),
  35. mix( dot( hash( i + vec3(0.0,1.0,0.0), frequency), f - vec3(0.0,1.0,0.0) ),
  36. dot( hash( i + vec3(1.0,1.0,0.0), frequency), f - vec3(1.0,1.0,0.0) ), u.x), u.y),
  37. mix( mix( dot( hash( i + vec3(0.0,0.0,1.0), frequency), f - vec3(0.0,0.0,1.0) ),
  38. dot( hash( i + vec3(1.0,0.0,1.0), frequency), f - vec3(1.0,0.0,1.0) ), u.x),
  39. mix( dot( hash( i + vec3(0.0,1.0,1.0), frequency), f - vec3(0.0,1.0,1.0) ),
  40. dot( hash( i + vec3(1.0,1.0,1.0), frequency), f - vec3(1.0,1.0,1.0) ), u.x), u.y), u.z );
  41. }
  42. float getPerlinNoise(vec3 pos, float frequency) {
  43. float octaveFrequencyFactor = 2.0;
  44. float sum = 0.0;
  45. float weightSum = 0.0;
  46. float weight = 1.0;
  47. for (int oct = 0; oct < 3; oct++) {
  48. vec3 p = pos * frequency;
  49. float val = 0.5 + 0.5 * gradientNoise(p, frequency);
  50. sum += val * weight;
  51. weightSum += weight;
  52. weight *= 0.5;
  53. frequency *= octaveFrequencyFactor;
  54. }
  55. float noise = (sum / weightSum);
  56. noise = saturate(noise);
  57. return noise;
  58. }
  59. float worley(vec3 pos, float numCells) {
  60. vec3 p = pos * numCells;
  61. float d = 1.0e10;
  62. for (int x = -1; x <= 1; x++) {
  63. for (int y = -1; y <= 1; y++) {
  64. for (int z = -1; z <= 1; z++) {
  65. vec3 tp = floor(p) + vec3(x, y, z);
  66. tp = p - tp - (hash(tp, numCells) * 0.5 + 0.5);
  67. d = min(d, dot(tp, tp));
  68. }
  69. }
  70. }
  71. return 1.0 - clamp(d, 0.0, 1.0);
  72. }
  73. vec3 get3Dfrom2D(vec2 uv) {
  74. vec2 tile = floor(uv);
  75. float z = floor(${p.float(t)} * tile.y + tile.x);
  76. return vec3(fract(uv), z);
  77. }
  78. float getTextureForPointPerlinWorley(vec3 p) {
  79. float perlinNoise = getPerlinNoise(p, ${p.float(o)});
  80. float worley0 = worley(p, ${p.float(e)} * 2.0);
  81. float worley1 = worley(p, ${p.float(e)} * 8.0);
  82. float worley2 = worley(p, ${p.float(e)} * 14.0);
  83. float worleyFBM = worley0 * 0.625 + worley1 * 0.25 + worley2 * 0.125;
  84. return remap(perlinNoise, 0.0, 1.0, worleyFBM, 1.0);
  85. }
  86. float getTextureForPointWorley(vec3 p) {
  87. float worley0 = worley(p, ${p.float(e)});
  88. float worley1 = worley(p, ${p.float(e)} * 2.0);
  89. float worley2 = worley(p, ${p.float(e)} * 4.0);
  90. float worley3 = worley(p, ${p.float(e)} * 8.0);
  91. float FBM0 = worley0 * 0.625 + worley1 * 0.25 + worley2 * 0.125;
  92. float FBM1 = worley1 * 0.625 + worley2 * 0.25 + worley3 * 0.125;
  93. float FBM2 = worley2 * 0.75 + worley3 * 0.25;
  94. return FBM0 * 0.625 + FBM1 * 0.25 + FBM2 * 0.125;
  95. }
  96. `)}return n.fragment.uniforms.add(new f("weatherTile",(e=>e.weatherTile))),n.fragment.code.add(p`
  97. vec2 modulo(vec2 m, float n){
  98. return mod(mod(m, n) + n, n);
  99. }
  100. vec2 hash(vec2 p){
  101. // Get position of p in weather tile
  102. p = modulo(p, ${p.float(r)});
  103. // Get global coordinates of p
  104. p += weatherTile * ${p.float(r)};
  105. // Limit position to avoid numerical instability
  106. p = modulo(p, ${p.float(a)});
  107. vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));
  108. p3 += dot(p3, p3.yzx + 33.33);
  109. return 2.0 * fract((p3.xx + p3.yz) * p3.zy) - 1.0;
  110. }
  111. vec2 fade(vec2 t){
  112. return (t * t * t) * (t * (t * 6.0 - 15.0) + 10.0);
  113. }
  114. float gradientNoise(vec2 p){
  115. vec2 i = floor( p );
  116. vec2 f = fract( p );
  117. vec2 u = fade(f);
  118. // Bilinear interpolation of gradients at cell vertices around point
  119. return mix(
  120. mix(dot( hash( i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ),
  121. dot( hash( i + vec2(1.0,0.0) ), f - vec2(1.0,0.0) ), u.x),
  122. mix(dot( hash( i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ),
  123. dot( hash( i + vec2(1.0,1.0) ), f - vec2(1.0,1.0) ), u.x),
  124. u.y);
  125. }
  126. float worley(vec2 p){
  127. float d = 1.0e10;
  128. for (int x = -1; x <= 1; x++){
  129. for (int y = -1; y <= 1; y++){
  130. vec2 tp = floor(p) + vec2(x, y);
  131. tp = p - tp - (0.5 + 0.5 * hash(tp));
  132. d = min(d, dot(tp, tp));
  133. }
  134. }
  135. return 1.0 - clamp(d, 0.0, 1.0);
  136. }
  137. `),n.fragment.code.add(p`void main() {`),e.mode===o.Full&&n.fragment.code.add(p`
  138. float padWidth = 1.0;
  139. float paddedSize = ${p.float(l)} + 2.0 * padWidth;
  140. float tileCount = ${p.float(t)} * ${p.float(t)};
  141. vec2 tile = floor((gl_FragCoord.xy - 0.5) / paddedSize);
  142. bool padCell = false;
  143. if (mod(gl_FragCoord.x, paddedSize) == 0.5 || mod(gl_FragCoord.x, paddedSize) == paddedSize - 0.5) {
  144. padCell = true;
  145. }
  146. if (mod(gl_FragCoord.y, paddedSize) == 0.5 || mod(gl_FragCoord.y, paddedSize) == paddedSize - 0.5) {
  147. padCell = true;
  148. }
  149. bool startPadX = false;
  150. bool startPadY = false;
  151. bool endPadX = false;
  152. bool endPadY = false;
  153. if (gl_FragCoord.x == tile.x * paddedSize + 0.5) {
  154. startPadX = true;
  155. }
  156. if (gl_FragCoord.y == tile.y * paddedSize + 0.5) {
  157. startPadY = true;
  158. }
  159. if (gl_FragCoord.x == (tile.x + 1.0) * paddedSize - 0.5) {
  160. endPadX = true;
  161. }
  162. if (gl_FragCoord.y == (tile.y + 1.0) * paddedSize - 0.5) {
  163. endPadY = true;
  164. }
  165. vec2 padding = vec2(2.0 * padWidth) * tile;
  166. vec2 uv;
  167. if (padCell) {
  168. vec2 pixel = gl_FragCoord.xy - padWidth - padding;
  169. if (startPadX) {
  170. pixel.x += ${p.float(l)};
  171. }
  172. if (startPadY) {
  173. pixel.y += ${p.float(l)};
  174. }
  175. if (endPadX) {
  176. pixel.x -= ${p.float(l)};
  177. }
  178. if (endPadY) {
  179. pixel.y -= ${p.float(l)};
  180. }
  181. uv = vec2(pixel.xy / ${p.float(l)});
  182. } else {
  183. vec2 pixel = gl_FragCoord.xy - padWidth - padding;
  184. uv = vec2(pixel.xy / ${p.float(l)});
  185. }
  186. vec3 p_ = get3Dfrom2D(uv);
  187. vec3 p = p_;
  188. p.z /= (${p.float(t)} * ${p.float(t)});
  189. float worleyPerlinNoise = getTextureForPointPerlinWorley(p);
  190. float worleyNoise = getTextureForPointWorley(p);
  191. gl_FragColor.r = saturate(remap(worleyPerlinNoise, worleyNoise, 1.0, 0.0, 1.0));
  192. p_ = mod(p_ + 1.0, ${p.float(t)} * ${p.float(t)});
  193. p = p_;
  194. p.z /= (${p.float(t)} * ${p.float(t)});
  195. worleyPerlinNoise = getTextureForPointPerlinWorley(p);
  196. worleyNoise = getTextureForPointWorley(p);
  197. gl_FragColor.g = saturate(remap(worleyPerlinNoise, worleyNoise, 1.0, 0.0, 1.0));
  198. `),n.fragment.code.add(p`
  199. vec2 mapUV = ${p.float(r)} * (gl_FragCoord.xy / ${p.float(i)});
  200. float map = abs(gradientNoise(mapUV));
  201. map = remap(map, 0.25 * (1.0 - worley(8.0 * mapUV)), 1.0, 0.0, 1.0);
  202. ${e.mode===o.Full?p`gl_FragColor.ba = vec2(0.0, map);`:p`gl_FragColor = vec4(map);`};
  203. }
  204. `),n}const v=Object.freeze(Object.defineProperty({__proto__:null,NoiseTextureAtlasPassParameters:s,build:u},Symbol.toStringTag,{value:"Module"}));export{s as N,v as a,u as b};