Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion docs/api/en/lights/SpotLight.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ <h1>[name]</h1>

<h2>Code Example</h2>
<code>
// white spotlight shining from the side, casting a shadow
// white spotlight shining from the side, modulated by a texture, casting a shadow

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

spotLight.castShadow = true;

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

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

<h2>Methods</h2>

Expand Down
11 changes: 10 additions & 1 deletion docs/api/zh/lights/SpotLight.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ <h1>聚光灯([name])</h1>

<h2>代码示例</h2>
<code>
// white spotlight shining from the side, casting a shadow
// white spotlight shining from the side, modulated by a texture, casting a shadow

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

spotLight.castShadow = true;

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

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


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

Expand Down
24 changes: 23 additions & 1 deletion examples/webgl_lights_spotlight.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@

let spotLight, lightHelper, shadowCameraHelper;

let textureUrls, textures;

let gui;

function init() {
Expand Down Expand Up @@ -64,6 +66,18 @@
const ambient = new THREE.AmbientLight( 0xffffff, 0.1 );
scene.add( ambient );

const textureLoader = new THREE.TextureLoader();
textureUrls = [ 'none', 'uv_grid_opengl.jpg', 'sprite2.png', 'colors.png' ];
textures = { none: null }

for ( let i = 1; i < textureUrls.length; i ++ ) {

textures[ textureUrls[ i ] ] = textureLoader.load( 'textures/' + textureUrls[ i ] );
textures[ textureUrls[ i ] ].minFilter = THREE.LinearFilter;
textures[ textureUrls[ i ] ].magFilter = THREE.LinearFilter;

}

spotLight = new THREE.SpotLight( 0xffffff, 1 );
spotLight.position.set( 15, 40, 35 );
spotLight.angle = Math.PI / 4;
Expand Down Expand Up @@ -144,7 +158,8 @@
angle: spotLight.angle,
penumbra: spotLight.penumbra,
decay: spotLight.decay,
focus: spotLight.shadow.focus
focus: spotLight.shadow.focus,
map: 'none'
};

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

} );

gui.add( params, 'map', textureUrls ).onChange( function ( val ) {

spotLight.map = textures[ val ];
render();

} );

gui.open();

}
Expand Down
2 changes: 2 additions & 0 deletions src/lights/SpotLight.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class SpotLight extends Light {
this.penumbra = penumbra;
this.decay = decay; // for physically correct lights, should be 2.

this.map = null;

this.shadow = new SpotLightShadow();

}
Expand Down
3 changes: 2 additions & 1 deletion src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1428,7 +1428,8 @@ function WebGLRenderer( parameters = {} ) {
uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
uniforms.spotShadowMap.value = lights.state.spotShadowMap;
uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
uniforms.spotLightMatrix.value = lights.state.spotLightMatrix;
uniforms.spotLightMap.value = lights.state.spotLightMap;
uniforms.pointShadowMap.value = lights.state.pointShadowMap;
uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
// TODO (abelnation): add area lights shadow info to uniforms
Expand Down
26 changes: 25 additions & 1 deletion src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ IncidentLight directLight;
#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )

SpotLight spotLight;
vec4 spotColor;
vec3 spotLightCoord;
bool inSpotLightMap;

#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0
SpotLightShadow spotLightShadow;
#endif
Expand All @@ -93,9 +97,29 @@ IncidentLight directLight;

getSpotLightInfo( spotLight, geometry, directLight );

// spot lights are ordered [shadows with maps, shadows without maps, maps without shadows, none]
#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )
#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX
#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS
#else
#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )
#endif

#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )
spotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;
inSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );
spotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );
inSpotLightMap = inSpotLightMap && ( spotColor.a > 0. );
directLight.visible = directLight.visible || inSpotLightMap;
directLight.color = inSpotLightMap ? mix( directLight.color, spotLight.color * spotColor.rgb, spotColor.a ) : directLight.color;
#endif

#undef SPOT_LIGHT_MAP_INDEX

#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
spotLightShadow = spotLightShadows[ i ];
directLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
directLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;
#endif

RE_Direct( directLight, geometry, material, reflectedLight );
Expand Down
25 changes: 18 additions & 7 deletions src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
export default /* glsl */`
#if NUM_SPOT_LIGHT_COORDS > 0

varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];

#endif

#if NUM_SPOT_LIGHT_MAPS > 0

uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];

#endif

#ifdef USE_SHADOWMAP

#if NUM_DIR_LIGHT_SHADOWS > 0
Expand All @@ -20,7 +32,6 @@ export default /* glsl */`
#if NUM_SPOT_LIGHT_SHADOWS > 0

uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];
varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];

struct SpotLightShadow {
float shadowBias;
Expand Down Expand Up @@ -159,22 +170,22 @@ export default /* glsl */`
texture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +
texture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +
texture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +
mix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),
mix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),
texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),
f.x ) +
mix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),
mix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),
texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),
f.x ) +
mix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),
mix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),
texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),
f.y ) +
mix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),
mix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),
texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),
f.y ) +
mix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),
mix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),
texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),
f.x ),
mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),
mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),
texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),
f.x ),
f.y )
Expand Down
11 changes: 8 additions & 3 deletions src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
export default /* glsl */`

#if NUM_SPOT_LIGHT_COORDS > 0

uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];
varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];

#endif

#ifdef USE_SHADOWMAP

#if NUM_DIR_LIGHT_SHADOWS > 0
Expand All @@ -19,9 +27,6 @@ export default /* glsl */`

#if NUM_SPOT_LIGHT_SHADOWS > 0

uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];
varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];

struct SpotLightShadow {
float shadowBias;
float shadowNormalBias;
Expand Down
15 changes: 9 additions & 6 deletions src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export default /* glsl */`
#ifdef USE_SHADOWMAP
#if defined( USE_SHADOWMAP ) || ( NUM_SPOT_LIGHT_COORDS > 0 )

#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0
#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_COORDS > 0 || NUM_POINT_LIGHT_SHADOWS > 0

// Offsetting the position used for querying occlusion along the world normal can be used to reduce shadow acne.
vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );
Expand All @@ -22,13 +22,16 @@ export default /* glsl */`

#endif

#if NUM_SPOT_LIGHT_SHADOWS > 0
#if NUM_SPOT_LIGHT_COORDS > 0

#pragma unroll_loop_start
for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {
for ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {

shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias, 0 );
vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * shadowWorldPosition;
shadowWorldPosition = worldPosition;
#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
shadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;
#endif
vSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;

}
#pragma unroll_loop_end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ float getShadowMask() {
for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {

spotLight = spotLightShadows[ i ];
shadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
shadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;

}
#pragma unroll_loop_end
Expand Down
2 changes: 1 addition & 1 deletion src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export default /* glsl */`
#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION )
#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_MAPS > 0

vec4 worldPosition = vec4( transformed, 1.0 );

Expand Down
3 changes: 2 additions & 1 deletion src/renderers/shaders/UniformsLib.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,9 @@ const UniformsLib = {
shadowMapSize: {}
} },

spotLightMap: { value: [] },
spotShadowMap: { value: [] },
spotShadowMatrix: { value: [] },
spotLightMatrix: { value: [] },

pointLights: { value: [], properties: {
color: {},
Expand Down
Loading