shader.frag.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. export default `
  7. precision highp float;
  8. precision highp int;
  9. precision highp sampler2D;
  10. uniform vec2 uQuadShift;
  11. uniform vec3 uDimensions;
  12. uniform vec3 uMin;
  13. uniform vec3 uDelta;
  14. uniform sampler2D tCenters;
  15. uniform sampler2D tInfo;
  16. uniform sampler2D tCoeff;
  17. uniform sampler2D tAlpha;
  18. uniform int uNCenters;
  19. uniform int uNCoeff;
  20. uniform int uNAlpha;
  21. uniform int uLittleEndian;
  22. float shiftRight (float v, float amt) {
  23. v = floor(v) + 0.5;
  24. return floor(v / exp2(amt));
  25. }
  26. float shiftLeft (float v, float amt) {
  27. return floor(v * exp2(amt) + 0.5);
  28. }
  29. float maskLast (float v, float bits) {
  30. return mod(v, shiftLeft(1.0, bits));
  31. }
  32. float extractBits (float num, float from, float to) {
  33. from = floor(from + 0.5); to = floor(to + 0.5);
  34. return maskLast(shiftRight(num, from), to - from);
  35. }
  36. // Adapted from https://github.com/equinor/glsl-float-to-rgba
  37. // MIT License, Copyright (c) 2020 Equinor
  38. vec4 floatToRgba(float texelFloat) {
  39. if (texelFloat == 0.0) return vec4(0, 0, 0, 0);
  40. float sign = texelFloat > 0.0 ? 0.0 : 1.0;
  41. texelFloat = abs(texelFloat);
  42. float exponent = floor(log2(texelFloat));
  43. float biased_exponent = exponent + 127.0;
  44. float fraction = ((texelFloat / exp2(exponent)) - 1.0) * 8388608.0;
  45. float t = biased_exponent / 2.0;
  46. float last_bit_of_biased_exponent = fract(t) * 2.0;
  47. float remaining_bits_of_biased_exponent = floor(t);
  48. float byte4 = extractBits(fraction, 0.0, 8.0) / 255.0;
  49. float byte3 = extractBits(fraction, 8.0, 16.0) / 255.0;
  50. float byte2 = (last_bit_of_biased_exponent * 128.0 + extractBits(fraction, 16.0, 23.0)) / 255.0;
  51. float byte1 = (sign * 128.0 + remaining_bits_of_biased_exponent) / 255.0;
  52. return (
  53. uLittleEndian > 0
  54. ? vec4(byte4, byte3, byte2, byte1)
  55. : vec4(byte1, byte2, byte3, byte4)
  56. );
  57. }
  58. float L1(vec3 p, float a0, float a1, float a2) {
  59. return a0 * p.z + a1 * p.x + a2 * p.y;
  60. }
  61. float L2(vec3 p, float a0, float a1, float a2, float a3, float a4) {
  62. float x = p.x, y = p.y, z = p.z;
  63. float xx = x * x, yy = y * y, zz = z * z;
  64. return (
  65. a0 * (-0.5 * xx - 0.5 * yy + zz) +
  66. a1 * (1.7320508075688772 * x * z) +
  67. a2 * (1.7320508075688772 * y * z) +
  68. a3 * (0.8660254037844386 * xx - 0.8660254037844386 * yy) +
  69. a4 * (1.7320508075688772 * x * y)
  70. );
  71. }
  72. float L3(vec3 p, float a0, float a1, float a2, float a3, float a4, float a5, float a6) {
  73. float x = p.x, y = p.y, z = p.z;
  74. float xx = x * x, yy = y * y, zz = z * z;
  75. float xxx = xx * x, yyy = yy * y, zzz = zz * z;
  76. return (
  77. a0 * (-1.5 * xx * z - 1.5 * yy * z + zzz) +
  78. a1 * (-0.6123724356957945 * xxx - 0.6123724356957945 * x * yy + 2.449489742783178 * x * zz) +
  79. a2 * (-0.6123724356957945 * xx * y - 0.6123724356957945 * yyy + 2.449489742783178 * y * zz) +
  80. a3 * (1.9364916731037085 * xx * z - 1.9364916731037085 * yy * z) +
  81. a4 * (3.872983346207417 * x * y * z) +
  82. a5 * (0.7905694150420949 * xxx - 2.3717082451262845 * x * yy) +
  83. a6 * (2.3717082451262845 * xx * y - 0.7905694150420949 * yyy)
  84. );
  85. }
  86. void main(void) {
  87. // TODO: use "integer division" to avoid rounding errors for non power of 2 dimensions
  88. vec3 idx = vec3(gl_FragCoord.x - 0.5, mod(gl_FragCoord.y - 0.5, uDimensions.z), floor((gl_FragCoord.y - 0.5) / uDimensions.y));
  89. float offset = idx.x + idx.y * uDimensions.x + idx.z * uDimensions.x * uDimensions.y;
  90. // TODO: is there render target ordering that does not require the remapping of the coords?
  91. float k = mod(offset, uDimensions.z), kk = floor(offset / uDimensions.z);
  92. float j = mod(kk, uDimensions.y);
  93. float i = floor(kk / uDimensions.y);
  94. vec3 xyz = uMin + uDelta * vec3(i, j, k);
  95. float fCenter = 1.0 / float(uNCenters - 1);
  96. float fCoeff = 1.0 / float(uNCoeff - 1);
  97. float fAlpha = 1.0 / float(uNAlpha - 1);
  98. float v = 0.0;
  99. for (int i = 0; i < uNCenters; i++) {
  100. vec2 cCoord = vec2(float(i) * fCenter, 0.5);
  101. vec4 center = texture2D(tCenters, cCoord);
  102. vec3 X = xyz - center.xyz;
  103. float R2 = dot(X, X);
  104. // center.w is squared cutoff radius
  105. if (R2 > center.w) {
  106. continue;
  107. }
  108. vec4 info = texture2D(tInfo, cCoord);
  109. int L = int(info.x);
  110. float alphaOffset = info.y;
  111. int coeffStart = int(info.z);
  112. int coeffEnd = int(info.w);
  113. float gauss = 0.0;
  114. for (int j = coeffStart; j < coeffEnd; j++) {
  115. vec2 c = texture2D(tCoeff, vec2(float(j) * fCoeff, 0.5)).xy;
  116. gauss += c.x * exp(-c.y * R2);
  117. }
  118. float spherical = 0.0;
  119. if (L == 0) {
  120. spherical = texture2D(tAlpha, vec2(alphaOffset * fAlpha, 0.5)).x;
  121. } else if (L == 1) {
  122. spherical = L1(
  123. X,
  124. texture2D(tAlpha, vec2(alphaOffset * fAlpha, 0.5)).x,
  125. texture2D(tAlpha, vec2((alphaOffset + 1.0) * fAlpha, 0.5)).x,
  126. texture2D(tAlpha, vec2((alphaOffset + 2.0) * fAlpha, 0.5)).x
  127. );
  128. } else if (L == 2) {
  129. spherical = L2(
  130. X,
  131. texture2D(tAlpha, vec2(alphaOffset * fAlpha, 0.5)).x,
  132. texture2D(tAlpha, vec2((alphaOffset + 1.0) * fAlpha, 0.5)).x,
  133. texture2D(tAlpha, vec2((alphaOffset + 2.0) * fAlpha, 0.5)).x,
  134. texture2D(tAlpha, vec2((alphaOffset + 3.0) * fAlpha, 0.5)).x,
  135. texture2D(tAlpha, vec2((alphaOffset + 4.0) * fAlpha, 0.5)).x
  136. );
  137. } else if (L == 3) {
  138. spherical = L3(
  139. X,
  140. texture2D(tAlpha, vec2(alphaOffset * fAlpha, 0.5)).x,
  141. texture2D(tAlpha, vec2((alphaOffset + 1.0) * fAlpha, 0.5)).x,
  142. texture2D(tAlpha, vec2((alphaOffset + 2.0) * fAlpha, 0.5)).x,
  143. texture2D(tAlpha, vec2((alphaOffset + 3.0) * fAlpha, 0.5)).x,
  144. texture2D(tAlpha, vec2((alphaOffset + 4.0) * fAlpha, 0.5)).x,
  145. texture2D(tAlpha, vec2((alphaOffset + 5.0) * fAlpha, 0.5)).x,
  146. texture2D(tAlpha, vec2((alphaOffset + 6.0) * fAlpha, 0.5)).x
  147. );
  148. }
  149. // TODO: do we need L > 3?
  150. v += gauss * spherical;
  151. }
  152. // TODO: render to single component float32 texture in WebGL2
  153. gl_FragColor = floatToRgba(v);
  154. }
  155. `;