Skip to content

Commit 3f79a4f

Browse files
committed
SpotLightMap
1 parent 840872b commit 3f79a4f

17 files changed

+206
-48
lines changed

docs/api/en/lights/SpotLight.html

Lines changed: 11 additions & 2 deletions
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(textureUrl);
2728

2829
spotLight.castShadow = true;
2930

@@ -47,7 +48,7 @@ <h2>Examples</h2>
4748
<h2>Constructor</h2>
4849

4950

50-
<h3>[name]( [param:Integer color], [param:Float intensity], [param:Float distance], [param:Radians angle], [param:Float penumbra], [param:Float decay] )</h3>
51+
<h3>[name]( [param:Integer color], [param:Float intensity], [param:Float distance], [param:Radians angle], [param:Float penumbra], [param:Float decay], [param:Texture map] )</h3>
5152
<p>
5253
[page:Integer color] - (optional) hexadecimal color of the light. Default is 0xffffff (white).<br />
5354
[page:Float intensity] - (optional) numeric value of the light's strength/intensity. Default is 1.<br /><br />
@@ -57,6 +58,7 @@ <h3>[name]( [param:Integer color], [param:Float intensity], [param:Float distanc
5758
[page:Float penumbra] - Percent of the spotlight cone that is attenuated due to penumbra.
5859
Takes values between zero and 1. Default is zero.<br />
5960
[page:Float decay] - The amount the light dims along the distance of the light.<br /><br />
61+
[page:Texture map] - (optional) a texture to modulate the light.<br /><br />
6062

6163
Creates a new [name].
6264
</p>
@@ -158,6 +160,13 @@ <h3>[property:Object3D target]</h3>
158160
The spotlight will now track the target object.
159161
</p>
160162

163+
<h3>[property:Texture map]</h3>
164+
<p>
165+
A [page:Texture] used to modulate the color of the light. The spot light color is mixed
166+
with the RGB value of this texture, with a ratio corresponding to its
167+
alpha value. The cookie-like masking effect is reproduced using pixel values (0, 0, 0, 1-cookie_value).
168+
*Warning*: [param:SpotLight map] is disabled if [param:SpotLight castShadow] is *false*.
169+
</p>
161170

162171
<h2>Methods</h2>
163172

docs/api/zh/lights/SpotLight.html

Lines changed: 12 additions & 2 deletions
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(textureUrl);
2627

2728
spotLight.castShadow = true;
2829

@@ -46,14 +47,15 @@ <h2>例子</h2>
4647
<h2>构造器(Constructor)</h2>
4748

4849

49-
<h3>[name]( [param:Integer color], [param:Float intensity], [param:Float distance], [param:Radians angle], [param:Float penumbra], [param:Float decay] )</h3>
50+
<h3>[name]( [param:Integer color], [param:Float intensity], [param:Float distance], [param:Radians angle], [param:Float penumbra], [param:Float decay], [param:Texture map] )</h3>
5051
<p>
5152
[page:Integer color] - (可选参数) 十六进制光照颜色。 缺省值 0xffffff (白色)。<br />
5253
[page:Float intensity] - (可选参数) 光照强度。 缺省值 1。<br /><br />
5354
[page:Float distance] - 从光源发出光的最大距离,其强度根据光源的距离线性衰减。 <br />
5455
[page:Radians angle] - 光线散射角度,最大为Math.PI/2。<br />
5556
[page:Float penumbra] - 聚光锥的半影衰减百分比。在0和1之间的值。默认为0。<br />
5657
[page:Float decay] - 沿着光照距离的衰减量。<br /><br />
58+
[page:Texture map] - (optional) a texture to modulate the light.<br /><br />
5759

5860
创建一个新的聚光灯。
5961
</p>
@@ -139,6 +141,14 @@ <h3>[property:Object3D target]</h3>
139141
完成上述操作后,聚光灯现在就可以追踪到目标对像了。
140142
</p>
141143

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

143153
<h2>方法(Methods)</h2>
144154

6.64 KB
Loading

examples/webgl_lights_spotlight.html

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - spotlight by <a href="http://master-domain.com" target="_blank" rel="noopener">Master James</a><br />
1313
</div>
1414

15+
<video id="video" loop crossOrigin="anonymous" webkit-playsinline style="display:none">
16+
<source src="textures/sintel.ogv" type='video/ogg; codecs="theora, vorbis"'>
17+
<source src="textures/sintel.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
18+
</video>
19+
1520
<script type="module">
1621

1722
import * as THREE from '../build/three.module.js';
@@ -24,6 +29,8 @@
2429

2530
let spotLight, lightHelper, shadowCameraHelper;
2631

32+
let textureUrls, textures;
33+
2734
let gui;
2835

2936
function init() {
@@ -52,6 +59,23 @@
5259
const ambient = new THREE.AmbientLight( 0xffffff, 0.1 );
5360
scene.add( ambient );
5461

62+
const textureLoader = new THREE.TextureLoader();
63+
textureUrls = [ 'none', 'sintel (video)', 'uv_grid_opengl.jpg', 'sprite2.png', 'colors.png' ];
64+
textures = { none: null };
65+
66+
const video = document.getElementById( 'video' );
67+
textures[textureUrls[1]] = new THREE.VideoTexture( video );
68+
textures[textureUrls[1]].minFilter = THREE.LinearFilter;
69+
textures[textureUrls[1]].magFilter = THREE.LinearFilter;
70+
71+
for ( let i = 2; i < textureUrls.length; ++i ) {
72+
73+
textures[textureUrls[i]] = textureLoader.load( 'textures/' + textureUrls[i] );
74+
textures[textureUrls[i]].minFilter = THREE.LinearFilter;
75+
textures[textureUrls[i]].magFilter = THREE.LinearFilter;
76+
77+
}
78+
5579
spotLight = new THREE.SpotLight( 0xffffff, 1 );
5680
spotLight.position.set( 15, 40, 35 );
5781
spotLight.angle = Math.PI / 4;
@@ -132,7 +156,8 @@
132156
angle: spotLight.angle,
133157
penumbra: spotLight.penumbra,
134158
decay: spotLight.decay,
135-
focus: spotLight.shadow.focus
159+
focus: spotLight.shadow.focus,
160+
map: 'none'
136161
};
137162

138163
gui.addColor( params, 'light color' ).onChange( function ( val ) {
@@ -185,6 +210,15 @@
185210

186211
} );
187212

213+
gui.add( params, 'map', textureUrls ).onChange( function ( val ) {
214+
215+
if (spotLight.map && spotLight.map.isVideoTexture) video.pause();
216+
spotLight.map = textures[val];
217+
if (spotLight.map && spotLight.map.isVideoTexture) video.play();
218+
animate();
219+
220+
} );
221+
188222
gui.open();
189223

190224
}
@@ -193,7 +227,14 @@
193227

194228
buildGui();
195229

196-
render();
230+
animate();
231+
232+
function animate() {
233+
234+
if (spotLight.map && spotLight.map.isVideoTexture) requestAnimationFrame( animate );
235+
render();
236+
237+
}
197238

198239
</script>
199240

examples/webgl_shadowmap_viewer.html

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import { ShadowMapViewer } from './jsm/utils/ShadowMapViewer.js';
2222

2323
let camera, scene, renderer, clock, stats;
24-
let dirLight, spotLight;
24+
let dirLight, spotLight, spotLight2;
2525
let torusKnot, cube;
2626
let dirLightShadowMapViewer, spotLightShadowMapViewer;
2727

@@ -46,15 +46,17 @@
4646
camera.position.set( 0, 15, 35 );
4747

4848
scene = new THREE.Scene();
49+
const textureLoader = new THREE.TextureLoader();
4950

5051
// Lights
5152

5253
scene.add( new THREE.AmbientLight( 0x404040 ) );
5354

5455
spotLight = new THREE.SpotLight( 0xffffff );
5556
spotLight.name = 'Spot Light';
57+
spotLight.intensity = 0.6;
5658
spotLight.angle = Math.PI / 5;
57-
spotLight.penumbra = 0.3;
59+
spotLight.penumbra = 0.2;
5860
spotLight.position.set( 10, 10, 5 );
5961
spotLight.castShadow = true;
6062
spotLight.shadow.camera.near = 8;
@@ -65,8 +67,25 @@
6567

6668
scene.add( new THREE.CameraHelper( spotLight.shadow.camera ) );
6769

70+
spotLight2 = new THREE.SpotLight( 0xffffff );
71+
spotLight2.name = 'Textured Spot Light';
72+
spotLight2.intensity = 0.6;
73+
spotLight2.angle = Math.PI / 5;
74+
spotLight2.penumbra = 0.3;
75+
spotLight2.position.set( -10, 5, 0 );
76+
spotLight2.castShadow = true;
77+
spotLight2.shadow.camera.near = 2;
78+
spotLight2.shadow.camera.far = 25;
79+
spotLight2.shadow.mapSize.width = 1024;
80+
spotLight2.shadow.mapSize.height = 1024;
81+
spotLight2.map = textureLoader.load( 'textures/uv_grid_opengl.jpg' );
82+
scene.add( spotLight2 );
83+
84+
scene.add( new THREE.CameraHelper( spotLight2.shadow.camera ) );
85+
6886
dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
6987
dirLight.name = 'Dir. Light';
88+
dirLight.intensity = 0.3;
7089
dirLight.position.set( 0, 10, 0 );
7190
dirLight.castShadow = true;
7291
dirLight.shadow.camera.near = 1;

src/lights/SpotLight.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Object3D } from '../core/Object3D.js';
44

