Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Textured lighting as a spotLight.map property #14621

Closed
wants to merge 3 commits into from
Closed
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
13 changes: 11 additions & 2 deletions docs/api/lights/SpotLight.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ <h2>Other Examples</h2>

<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

var spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( 100, 1000, 100 );
Expand All @@ -61,13 +61,15 @@ <h2>Code Example</h2>
spotLight.shadow.camera.far = 4000;
spotLight.shadow.camera.fov = 30;

spotLight.map = new THREE.TextureLoader().load(textureUrl);

scene.add( spotLight );
</code>

<h2>Constructor</h2>


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

Creates a new [name].
</p>
Expand Down Expand Up @@ -175,6 +178,12 @@ <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).
</p>

<h2>Methods</h2>

Expand Down
42 changes: 40 additions & 2 deletions examples/webgl_lights_spotlight.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@

<script src="js/Detector.js"></script>

<video id="video" autoplay loop crossOrigin="anonymous" webkit-playsinline style="display:none">
<source src="textures/sintel.ogv" type='video/ogg; codecs="theora, vorbis"'>
<source src="textures/sintel.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
</video>

<script>

if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
Expand All @@ -52,6 +57,8 @@

var spotLight, lightHelper, shadowCameraHelper;

var textureUrls, textures;

var gui;

function init() {
Expand Down Expand Up @@ -80,6 +87,22 @@
var ambient = new THREE.AmbientLight( 0xffffff, 0.1 );
scene.add( ambient );

var textureLoader = new THREE.TextureLoader();
textureUrls = [ 'none', 'sintel (video)', 'UV_Grid_Sm.jpg', 'roughness_map.jpg', 'memorial.png', 'sprite2.png', 'perlin-512.png' ];
textures = { none: null };

var video = document.getElementById( 'video' );
textures[textureUrls[1]] = new THREE.VideoTexture( video );
textures[textureUrls[1]].minFilter = THREE.LinearFilter;
textures[textureUrls[1]].magFilter = THREE.LinearFilter;

for ( var i = 2; 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 @@ -157,7 +180,8 @@
distance: spotLight.distance,
angle: spotLight.angle,
penumbra: spotLight.penumbra,
decay: spotLight.decay
decay: spotLight.decay,
map: 'none'
}

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

} );

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

spotLight.map = textures[url];
animate();

} );

gui.open();

}
Expand All @@ -211,7 +242,14 @@

buildGui();

render();
animate();

function animate() {

if (spotLight.map && spotLight.map.isVideoTexture) requestAnimationFrame( animate );
render();

}

</script>

Expand Down
25 changes: 22 additions & 3 deletions examples/webgl_shadowmap_viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();

var camera, scene, renderer, clock, stats;
var dirLight, spotLight;
var dirLight, spotLight, spotLight2;
var torusKnot, cube;
var dirLightShadowMapViewer, spotLightShadowMapViewer;

Expand All @@ -65,15 +65,17 @@
camera.position.set( 0, 15, 35 );

scene = new THREE.Scene();
var textureLoader = new THREE.TextureLoader();

// Lights

scene.add( new THREE.AmbientLight( 0x404040 ) );
scene.add( new THREE.AmbientLight( 0x202020 ) );

spotLight = new THREE.SpotLight( 0xffffff );
spotLight.name = 'Spot Light';
spotLight.intensity = 0.3;
spotLight.angle = Math.PI / 5;
spotLight.penumbra = 0.3;
spotLight.penumbra = 0.2;
spotLight.position.set( 10, 10, 5 );
spotLight.castShadow = true;
spotLight.shadow.camera.near = 8;
Expand All @@ -84,8 +86,25 @@

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

spotLight2 = new THREE.SpotLight( 0xffffff );
spotLight2.name = 'Textured Spot Light';
spotLight2.intensity = 0.3;
spotLight2.angle = Math.PI / 5;
spotLight2.penumbra = 0.3;
spotLight2.position.set( -10, 5, 0 );
spotLight2.castShadow = true;
spotLight2.shadow.camera.near = 8;
spotLight2.shadow.camera.far = 25;
spotLight2.shadow.mapSize.width = 1024;
spotLight2.shadow.mapSize.height = 1024;
spotLight2.map = textureLoader.load( 'textures/UV_Grid_Sm.jpg' );
scene.add( spotLight2 );

scene.add( new THREE.CameraHelper( spotLight2.shadow.camera ) );

dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
dirLight.name = 'Dir. Light';
dirLight.intensity = 0.3;
dirLight.position.set( 0, 10, 0 );
dirLight.castShadow = true;
dirLight.shadow.camera.near = 1;
Expand Down
3 changes: 2 additions & 1 deletion src/lights/SpotLight.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Object3D } from '../core/Object3D.js';
* @author alteredq / http://alteredqualia.com/
*/

