2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
7 Copyright (c) 2006 Torus Knot Software Ltd
8 Also see acknowledgements in Readme.html
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22 http://www.gnu.org/copyleft/lesser.txt.
24 You may alternatively use this source under the terms of a specific version of
25 the OGRE Unrestricted License provided you have obtained such a license from
26 Torus Knot Software Ltd.
27 -----------------------------------------------------------------------------
30 #include "OgreStableHeaders.h"
31 #include "OgreCommon.h"
32 #include "OgreSceneManager.h"
33 #include "OgreLight.h"
34 #include "OgreShadowCameraSetup.h"
35 #include "OgreCamera.h"
36 #include "OgreViewport.h"
41 /// Default constructor
42 DefaultShadowCameraSetup::DefaultShadowCameraSetup() {}
45 DefaultShadowCameraSetup::~DefaultShadowCameraSetup() {}
47 /// Default shadow camera setup implementation
48 void DefaultShadowCameraSetup::getShadowCamera (const SceneManager
*sm
, const Camera
*cam
,
49 const Viewport
*vp
, const Light
*light
, Camera
*texCam
, size_t iteration
) const
53 // reset custom view / projection matrix in case already set
54 texCam
->setCustomViewMatrix(false);
55 texCam
->setCustomProjectionMatrix(false);
56 texCam
->setNearClipDistance(light
->_deriveShadowNearClipDistance(cam
));
57 texCam
->setFarClipDistance(light
->_deriveShadowFarClipDistance(cam
));
59 // get the shadow frustum's far distance
60 Real shadowDist
= light
->getShadowFarDistance();
63 // need a shadow distance, make one up
64 shadowDist
= cam
->getNearClipDistance() * 300;
66 Real shadowOffset
= shadowDist
* (sm
->getShadowDirLightTextureOffset());
69 if (light
->getType() == Light::LT_DIRECTIONAL
)
71 // set up the shadow texture
72 // Set ortho projection
73 texCam
->setProjectionType(PT_ORTHOGRAPHIC
);
74 // set ortho window so that texture covers far dist
75 texCam
->setOrthoWindow(shadowDist
* 2, shadowDist
* 2);
77 // Calculate look at position
78 // We want to look at a spot shadowOffset away from near plane
79 // 0.5 is a litle too close for angles
80 Vector3 target
= cam
->getDerivedPosition() +
81 (cam
->getDerivedDirection() * shadowOffset
);
83 // Calculate direction, which same as directional light direction
84 dir
= - light
->getDerivedDirection(); // backwards since point down -z
88 // We want to be in the -ve direction of the light direction
89 // far enough to project for the dir light extrusion distance
90 pos
= target
+ dir
* sm
->getShadowDirectionalLightExtrusionDistance();
92 // Round local x/y position based on a world-space texel; this helps to reduce
93 // jittering caused by the projection moving with the camera
94 // Viewport is 2 * near clip distance across (90 degree fov)
95 //~ Real worldTexelSize = (texCam->getNearClipDistance() * 20) / vp->getActualWidth();
96 //~ pos.x -= fmod(pos.x, worldTexelSize);
97 //~ pos.y -= fmod(pos.y, worldTexelSize);
98 //~ pos.z -= fmod(pos.z, worldTexelSize);
99 Real worldTexelSize
= (shadowDist
* 2) / texCam
->getViewport()->getActualWidth();
101 //get texCam orientation
103 Vector3 up
= Vector3::UNIT_Y
;
104 // Check it's not coincident with dir
105 if (Math::Abs(up
.dotProduct(dir
)) >= 1.0f
)
108 up
= Vector3::UNIT_Z
;
110 // cross twice to rederive, only direction is unaltered
111 Vector3 left
= dir
.crossProduct(up
);
113 up
= dir
.crossProduct(left
);
115 // Derive quaternion from axes
117 q
.FromAxes(left
, up
, dir
);
119 //convert world space camera position into light space
120 Vector3 lightSpacePos
= q
.Inverse() * pos
;
122 //snap to nearest texel
123 lightSpacePos
.x
-= fmod(lightSpacePos
.x
, worldTexelSize
);
124 lightSpacePos
.y
-= fmod(lightSpacePos
.y
, worldTexelSize
);
126 //convert back to world space
127 pos
= q
* lightSpacePos
;
131 else if (light
->getType() == Light::LT_SPOTLIGHT
)
133 // Set perspective projection
134 texCam
->setProjectionType(PT_PERSPECTIVE
);
135 // set FOV slightly larger than the spotlight range to ensure coverage
136 Radian fovy
= light
->getSpotlightOuterAngle()*1.2;
138 if (fovy
.valueDegrees() > 175)
140 texCam
->setFOVy(fovy
);
142 // Calculate position, which same as spotlight position
143 pos
= light
->getDerivedPosition();
145 // Calculate direction, which same as spotlight direction
146 dir
= - light
->getDerivedDirection(); // backwards since point down -z
152 // Set perspective projection
153 texCam
->setProjectionType(PT_PERSPECTIVE
);
154 // Use 120 degree FOV for point light to ensure coverage more area
155 texCam
->setFOVy(Degree(120));
157 // Calculate look at position
158 // We want to look at a spot shadowOffset away from near plane
159 // 0.5 is a litle too close for angles
160 Vector3 target
= cam
->getDerivedPosition() +
161 (cam
->getDerivedDirection() * shadowOffset
);
163 // Calculate position, which same as point light position
164 pos
= light
->getDerivedPosition();
166 dir
= (pos
- target
); // backwards since point down -z
170 // Finally set position
171 texCam
->setPosition(pos
);
173 // Calculate orientation based on direction calculated above
175 // Next section (camera oriented shadow map) abandoned
176 // Always point in the same direction, if we don't do this then
177 // we get 'shadow swimming' as camera rotates
178 // As it is, we get swimming on moving but this is less noticeable
180 // calculate up vector, we want it aligned with cam direction
181 Vector3 up = cam->getDerivedDirection();
182 // Check it's not coincident with dir
183 if (up.dotProduct(dir) >= 1.0f)
189 Vector3 up
= Vector3::UNIT_Y
;
190 // Check it's not coincident with dir
191 if (Math::Abs(up
.dotProduct(dir
)) >= 1.0f
)
194 up
= Vector3::UNIT_Z
;
196 // cross twice to rederive, only direction is unaltered
197 Vector3 left
= dir
.crossProduct(up
);
199 up
= dir
.crossProduct(left
);
201 // Derive quaternion from axes
203 q
.FromAxes(left
, up
, dir
);
204 texCam
->setOrientation(q
);