Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreShadowCameraSetupPlaneOptimal.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

File size: 11.7 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
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25
26#include "OgreStableHeaders.h"
27#include "OgreCommon.h"
28#include "OgreSceneManager.h"
29#include "OgreLight.h"
30#include "OgreShadowCameraSetupPlaneOptimal.h"
31#include "OgreNumerics.h"
32#include "OgreCamera.h"
33#include "OgreViewport.h"
34
35
36namespace Ogre
37{
38        // --------------------------------------------------------------------
39        Matrix4 PlaneOptimalShadowCameraSetup::computeConstrainedProjection(
40                const Vector4& pinhole, 
41                const std::vector<Vector4>& fpoint, 
42                const std::vector<Vector2>& constraint) const
43        {
44                // NOTE: will assume the z coordinates should be decided such that
45                // the first 3 points (in fpoint) will have post projective
46                // z coordinates of about +1 and the 4th (in fpoint) will have a
47                // post projective z coordinate of about -1.
48
49                // TODO: could use SVD to avoid arbitrarily choosing one
50                // matrix element to be 1.0 (and thereby fix the scale).
51
52                Matrix4 ret;
53                int i;
54                bool incrPrecision = false; // use to control numerical solving
55
56                if(fpoint.size() < 4 || constraint.size() < 4) {
57                        return Matrix4::IDENTITY;
58                }
59
60                // allocate memory
61                PreciseReal **mat = NULL;
62                PreciseReal **backmat = NULL;
63                {
64                        mat = new PreciseReal*[11];
65                        if(incrPrecision)
66                                backmat = new PreciseReal*[11];
67                        for(i=0; i<11; i++) 
68                        {
69                                mat[i] = new PreciseReal[11];
70                                if(incrPrecision)
71                                        backmat[i] = new PreciseReal[11];
72                        }
73                }
74
75                // set up linear system to solve for all rows of projective matrix
76                // except for the 3rd which corresponds to mapping of z values
77
78                // we choose a nonzero element of the last row to set to the arbitrary
79                // constant 1.0.
80                int nzind = 3;
81                PreciseReal col[11];
82                PreciseReal backcol[11];
83
84                // fill in light position constraints
85                mat[0][0] = pinhole.x;
86                mat[0][1] = pinhole.y;
87                mat[0][2] = pinhole.z;
88                mat[0][3] = pinhole.w;
89                for(i=4; i<11; i++)
90                        mat[0][i] = 0.0;
91                col[0] = 0.0;
92
93                for(i=0; i<11; i++)
94                        mat[1][i] = 0.0;
95                mat[1][4] = pinhole.x;
96                mat[1][5] = pinhole.y;
97                mat[1][6] = pinhole.z;
98                mat[1][7] = pinhole.w;
99                col[1] = 0.0;
100
101                PreciseReal larr[4];
102                larr[0] = pinhole.x;
103                larr[1] = pinhole.y;
104                larr[2] = pinhole.z;
105                larr[3] = pinhole.w;
106                for(i=0; i<8; i++)
107                        mat[2][i] = 0.0;
108                int ind = 8;
109                for(i=0; i<4; i++)
110                {
111                        if(nzind == i)
112                                continue;
113                        mat[2][ind++] = larr[i];
114                }
115                col[2] = -larr[nzind];
116
117                // fill in all the other constraints
118                int row=3;
119                for(i=0; i<4; i++)
120                {
121                        int j;
122                        larr[0] = fpoint[i].x;
123                        larr[1] = fpoint[i].y;
124                        larr[2] = fpoint[i].z;
125                        larr[3] = fpoint[i].w;
126
127                        // lexel s coordinate constraint
128                        for(j=0; j<4; j++)
129                                mat[row][j] = larr[j];
130                        for(j=4; j<8; j++)
131                                mat[row][j] = 0.0;
132                        ind=8;
133                        for(j=0; j<4; j++)
134                        {
135                                if(nzind==j)
136                                        continue;
137                                mat[row][ind++] = larr[j] * (-constraint[i].x);
138                        }
139                        col[row] = larr[nzind] * constraint[i].x;
140                        ++row;
141
142                        // lexel t coordinate constraint
143                        for(j=0; j<4; j++)
144                                mat[row][j] = 0.0;
145                        for(j=4; j<8; j++)
146                                mat[row][j] = larr[j-4];
147
148                        ind=8;
149                        for(j=0; j<4; j++)
150                        {
151                                if(nzind==j)
152                                        continue;
153                                mat[row][ind++] = larr[j] * (-constraint[i].y);
154                        }
155                        col[row] = larr[nzind] * constraint[i].y;
156                        ++row;
157                }
158
159                // copy the matrix and vector for later computation
160                if(incrPrecision)
161                {
162                        for (i=0; i<11; i++)
163                        {
164                                for(int j=0; j<11; j++)
165                                        backmat[i][j] = mat[i][j];
166                                backcol[i] = col[i];
167                        }
168                }
169
170                // solve for the matrix elements
171                if(!NumericSolver::solveNxNLinearSysDestr(11, mat, col)) 
172                {
173                        // error solving for projective matrix (rows 1,2,4)
174                }
175
176                // get a little more precision
177                if(incrPrecision)
178                {
179                        for (int k=0; k<3; k++)
180                        {
181                                PreciseReal nvec[11];
182                                for(i=0; i<11; i++)
183                                {
184                                        int j;
185                                        nvec[i] = backmat[i][0] * col[0];
186                                        mat[i][0] = backmat[i][0];
187                                        for(j=1; j<11; j++) 
188                                        {
189                                                nvec[i] += backmat[i][j] * col[j];
190                                                mat[i][j] = backmat[i][j];
191                                        }
192                                        nvec[i] -= backcol[i];
193                                }
194                                if(!NumericSolver::solveNxNLinearSysDestr(11, mat, nvec)) 
195                                {
196                                        // error solving for increased precision rows 1,2,4
197                                }
198                                for(i=0; i<11; i++)
199                                        col[i] -= nvec[i];
200                        }
201                }
202
203                PreciseReal row4[4];
204                ind = 8;
205                for(i=0; i<4; i++)
206                {
207                        if (i == nzind)
208                                row4[i] = 1.0;
209                        else
210                                row4[i] = col[ind++];
211                }
212
213
214                // now solve for the 3rd row which affects depth precision
215                PreciseReal zrow[4];
216
217                // we want the affine skew such that isoplanes of constant depth are parallel to
218                // the world plane of interest
219                // NOTE: recall we perturbed the last fpoint off the plane, so we'll again modify
220                // this one since we want 3 points on the plane = far plane, and 1 on the near plane
221                int nearind = 3;
222                for(i=0; i<3; i++)
223                {
224                        mat[i][0] = fpoint[i].x;
225                        mat[i][1] = fpoint[i].y;
226                        mat[i][2] = fpoint[i].z;
227                        mat[i][3] = 1.0;
228                        zrow[i] = (row4[0] * fpoint[i].x +
229                                row4[1] * fpoint[i].y +
230                                row4[2] * fpoint[i].z +
231                                row4[3]) * 0.99 ;
232                }
233                mat[3][0] = fpoint[nearind].x;
234                mat[3][1] = fpoint[nearind].y;
235                mat[3][2] = fpoint[nearind].z;
236                mat[3][3] = 1.0;
237                zrow[3] =        -row4[0] * fpoint[nearind].x -
238                        row4[1] * fpoint[nearind].y -
239                        row4[2] * fpoint[nearind].z -
240                        row4[3] ;
241
242                // solve for the z row of the matrix
243                if(!NumericSolver::solveNxNLinearSysDestr(4, mat, zrow)) 
244                {
245                        // error solving for projective matrix (row 3)
246                }
247
248                // set projective texture matrix
249                ret = Matrix4(  col[0],  col[1],  col[2],  col[3],
250                        col[4],  col[5],  col[6],  col[7], 
251                        zrow[0], zrow[1], zrow[2], zrow[3],
252                        row4[0], row4[1], row4[2], row4[3] );
253
254
255                // check for clip
256                Vector4 testCoord = ret * fpoint[0];
257                if(testCoord.w < 0.0) 
258                        ret = ret *  (-1.0);
259
260                // free memory
261                for (i=0; i<11; i++)
262                {
263                        if (mat[i])
264                                delete [] mat[i];
265                        if (incrPrecision)
266                                delete [] backmat[i];
267                }
268                delete [] mat;
269                if(incrPrecision)
270                        delete [] backmat;
271
272                return ret;
273
274        }
275
276        // --------------------------------------------------------------------
277
278        /// Construct object to consider a specified plane of interest
279        PlaneOptimalShadowCameraSetup::PlaneOptimalShadowCameraSetup(MovablePlane* plane)
280        {
281                m_plane = plane;
282        }
283
284        /// Destructor
285        PlaneOptimalShadowCameraSetup::~PlaneOptimalShadowCameraSetup() {}
286
287        /// Implements the plane optimal shadow camera setup algorithm
288        void PlaneOptimalShadowCameraSetup::getShadowCamera (const SceneManager *sm, const Camera *cam, 
289                const Viewport *vp, const Light *light, Camera *texCam) const
290        {
291                // get the plane transformed by the parent node(s)
292                // Also, make sure the plane is normalized
293                Plane worldPlane = m_plane->_getDerivedPlane();
294                worldPlane.normalise();
295
296                // get camera's projection matrix
297                Matrix4 camProjection = cam->getProjectionMatrix() * cam->getViewMatrix();
298
299                // get the world points to constrain
300                std::vector<Vector4> vhull;
301                cam->forwardIntersect(worldPlane, &vhull);
302                if (vhull.size() < 4)
303                        return;
304
305                // make sure the last point is a finite point (not point at infinity)
306        if (vhull[3].w == 0.0)
307        {
308                    int finiteIndex = -1;
309                    for (uint loopIndex = 0; loopIndex < vhull.size(); loopIndex++)
310                    {
311                            if (vhull[loopIndex].w != 0.0)
312                {
313                                    finiteIndex = loopIndex;
314                    break;
315                }
316                    }
317                    if (finiteIndex == -1)
318                    {
319                // there are no finite points, which means camera doesn't see plane of interest.
320                // so we don't care what the shadow map matrix is
321                // We'll map points off the shadow map so they aren't even stored
322                Matrix4 crazyMat(0.0, 0.0, 0.0, 5.0,
323                                 0.0, 0.0, 0.0, 5.0,
324                                 0.0, 0.0, 0.0, 5.0,
325                                 0.0, 0.0, 0.0, 1.0);
326                texCam->setCustomViewMatrix(true, Matrix4::IDENTITY);
327                texCam->setCustomProjectionMatrix(true, crazyMat);     
328                return;
329                    }
330            // swap finite point to last point
331            std::swap(vhull[3], vhull[finiteIndex]);
332        }
333        vhull.resize(4);
334
335                // get the post-projective coordinate constraints
336                std::vector<Vector2> constraint;
337                for (int i=0; i<4; i++)
338                {
339                        Vector4 postProjPt = camProjection * vhull[i];
340                        postProjPt *= 1.0 / postProjPt.w;
341                        constraint.push_back(Vector2(postProjPt.x, postProjPt.y));
342                }
343
344                // perturb one point so we don't have coplanarity
345                const Vector4& pinhole = light->getAs4DVector();
346                const Vector4& oldPt = vhull.back();
347        Vector4 newPt;
348        if (pinhole.w == 0)
349        {
350            // It's directional light
351            static const Real NEAR_SCALE = 100.0;
352            newPt = oldPt + (pinhole * (cam->getNearClipDistance() * NEAR_SCALE));
353        }
354        else
355        {
356            // It's point or spotlight
357                    Vector4 displacement = oldPt - pinhole;
358                    Vector3 displace3    = Vector3(displacement.x, displacement.y, displacement.z);
359                    Real dotProd = fabs(displace3.dotProduct(worldPlane.normal));
360                    static const Real NEAR_FACTOR = 0.05;
361                    newPt = pinhole + (displacement * (cam->getNearClipDistance() * NEAR_FACTOR / dotProd));
362        }
363                vhull.back() = newPt;
364
365                // solve for the matrix that stabilizes the plane
366                Matrix4 customMatrix = computeConstrainedProjection(pinhole, vhull, constraint);
367
368        if (pinhole.w == 0)
369        {
370            // TODO: factor into view and projection pieces.
371            // Note: In fact, it's unnecessary to factor into view and projection pieces,
372            // but if we do, we will more according with academic requirement :)
373            texCam->setCustomViewMatrix(true, Matrix4::IDENTITY);
374            texCam->setCustomProjectionMatrix(true, customMatrix);
375            return;
376        }
377
378        Vector3 tempPos = Vector3(pinhole.x, pinhole.y, pinhole.z);
379
380                // factor into view and projection pieces
381                Matrix4    translation(1.0, 0.0, 0.0,  tempPos.x,
382                        0.0, 1.0, 0.0,  tempPos.y,
383                        0.0, 0.0, 1.0,  tempPos.z,
384                        0.0, 0.0, 0.0,  1.0);
385                Matrix4 invTranslation(1.0, 0.0, 0.0, -tempPos.x,
386                        0.0, 1.0, 0.0, -tempPos.y,
387                        0.0, 0.0, 1.0, -tempPos.z,
388                        0.0, 0.0, 0.0,  1.0);
389                Matrix4 tempMatrix = customMatrix * translation;
390                Vector3 zRow(-tempMatrix[3][0], -tempMatrix[3][1], -tempMatrix[3][2]);
391                zRow.normalise();
392                Vector3 up;
393                if (zRow.y == 1.0)
394                        up = Vector3(1,0,0);
395                else
396                        up = Vector3(0,1,0);
397                Vector3 xDir = up.crossProduct(zRow);
398                xDir.normalise();
399                up = zRow.crossProduct(xDir);
400                Matrix4 rotation(xDir.x, up.x, zRow.x, 0.0,
401                        xDir.y, up.y, zRow.y, 0.0,
402                        xDir.z, up.z, zRow.z, 0.0,
403                        0.0,  0.0,    0.0, 1.0 );
404                Matrix4 customProj = tempMatrix * rotation;
405                Matrix4 customView = rotation.transpose() * invTranslation;
406                // note: now customProj * (0,0,0,1)^t = (0, 0, k, 0)^t for k some constant
407                // note: also customProj's 4th row is (0, 0, c, 0) for some negative c.
408
409
410                // set the shadow map camera
411                texCam->setCustomViewMatrix(true, customView);
412                texCam->setCustomProjectionMatrix(true, customProj);
413        }
414
415}
416
Note: See TracBrowser for help on using the repository browser.