@react-three/drei 9.48.6 → 9.50.0

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.
@@ -1,10 +1,14 @@
1
+ import * as React from 'react';
1
2
  import * as THREE from 'three';
3
+ import { useThree } from '@react-three/fiber';
4
+
5
+ // From: https://github.com/mrdoob/three.js/blob/dev/examples/webgl_shadowmap_pcss.html
2
6
 
3
7
  const pcss = ({
4
8
  frustum = 3.75,
5
9
  size = 0.005,
6
10
  near = 9.5,
7
- samples = 17,
11
+ samples = 10,
8
12
  rings = 11
9
13
  } = {}) => `#define LIGHT_WORLD_SIZE ${size}
10
14
  #define LIGHT_FRUSTUM_WIDTH ${frustum}
@@ -14,70 +18,95 @@ const pcss = ({
14
18
  #define NUM_SAMPLES ${samples}
15
19
  #define NUM_RINGS ${rings}
16
20
  #define BLOCKER_SEARCH_NUM_SAMPLES NUM_SAMPLES
17
- #define PCF_NUM_SAMPLES NUM_SAMPLES
18
21
 
19
22
  vec2 poissonDisk[NUM_SAMPLES];
20
23
 
21
- void initPoissonSamples(const in vec2 randomSeed) {
22
- float ANGLE_STEP = PI2 * float(NUM_RINGS) / float(NUM_SAMPLES);
23
- float INV_NUM_SAMPLES = 1.0 / float(NUM_SAMPLES);
24
- float angle = rand(randomSeed) * PI2;
24
+ void initPoissonSamples( const in vec2 randomSeed ) {
25
+ float ANGLE_STEP = PI2 * float( NUM_RINGS ) / float( NUM_SAMPLES );
26
+ float INV_NUM_SAMPLES = 1.0 / float( NUM_SAMPLES );
27
+
28
+ // jsfiddle that shows sample pattern: https://jsfiddle.net/a16ff1p7/
29
+ float angle = rand( randomSeed ) * PI2;
25
30
  float radius = INV_NUM_SAMPLES;
26
31
  float radiusStep = radius;
27
- for (int i = 0; i < NUM_SAMPLES; i++) {
28
- poissonDisk[i] = vec2(cos(angle), sin(angle)) * pow(radius, 0.75);
32
+
33
+ #pragma unroll_loop_start
34
+ for( int i = 0; i < ${samples}; i ++ ) {
35
+ poissonDisk[i] = vec2( cos( angle ), sin( angle ) ) * pow( radius, 0.75 );
29
36
  radius += radiusStep;
30
37
  angle += ANGLE_STEP;
31
38
  }
39
+ #pragma unroll_loop_end
32
40
  }
33
41
 
34
- float penumbraSize(const in float zReceiver, const in float zBlocker) { // Parallel plane estimation
42
+ float penumbraSize( const in float zReceiver, const in float zBlocker ) { // Parallel plane estimation
35
43
  return (zReceiver - zBlocker) / zBlocker;
36
44
  }
37
45
 
38
- float findBlocker(sampler2D shadowMap, const in vec2 uv, const in float zReceiver) {
39
- float searchRadius = LIGHT_SIZE_UV * (zReceiver - NEAR_PLANE) / zReceiver;
46
+ float findBlocker( sampler2D shadowMap, const in vec2 uv, const in float zReceiver ) {
47
+ // This uses similar triangles to compute what
48
+ // area of the shadow map we should search
49
+ float searchRadius = LIGHT_SIZE_UV * ( zReceiver - NEAR_PLANE ) / zReceiver;
40
50
  float blockerDepthSum = 0.0;
41
- int numBlockers = 0;
42
- for (int i = 0; i < BLOCKER_SEARCH_NUM_SAMPLES; i++) {
43
- float shadowMapDepth = unpackRGBAToDepth(texture2D(shadowMap, uv + poissonDisk[i] * searchRadius));
44
- if (shadowMapDepth < zReceiver) {
51
+ float shadowMapDepth = 0.0;
52
+ int numBlockers = 0;
53
+ #pragma unroll_loop_start
54
+ for( int i = 0; i < ${samples}; i++ ) {
55
+ shadowMapDepth = unpackRGBAToDepth(texture2D(shadowMap, uv + poissonDisk[i] * searchRadius));
56
+ if ( shadowMapDepth < zReceiver ) {
45
57
  blockerDepthSum += shadowMapDepth;
46
- numBlockers++;
58
+ numBlockers ++;
47
59
  }
48
60
  }
49
- if (numBlockers == 0) return -1.0;
50
- return blockerDepthSum / float(numBlockers);
61
+ #pragma unroll_loop_end
62
+
63
+ if( numBlockers == 0 ) return -1.0;
64
+ return blockerDepthSum / float( numBlockers );
51
65
  }
52
66
 
53
- float PCF_Filter(sampler2D shadowMap, vec2 uv, float zReceiver, float filterRadius) {
67
+ float PCF_Filter(sampler2D shadowMap, vec2 uv, float zReceiver, float filterRadius ) {
54
68
  float sum = 0.0;
55
- for (int i = 0; i < PCF_NUM_SAMPLES; i++) {
56
- float depth = unpackRGBAToDepth(texture2D(shadowMap, uv + poissonDisk[ i ] * filterRadius));
57
- if (zReceiver <= depth) sum += 1.0;
69
+ float depth;
70
+ #pragma unroll_loop_start
71
+ for( int i = 0; i < ${samples}; i ++ ) {
72
+ depth = unpackRGBAToDepth( texture2D( shadowMap, uv + poissonDisk[ i ] * filterRadius ) );
73
+ if( zReceiver <= depth ) sum += 1.0;
58
74
  }
59
- for (int i = 0; i < PCF_NUM_SAMPLES; i++) {
60
- float depth = unpackRGBAToDepth(texture2D(shadowMap, uv + -poissonDisk[ i ].yx * filterRadius));
61
- if (zReceiver <= depth) sum += 1.0;
75
+ #pragma unroll_loop_end
76
+ #pragma unroll_loop_start
77
+ for( int i = 0; i < ${samples}; i ++ ) {
78
+ depth = unpackRGBAToDepth( texture2D( shadowMap, uv + -poissonDisk[ i ].yx * filterRadius ) );
79
+ if( zReceiver <= depth ) sum += 1.0;
62
80
  }
63
- return sum / (2.0 * float(PCF_NUM_SAMPLES));
81
+ #pragma unroll_loop_end
82
+ return sum / ( 2.0 * float( ${samples} ) );
64
83
  }
65
84
 
66
- float PCSS(sampler2D shadowMap, vec4 coords) {
85
+ float PCSS ( sampler2D shadowMap, vec4 coords ) {
67
86
  vec2 uv = coords.xy;
68
87
  float zReceiver = coords.z; // Assumed to be eye-space z in this code
69
- initPoissonSamples(uv);
70
- float avgBlockerDepth = findBlocker(shadowMap, uv, zReceiver);
71
- if (avgBlockerDepth == -1.0) return 1.0;
72
- float penumbraRatio = penumbraSize(zReceiver, avgBlockerDepth);
88
+
89
+ initPoissonSamples( uv );
90
+ // STEP 1: blocker search
91
+ float avgBlockerDepth = findBlocker( shadowMap, uv, zReceiver );
92
+
93
+ //There are no occluders so early out (this saves filtering)
94
+ if( avgBlockerDepth == -1.0 ) return 1.0;
95
+
96
+ // STEP 2: penumbra size
97
+ float penumbraRatio = penumbraSize( zReceiver, avgBlockerDepth );
73
98
  float filterRadius = penumbraRatio * LIGHT_SIZE_UV * NEAR_PLANE / zReceiver;
74
- return PCF_Filter(shadowMap, uv, zReceiver, filterRadius);
99
+
100
+ // STEP 3: filtering
101
+ //return avgBlockerDepth;
102
+ return PCF_Filter( shadowMap, uv, zReceiver, filterRadius );
75
103
  }`;
