Skip to content

Commit a827f0b

Browse files
mbredifMugen87mrdoob
authored andcommitted
SpotLightMap v3 (mrdoob#21944)
* SpotLightMap * Update webgl_lights_spotlight.html Simplify spot light example. * Update WebGLProgram.js * Update lights_fragment_begin.glsl.js * Update WebGLLights.js * Update SpotLight.html * Update SpotLight.html * Update SpotLight.js * Update shadowmap_vertex.glsl.js * Update SpotLight.js * Update lights_fragment_begin.glsl.js * Update SpotLight.html * Update SpotLight.html * Update shadowmap_vertex.glsl.js * Update shadowmap_vertex.glsl.js * Update WebGLLights.js * Update WebGLLights.js * Update shadowmap_vertex.glsl.js * Update WebGLLights.js Co-authored-by: Michael Herzog <michael.herzog@human-interactive.org> Co-authored-by: mrdoob <info@mrdoob.com>
1 parent 3062df2 commit a827f0b

15 files changed

+156
-37
lines changed

docs/api/en/lights/SpotLight.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ <h1>[name]</h1>
2020

2121
<h2>Code Example</h2>
2222
<code>
23-
// white spotlight shining from the side, casting a shadow
23+
// white spotlight shining from the side, modulated by a texture, casting a shadow
2424

2525
const spotLight = new THREE.SpotLight( 0xffffff );
2626
spotLight.position.set( 100, 1000, 100 );
27+
spotLight.map = new THREE.TextureLoader().load( url );
2728

2829
spotLight.castShadow = true;
2930

@@ -170,6 +171,13 @@ <h3>[property:Object3D target]</h3>
170171
The spotlight will now track the target object.
171172
</p>
172173

174+
<h3>[property:Texture map]</h3>
175+
<p>
176+
A [page:Texture] used to modulate the color of the light. The spot light color is mixed
177+
with the RGB value of this texture, with a ratio corresponding to its
178+
alpha value. The cookie-like masking effect is reproduced using pixel values (0, 0, 0, 1-cookie_value).
179+
*Warning*: [param:SpotLight map] is disabled if [param:SpotLight castShadow] is *false*.
180+
</p>
173181

174182
<h2>Methods</h2>
175183

docs/api/zh/lights/SpotLight.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ <h1>聚光灯([name])</h1>
1919

2020
<h2>代码示例</h2>
2121
<code>
22-
// white spotlight shining from the side, casting a shadow
22+
// white spotlight shining from the side, modulated by a texture, casting a shadow
2323

2424
const spotLight = new THREE.SpotLight( 0xffffff );
2525
spotLight.position.set( 100, 1000, 100 );
26+
spotLight.map = new THREE.TextureLoader().load( url );
2627

2728
spotLight.castShadow = true;
2829

@@ -144,6 +145,14 @@ <h3>[property:Object3D target]</h3>
144145
完成上述操作后,聚光灯现在就可以追踪到目标对像了。
145146
</p>
146147

148+
<h3>[property:Texture map]</h3>
149+
<p>
150+
A [page:Texture] used to modulate the color of the light. The spot light color is mixed
151+
with the RGB value of this texture, with a ratio corresponding to its
152+
alpha value. The cookie-like masking effect is reproduced using pixel values (0, 0, 0, 1-cookie_value).
153+
*Warning*: [param:SpotLight map] is disabled if [param:SpotLight castShadow] is *false*.
154+
</p>
155+
147156

148157
<h2>方法(Methods)</h2>
149158

examples/webgl_lights_spotlight.html

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636

3737
let spotLight, lightHelper, shadowCameraHelper;
3838

39+
let textureUrls, textures;
40+
3941
let gui;
4042

4143
function init() {
@@ -64,6 +66,18 @@
6466
const ambient = new THREE.AmbientLight( 0xffffff, 0.1 );
6567
scene.add( ambient );
6668

69+
const textureLoader = new THREE.TextureLoader();
70+
textureUrls = [ 'none', 'uv_grid_opengl.jpg', 'sprite2.png', 'colors.png' ];
71+
textures = { none: null }
72+
73+
for ( let i = 1; i < textureUrls.length; i ++ ) {
74+
75+
textures[ textureUrls[ i ] ] = textureLoader.load( 'textures/' + textureUrls[ i ] );
76+
textures[ textureUrls[ i ] ].minFilter = THREE.LinearFilter;
77+
textures[ textureUrls[ i ] ].magFilter = THREE.LinearFilter;
78+
79+
}
80+
6781
spotLight = new THREE.SpotLight( 0xffffff, 1 );
6882
spotLight.position.set( 15, 40, 35 );
6983
spotLight.angle = Math.PI / 4;
@@ -144,7 +158,8 @@
144158
angle: spotLight.angle,
145159
penumbra: spotLight.penumbra,
146160
decay: spotLight.decay,
147-
focus: spotLight.shadow.focus
161+
focus: spotLight.shadow.focus,
162+
map: 'none'
148163
};
149164

150165
gui.addColor( params, 'light color' ).onChange( function ( val ) {
@@ -197,6 +212,13 @@
197212

198213
} );
199214

215+
gui.add( params, 'map', textureUrls ).onChange( function ( val ) {
216+
217+
spotLight.map = textures[ val ];
218+
render();
219+
220+
} );
221+
200222
gui.open();
201223

202224
}

