Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreShadowCameraSetupLiSPSM.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 10.9 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2006  Torus Knot Software Ltd
8Copyright (c) 2006 Matthias Fink, netAllied GmbH <matthias.fink@web.de>                                                         
9Also see acknowledgements in Readme.html
10
11This program is free software; you can redistribute it and/or modify it under
12the terms of the GNU Lesser General Public License as published by the Free Software
13Foundation; either version 2 of the License, or (at your option) any later
14version.
15
16This program is distributed in the hope that it will be useful, but WITHOUT
17ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
19
20You should have received a copy of the GNU Lesser General Public License along with
21this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22Place - Suite 330, Boston, MA 02111-1307, USA, or go to
23http://www.gnu.org/copyleft/lesser.txt.
24
25You may alternatively use this source under the terms of a specific version of
26the OGRE Unrestricted License provided you have obtained such a license from
27Torus Knot Software Ltd.
28-----------------------------------------------------------------------------
29*/
30
31#include "OgreStableHeaders.h"
32#include "OgreShadowCameraSetupLiSPSM.h"
33#include "OgreRoot.h"
34#include "OgreSceneManager.h"
35#include "OgreCamera.h"
36#include "OgreLight.h"
37#include "OgrePlane.h"
38#include "OgreConvexBody.h"
39
40namespace Ogre
41{
42
43
44        LiSPSMShadowCameraSetup::LiSPSMShadowCameraSetup(void)
45                : mOptAdjustFactor(0.1f), mUseSimpleNOpt(true)
46        {
47        }
48        //-----------------------------------------------------------------------
49        LiSPSMShadowCameraSetup::~LiSPSMShadowCameraSetup(void)
50        {
51        }
52        //-----------------------------------------------------------------------
53        Matrix4 LiSPSMShadowCameraSetup::calculateLiSPSM(const Matrix4& lightSpace, 
54                const PointListBody& bodyB, const PointListBody& bodyLVS,
55                const SceneManager& sm, const Camera& cam, const Light& light) const
56        {
57                // set up bodyB AAB in light space
58                AxisAlignedBox bodyBAAB_ls;
59                for (size_t i = 0; i < bodyB.getPointCount(); ++i)
60                {
61                        bodyBAAB_ls.merge(lightSpace * bodyB.getPoint(i));
62                }
63
64                // near camera point in light space
65                const Vector3 e_ls = lightSpace * getNearCameraPoint_ws(cam.getViewMatrix(), bodyLVS);
66
67                // C_start has x and y of e and z from the bodyABB_ls (we look down the negative z axis, so take the maximum z value)
68                const Vector3 C_start_ls(e_ls.x, e_ls.y, bodyBAAB_ls.getMaximum().z);
69
70                // calculate the optimal distance between origin and near plane
71                Real n_opt;
72
73                if (mUseSimpleNOpt)
74                        n_opt = calculateNOptSimple(bodyLVS, cam);
75                else
76                        n_opt = calculateNOpt(lightSpace, bodyBAAB_ls, bodyLVS, cam);
77
78                // in case n_opt is null, uniform shadow mapping will be done
79                if (n_opt <= 0.0)
80                {
81                        return Matrix4::IDENTITY;
82                }
83
84                // calculate the projection center C which is n units behind the near plane of P
85                // we look into the negative z direction so add n
86                const Vector3 C(C_start_ls + n_opt * Vector3::UNIT_Z);
87
88                // set up a transformation matrix to transform the light space to its new origin
89                Matrix4 lightSpaceTranslation(Matrix4::IDENTITY);
90                lightSpaceTranslation.setTrans(-C);
91
92                // range from bMin to bMax; d = |B_z_far - B_z_near|
93                Real d = Math::Abs(bodyBAAB_ls.getMaximum().z - bodyBAAB_ls.getMinimum().z);
94
95                // set up the LiSPSM perspective transformation
96                // build up frustum to map P onto the unit cube with (-1/-1/-1) and (+1/+1/+1)
97                Matrix4 P = buildFrustumProjection(-1, 1, -1, 1, n_opt, n_opt + d);
98
99                return P * lightSpaceTranslation;
100        }
101        //-----------------------------------------------------------------------
102        Real LiSPSMShadowCameraSetup::calculateNOpt(const Matrix4& lightSpace, 
103                const AxisAlignedBox& bodyBABB_ls, const PointListBody& bodyLVS, 
104                const Camera& cam) const
105        {
106                // get inverse light space matrix
107                Matrix4 invLightSpace = lightSpace.inverse();
108
109                // get view matrix
110                const Matrix4& viewMatrix = cam.getViewMatrix();
111
112                // calculate z0_ls
113                const Vector3 e_ws  = getNearCameraPoint_ws(viewMatrix, bodyLVS);
114                const Vector3 z0_ls = calculateZ0_ls(lightSpace, e_ws, bodyBABB_ls.getMaximum().z, cam);
115
116                // z1_ls has the same x and y values as z0_ls and the minimum z values of bodyABB_ls
117                const Vector3 z1_ls = Vector3(z0_ls.x, z0_ls.y, bodyBABB_ls.getMinimum().z);
118
119                // world
120                const Vector3 z0_ws = invLightSpace * z0_ls;
121                const Vector3 z1_ws = invLightSpace * z1_ls;
122
123                // eye
124                const Vector3 z0_es = viewMatrix * z0_ws;
125                const Vector3 z1_es = viewMatrix * z1_ws;
126
127                const Real z0 = z0_es.z;
128                const Real z1 = z1_es.z;
129
130                // check if we have to do uniform shadow mapping
131                if ((z0 < 0 && z1 > 0) ||
132                        (z1 < 0 && z0 > 0))
133                {
134                        // apply uniform shadow mapping
135                        return 0.0;
136                }
137                return cam.getNearClipDistance() + Math::Sqrt(z0 * z1) * mOptAdjustFactor;
138        }
139        //-----------------------------------------------------------------------
140        Real LiSPSMShadowCameraSetup::calculateNOptSimple(const PointListBody& bodyLVS, 
141                const Camera& cam) const
142        {
143                // get view matrix
144                const Matrix4& viewMatrix = cam.getViewMatrix();
145
146                // calculate e_es
147                const Vector3 e_ws  = getNearCameraPoint_ws(viewMatrix, bodyLVS);
148                const Vector3 e_es = viewMatrix * e_ws;
149
150                // according to the new formula (mainly for directional lights)
151                // n_opt = zn + sqrt(z0 * z1);
152                // zn is set to Abs(near eye point)
153                // z0 is set to the near camera clip distance
154                // z1 is set to the far camera clip distance
155                return (Math::Abs(e_es.z) + Math::Sqrt(cam.getNearClipDistance() * cam.getFarClipDistance())) * mOptAdjustFactor;
156        }
157        //-----------------------------------------------------------------------
158        Vector3 LiSPSMShadowCameraSetup::calculateZ0_ls(const Matrix4& lightSpace, 
159                const Vector3& e, Real bodyB_zMax_ls, const Camera& cam) const
160        {
161                // z0_ls lies on the intersection point between the planes 'bodyB_ls near plane
162                // (z = bodyB_zNear_ls)' and plane with normal UNIT_X where e_ls lies upon (x = e_ls_x)
163                // and the camera's near clipping plane (ls). We are looking towards the negative
164                // z-direction, so bodyB_zNear_ls equals bodyB_zMax_ls.
165
166                const Vector3& camDir = cam.getDerivedDirection();
167                const Vector3 e_ls = lightSpace * e;
168
169                // set up a plane with the camera direction as normal and e as a point on the plane
170                Plane plane(camDir, e);
171
172                plane = lightSpace * plane;
173
174                // try to intersect plane with a ray from origin V3(e_ls_x, 0.0, bodyB_zNear_ls)T
175                // and direction +/- UNIT_Y
176                Ray ray(Vector3(e_ls.x, 0.0, bodyB_zMax_ls), Vector3::UNIT_Y);
177                std::pair< bool, Real > intersect = ray.intersects(plane);
178
179                // we got an intersection point
180                if (intersect.first == true)
181                {
182                        return ray.getPoint(intersect.second);
183                }
184                else
185                {
186                        // try the other direction
187                        ray = Ray(Vector3(e_ls.x, 0.0, bodyB_zMax_ls), Vector3::NEGATIVE_UNIT_Y);
188                        std::pair< bool, Real > intersect = ray.intersects(plane);
189
190                        // we got an intersection point
191                        if (intersect.first == true)
192                        {
193                                return ray.getPoint(intersect.second);
194                        }
195                        else
196                        {
197                                // failure!
198                                return Vector3(0.0, 0.0, 0.0);
199                        }
200                }
201        }
202        //-----------------------------------------------------------------------
203        Matrix4 LiSPSMShadowCameraSetup::buildFrustumProjection(Real left, Real right, 
204                Real bottom, Real top, Real near, Real far) const
205        {
206                Real m00 = 2 * near / (right - left),
207                        m02 = (right + left) / (right - left),
208                        m11 = 2 * near / (top - bottom),
209                        m12 = (top + bottom) / (top - bottom),
210                        m22 = -(far + near) / (far - near),
211                        m23 = -2 * far * near / (far - near),
212                        m32 = -1;
213
214                Matrix4 m(m00, 0.0, m02, 0.0,
215                        0.0, m11, m12, 0.0,
216                        0.0, 0.0, m22, m23,
217                        0.0, 0.0, m32, 0.0);
218
219                return m;
220        }
221        //-----------------------------------------------------------------------
222        void LiSPSMShadowCameraSetup::getShadowCamera (const SceneManager *sm, const Camera *cam, 
223                const Viewport *vp, const Light *light, Camera *texCam) const
224        {
225                // check availability - viewport not needed
226                OgreAssert(sm != NULL, "SceneManager is NULL");
227                OgreAssert(cam != NULL, "Camera (viewer) is NULL");
228                OgreAssert(light != NULL, "Light is NULL");
229                OgreAssert(texCam != NULL, "Camera (texture) is NULL");
230                mLightFrustumCameraCalculated = false;
231
232
233                // calculate standard shadow mapping matrix
234                Matrix4 LView, LProj;
235                calculateShadowMappingMatrix(*sm, *cam, *light, &LView, &LProj, NULL);
236
237                // build scene bounding box
238                const VisibleObjectsBoundsInfo& visInfo = sm->getShadowCasterBoundsInfo(light);
239                AxisAlignedBox sceneBB = visInfo.aabb;
240                sceneBB.merge(sm->getVisibleObjectsBoundsInfo(cam).aabb);
241                sceneBB.merge(cam->getDerivedPosition());
242
243                // in case the sceneBB is empty (e.g. nothing visible to the cam) simply
244                // return the standard shadow mapping matrix
245                if (sceneBB.isNull())
246                {
247                        texCam->setCustomViewMatrix(true, LView);
248                        texCam->setCustomProjectionMatrix(true, LProj);
249                        return;
250                }
251
252                // calculate the intersection body B
253                mPointListBodyB.reset();
254                calculateB(*sm, *cam, *light, sceneBB, &mPointListBodyB);
255
256                // in case the bodyB is empty (e.g. nothing visible to the light or the cam)
257                // simply return the standard shadow mapping matrix
258                if (mPointListBodyB.getPointCount() == 0)
259                {
260                        texCam->setCustomViewMatrix(true, LView);
261                        texCam->setCustomProjectionMatrix(true, LProj);
262                        return;
263                }
264
265                // transform to light space: y -> -z, z -> y
266                LProj = msNormalToLightSpace * LProj;
267
268                // calculate LVS so it does not need to be calculated twice
269                // calculate the body L \cap V \cap S to make sure all returned points are in
270                // front of the camera
271                calculateLVS(*sm, *cam, *light, sceneBB, &mPointListBodyLVS);
272
273                // fetch the viewing direction
274                const Vector3 viewDir = getLSProjViewDir(LProj * LView, *cam, mPointListBodyLVS);
275
276                // The light space will be rotated in such a way, that the projected light view
277                // always points upwards, so the up-vector is the y-axis (we already prepared the
278                // light space for this usage).The transformation matrix is set up with the
279                // following parameters:
280                // - position is the origin
281                // - the view direction is the calculated viewDir
282                // - the up vector is the y-axis
283                LProj = buildViewMatrix(Vector3::ZERO, viewDir, Vector3::UNIT_Y) * LProj;
284
285                // calculate LiSPSM projection
286                LProj = calculateLiSPSM(LProj * LView, mPointListBodyB, mPointListBodyLVS, *sm, *cam, *light) * LProj;
287
288                // map bodyB to unit cube
289                LProj = transformToUnitCube(LProj * LView, mPointListBodyB) * LProj;
290
291                // transform from light space to normal space: y -> z, z -> -y
292                LProj = msLightSpaceToNormal * LProj;
293
294                // LView = Lv^-1
295                // LProj = Switch_{-ls} * FocusBody * P * L_r * Switch_{ls} * L_p
296                texCam->setCustomViewMatrix(true, LView);
297                texCam->setCustomProjectionMatrix(true, LProj);
298        }
299
300}
301
Note: See TracBrowser for help on using the repository browser.