@@ -11,6 +11,23 @@ var CubeLoader = new THREE.CubeTextureLoader();
1111
1212var probeCache = { } ;
1313
14+ function distanceOfPointFromPlane ( positionOnPlane , planeNormal , p1 ) {
15+ // the d value in the plane equation a*x + b*y + c*z=d
16+ var d = planeNormal . dot ( positionOnPlane ) ;
17+
18+ // distance of point from plane
19+ return ( d - planeNormal . dot ( p1 ) ) / planeNormal . length ( ) ;
20+ }
21+
22+ function nearestPointInPlane ( positionOnPlane , planeNormal , p1 , out ) {
23+ var t = distanceOfPointFromPlane ( positionOnPlane , planeNormal , p1 ) ;
24+ // closest point on the plane
25+ out . copy ( planeNormal ) ;
26+ out . multiplyScalar ( t ) ;
27+ out . add ( p1 ) ;
28+ return out ;
29+ }
30+
1431/**
1532 * Light component.
1633 */
@@ -42,6 +59,7 @@ module.exports.Component = registerComponent('light', {
4259 shadowCameraBottom : { default : - 5 , if : { castShadow : true } } ,
4360 shadowCameraLeft : { default : - 5 , if : { castShadow : true } } ,
4461 shadowCameraVisible : { default : false , if : { castShadow : true } } ,
62+ shadowCameraAutoTarget : { default : '' , if : { type : [ 'spot' , 'directional' ] } } ,
4563 shadowMapHeight : { default : 512 , if : { castShadow : true } } ,
4664 shadowMapWidth : { default : 512 , if : { castShadow : true } } ,
4765 shadowRadius : { default : 1 , if : { castShadow : true } }
@@ -141,11 +159,59 @@ module.exports.Component = registerComponent('light', {
141159 return ;
142160 }
143161
162+ if ( data . shadowCameraAutoTarget ) {
163+ this . shadowCameraAutoTargetEls = Array . from ( document . querySelectorAll ( data . shadowCameraAutoTarget ) ) ;
164+ }
165+
144166 // No light yet or light type has changed. Create and add light.
145167 this . setLight ( this . data ) ;
146168 this . updateShadow ( ) ;
147169 } ,
148170
171+ tick : ( function tickSetup ( ) {
172+ var bbox = new THREE . Box3 ( ) ;
173+ var normal = new THREE . Vector3 ( ) ;
174+ var cameraWorldPosition = new THREE . Vector3 ( ) ;
175+ var tempMat = new THREE . Matrix4 ( ) ;
176+ var sphere = new THREE . Sphere ( ) ;
177+ var tempVector = new THREE . Vector3 ( ) ;
178+
179+ return function tick ( ) {
180+ if (
181+ this . data . type === 'directional' &&
182+ this . light . shadow &&
183+ this . light . shadow . camera instanceof THREE . OrthographicCamera &&
184+ this . shadowCameraAutoTargetEls . length
185+ ) {
186+ var camera = this . light . shadow . camera ;
187+ camera . getWorldDirection ( normal ) ;
188+ camera . getWorldPosition ( cameraWorldPosition ) ;
189+ tempMat . copy ( camera . matrixWorld ) ;
190+ tempMat . invert ( ) ;
191+
192+ camera . near = 1 ;
193+ camera . left = 100000 ;
194+ camera . right = - 100000 ;
195+ camera . top = - 100000 ;
196+ camera . bottom = 100000 ;
197+ this . shadowCameraAutoTargetEls . forEach ( function ( el ) {
198+ bbox . setFromObject ( el . object3D ) ;
199+ bbox . getBoundingSphere ( sphere ) ;
200+ var distanceToPlane = distanceOfPointFromPlane ( cameraWorldPosition , normal , sphere . center ) ;
201+ var pointOnCameraPlane = nearestPointInPlane ( cameraWorldPosition , normal , sphere . center , tempVector ) ;
202+
203+ var pointInXYPlane = pointOnCameraPlane . applyMatrix4 ( tempMat ) ;
204+ camera . near = Math . min ( - distanceToPlane - sphere . radius - 1 , camera . near ) ;
205+ camera . left = Math . min ( - sphere . radius + pointInXYPlane . x , camera . left ) ;
206+ camera . right = Math . max ( sphere . radius + pointInXYPlane . x , camera . right ) ;
207+ camera . top = Math . max ( sphere . radius + pointInXYPlane . y , camera . top ) ;
208+ camera . bottom = Math . min ( - sphere . radius + pointInXYPlane . y , camera . bottom ) ;
209+ } ) ;
210+ camera . updateProjectionMatrix ( ) ;
211+ }
212+ } ;
213+ } ( ) ) ,
214+
149215 setLight : function ( data ) {
150216 var el = this . el ;
151217 var newLight = this . getLight ( data ) ;
0 commit comments