src/lights/SpotLight.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ class SpotLight extends Light {
2222
this.penumbra = penumbra;
2323
this.decay = decay; // for physically correct lights, should be 2.
2424

25+
this.map = null;
26+
2527
this.shadow = new SpotLightShadow();
2628

2729
}

src/renderers/WebGLRenderer.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1428,7 +1428,8 @@ function WebGLRenderer( parameters = {} ) {
14281428
uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
14291429
uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
14301430
uniforms.spotShadowMap.value = lights.state.spotShadowMap;
1431-
uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
1431+
uniforms.spotLightMatrix.value = lights.state.spotLightMatrix;
1432+
uniforms.spotLightMap.value = lights.state.spotLightMap;
14321433
uniforms.pointShadowMap.value = lights.state.pointShadowMap;
14331434
uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
14341435
// TODO (abelnation): add area lights shadow info to uniforms

src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ IncidentLight directLight;
8282
#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )
8383
8484
SpotLight spotLight;
85+
vec4 spotColor;
86+
vec3 spotLightCoord;
87+
bool inSpotLightMap;
88+
8589
#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0
8690
SpotLightShadow spotLightShadow;
8791
#endif
@@ -93,9 +97,29 @@ IncidentLight directLight;
9397
9498
getSpotLightInfo( spotLight, geometry, directLight );
9599
100+
// spot lights are ordered [shadows with maps, shadows without maps, maps without shadows, none]
101+
#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )
102+
#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX
103+
#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
104+
#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS
105+
#else
106+
#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )
107+
#endif
108+
109+
#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )
110+
spotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;
111+
inSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );
112+
spotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );
113+
inSpotLightMap = inSpotLightMap && ( spotColor.a > 0. );
114+
directLight.visible = directLight.visible || inSpotLightMap;
115+
directLight.color = inSpotLightMap ? mix( directLight.color, spotLight.color * spotColor.rgb, spotColor.a ) : directLight.color;
116+
#endif
117+
118+
#undef SPOT_LIGHT_MAP_INDEX
119+
96120
#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
97121
spotLightShadow = spotLightShadows[ i ];
98-
directLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
122+
directLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;
99123
#endif
100124
101125
RE_Direct( directLight, geometry, material, reflectedLight );

src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
export default /* glsl */`
2+
#if NUM_SPOT_LIGHT_COORDS > 0
3+
4+
varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];
5+
6+
#endif
7+
8+
#if NUM_SPOT_LIGHT_MAPS > 0
9+
10+
uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];
11+
12+
#endif
13+
214
#ifdef USE_SHADOWMAP
315
416
#if NUM_DIR_LIGHT_SHADOWS > 0
@@ -20,7 +32,6 @@ export default /* glsl */`
2032
#if NUM_SPOT_LIGHT_SHADOWS > 0
2133
2234
uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];
23-
varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
2435
2536
struct SpotLightShadow {
2637
float shadowBias;
@@ -159,22 +170,22 @@ export default /* glsl */`
159170
texture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +
160171
texture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +
161172
texture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +
162-
mix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),
173+
mix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),
163174
texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),
164175
f.x ) +
165-
mix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),
176+
mix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),
166177
texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),
167178
f.x ) +
168-
mix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),
179+
mix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),
169180
texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),
170181
f.y ) +
171-
mix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),
182+
mix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),
172183
texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),
173184
f.y ) +
174-
mix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),
185+
mix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),
175186
texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),
176187
f.x ),
177-
mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),
188+
mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),
178189
texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),
179190
f.x ),
180191
f.y )

src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
export default /* glsl */`
2+
3+
#if NUM_SPOT_LIGHT_COORDS > 0
4+
5+
uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];
6+
varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];
7+
8+
#endif
9+
210
#ifdef USE_SHADOWMAP
311
412
#if NUM_DIR_LIGHT_SHADOWS > 0
@@ -19,9 +27,6 @@ export default /* glsl */`
1927
2028
#if NUM_SPOT_LIGHT_SHADOWS > 0
2129
22-
uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];
23-
varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
24-
2530
struct SpotLightShadow {
2631
float shadowBias;
2732
float shadowNormalBias;

src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export default /* glsl */`
2-
#ifdef USE_SHADOWMAP
2+
#if defined( USE_SHADOWMAP ) || ( NUM_SPOT_LIGHT_COORDS > 0 )
33
4-
#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0
4+
#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_COORDS > 0 || NUM_POINT_LIGHT_SHADOWS > 0
55
66
// Offsetting the position used for querying occlusion along the world normal can be used to reduce shadow acne.
77
vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );
@@ -22,13 +22,16 @@ export default /* glsl */`
2222
2323
#endif
2424
25-
#if NUM_SPOT_LIGHT_SHADOWS > 0
25+
#if NUM_SPOT_LIGHT_COORDS > 0
2626
2727
#pragma unroll_loop_start
28-
for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {
28+
for ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {
2929
30-
shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias, 0 );
31-
vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * shadowWorldPosition;
30+
shadowWorldPosition = worldPosition;
31+
#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
32+
shadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;
33+
#endif
34+
vSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;
3235
3336
}
3437
#pragma unroll_loop_end

src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ float getShadowMask() {
2828
for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {
2929
3030
spotLight = spotLightShadows[ i ];
31-
shadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
31+
shadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;
3232
3333
}
3434
#pragma unroll_loop_end

0 commit comments

Comments
 (0)