angular-three-soba 4.0.4 → 4.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1816,7 +1816,10 @@ const defaultOptions = {
1816
1816
  samples: 10,
1817
1817
  focus: 0,
1818
1818
  };
1819
- function pcss(options) {
1819
+ /**
1820
+ * Generates PCSS shader code for Three.js < r182 (uses RGBA-packed depth)
1821
+ */
1822
+ function pcssLegacy(options) {
1820
1823
  const { focus, size, samples } = options;
1821
1824
  return `
1822
1825
  #define PENUMBRA_FILTER_SIZE float(${size})
@@ -1830,8 +1833,6 @@ vec3 randRGB(vec2 uv) {
1830
1833
  }
1831
1834
 
1832
1835
  vec3 lowPassRandRGB(vec2 uv) {
1833
- // 3x3 convolution (average)
1834
- // can be implemented as separable with an extra buffer for a total of 6 samples instead of 9
1835
1836
  vec3 result = vec3(0);
1836
1837
  result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, -1.0));
1837
1838
  result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, 0.0));
@@ -1842,32 +1843,31 @@ vec3 lowPassRandRGB(vec2 uv) {
1842
1843
  result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, -1.0));
1843
1844
  result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, 0.0));
1844
1845
  result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, +1.0));
1845
- result *= 0.111111111; // 1.0 / 9.0
1846
+ result *= 0.111111111;
1846
1847
  return result;
1847
1848
  }
1849
+
1848
1850
  vec3 highPassRandRGB(vec2 uv) {
1849
- // by subtracting the low-pass signal from the original signal, we're being left with the high-pass signal
1850
- // hp(x) = x - lp(x)
1851
1851
  return RGB_NOISE_FUNCTION(uv) - lowPassRandRGB(uv) + 0.5;
1852
1852
  }
1853
1853
 
1854
-
1855
1854
  vec2 vogelDiskSample(int sampleIndex, int sampleCount, float angle) {
1856
- const float goldenAngle = 2.399963f; // radians
1855
+ const float goldenAngle = 2.399963f;
1857
1856
  float r = sqrt(float(sampleIndex) + 0.5f) / sqrt(float(sampleCount));
1858
1857
  float theta = float(sampleIndex) * goldenAngle + angle;
1859
1858
  float sine = sin(theta);
1860
1859
  float cosine = cos(theta);
1861
1860
  return vec2(cosine, sine) * r;
1862
1861
  }
1863
- float penumbraSize( const in float zReceiver, const in float zBlocker ) { // Parallel plane estimation
1862
+
1863
+ float penumbraSize( const in float zReceiver, const in float zBlocker ) {
1864
1864
  return (zReceiver - zBlocker) / zBlocker;
1865
1865
  }
1866
+
1866
1867
  float findBlocker(sampler2D shadowMap, vec2 uv, float compare, float angle) {
1867
1868
  float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);
1868
1869
  float blockerDepthSum = float(${focus});
1869
1870
  float blockers = 0.0;
1870
-
1871
1871
  int j = 0;
1872
1872
  vec2 offset = vec2(0.);
1873
1873
  float depth = 0.;
@@ -1875,7 +1875,7 @@ float findBlocker(sampler2D shadowMap, vec2 uv, float compare, float angle) {
1875
1875
  #pragma unroll_loop_start
1876
1876
  for(int i = 0; i < ${samples}; i ++) {
1877
1877
  offset = (vogelDiskSample(j, ${samples}, angle) * texelSize) * 2.0 * PENUMBRA_FILTER_SIZE;
1878
- depth = unpackRGBAToDepth( texture2D( shadowMap, uv + offset));
1878
+ depth = unpackRGBAToDepth( texture2D( shadowMap, uv + offset ) );
1879
1879
  if (depth < compare) {
1880
1880
  blockerDepthSum += depth;
1881
1881
  blockers++;
@@ -1890,13 +1890,13 @@ float findBlocker(sampler2D shadowMap, vec2 uv, float compare, float angle) {
1890
1890
  return -1.0;
1891
1891
  }
1892
1892
 
1893
-
1894
1893
  float vogelFilter(sampler2D shadowMap, vec2 uv, float zReceiver, float filterRadius, float angle) {
1895
1894
  float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);
1896
1895
  float shadow = 0.0f;
1897
1896
  int j = 0;
1898
1897
  vec2 vogelSample = vec2(0.0);
1899
1898
  vec2 offset = vec2(0.0);
1899
+
1900
1900
  #pragma unroll_loop_start
1901
1901
  for (int i = 0; i < ${samples}; i++) {
1902
1902
  vogelSample = vogelDiskSample(j, ${samples}, angle) * texelSize;
@@ -1905,12 +1905,13 @@ float vogelFilter(sampler2D shadowMap, vec2 uv, float zReceiver, float filterRad
1905
1905
  j++;
1906
1906
  }
1907
1907
  #pragma unroll_loop_end
1908
+
1908
1909
  return shadow * 1.0 / ${samples}.0;
1909
1910
  }
1910
1911
 
1911
1912
  float PCSS (sampler2D shadowMap, vec4 coords) {
1912
1913
  vec2 uv = coords.xy;
1913
- float zReceiver = coords.z; // Assumed to be eye-space z in this code
1914
+ float zReceiver = coords.z;
1914
1915
  float angle = highPassRandRGB(gl_FragCoord.xy).r * PI2;
1915
1916
  float avgBlockerDepth = findBlocker(shadowMap, uv, zReceiver, angle);
1916
1917
  if (avgBlockerDepth == -1.0) {
@@ -1920,6 +1921,127 @@ float PCSS (sampler2D shadowMap, vec4 coords) {
1920
1921
  return vogelFilter(shadowMap, uv, zReceiver, 1.25 * penumbraRatio, angle);
1921
1922
  }`;
1922
1923
  }
1924
+ /**
1925
+ * Generates PCSS shader code for Three.js >= r182 (uses native depth textures)
1926
+ */
1927
+ function pcssModern(options) {
1928
+ const { focus, size, samples } = options;
1929
+ return `
1930
+ #define PENUMBRA_FILTER_SIZE float(${size})
1931
+ #define RGB_NOISE_FUNCTION(uv) (randRGB(uv))
1932
+ vec3 randRGB(vec2 uv) {
1933
+ return vec3(
1934
+ fract(sin(dot(uv, vec2(12.75613, 38.12123))) * 13234.76575),
1935
+ fract(sin(dot(uv, vec2(19.45531, 58.46547))) * 43678.23431),
1936
+ fract(sin(dot(uv, vec2(23.67817, 78.23121))) * 93567.23423)
1937
+ );
1938
+ }
1939
+
1940
+ vec3 lowPassRandRGB(vec2 uv) {
1941
+ vec3 result = vec3(0);
1942
+ result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, -1.0));
1943
+ result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, 0.0));
1944
+ result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, +1.0));
1945
+ result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, -1.0));
1946
+ result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, 0.0));
1947
+ result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, +1.0));
1948
+ result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, -1.0));
1949
+ result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, 0.0));
1950
+ result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, +1.0));
1951
+ result *= 0.111111111;
1952
+ return result;
1953
+ }
1954
+
1955
+ vec3 highPassRandRGB(vec2 uv) {
1956
+ return RGB_NOISE_FUNCTION(uv) - lowPassRandRGB(uv) + 0.5;
1957
+ }
1958
+
1959
+ vec2 pcssVogelDiskSample(int sampleIndex, int sampleCount, float angle) {
1960
+ const float goldenAngle = 2.399963f;
1961
+ float r = sqrt(float(sampleIndex) + 0.5f) / sqrt(float(sampleCount));
1962
+ float theta = float(sampleIndex) * goldenAngle + angle;
1963
+ float sine = sin(theta);
1964
+ float cosine = cos(theta);
1965
+ return vec2(cosine, sine) * r;
1966
+ }
1967
+
1968
+ float penumbraSize( const in float zReceiver, const in float zBlocker ) {
1969
+ return (zReceiver - zBlocker) / zBlocker;
1970
+ }
1971
+
1972
+ float findBlocker(sampler2D shadowMap, vec2 uv, float compare, float angle) {
1973
+ float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);
1974
+ float blockerDepthSum = float(${focus});
1975
+ float blockers = 0.0;
1976
+ int j = 0;
1977
+ vec2 offset = vec2(0.);
1978
+ float depth = 0.;
1979
+
1980
+ #pragma unroll_loop_start
1981
+ for(int i = 0; i < ${samples}; i ++) {
1982
+ offset = (pcssVogelDiskSample(j, ${samples}, angle) * texelSize) * 2.0 * PENUMBRA_FILTER_SIZE;
1983
+ depth = texture2D( shadowMap, uv + offset ).r;
1984
+ if (depth < compare) {
1985
+ blockerDepthSum += depth;
1986
+ blockers++;
1987
+ }
1988
+ j++;
1989
+ }
1990
+ #pragma unroll_loop_end
1991
+
1992
+ if (blockers > 0.0) {
1993
+ return blockerDepthSum / blockers;
1994
+ }
1995
+ return -1.0;
1996
+ }
1997
+
1998
+ float pcssVogelFilter(sampler2D shadowMap, vec2 uv, float zReceiver, float filterRadius, float angle) {
1999
+ float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);
2000
+ float shadow = 0.0f;
2001
+ int j = 0;
2002
+ vec2 vogelSample = vec2(0.0);
2003
+ vec2 offset = vec2(0.0);
2004
+
2005
+ #pragma unroll_loop_start
2006
+ for (int i = 0; i < ${samples}; i++) {
2007
+ vogelSample = pcssVogelDiskSample(j, ${samples}, angle) * texelSize;
2008
+ offset = vogelSample * (1.0 + filterRadius * float(${size}));
2009
+ shadow += step( zReceiver, texture2D( shadowMap, uv + offset ).r );
2010
+ j++;
2011
+ }
2012
+ #pragma unroll_loop_end
2013
+
2014
+ return shadow * 1.0 / ${samples}.0;
2015
+ }
2016
+
2017
+ float PCSS (sampler2D shadowMap, vec4 coords, float shadowIntensity) {
2018
+ vec2 uv = coords.xy;
2019
+ float zReceiver = coords.z;
2020
+ float angle = highPassRandRGB(gl_FragCoord.xy).r * PI2;
2021
+ float avgBlockerDepth = findBlocker(shadowMap, uv, zReceiver, angle);
2022
+ if (avgBlockerDepth == -1.0) {
2023
+ return 1.0;
2024
+ }
2025
+ float penumbraRatio = penumbraSize(zReceiver, avgBlockerDepth);
2026
+ float shadow = pcssVogelFilter(shadowMap, uv, zReceiver, 1.25 * penumbraRatio, angle);
2027
+ return mix( 1.0, shadow, shadowIntensity );
2028
+ }`;
2029
+ }
2030
+ /**
2031
+ * Generates the replacement getShadow function for r182+
2032
+ */
2033
+ function getShadowReplacement() {
2034
+ return `float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord ) {
2035
+ shadowCoord.xyz /= shadowCoord.w;
2036
+ shadowCoord.z += shadowBias;
2037
+ bool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;
2038
+ bool frustumTest = inFrustum && shadowCoord.z <= 1.0;
2039
+ if ( frustumTest ) {
2040
+ return PCSS( shadowMap, shadowCoord, shadowIntensity );
2041
+ }
2042
+ return 1.0;
2043
+ }`;
2044
+ }
1923
2045
  function reset(gl, scene, camera) {
1924
2046
  scene.traverse((object) => {
1925
2047
  if (object.material) {
@@ -1948,10 +2070,24 @@ class NgtsSoftShadows {
1948
2070
  effect((onCleanup) => {
1949
2071
  const { gl, scene, camera } = store.snapshot;
1950
2072
  const options = this.options();
2073
+ const version = getVersion();
1951
2074
  const original = THREE.ShaderChunk.shadowmap_pars_fragment;
1952
- THREE.ShaderChunk.shadowmap_pars_fragment = THREE.ShaderChunk.shadowmap_pars_fragment
1953
- .replace('#ifdef USE_SHADOWMAP', '#ifdef USE_SHADOWMAP\n' + pcss(options))
1954
- .replace('#if defined( SHADOWMAP_TYPE_PCF )', '\nreturn PCSS(shadowMap, shadowCoord);\n#if defined( SHADOWMAP_TYPE_PCF )');
2075
+ if (version >= 182) {
2076
+ // Three.js r182+ uses native depth textures and has a different shader structure
2077
+ // We need to replace the getShadow function entirely
2078
+ const pcssCode = pcssModern(options);
2079
+ // Find and replace the PCF getShadow function
2080
+ const getShadowRegex = /(#if defined\( SHADOWMAP_TYPE_PCF \)\s+float getShadow\( sampler2DShadow shadowMap[^}]+\})/s;
2081
+ THREE.ShaderChunk.shadowmap_pars_fragment = THREE.ShaderChunk.shadowmap_pars_fragment
2082
+ .replace('#ifdef USE_SHADOWMAP', '#ifdef USE_SHADOWMAP\n' + pcssCode)
2083
+ .replace(getShadowRegex, `#if defined( SHADOWMAP_TYPE_PCF )\n\t\t${getShadowReplacement()}`);
2084
+ }
2085
+ else {
2086
+ // Three.js < r182 uses RGBA-packed depth
2087
+ THREE.ShaderChunk.shadowmap_pars_fragment = THREE.ShaderChunk.shadowmap_pars_fragment
2088
+ .replace('#ifdef USE_SHADOWMAP', '#ifdef USE_SHADOWMAP\n' + pcssLegacy(options))
2089
+ .replace('#if defined( SHADOWMAP_TYPE_PCF )', '\nreturn PCSS(shadowMap, shadowCoord);\n#if defined( SHADOWMAP_TYPE_PCF )');
2090
+ }
1955
2091
  reset(gl, scene, camera);
1956
2092
  onCleanup(() => {
1957
2093
  THREE.ShaderChunk.shadowmap_pars_fragment = original;