function SpotLight( color, intensity, distance, angle, penumbra, decay ) {
function SpotLight( color, intensity, distance, angle, penumbra, decay, map ) {

Light.call( this, color, intensity );

Expand Down Expand Up @@ -40,6 +40,7 @@ function SpotLight( color, intensity, distance, angle, penumbra, decay ) {
this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2.

this.shadow = new SpotLightShadow();
this.map = map || null;

}

Expand Down
5 changes: 5 additions & 0 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,7 @@ function WebGLRenderer( parameters ) {
lightsHash.directionalLength !== lightsStateHash.directionalLength ||
lightsHash.pointLength !== lightsStateHash.pointLength ||
lightsHash.spotLength !== lightsStateHash.spotLength ||
lightsHash.spotMapLength !== lightsStateHash.spotMapLength ||
lightsHash.rectAreaLength !== lightsStateHash.rectAreaLength ||
lightsHash.hemiLength !== lightsStateHash.hemiLength ||
lightsHash.shadowsLength !== lightsStateHash.shadowsLength ) {
Expand All @@ -1455,6 +1456,7 @@ function WebGLRenderer( parameters ) {
lightsHash.directionalLength = lightsStateHash.directionalLength;
lightsHash.pointLength = lightsStateHash.pointLength;
lightsHash.spotLength = lightsStateHash.spotLength;
lightsHash.spotMapLength = lightsStateHash.spotMapLength;
lightsHash.rectAreaLength = lightsStateHash.rectAreaLength;
lightsHash.hemiLength = lightsStateHash.hemiLength;
lightsHash.shadowsLength = lightsStateHash.shadowsLength;
Expand Down Expand Up @@ -1568,6 +1570,7 @@ function WebGLRenderer( parameters ) {
lightsHash.directionalLength = lightsStateHash.directionalLength;
lightsHash.pointLength = lightsStateHash.pointLength;
lightsHash.spotLength = lightsStateHash.spotLength;
lightsHash.spotMapLength = lightsStateHash.spotMapLength;
lightsHash.rectAreaLength = lightsStateHash.rectAreaLength;
lightsHash.hemiLength = lightsStateHash.hemiLength;
lightsHash.shadowsLength = lightsStateHash.shadowsLength;
Expand All @@ -1585,6 +1588,7 @@ function WebGLRenderer( parameters ) {

uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
uniforms.spotMap.value = lights.state.spotMap;
uniforms.spotShadowMap.value = lights.state.spotShadowMap;
uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
uniforms.pointShadowMap.value = lights.state.pointShadowMap;
Expand Down Expand Up @@ -1644,6 +1648,7 @@ function WebGLRenderer( parameters ) {
lightsHash.directionalLength !== lightsStateHash.directionalLength ||
lightsHash.pointLength !== lightsStateHash.pointLength ||
lightsHash.spotLength !== lightsStateHash.spotLength ||
lightsHash.spotMapLength !== lightsStateHash.spotMapLength ||
lightsHash.rectAreaLength !== lightsStateHash.rectAreaLength ||
lightsHash.hemiLength !== lightsStateHash.hemiLength ||
lightsHash.shadowsLength !== lightsStateHash.shadowsLength ) ) {
Expand Down
29 changes: 27 additions & 2 deletions src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,41 @@ IncidentLight directLight;
#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )

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

#pragma unroll_loop
for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
for ( int i = 0; i < NUM_SPOT_LIGHT_MAPS; i ++ ) {

spotLight = spotLights[ i ];

getSpotDirectLightIrradiance( spotLight, geometry, directLight );

spotShadowCoord = vSpotShadowCoord[ i ].xyz / vSpotShadowCoord[ i ].w;
inSpotLightMap = all( lessThan( abs( spotShadowCoord * 2. - 1. ), vec3( 1.0 ) ) );
spotColor = texture2D( spotMap[ i ], spotShadowCoord.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;

#ifdef USE_SHADOWMAP
directLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
#endif

RE_Direct( directLight, geometry, material, reflectedLight );

}

#pragma unroll_loop
for ( int i = NUM_SPOT_LIGHT_MAPS; i < NUM_SPOT_LIGHTS; i ++ ) {

spotLight = spotLights[ i ];

getSpotDirectLightIrradiance( spotLight, geometry, directLight );

#ifdef USE_SHADOWMAP
directLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
directLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
#endif

RE_Direct( directLight, geometry, material, reflectedLight );
Expand Down
13 changes: 12 additions & 1 deletion src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
#if NUM_SPOT_LIGHT_COORDS > 0

varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_COORDS ];

#endif

#if NUM_SPOT_LIGHT_MAPS > 0

uniform sampler2D spotMap[ NUM_SPOT_LIGHT_MAPS ];

#endif

#ifdef USE_SHADOWMAP

#if NUM_DIR_LIGHTS > 0
Expand All @@ -10,7 +22,6 @@
#if NUM_SPOT_LIGHTS > 0

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

#endif

Expand Down
14 changes: 7 additions & 7 deletions src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
#if NUM_SPOT_LIGHT_COORDS > 0

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

#endif

#ifdef USE_SHADOWMAP

#if NUM_DIR_LIGHTS > 0
Expand All @@ -7,13 +14,6 @@

#endif

#if NUM_SPOT_LIGHTS > 0

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

#endif

#if NUM_POINT_LIGHTS > 0

uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];
Expand Down
18 changes: 9 additions & 9 deletions src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
#ifdef USE_SHADOWMAP

#if NUM_DIR_LIGHTS > 0
#if NUM_SPOT_LIGHT_COORDS > 0

#pragma unroll_loop
for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
for ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {

vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;
vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;

}

#endif
#endif

#ifdef USE_SHADOWMAP

#if NUM_SPOT_LIGHTS > 0
#if NUM_DIR_LIGHTS > 0

#pragma unroll_loop
for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {

vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;
vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;

}

Expand Down
2 changes: 1 addition & 1 deletion src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )
#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || NUM_SPOT_LIGHT_MAPS > 0

vec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );

Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/UniformsLib.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ var UniformsLib = {
shadowMapSize: {}
} },

spotMap: { value: [] },
spotShadowMap: { value: [] },
spotShadowMatrix: { value: [] },

Expand Down
Loading