Patch 2793067: fix trunk with OGRE_THREAD_SUPPORT=1 on non-Windows platforms (don...
[ogre3d.git] / OgreMain / src / OgreShadowCameraSetup.cpp
blobd81c010cda2ced439e9f67f598534ee6f328050c
1 /*
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
13 version.
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"
39 namespace Ogre
41 /// Default constructor
42 DefaultShadowCameraSetup::DefaultShadowCameraSetup() {}
44 /// Destructor
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
51 Vector3 pos, dir;
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();
61 if (!shadowDist)
63 // need a shadow distance, make one up
64 shadowDist = cam->getNearClipDistance() * 300;
66 Real shadowOffset = shadowDist * (sm->getShadowDirLightTextureOffset());
68 // Directional lights
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
85 dir.normalise();
87 // Calculate position
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)
107 // Use camera up
108 up = Vector3::UNIT_Z;
110 // cross twice to rederive, only direction is unaltered
111 Vector3 left = dir.crossProduct(up);
112 left.normalise();
113 up = dir.crossProduct(left);
114 up.normalise();
115 // Derive quaternion from axes
116 Quaternion q;
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;
130 // Spotlight
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;
137 // limit angle
138 if (fovy.valueDegrees() > 175)
139 fovy = Degree(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
147 dir.normalise();
149 // Point light
150 else
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
167 dir.normalise();
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)
185 // Use camera up
186 up = cam->getUp();
189 Vector3 up = Vector3::UNIT_Y;
190 // Check it's not coincident with dir
191 if (Math::Abs(up.dotProduct(dir)) >= 1.0f)
193 // Use camera up
194 up = Vector3::UNIT_Z;
196 // cross twice to rederive, only direction is unaltered
197 Vector3 left = dir.crossProduct(up);
198 left.normalise();
199 up = dir.crossProduct(left);
200 up.normalise();
201 // Derive quaternion from axes
202 Quaternion q;
203 q.FromAxes(left, up, dir);
204 texCam->setOrientation(q);