55
class SpotLight extends Light {
66

7-
constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 1 ) {
7+
constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 1, map = null ) {
88

99
super( color, intensity );
1010

@@ -19,6 +19,7 @@ class SpotLight extends Light {
1919
this.angle = angle;
2020
this.penumbra = penumbra;
2121
this.decay = decay; // for physically correct lights, should be 2.
22+
this.map = map;
2223

2324
this.shadow = new SpotLightShadow();
2425

src/renderers/WebGLRenderer.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1458,7 +1458,8 @@ function WebGLRenderer( parameters ) {
14581458
uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
14591459
uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
14601460
uniforms.spotShadowMap.value = lights.state.spotShadowMap;
1461-
uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
1461+
uniforms.spotLightMatrix.value = lights.state.spotLightMatrix;
1462+
uniforms.spotLightMap.value = lights.state.spotLightMap;
14621463
uniforms.pointShadowMap.value = lights.state.pointShadowMap;
14631464
uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
14641465
// TODO (abelnation): add area lights shadow info to uniforms

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

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ IncidentLight directLight;
5757
#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )
5858
5959
SpotLight spotLight;
60+
vec4 spotColor;
61+
vec3 spotLightCoord;
62+
bool inSpotLightMap;
63+
6064
#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0
6165
SpotLightShadow spotLightShadow;
6266
#endif
@@ -68,9 +72,29 @@ IncidentLight directLight;
6872
6973
getSpotDirectLightIrradiance( spotLight, geometry, directLight );
7074
71-
#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
72-
spotLightShadow = spotLightShadows[ i ];
73-
directLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
75+
// spot lights are ordered [shadows with maps, shadows without maps, maps without shadows, none]
76+
#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )
77+
#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX
78+
#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
79+
#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS
80+
#else
81+
#define SPOT_LIGHT_MAP_INDEX (UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS)
82+
#endif
83+
84+
#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )
85+
spotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;
86+
inSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );
87+
spotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );
88+
inSpotLightMap = inSpotLightMap && ( spotColor.a > 0. );
89+
directLight.visible = directLight.visible || inSpotLightMap;
90+
directLight.color = inSpotLightMap ? mix( directLight.color, spotLight.color * spotColor.rgb, spotColor.a ) : directLight.color;
91+
#endif
92+
93+
#undef SPOT_LIGHT_MAP_INDEX
94+
95+
#if defined(USE_SHADOWMAP) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
96+
spotLightShadow = spotLightShadows[ i ];
97+
directLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;
7498
#endif
7599
76100
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;

0 commit comments

Comments
 (0)