76
104
 
77
105
  let deployed = false;
78
106
  const softShadows = props => {
79
107
  // Avoid adding the effect twice, which may happen in HMR scenarios
80
108
  if (!deployed) {
109
+ console.warn('drei/softShadows() is deprecated, use <SoftShadows> instead');
81
110
  deployed = true;
82
111
  let shader = THREE.ShaderChunk.shadowmap_pars_fragment;
83
112
  shader = shader.replace('#ifdef USE_SHADOWMAP', '#ifdef USE_SHADOWMAP\n' + pcss({ ...props
@@ -87,4 +116,42 @@ const softShadows = props => {
87
116
  }
88
117
  };
89
118
 
90
- export { softShadows };
119
+ function reset(gl, scene, camera) {
120
+ scene.traverse(object => {
121
+ if (object.material) gl.properties.remove(object.material);
122
+ });
123
+ gl.info.programs.length = 0;
124
+ gl.compile(scene, camera);
125
+ }
126
+
127
+ function SoftShadows({
128
+ frustum = 3.75,
129
+ size = 0.005,
130
+ near = 9.5,
131
+ samples = 10,
132
+ rings = 11
133
+ }) {
134
+ const gl = useThree(state => state.gl);
135
+ const scene = useThree(state => state.scene);
136
+ const camera = useThree(state => state.camera);
137
+ React.useEffect(() => {
138
+ const original = THREE.ShaderChunk.shadowmap_pars_fragment;
139
+ let shader = THREE.ShaderChunk.shadowmap_pars_fragment;
140
+ shader = shader.replace('#ifdef USE_SHADOWMAP', '#ifdef USE_SHADOWMAP\n' + pcss({
141
+ frustum,
142
+ size,
143
+ near,
144
+ samples,
145
+ rings
146
+ }));
147
+ shader = shader.replace('#if defined( SHADOWMAP_TYPE_PCF )', '\nreturn PCSS(shadowMap, shadowCoord);\n#if defined( SHADOWMAP_TYPE_PCF )');
148
+ THREE.ShaderChunk.shadowmap_pars_fragment = shader;
149
+ reset(gl, scene, camera);
150
+ return () => {
151
+ THREE.ShaderChunk.shadowmap_pars_fragment = original;
152
+ reset(gl, scene, camera);
153
+ };
154
+ }, [frustum, size, near, samples, rings]);
155
+ }
156
+
157
+ export { SoftShadows, softShadows };